1 //===-- llvm/CodeGen/GlobalISel/LegalizerHelper.cpp -----------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 /// \file This file implements the LegalizerHelper class to legalize
11 /// individual instructions and the LegalizeMachineIR wrapper pass for the
12 /// primary legalization.
13 //
14 //===----------------------------------------------------------------------===//
15 
16 #include "llvm/CodeGen/GlobalISel/LegalizerHelper.h"
17 #include "llvm/CodeGen/GlobalISel/CallLowering.h"
18 #include "llvm/CodeGen/GlobalISel/LegalizerInfo.h"
19 #include "llvm/CodeGen/MachineRegisterInfo.h"
20 #include "llvm/Support/Debug.h"
21 #include "llvm/Support/raw_ostream.h"
22 #include "llvm/Target/TargetLowering.h"
23 #include "llvm/Target/TargetSubtargetInfo.h"
24 
25 #include <sstream>
26 
27 #define DEBUG_TYPE "legalize-mir"
28 
29 using namespace llvm;
30 
31 LegalizerHelper::LegalizerHelper(MachineFunction &MF)
32   : MRI(MF.getRegInfo()) {
33   MIRBuilder.setMF(MF);
34 }
35 
36 LegalizerHelper::LegalizeResult
37 LegalizerHelper::legalizeInstrStep(MachineInstr &MI,
38                                    const LegalizerInfo &LegalizerInfo) {
39   auto Action = LegalizerInfo.getAction(MI, MRI);
40   switch (std::get<0>(Action)) {
41   case LegalizerInfo::Legal:
42     return AlreadyLegal;
43   case LegalizerInfo::Libcall:
44     return libcall(MI);
45   case LegalizerInfo::NarrowScalar:
46     return narrowScalar(MI, std::get<1>(Action), std::get<2>(Action));
47   case LegalizerInfo::WidenScalar:
48     return widenScalar(MI, std::get<1>(Action), std::get<2>(Action));
49   case LegalizerInfo::Lower:
50     return lower(MI, std::get<1>(Action), std::get<2>(Action));
51   case LegalizerInfo::FewerElements:
52     return fewerElementsVector(MI, std::get<1>(Action), std::get<2>(Action));
53   default:
54     return UnableToLegalize;
55   }
56 }
57 
58 LegalizerHelper::LegalizeResult
59 LegalizerHelper::legalizeInstr(MachineInstr &MI,
60                                const LegalizerInfo &LegalizerInfo) {
61   SmallVector<MachineInstr *, 4> WorkList;
62   MIRBuilder.recordInsertions(
63       [&](MachineInstr *MI) { WorkList.push_back(MI); });
64   WorkList.push_back(&MI);
65 
66   bool Changed = false;
67   LegalizeResult Res;
68   unsigned Idx = 0;
69   do {
70     Res = legalizeInstrStep(*WorkList[Idx], LegalizerInfo);
71     if (Res == UnableToLegalize) {
72       MIRBuilder.stopRecordingInsertions();
73       return UnableToLegalize;
74     }
75     Changed |= Res == Legalized;
76     ++Idx;
77   } while (Idx < WorkList.size());
78 
79   MIRBuilder.stopRecordingInsertions();
80 
81   return Changed ? Legalized : AlreadyLegal;
82 }
83 
84 void LegalizerHelper::extractParts(unsigned Reg, LLT Ty, int NumParts,
85                                    SmallVectorImpl<unsigned> &VRegs) {
86   unsigned Size = Ty.getSizeInBits();
87   SmallVector<uint64_t, 4> Indexes;
88   for (int i = 0; i < NumParts; ++i) {
89     VRegs.push_back(MRI.createGenericVirtualRegister(Ty));
90     Indexes.push_back(i * Size);
91   }
92   MIRBuilder.buildExtract(VRegs, Indexes, Reg);
93 }
94 
95 LegalizerHelper::LegalizeResult
96 LegalizerHelper::libcall(MachineInstr &MI) {
97   LLT Ty = MRI.getType(MI.getOperand(0).getReg());
98   unsigned Size = Ty.getSizeInBits();
99   MIRBuilder.setInstr(MI);
100 
101   switch (MI.getOpcode()) {
102   default:
103     return UnableToLegalize;
104   case TargetOpcode::G_FREM: {
105     auto &Ctx = MIRBuilder.getMF().getFunction()->getContext();
106     Type *Ty = Size == 64 ? Type::getDoubleTy(Ctx) : Type::getFloatTy(Ctx);
107     auto &CLI = *MIRBuilder.getMF().getSubtarget().getCallLowering();
108     auto &TLI = *MIRBuilder.getMF().getSubtarget().getTargetLowering();
109     const char *Name =
110         TLI.getLibcallName(Size == 64 ? RTLIB::REM_F64 : RTLIB::REM_F32);
111 
112     CLI.lowerCall(
113         MIRBuilder, MachineOperand::CreateES(Name),
114         {MI.getOperand(0).getReg(), Ty},
115         {{MI.getOperand(1).getReg(), Ty}, {MI.getOperand(2).getReg(), Ty}});
116     MI.eraseFromParent();
117     return Legalized;
118   }
119   }
120 }
121 
122 LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI,
123                                                               unsigned TypeIdx,
124                                                               LLT NarrowTy) {
125   // FIXME: Don't know how to handle secondary types yet.
126   if (TypeIdx != 0)
127     return UnableToLegalize;
128 
129   MIRBuilder.setInstr(MI);
130 
131   switch (MI.getOpcode()) {
132   default:
133     return UnableToLegalize;
134   case TargetOpcode::G_ADD: {
135     // Expand in terms of carry-setting/consuming G_ADDE instructions.
136     unsigned NarrowSize = NarrowTy.getSizeInBits();
137     int NumParts = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits() /
138                    NarrowTy.getSizeInBits();
139 
140     SmallVector<unsigned, 2> Src1Regs, Src2Regs, DstRegs;
141     SmallVector<uint64_t, 2> Indexes;
142     extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, Src1Regs);
143     extractParts(MI.getOperand(2).getReg(), NarrowTy, NumParts, Src2Regs);
144 
145     unsigned CarryIn = MRI.createGenericVirtualRegister(LLT::scalar(1));
146     MIRBuilder.buildConstant(CarryIn, 0);
147 
148     for (int i = 0; i < NumParts; ++i) {
149       unsigned DstReg = MRI.createGenericVirtualRegister(NarrowTy);
150       unsigned CarryOut = MRI.createGenericVirtualRegister(LLT::scalar(1));
151 
152       MIRBuilder.buildUAdde(DstReg, CarryOut, Src1Regs[i],
153                             Src2Regs[i], CarryIn);
154 
155       DstRegs.push_back(DstReg);
156       Indexes.push_back(i * NarrowSize);
157       CarryIn = CarryOut;
158     }
159     unsigned DstReg = MI.getOperand(0).getReg();
160     MIRBuilder.buildSequence(DstReg, DstRegs, Indexes);
161     MI.eraseFromParent();
162     return Legalized;
163   }
164   case TargetOpcode::G_STORE: {
165     unsigned NarrowSize = NarrowTy.getSizeInBits();
166     int NumParts =
167         MRI.getType(MI.getOperand(0).getReg()).getSizeInBits() / NarrowSize;
168     LLT NarrowPtrTy = LLT::pointer(
169         MRI.getType(MI.getOperand(1).getReg()).getAddressSpace(), NarrowSize);
170 
171     SmallVector<unsigned, 2> SrcRegs;
172     extractParts(MI.getOperand(0).getReg(), NarrowTy, NumParts, SrcRegs);
173 
174     for (int i = 0; i < NumParts; ++i) {
175       unsigned DstReg = MRI.createGenericVirtualRegister(NarrowPtrTy);
176       unsigned Offset = MRI.createGenericVirtualRegister(LLT::scalar(64));
177       MIRBuilder.buildConstant(Offset, i * NarrowSize / 8);
178       MIRBuilder.buildGEP(DstReg, MI.getOperand(1).getReg(), Offset);
179       MIRBuilder.buildStore(SrcRegs[i], DstReg, **MI.memoperands_begin());
180     }
181     MI.eraseFromParent();
182     return Legalized;
183   }
184   }
185 }
186 
187 LegalizerHelper::LegalizeResult
188 LegalizerHelper::widenScalar(MachineInstr &MI, unsigned TypeIdx, LLT WideTy) {
189   MIRBuilder.setInstr(MI);
190 
191   switch (MI.getOpcode()) {
192   default:
193     return UnableToLegalize;
194   case TargetOpcode::G_ADD:
195   case TargetOpcode::G_AND:
196   case TargetOpcode::G_MUL:
197   case TargetOpcode::G_OR:
198   case TargetOpcode::G_XOR:
199   case TargetOpcode::G_SUB: {
200     // Perform operation at larger width (any extension is fine here, high bits
201     // don't affect the result) and then truncate the result back to the
202     // original type.
203     unsigned Src1Ext = MRI.createGenericVirtualRegister(WideTy);
204     unsigned Src2Ext = MRI.createGenericVirtualRegister(WideTy);
205     MIRBuilder.buildAnyExt(Src1Ext, MI.getOperand(1).getReg());
206     MIRBuilder.buildAnyExt(Src2Ext, MI.getOperand(2).getReg());
207 
208     unsigned DstExt = MRI.createGenericVirtualRegister(WideTy);
209     MIRBuilder.buildInstr(MI.getOpcode())
210         .addDef(DstExt)
211         .addUse(Src1Ext)
212         .addUse(Src2Ext);
213 
214     MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), DstExt);
215     MI.eraseFromParent();
216     return Legalized;
217   }
218   case TargetOpcode::G_SDIV:
219   case TargetOpcode::G_UDIV: {
220     unsigned ExtOp = MI.getOpcode() == TargetOpcode::G_SDIV
221                           ? TargetOpcode::G_SEXT
222                           : TargetOpcode::G_ZEXT;
223 
224     unsigned LHSExt = MRI.createGenericVirtualRegister(WideTy);
225     MIRBuilder.buildInstr(ExtOp).addDef(LHSExt).addUse(
226         MI.getOperand(1).getReg());
227 
228     unsigned RHSExt = MRI.createGenericVirtualRegister(WideTy);
229     MIRBuilder.buildInstr(ExtOp).addDef(RHSExt).addUse(
230         MI.getOperand(2).getReg());
231 
232     unsigned ResExt = MRI.createGenericVirtualRegister(WideTy);
233     MIRBuilder.buildInstr(MI.getOpcode())
234         .addDef(ResExt)
235         .addUse(LHSExt)
236         .addUse(RHSExt);
237 
238     MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), ResExt);
239     MI.eraseFromParent();
240     return Legalized;
241   }
242   case TargetOpcode::G_LOAD: {
243     assert(alignTo(MRI.getType(MI.getOperand(0).getReg()).getSizeInBits(), 8) ==
244                WideTy.getSizeInBits() &&
245            "illegal to increase number of bytes loaded");
246 
247     unsigned DstExt = MRI.createGenericVirtualRegister(WideTy);
248     MIRBuilder.buildLoad(DstExt, MI.getOperand(1).getReg(),
249                          **MI.memoperands_begin());
250     MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), DstExt);
251     MI.eraseFromParent();
252     return Legalized;
253   }
254   case TargetOpcode::G_STORE: {
255     assert(alignTo(MRI.getType(MI.getOperand(0).getReg()).getSizeInBits(), 8) ==
256                WideTy.getSizeInBits() &&
257            "illegal to increase number of bytes modified by a store");
258 
259     unsigned SrcExt = MRI.createGenericVirtualRegister(WideTy);
260     MIRBuilder.buildAnyExt(SrcExt, MI.getOperand(0).getReg());
261     MIRBuilder.buildStore(SrcExt, MI.getOperand(1).getReg(),
262                           **MI.memoperands_begin());
263     MI.eraseFromParent();
264     return Legalized;
265   }
266   case TargetOpcode::G_CONSTANT: {
267     unsigned DstExt = MRI.createGenericVirtualRegister(WideTy);
268     MIRBuilder.buildConstant(DstExt, *MI.getOperand(1).getCImm());
269     MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), DstExt);
270     MI.eraseFromParent();
271     return Legalized;
272   }
273   case TargetOpcode::G_FCONSTANT: {
274     unsigned DstExt = MRI.createGenericVirtualRegister(WideTy);
275     MIRBuilder.buildFConstant(DstExt, *MI.getOperand(1).getFPImm());
276     MIRBuilder.buildFPTrunc(MI.getOperand(0).getReg(), DstExt);
277     MI.eraseFromParent();
278     return Legalized;
279   }
280   case TargetOpcode::G_BRCOND: {
281     unsigned TstExt = MRI.createGenericVirtualRegister(WideTy);
282     MIRBuilder.buildAnyExt(TstExt, MI.getOperand(0).getReg());
283     MIRBuilder.buildBrCond(TstExt, *MI.getOperand(1).getMBB());
284     MI.eraseFromParent();
285     return Legalized;
286   }
287   case TargetOpcode::G_ICMP: {
288     assert(TypeIdx == 1 && "unable to legalize predicate");
289     bool IsSigned = CmpInst::isSigned(
290         static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate()));
291     unsigned Op0Ext = MRI.createGenericVirtualRegister(WideTy);
292     unsigned Op1Ext = MRI.createGenericVirtualRegister(WideTy);
293     if (IsSigned) {
294       MIRBuilder.buildSExt(Op0Ext, MI.getOperand(2).getReg());
295       MIRBuilder.buildSExt(Op1Ext, MI.getOperand(3).getReg());
296     } else {
297       MIRBuilder.buildZExt(Op0Ext, MI.getOperand(2).getReg());
298       MIRBuilder.buildZExt(Op1Ext, MI.getOperand(3).getReg());
299     }
300     MIRBuilder.buildICmp(
301         static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate()),
302         MI.getOperand(0).getReg(), Op0Ext, Op1Ext);
303     MI.eraseFromParent();
304     return Legalized;
305   }
306   case TargetOpcode::G_GEP: {
307     assert(TypeIdx == 1 && "unable to legalize pointer of GEP");
308     unsigned OffsetExt = MRI.createGenericVirtualRegister(WideTy);
309     MIRBuilder.buildSExt(OffsetExt, MI.getOperand(2).getReg());
310     MI.getOperand(2).setReg(OffsetExt);
311     return Legalized;
312   }
313   }
314 }
315 
316 LegalizerHelper::LegalizeResult
317 LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT Ty) {
318   using namespace TargetOpcode;
319   MIRBuilder.setInstr(MI);
320 
321   switch(MI.getOpcode()) {
322   default:
323     return UnableToLegalize;
324   case TargetOpcode::G_SREM:
325   case TargetOpcode::G_UREM: {
326     unsigned QuotReg = MRI.createGenericVirtualRegister(Ty);
327     MIRBuilder.buildInstr(MI.getOpcode() == G_SREM ? G_SDIV : G_UDIV)
328         .addDef(QuotReg)
329         .addUse(MI.getOperand(1).getReg())
330         .addUse(MI.getOperand(2).getReg());
331 
332     unsigned ProdReg = MRI.createGenericVirtualRegister(Ty);
333     MIRBuilder.buildMul(ProdReg, QuotReg, MI.getOperand(2).getReg());
334     MIRBuilder.buildSub(MI.getOperand(0).getReg(), MI.getOperand(1).getReg(),
335                         ProdReg);
336     MI.eraseFromParent();
337     return Legalized;
338   }
339   }
340 }
341 
342 LegalizerHelper::LegalizeResult
343 LegalizerHelper::fewerElementsVector(MachineInstr &MI, unsigned TypeIdx,
344                                      LLT NarrowTy) {
345   // FIXME: Don't know how to handle secondary types yet.
346   if (TypeIdx != 0)
347     return UnableToLegalize;
348   switch (MI.getOpcode()) {
349   default:
350     return UnableToLegalize;
351   case TargetOpcode::G_ADD: {
352     unsigned NarrowSize = NarrowTy.getSizeInBits();
353     unsigned DstReg = MI.getOperand(0).getReg();
354     int NumParts = MRI.getType(DstReg).getSizeInBits() / NarrowSize;
355 
356     MIRBuilder.setInstr(MI);
357 
358     SmallVector<unsigned, 2> Src1Regs, Src2Regs, DstRegs;
359     SmallVector<uint64_t, 2> Indexes;
360     extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, Src1Regs);
361     extractParts(MI.getOperand(2).getReg(), NarrowTy, NumParts, Src2Regs);
362 
363     for (int i = 0; i < NumParts; ++i) {
364       unsigned DstReg = MRI.createGenericVirtualRegister(NarrowTy);
365       MIRBuilder.buildAdd(DstReg, Src1Regs[i], Src2Regs[i]);
366       DstRegs.push_back(DstReg);
367       Indexes.push_back(i * NarrowSize);
368     }
369 
370     MIRBuilder.buildSequence(DstReg, DstRegs, Indexes);
371     MI.eraseFromParent();
372     return Legalized;
373   }
374   }
375 }
376