[InstCombine] Signed saturation patterns
[llvm-core.git] / lib / Target / Mips / MipsLegalizerInfo.cpp
blobbb4a1d902d75d093c05759ed7b58dae9846dab2f
1 //===- MipsLegalizerInfo.cpp ------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 /// \file
9 /// This file implements the targeting of the Machinelegalizer class for Mips.
10 /// \todo This should be generated by TableGen.
11 //===----------------------------------------------------------------------===//
13 #include "MipsLegalizerInfo.h"
14 #include "MipsTargetMachine.h"
15 #include "llvm/CodeGen/GlobalISel/LegalizerHelper.h"
17 using namespace llvm;
19 struct TypesAndMemOps {
20 LLT ValTy;
21 LLT PtrTy;
22 unsigned MemSize;
23 bool MustBeNaturallyAligned;
26 static bool
27 CheckTy0Ty1MemSizeAlign(const LegalityQuery &Query,
28 std::initializer_list<TypesAndMemOps> SupportedValues) {
29 for (auto &Val : SupportedValues) {
30 if (Val.ValTy != Query.Types[0])
31 continue;
32 if (Val.PtrTy != Query.Types[1])
33 continue;
34 if (Val.MemSize != Query.MMODescrs[0].SizeInBits)
35 continue;
36 if (Val.MustBeNaturallyAligned &&
37 Query.MMODescrs[0].SizeInBits % Query.MMODescrs[0].AlignInBits != 0)
38 continue;
39 return true;
41 return false;
44 static bool CheckTyN(unsigned N, const LegalityQuery &Query,
45 std::initializer_list<LLT> SupportedValues) {
46 for (auto &Val : SupportedValues)
47 if (Val == Query.Types[N])
48 return true;
49 return false;
52 MipsLegalizerInfo::MipsLegalizerInfo(const MipsSubtarget &ST) {
53 using namespace TargetOpcode;
55 const LLT s1 = LLT::scalar(1);
56 const LLT s32 = LLT::scalar(32);
57 const LLT s64 = LLT::scalar(64);
58 const LLT v16s8 = LLT::vector(16, 8);
59 const LLT v8s16 = LLT::vector(8, 16);
60 const LLT v4s32 = LLT::vector(4, 32);
61 const LLT v2s64 = LLT::vector(2, 64);
62 const LLT p0 = LLT::pointer(0, 32);
64 getActionDefinitionsBuilder({G_SUB, G_MUL})
65 .legalFor({s32})
66 .clampScalar(0, s32, s32);
68 getActionDefinitionsBuilder(G_ADD)
69 .legalIf([=, &ST](const LegalityQuery &Query) {
70 if (CheckTyN(0, Query, {s32}))
71 return true;
72 if (ST.hasMSA() && CheckTyN(0, Query, {v16s8, v8s16, v4s32, v2s64}))
73 return true;
74 return false;
76 .clampScalar(0, s32, s32);
78 getActionDefinitionsBuilder({G_UADDO, G_UADDE, G_USUBO, G_USUBE, G_UMULO})
79 .lowerFor({{s32, s1}});
81 getActionDefinitionsBuilder(G_UMULH)
82 .legalFor({s32})
83 .maxScalar(0, s32);
85 getActionDefinitionsBuilder({G_LOAD, G_STORE})
86 .legalIf([=, &ST](const LegalityQuery &Query) {
87 if (CheckTy0Ty1MemSizeAlign(Query, {{s32, p0, 8, ST.hasMips32r6()},
88 {s32, p0, 16, ST.hasMips32r6()},
89 {s32, p0, 32, ST.hasMips32r6()},
90 {p0, p0, 32, ST.hasMips32r6()},
91 {s64, p0, 64, ST.hasMips32r6()}}))
92 return true;
93 if (ST.hasMSA() &&
94 CheckTy0Ty1MemSizeAlign(Query, {{v16s8, p0, 128, false},
95 {v8s16, p0, 128, false},
96 {v4s32, p0, 128, false},
97 {v2s64, p0, 128, false}}))
98 return true;
99 return false;
101 .minScalar(0, s32);
103 getActionDefinitionsBuilder(G_IMPLICIT_DEF)
104 .legalFor({s32, s64});
106 getActionDefinitionsBuilder(G_UNMERGE_VALUES)
107 .legalFor({{s32, s64}});
109 getActionDefinitionsBuilder(G_MERGE_VALUES)
110 .legalFor({{s64, s32}});
112 getActionDefinitionsBuilder({G_ZEXTLOAD, G_SEXTLOAD})
113 .legalForTypesWithMemDesc({{s32, p0, 8, 8},
114 {s32, p0, 16, 8}})
115 .clampScalar(0, s32, s32);
117 getActionDefinitionsBuilder({G_ZEXT, G_SEXT})
118 .legalIf([](const LegalityQuery &Query) { return false; })
119 .maxScalar(0, s32);
121 getActionDefinitionsBuilder(G_TRUNC)
122 .legalIf([](const LegalityQuery &Query) { return false; })
123 .maxScalar(1, s32);
125 getActionDefinitionsBuilder(G_SELECT)
126 .legalForCartesianProduct({p0, s32, s64}, {s32})
127 .minScalar(0, s32)
128 .minScalar(1, s32);
130 getActionDefinitionsBuilder(G_BRCOND)
131 .legalFor({s32})
132 .minScalar(0, s32);
134 getActionDefinitionsBuilder(G_BRJT)
135 .legalFor({{p0, s32}});
137 getActionDefinitionsBuilder(G_BRINDIRECT)
138 .legalFor({p0});
140 getActionDefinitionsBuilder(G_PHI)
141 .legalFor({p0, s32, s64})
142 .minScalar(0, s32);
144 getActionDefinitionsBuilder({G_AND, G_OR, G_XOR})
145 .legalFor({s32})
146 .clampScalar(0, s32, s32);
148 getActionDefinitionsBuilder({G_SDIV, G_SREM, G_UREM, G_UDIV})
149 .legalFor({s32})
150 .minScalar(0, s32)
151 .libcallFor({s64});
153 getActionDefinitionsBuilder({G_SHL, G_ASHR, G_LSHR})
154 .legalFor({{s32, s32}})
155 .clampScalar(1, s32, s32)
156 .clampScalar(0, s32, s32);
158 getActionDefinitionsBuilder(G_ICMP)
159 .legalForCartesianProduct({s32}, {s32, p0})
160 .clampScalar(1, s32, s32)
161 .minScalar(0, s32);
163 getActionDefinitionsBuilder(G_CONSTANT)
164 .legalFor({s32})
165 .clampScalar(0, s32, s32);
167 getActionDefinitionsBuilder({G_GEP, G_INTTOPTR})
168 .legalFor({{p0, s32}});
170 getActionDefinitionsBuilder(G_PTRTOINT)
171 .legalFor({{s32, p0}});
173 getActionDefinitionsBuilder(G_FRAME_INDEX)
174 .legalFor({p0});
176 getActionDefinitionsBuilder({G_GLOBAL_VALUE, G_JUMP_TABLE})
177 .legalFor({p0});
179 getActionDefinitionsBuilder(G_DYN_STACKALLOC)
180 .lowerFor({{p0, s32}});
182 getActionDefinitionsBuilder(G_VASTART)
183 .legalFor({p0});
185 // FP instructions
186 getActionDefinitionsBuilder(G_FCONSTANT)
187 .legalFor({s32, s64});
189 getActionDefinitionsBuilder({G_FADD, G_FSUB, G_FMUL, G_FDIV, G_FABS, G_FSQRT})
190 .legalFor({s32, s64});
192 getActionDefinitionsBuilder(G_FCMP)
193 .legalFor({{s32, s32}, {s32, s64}})
194 .minScalar(0, s32);
196 getActionDefinitionsBuilder({G_FCEIL, G_FFLOOR})
197 .libcallFor({s32, s64});
199 getActionDefinitionsBuilder(G_FPEXT)
200 .legalFor({{s64, s32}});
202 getActionDefinitionsBuilder(G_FPTRUNC)
203 .legalFor({{s32, s64}});
205 // FP to int conversion instructions
206 getActionDefinitionsBuilder(G_FPTOSI)
207 .legalForCartesianProduct({s32}, {s64, s32})
208 .libcallForCartesianProduct({s64}, {s64, s32})
209 .minScalar(0, s32);
211 getActionDefinitionsBuilder(G_FPTOUI)
212 .libcallForCartesianProduct({s64}, {s64, s32})
213 .lowerForCartesianProduct({s32}, {s64, s32})
214 .minScalar(0, s32);
216 // Int to FP conversion instructions
217 getActionDefinitionsBuilder(G_SITOFP)
218 .legalForCartesianProduct({s64, s32}, {s32})
219 .libcallForCartesianProduct({s64, s32}, {s64})
220 .minScalar(1, s32);
222 getActionDefinitionsBuilder(G_UITOFP)
223 .libcallForCartesianProduct({s64, s32}, {s64})
224 .customForCartesianProduct({s64, s32}, {s32})
225 .minScalar(1, s32);
227 getActionDefinitionsBuilder(G_SEXT_INREG).lower();
229 computeTables();
230 verify(*ST.getInstrInfo());
233 bool MipsLegalizerInfo::legalizeCustom(MachineInstr &MI,
234 MachineRegisterInfo &MRI,
235 MachineIRBuilder &MIRBuilder,
236 GISelChangeObserver &Observer) const {
238 using namespace TargetOpcode;
240 MIRBuilder.setInstr(MI);
241 const MipsSubtarget &STI =
242 static_cast<const MipsSubtarget &>(MIRBuilder.getMF().getSubtarget());
243 const LLT s32 = LLT::scalar(32);
244 const LLT s64 = LLT::scalar(64);
246 switch (MI.getOpcode()) {
247 case G_UITOFP: {
248 Register Dst = MI.getOperand(0).getReg();
249 Register Src = MI.getOperand(1).getReg();
250 LLT DstTy = MRI.getType(Dst);
251 LLT SrcTy = MRI.getType(Src);
253 if (SrcTy != s32)
254 return false;
255 if (DstTy != s32 && DstTy != s64)
256 return false;
258 // Let 0xABCDEFGH be given unsigned in MI.getOperand(1). First let's convert
259 // unsigned to double. Mantissa has 52 bits so we use following trick:
260 // First make floating point bit mask 0x43300000ABCDEFGH.
261 // Mask represents 2^52 * 0x1.00000ABCDEFGH i.e. 0x100000ABCDEFGH.0 .
262 // Next, subtract 2^52 * 0x1.0000000000000 i.e. 0x10000000000000.0 from it.
263 // Done. Trunc double to float if needed.
265 MachineInstrBuilder Bitcast = MIRBuilder.buildInstr(
266 STI.isFP64bit() ? Mips::BuildPairF64_64 : Mips::BuildPairF64, {s64},
267 {Src, MIRBuilder.buildConstant(s32, UINT32_C(0x43300000))});
268 Bitcast.constrainAllUses(MIRBuilder.getTII(), *STI.getRegisterInfo(),
269 *STI.getRegBankInfo());
271 MachineInstrBuilder TwoP52FP = MIRBuilder.buildFConstant(
272 s64, BitsToDouble(UINT64_C(0x4330000000000000)));
274 if (DstTy == s64)
275 MIRBuilder.buildFSub(Dst, Bitcast, TwoP52FP);
276 else {
277 MachineInstrBuilder ResF64 = MIRBuilder.buildFSub(s64, Bitcast, TwoP52FP);
278 MIRBuilder.buildFPTrunc(Dst, ResF64);
281 MI.eraseFromParent();
282 break;
284 default:
285 return false;
288 return true;
291 static bool SelectMSA3OpIntrinsic(MachineInstr &MI, unsigned Opcode,
292 MachineIRBuilder &MIRBuilder,
293 const MipsSubtarget &ST) {
294 assert(ST.hasMSA() && "MSA intrinsic not supported on target without MSA.");
295 if (!MIRBuilder.buildInstr(Opcode)
296 .add(MI.getOperand(0))
297 .add(MI.getOperand(2))
298 .add(MI.getOperand(3))
299 .constrainAllUses(MIRBuilder.getTII(), *ST.getRegisterInfo(),
300 *ST.getRegBankInfo()))
301 return false;
302 MI.eraseFromParent();
303 return true;
306 static bool MSA3OpIntrinsicToGeneric(MachineInstr &MI, unsigned Opcode,
307 MachineIRBuilder &MIRBuilder,
308 const MipsSubtarget &ST) {
309 assert(ST.hasMSA() && "MSA intrinsic not supported on target without MSA.");
310 MIRBuilder.buildInstr(Opcode)
311 .add(MI.getOperand(0))
312 .add(MI.getOperand(2))
313 .add(MI.getOperand(3));
314 MI.eraseFromParent();
315 return true;
318 bool MipsLegalizerInfo::legalizeIntrinsic(MachineInstr &MI,
319 MachineRegisterInfo &MRI,
320 MachineIRBuilder &MIRBuilder) const {
321 const MipsSubtarget &ST =
322 static_cast<const MipsSubtarget &>(MI.getMF()->getSubtarget());
323 const MipsInstrInfo &TII = *ST.getInstrInfo();
324 const MipsRegisterInfo &TRI = *ST.getRegisterInfo();
325 const RegisterBankInfo &RBI = *ST.getRegBankInfo();
326 MIRBuilder.setInstr(MI);
328 switch (MI.getIntrinsicID()) {
329 case Intrinsic::memcpy:
330 case Intrinsic::memset:
331 case Intrinsic::memmove:
332 if (createMemLibcall(MIRBuilder, MRI, MI) ==
333 LegalizerHelper::UnableToLegalize)
334 return false;
335 MI.eraseFromParent();
336 return true;
337 case Intrinsic::trap: {
338 MachineInstr *Trap = MIRBuilder.buildInstr(Mips::TRAP);
339 MI.eraseFromParent();
340 return constrainSelectedInstRegOperands(*Trap, TII, TRI, RBI);
342 case Intrinsic::vacopy: {
343 Register Tmp = MRI.createGenericVirtualRegister(LLT::pointer(0, 32));
344 MachinePointerInfo MPO;
345 MIRBuilder.buildLoad(Tmp, MI.getOperand(2),
346 *MI.getMF()->getMachineMemOperand(
347 MPO, MachineMemOperand::MOLoad, 4, 4));
348 MIRBuilder.buildStore(Tmp, MI.getOperand(1),
349 *MI.getMF()->getMachineMemOperand(
350 MPO, MachineMemOperand::MOStore, 4, 4));
351 MI.eraseFromParent();
352 return true;
354 case Intrinsic::mips_addv_b:
355 case Intrinsic::mips_addv_h:
356 case Intrinsic::mips_addv_w:
357 case Intrinsic::mips_addv_d:
358 return MSA3OpIntrinsicToGeneric(MI, TargetOpcode::G_ADD, MIRBuilder, ST);
359 case Intrinsic::mips_addvi_b:
360 return SelectMSA3OpIntrinsic(MI, Mips::ADDVI_B, MIRBuilder, ST);
361 case Intrinsic::mips_addvi_h:
362 return SelectMSA3OpIntrinsic(MI, Mips::ADDVI_H, MIRBuilder, ST);
363 case Intrinsic::mips_addvi_w:
364 return SelectMSA3OpIntrinsic(MI, Mips::ADDVI_W, MIRBuilder, ST);
365 case Intrinsic::mips_addvi_d:
366 return SelectMSA3OpIntrinsic(MI, Mips::ADDVI_D, MIRBuilder, ST);
367 default:
368 break;
370 return true;