xref: /freebsd/contrib/llvm-project/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp (revision 1db9f3b21e39176dd5b67cf8ac378633b172463e)
1 //===-- RISCVLegalizerInfo.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 RISC-V.
10 /// \todo This should be generated by TableGen.
11 //===----------------------------------------------------------------------===//
12 
13 #include "RISCVLegalizerInfo.h"
14 #include "RISCVMachineFunctionInfo.h"
15 #include "RISCVSubtarget.h"
16 #include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h"
17 #include "llvm/CodeGen/GlobalISel/LegalizerHelper.h"
18 #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
19 #include "llvm/CodeGen/MachineRegisterInfo.h"
20 #include "llvm/CodeGen/TargetOpcodes.h"
21 #include "llvm/CodeGen/ValueTypes.h"
22 #include "llvm/IR/DerivedTypes.h"
23 #include "llvm/IR/Type.h"
24 
25 using namespace llvm;
26 using namespace LegalityPredicates;
27 using namespace LegalizeMutations;
28 
29 // Is this type supported by scalar FP arithmetic operations given the current
30 // subtarget.
31 static LegalityPredicate typeIsScalarFPArith(unsigned TypeIdx,
32                                              const RISCVSubtarget &ST) {
33   return [=, &ST](const LegalityQuery &Query) {
34     return Query.Types[TypeIdx].isScalar() &&
35            ((ST.hasStdExtF() && Query.Types[TypeIdx].getSizeInBits() == 32) ||
36             (ST.hasStdExtD() && Query.Types[TypeIdx].getSizeInBits() == 64));
37   };
38 }
39 
40 RISCVLegalizerInfo::RISCVLegalizerInfo(const RISCVSubtarget &ST)
41     : STI(ST), XLen(STI.getXLen()), sXLen(LLT::scalar(XLen)) {
42   const LLT sDoubleXLen = LLT::scalar(2 * XLen);
43   const LLT p0 = LLT::pointer(0, XLen);
44   const LLT s1 = LLT::scalar(1);
45   const LLT s8 = LLT::scalar(8);
46   const LLT s16 = LLT::scalar(16);
47   const LLT s32 = LLT::scalar(32);
48   const LLT s64 = LLT::scalar(64);
49 
50   using namespace TargetOpcode;
51 
52   getActionDefinitionsBuilder({G_ADD, G_SUB, G_AND, G_OR, G_XOR})
53       .legalFor({s32, sXLen})
54       .widenScalarToNextPow2(0)
55       .clampScalar(0, s32, sXLen);
56 
57   getActionDefinitionsBuilder(
58       {G_UADDE, G_UADDO, G_USUBE, G_USUBO}).lower();
59 
60   getActionDefinitionsBuilder({G_SADDO, G_SSUBO}).minScalar(0, sXLen).lower();
61 
62   auto &ShiftActions = getActionDefinitionsBuilder({G_ASHR, G_LSHR, G_SHL});
63   if (ST.is64Bit())
64     ShiftActions.customFor({{s32, s32}});
65   ShiftActions.legalFor({{s32, s32}, {s32, sXLen}, {sXLen, sXLen}})
66       .widenScalarToNextPow2(0)
67       .clampScalar(1, s32, sXLen)
68       .clampScalar(0, s32, sXLen)
69       .minScalarSameAs(1, 0);
70 
71   if (ST.is64Bit()) {
72     getActionDefinitionsBuilder({G_ZEXT, G_SEXT, G_ANYEXT})
73         .legalFor({{sXLen, s32}})
74         .maxScalar(0, sXLen);
75 
76     getActionDefinitionsBuilder(G_SEXT_INREG)
77         .customFor({sXLen})
78         .maxScalar(0, sXLen)
79         .lower();
80   } else {
81     getActionDefinitionsBuilder({G_ZEXT, G_SEXT, G_ANYEXT}).maxScalar(0, sXLen);
82 
83     getActionDefinitionsBuilder(G_SEXT_INREG).maxScalar(0, sXLen).lower();
84   }
85 
86   // Merge/Unmerge
87   for (unsigned Op : {G_MERGE_VALUES, G_UNMERGE_VALUES}) {
88     auto &MergeUnmergeActions = getActionDefinitionsBuilder(Op);
89     unsigned BigTyIdx = Op == G_MERGE_VALUES ? 0 : 1;
90     unsigned LitTyIdx = Op == G_MERGE_VALUES ? 1 : 0;
91     if (XLen == 32 && ST.hasStdExtD()) {
92       MergeUnmergeActions.legalIf(
93           all(typeIs(BigTyIdx, s64), typeIs(LitTyIdx, s32)));
94     }
95     MergeUnmergeActions.widenScalarToNextPow2(LitTyIdx, XLen)
96         .widenScalarToNextPow2(BigTyIdx, XLen)
97         .clampScalar(LitTyIdx, sXLen, sXLen)
98         .clampScalar(BigTyIdx, sXLen, sXLen);
99   }
100 
101   getActionDefinitionsBuilder({G_FSHL, G_FSHR}).lower();
102 
103   auto &RotateActions = getActionDefinitionsBuilder({G_ROTL, G_ROTR});
104   if (ST.hasStdExtZbb() || ST.hasStdExtZbkb()) {
105     RotateActions.legalFor({{s32, sXLen}, {sXLen, sXLen}});
106     // Widen s32 rotate amount to s64 so SDAG patterns will match.
107     if (ST.is64Bit())
108       RotateActions.widenScalarIf(all(typeIs(0, s32), typeIs(1, s32)),
109                                   changeTo(1, sXLen));
110   }
111   RotateActions.lower();
112 
113   getActionDefinitionsBuilder(G_BITREVERSE).maxScalar(0, sXLen).lower();
114 
115   auto &BSWAPActions = getActionDefinitionsBuilder(G_BSWAP);
116   if (ST.hasStdExtZbb() || ST.hasStdExtZbkb())
117     BSWAPActions.legalFor({sXLen}).clampScalar(0, sXLen, sXLen);
118   else
119     BSWAPActions.maxScalar(0, sXLen).lower();
120 
121   auto &CountZerosActions = getActionDefinitionsBuilder({G_CTLZ, G_CTTZ});
122   auto &CountZerosUndefActions =
123       getActionDefinitionsBuilder({G_CTLZ_ZERO_UNDEF, G_CTTZ_ZERO_UNDEF});
124   if (ST.hasStdExtZbb()) {
125     CountZerosActions.legalFor({{s32, s32}, {sXLen, sXLen}})
126         .clampScalar(0, s32, sXLen)
127         .widenScalarToNextPow2(0)
128         .scalarSameSizeAs(1, 0);
129   } else {
130     CountZerosActions.maxScalar(0, sXLen).scalarSameSizeAs(1, 0).lower();
131     CountZerosUndefActions.maxScalar(0, sXLen).scalarSameSizeAs(1, 0);
132   }
133   CountZerosUndefActions.lower();
134 
135   auto &CTPOPActions = getActionDefinitionsBuilder(G_CTPOP);
136   if (ST.hasStdExtZbb()) {
137     CTPOPActions.legalFor({{s32, s32}, {sXLen, sXLen}})
138         .clampScalar(0, s32, sXLen)
139         .widenScalarToNextPow2(0)
140         .scalarSameSizeAs(1, 0);
141   } else {
142     CTPOPActions.maxScalar(0, sXLen).scalarSameSizeAs(1, 0).lower();
143   }
144 
145   getActionDefinitionsBuilder({G_CONSTANT, G_IMPLICIT_DEF})
146       .legalFor({s32, sXLen, p0})
147       .widenScalarToNextPow2(0)
148       .clampScalar(0, s32, sXLen);
149 
150   getActionDefinitionsBuilder(G_ICMP)
151       .legalFor({{sXLen, sXLen}, {sXLen, p0}})
152       .widenScalarToNextPow2(1)
153       .clampScalar(1, sXLen, sXLen)
154       .clampScalar(0, sXLen, sXLen);
155 
156   auto &SelectActions = getActionDefinitionsBuilder(G_SELECT).legalFor(
157       {{s32, sXLen}, {p0, sXLen}});
158   if (XLen == 64 || ST.hasStdExtD())
159     SelectActions.legalFor({{s64, sXLen}});
160   SelectActions.widenScalarToNextPow2(0)
161       .clampScalar(0, s32, (XLen == 64 || ST.hasStdExtD()) ? s64 : s32)
162       .clampScalar(1, sXLen, sXLen);
163 
164   auto &LoadStoreActions =
165       getActionDefinitionsBuilder({G_LOAD, G_STORE})
166           .legalForTypesWithMemDesc({{s32, p0, s8, 8},
167                                      {s32, p0, s16, 16},
168                                      {s32, p0, s32, 32},
169                                      {p0, p0, sXLen, XLen}});
170   auto &ExtLoadActions =
171       getActionDefinitionsBuilder({G_SEXTLOAD, G_ZEXTLOAD})
172           .legalForTypesWithMemDesc({{s32, p0, s8, 8}, {s32, p0, s16, 16}});
173   if (XLen == 64) {
174     LoadStoreActions.legalForTypesWithMemDesc({{s64, p0, s8, 8},
175                                                {s64, p0, s16, 16},
176                                                {s64, p0, s32, 32},
177                                                {s64, p0, s64, 64}});
178     ExtLoadActions.legalForTypesWithMemDesc(
179         {{s64, p0, s8, 8}, {s64, p0, s16, 16}, {s64, p0, s32, 32}});
180   } else if (ST.hasStdExtD()) {
181     LoadStoreActions.legalForTypesWithMemDesc({{s64, p0, s64, 64}});
182   }
183   LoadStoreActions.clampScalar(0, s32, sXLen).lower();
184   ExtLoadActions.widenScalarToNextPow2(0).clampScalar(0, s32, sXLen).lower();
185 
186   getActionDefinitionsBuilder({G_PTR_ADD, G_PTRMASK}).legalFor({{p0, sXLen}});
187 
188   getActionDefinitionsBuilder(G_PTRTOINT)
189       .legalFor({{sXLen, p0}})
190       .clampScalar(0, sXLen, sXLen);
191 
192   getActionDefinitionsBuilder(G_INTTOPTR)
193       .legalFor({{p0, sXLen}})
194       .clampScalar(1, sXLen, sXLen);
195 
196   getActionDefinitionsBuilder(G_BRCOND).legalFor({sXLen}).minScalar(0, sXLen);
197 
198   getActionDefinitionsBuilder(G_BRJT).legalFor({{p0, sXLen}});
199 
200   getActionDefinitionsBuilder(G_BRINDIRECT).legalFor({p0});
201 
202   getActionDefinitionsBuilder(G_PHI)
203       .legalFor({p0, sXLen})
204       .widenScalarToNextPow2(0)
205       .clampScalar(0, sXLen, sXLen);
206 
207   getActionDefinitionsBuilder({G_GLOBAL_VALUE, G_JUMP_TABLE, G_CONSTANT_POOL})
208       .legalFor({p0});
209 
210   if (ST.hasStdExtM() || ST.hasStdExtZmmul()) {
211     getActionDefinitionsBuilder(G_MUL)
212         .legalFor({s32, sXLen})
213         .widenScalarToNextPow2(0)
214         .clampScalar(0, s32, sXLen);
215 
216     // clang-format off
217     getActionDefinitionsBuilder({G_SMULH, G_UMULH})
218         .legalFor({sXLen})
219         .lower();
220     // clang-format on
221 
222     getActionDefinitionsBuilder({G_SMULO, G_UMULO}).minScalar(0, sXLen).lower();
223   } else {
224     getActionDefinitionsBuilder(G_MUL)
225         .libcallFor({sXLen, sDoubleXLen})
226         .widenScalarToNextPow2(0)
227         .clampScalar(0, sXLen, sDoubleXLen);
228 
229     getActionDefinitionsBuilder({G_SMULH, G_UMULH}).lowerFor({sXLen});
230 
231     getActionDefinitionsBuilder({G_SMULO, G_UMULO})
232         .minScalar(0, sXLen)
233         // Widen sXLen to sDoubleXLen so we can use a single libcall to get
234         // the low bits for the mul result and high bits to do the overflow
235         // check.
236         .widenScalarIf(typeIs(0, sXLen),
237                        LegalizeMutations::changeTo(0, sDoubleXLen))
238         .lower();
239   }
240 
241   if (ST.hasStdExtM()) {
242     getActionDefinitionsBuilder({G_UDIV, G_SDIV, G_UREM, G_SREM})
243         .legalFor({s32, sXLen})
244         .libcallFor({sDoubleXLen})
245         .clampScalar(0, s32, sDoubleXLen)
246         .widenScalarToNextPow2(0);
247   } else {
248     getActionDefinitionsBuilder({G_UDIV, G_SDIV, G_UREM, G_SREM})
249         .libcallFor({sXLen, sDoubleXLen})
250         .clampScalar(0, sXLen, sDoubleXLen)
251         .widenScalarToNextPow2(0);
252   }
253 
254   auto &AbsActions = getActionDefinitionsBuilder(G_ABS);
255   if (ST.hasStdExtZbb())
256     AbsActions.customFor({s32, sXLen}).minScalar(0, sXLen);
257   AbsActions.lower();
258 
259   auto &MinMaxActions =
260       getActionDefinitionsBuilder({G_UMAX, G_UMIN, G_SMAX, G_SMIN});
261   if (ST.hasStdExtZbb())
262     MinMaxActions.legalFor({sXLen}).minScalar(0, sXLen);
263   MinMaxActions.lower();
264 
265   getActionDefinitionsBuilder(G_FRAME_INDEX).legalFor({p0});
266 
267   getActionDefinitionsBuilder({G_MEMCPY, G_MEMMOVE, G_MEMSET}).libcall();
268 
269   getActionDefinitionsBuilder(G_DYN_STACKALLOC).lower();
270 
271   // FP Operations
272 
273   getActionDefinitionsBuilder({G_FADD, G_FSUB, G_FMUL, G_FDIV, G_FMA, G_FNEG,
274                                G_FABS, G_FSQRT, G_FMAXNUM, G_FMINNUM})
275       .legalIf(typeIsScalarFPArith(0, ST));
276 
277   getActionDefinitionsBuilder(G_FCOPYSIGN)
278       .legalIf(all(typeIsScalarFPArith(0, ST), typeIsScalarFPArith(1, ST)));
279 
280   getActionDefinitionsBuilder(G_FPTRUNC).legalIf(
281       [=, &ST](const LegalityQuery &Query) -> bool {
282         return (ST.hasStdExtD() && typeIs(0, s32)(Query) &&
283                 typeIs(1, s64)(Query));
284       });
285   getActionDefinitionsBuilder(G_FPEXT).legalIf(
286       [=, &ST](const LegalityQuery &Query) -> bool {
287         return (ST.hasStdExtD() && typeIs(0, s64)(Query) &&
288                 typeIs(1, s32)(Query));
289       });
290 
291   getActionDefinitionsBuilder(G_FCMP)
292       .legalIf(all(typeIs(0, sXLen), typeIsScalarFPArith(1, ST)))
293       .clampScalar(0, sXLen, sXLen);
294 
295   // TODO: Support vector version of G_IS_FPCLASS.
296   getActionDefinitionsBuilder(G_IS_FPCLASS)
297       .customIf(all(typeIs(0, s1), typeIsScalarFPArith(1, ST)));
298 
299   getActionDefinitionsBuilder(G_FCONSTANT)
300       .legalIf(typeIsScalarFPArith(0, ST))
301       .lowerFor({s32, s64});
302 
303   getActionDefinitionsBuilder({G_FPTOSI, G_FPTOUI})
304       .legalIf(all(typeInSet(0, {s32, sXLen}), typeIsScalarFPArith(1, ST)))
305       .widenScalarToNextPow2(0)
306       .clampScalar(0, s32, sXLen);
307 
308   getActionDefinitionsBuilder({G_SITOFP, G_UITOFP})
309       .legalIf(all(typeIsScalarFPArith(0, ST), typeInSet(1, {s32, sXLen})))
310       .widenScalarToNextPow2(1)
311       .clampScalar(1, s32, sXLen);
312 
313   // FIXME: We can do custom inline expansion like SelectionDAG.
314   // FIXME: Legal with Zfa.
315   getActionDefinitionsBuilder({G_FCEIL, G_FFLOOR})
316       .libcallFor({s32, s64});
317 
318   getActionDefinitionsBuilder(G_VASTART).customFor({p0});
319 
320   // va_list must be a pointer, but most sized types are pretty easy to handle
321   // as the destination.
322   getActionDefinitionsBuilder(G_VAARG)
323       // TODO: Implement narrowScalar and widenScalar for G_VAARG for types
324       // outside the [s32, sXLen] range.
325       .clampScalar(0, s32, sXLen)
326       .lowerForCartesianProduct({s32, sXLen, p0}, {p0});
327 
328   getLegacyLegalizerInfo().computeTables();
329 }
330 
331 static Type *getTypeForLLT(LLT Ty, LLVMContext &C) {
332   if (Ty.isVector())
333     return FixedVectorType::get(IntegerType::get(C, Ty.getScalarSizeInBits()),
334                                 Ty.getNumElements());
335   return IntegerType::get(C, Ty.getSizeInBits());
336 }
337 
338 bool RISCVLegalizerInfo::legalizeIntrinsic(LegalizerHelper &Helper,
339                                            MachineInstr &MI) const {
340   Intrinsic::ID IntrinsicID = cast<GIntrinsic>(MI).getIntrinsicID();
341   switch (IntrinsicID) {
342   default:
343     return false;
344   case Intrinsic::vacopy: {
345     // vacopy arguments must be legal because of the intrinsic signature.
346     // No need to check here.
347 
348     MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
349     MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
350     MachineFunction &MF = *MI.getMF();
351     const DataLayout &DL = MIRBuilder.getDataLayout();
352     LLVMContext &Ctx = MF.getFunction().getContext();
353 
354     Register DstLst = MI.getOperand(1).getReg();
355     LLT PtrTy = MRI.getType(DstLst);
356 
357     // Load the source va_list
358     Align Alignment = DL.getABITypeAlign(getTypeForLLT(PtrTy, Ctx));
359     MachineMemOperand *LoadMMO = MF.getMachineMemOperand(
360         MachinePointerInfo(), MachineMemOperand::MOLoad, PtrTy, Alignment);
361     auto Tmp = MIRBuilder.buildLoad(PtrTy, MI.getOperand(2), *LoadMMO);
362 
363     // Store the result in the destination va_list
364     MachineMemOperand *StoreMMO = MF.getMachineMemOperand(
365         MachinePointerInfo(), MachineMemOperand::MOStore, PtrTy, Alignment);
366     MIRBuilder.buildStore(DstLst, Tmp, *StoreMMO);
367 
368     MI.eraseFromParent();
369     return true;
370   }
371   }
372 }
373 
374 bool RISCVLegalizerInfo::legalizeShlAshrLshr(
375     MachineInstr &MI, MachineIRBuilder &MIRBuilder,
376     GISelChangeObserver &Observer) const {
377   assert(MI.getOpcode() == TargetOpcode::G_ASHR ||
378          MI.getOpcode() == TargetOpcode::G_LSHR ||
379          MI.getOpcode() == TargetOpcode::G_SHL);
380   MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
381   // If the shift amount is a G_CONSTANT, promote it to a 64 bit type so the
382   // imported patterns can select it later. Either way, it will be legal.
383   Register AmtReg = MI.getOperand(2).getReg();
384   auto VRegAndVal = getIConstantVRegValWithLookThrough(AmtReg, MRI);
385   if (!VRegAndVal)
386     return true;
387   // Check the shift amount is in range for an immediate form.
388   uint64_t Amount = VRegAndVal->Value.getZExtValue();
389   if (Amount > 31)
390     return true; // This will have to remain a register variant.
391   auto ExtCst = MIRBuilder.buildConstant(LLT::scalar(64), Amount);
392   Observer.changingInstr(MI);
393   MI.getOperand(2).setReg(ExtCst.getReg(0));
394   Observer.changedInstr(MI);
395   return true;
396 }
397 
398 bool RISCVLegalizerInfo::legalizeVAStart(MachineInstr &MI,
399                                          MachineIRBuilder &MIRBuilder) const {
400   // Stores the address of the VarArgsFrameIndex slot into the memory location
401   assert(MI.getOpcode() == TargetOpcode::G_VASTART);
402   MachineFunction *MF = MI.getParent()->getParent();
403   RISCVMachineFunctionInfo *FuncInfo = MF->getInfo<RISCVMachineFunctionInfo>();
404   int FI = FuncInfo->getVarArgsFrameIndex();
405   LLT AddrTy = MIRBuilder.getMRI()->getType(MI.getOperand(0).getReg());
406   auto FINAddr = MIRBuilder.buildFrameIndex(AddrTy, FI);
407   assert(MI.hasOneMemOperand());
408   MIRBuilder.buildStore(FINAddr, MI.getOperand(0).getReg(),
409                         *MI.memoperands()[0]);
410   MI.eraseFromParent();
411   return true;
412 }
413 
414 bool RISCVLegalizerInfo::legalizeCustom(
415     LegalizerHelper &Helper, MachineInstr &MI,
416     LostDebugLocObserver &LocObserver) const {
417   MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
418   GISelChangeObserver &Observer = Helper.Observer;
419   switch (MI.getOpcode()) {
420   default:
421     // No idea what to do.
422     return false;
423   case TargetOpcode::G_ABS:
424     return Helper.lowerAbsToMaxNeg(MI);
425   case TargetOpcode::G_SHL:
426   case TargetOpcode::G_ASHR:
427   case TargetOpcode::G_LSHR:
428     return legalizeShlAshrLshr(MI, MIRBuilder, Observer);
429   case TargetOpcode::G_SEXT_INREG: {
430     // Source size of 32 is sext.w.
431     int64_t SizeInBits = MI.getOperand(2).getImm();
432     if (SizeInBits == 32)
433       return true;
434 
435     return Helper.lower(MI, 0, /* Unused hint type */ LLT()) ==
436            LegalizerHelper::Legalized;
437   }
438   case TargetOpcode::G_IS_FPCLASS: {
439     Register GISFPCLASS = MI.getOperand(0).getReg();
440     Register Src = MI.getOperand(1).getReg();
441     const MachineOperand &ImmOp = MI.getOperand(2);
442     MachineIRBuilder MIB(MI);
443 
444     // Turn LLVM IR's floating point classes to that in RISC-V,
445     // by simply rotating the 10-bit immediate right by two bits.
446     APInt GFpClassImm(10, static_cast<uint64_t>(ImmOp.getImm()));
447     auto FClassMask = MIB.buildConstant(sXLen, GFpClassImm.rotr(2).zext(XLen));
448     auto ConstZero = MIB.buildConstant(sXLen, 0);
449 
450     auto GFClass = MIB.buildInstr(RISCV::G_FCLASS, {sXLen}, {Src});
451     auto And = MIB.buildAnd(sXLen, GFClass, FClassMask);
452     MIB.buildICmp(CmpInst::ICMP_NE, GISFPCLASS, And, ConstZero);
453 
454     MI.eraseFromParent();
455     return true;
456   }
457   case TargetOpcode::G_VASTART:
458     return legalizeVAStart(MI, MIRBuilder);
459   }
460 
461   llvm_unreachable("expected switch to return");
462 }
463