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