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 static RTLIB::Libcall getRTLibDesc(unsigned Opcode, unsigned Size) {
96   switch (Opcode) {
97   case TargetOpcode::G_FREM:
98     return Size == 64 ? RTLIB::REM_F64 : RTLIB::REM_F32;
99   case TargetOpcode::G_FPOW:
100     return Size == 64 ? RTLIB::POW_F64 : RTLIB::POW_F32;
101   }
102   llvm_unreachable("Unknown libcall function");
103 }
104 
105 LegalizerHelper::LegalizeResult
106 LegalizerHelper::libcall(MachineInstr &MI) {
107   LLT Ty = MRI.getType(MI.getOperand(0).getReg());
108   unsigned Size = Ty.getSizeInBits();
109   MIRBuilder.setInstr(MI);
110 
111   switch (MI.getOpcode()) {
112   default:
113     return UnableToLegalize;
114   case TargetOpcode::G_FPOW:
115   case TargetOpcode::G_FREM: {
116     auto &Ctx = MIRBuilder.getMF().getFunction()->getContext();
117     Type *Ty = Size == 64 ? Type::getDoubleTy(Ctx) : Type::getFloatTy(Ctx);
118     auto &CLI = *MIRBuilder.getMF().getSubtarget().getCallLowering();
119     auto &TLI = *MIRBuilder.getMF().getSubtarget().getTargetLowering();
120     const char *Name = TLI.getLibcallName(getRTLibDesc(MI.getOpcode(), Size));
121     CLI.lowerCall(
122         MIRBuilder, MachineOperand::CreateES(Name),
123         {MI.getOperand(0).getReg(), Ty},
124         {{MI.getOperand(1).getReg(), Ty}, {MI.getOperand(2).getReg(), Ty}});
125     MI.eraseFromParent();
126     return Legalized;
127   }
128   }
129 }
130 
131 void LegalizerHelper::findInsertionsForRange(
132     int64_t DstStart, int64_t DstEnd, MachineInstr::mop_iterator &CurOp,
133     MachineInstr::mop_iterator &EndOp, MachineInstr &MI) {
134   while (CurOp != MI.operands_end() && std::next(CurOp)->getImm() < DstStart)
135     CurOp += 2;
136 
137   EndOp = CurOp;
138   while (EndOp != MI.operands_end() && std::next(EndOp)->getImm() < DstEnd)
139     EndOp += 2;
140 }
141 
142 LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI,
143                                                               unsigned TypeIdx,
144                                                               LLT NarrowTy) {
145   // FIXME: Don't know how to handle secondary types yet.
146   if (TypeIdx != 0)
147     return UnableToLegalize;
148 
149   MIRBuilder.setInstr(MI);
150 
151   switch (MI.getOpcode()) {
152   default:
153     return UnableToLegalize;
154   case TargetOpcode::G_ADD: {
155     // Expand in terms of carry-setting/consuming G_ADDE instructions.
156     unsigned NarrowSize = NarrowTy.getSizeInBits();
157     int NumParts = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits() /
158                    NarrowTy.getSizeInBits();
159 
160     SmallVector<unsigned, 2> Src1Regs, Src2Regs, DstRegs;
161     SmallVector<uint64_t, 2> Indexes;
162     extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, Src1Regs);
163     extractParts(MI.getOperand(2).getReg(), NarrowTy, NumParts, Src2Regs);
164 
165     unsigned CarryIn = MRI.createGenericVirtualRegister(LLT::scalar(1));
166     MIRBuilder.buildConstant(CarryIn, 0);
167 
168     for (int i = 0; i < NumParts; ++i) {
169       unsigned DstReg = MRI.createGenericVirtualRegister(NarrowTy);
170       unsigned CarryOut = MRI.createGenericVirtualRegister(LLT::scalar(1));
171 
172       MIRBuilder.buildUAdde(DstReg, CarryOut, Src1Regs[i],
173                             Src2Regs[i], CarryIn);
174 
175       DstRegs.push_back(DstReg);
176       Indexes.push_back(i * NarrowSize);
177       CarryIn = CarryOut;
178     }
179     unsigned DstReg = MI.getOperand(0).getReg();
180     MIRBuilder.buildSequence(DstReg, DstRegs, Indexes);
181     MI.eraseFromParent();
182     return Legalized;
183   }
184   case TargetOpcode::G_INSERT: {
185     if (TypeIdx != 0)
186       return UnableToLegalize;
187 
188     unsigned NarrowSize = NarrowTy.getSizeInBits();
189     int NumParts =
190         MRI.getType(MI.getOperand(0).getReg()).getSizeInBits() / NarrowSize;
191 
192     SmallVector<unsigned, 2> SrcRegs, DstRegs;
193     SmallVector<uint64_t, 2> Indexes;
194     extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, SrcRegs);
195 
196     MachineInstr::mop_iterator CurOp = MI.operands_begin() + 2, EndOp;
197     for (int i = 0; i < NumParts; ++i) {
198       unsigned DstStart = i * NarrowSize;
199       unsigned DstReg = MRI.createGenericVirtualRegister(NarrowTy);
200       Indexes.push_back(DstStart);
201 
202       findInsertionsForRange(DstStart, DstStart + NarrowSize, CurOp, EndOp, MI);
203 
204       if (CurOp == EndOp) {
205         // No part of the insert affects this subregister, forward the original.
206         DstRegs.push_back(SrcRegs[i]);
207         continue;
208       } else if (MRI.getType(CurOp->getReg()) == NarrowTy &&
209                  std::next(CurOp)->getImm() == DstStart) {
210         // The entire subregister is defined by this insert, forward the new
211         // value.
212         DstRegs.push_back(CurOp->getReg());
213         continue;
214       }
215 
216       auto MIB = MIRBuilder.buildInstr(TargetOpcode::G_INSERT)
217         .addDef(DstReg)
218         .addUse(SrcRegs[i]);
219 
220       for (; CurOp != EndOp; CurOp += 2) {
221         unsigned Reg = CurOp->getReg();
222         uint64_t Offset = std::next(CurOp)->getImm() - DstStart;
223 
224         // Make sure we don't have a cross-register insert.
225         if (Offset + MRI.getType(Reg).getSizeInBits() > NarrowSize) {
226           // FIXME: we should handle this case, though it's unlikely to be
227           // common given ABI-related layout restrictions.
228           return UnableToLegalize;
229         }
230 
231         MIB.addUse(Reg);
232         MIB.addImm(Offset);
233       }
234 
235       DstRegs.push_back(DstReg);
236     }
237 
238     assert(DstRegs.size() == (unsigned)NumParts && "not all parts covered");
239     MIRBuilder.buildSequence(MI.getOperand(0).getReg(), DstRegs, Indexes);
240     MI.eraseFromParent();
241     return Legalized;
242   }
243   case TargetOpcode::G_LOAD: {
244     unsigned NarrowSize = NarrowTy.getSizeInBits();
245     int NumParts =
246         MRI.getType(MI.getOperand(0).getReg()).getSizeInBits() / NarrowSize;
247     LLT NarrowPtrTy = LLT::pointer(
248         MRI.getType(MI.getOperand(1).getReg()).getAddressSpace(), NarrowSize);
249 
250     SmallVector<unsigned, 2> DstRegs;
251     SmallVector<uint64_t, 2> Indexes;
252     for (int i = 0; i < NumParts; ++i) {
253       unsigned DstReg = MRI.createGenericVirtualRegister(NarrowTy);
254       unsigned SrcReg = MRI.createGenericVirtualRegister(NarrowPtrTy);
255       unsigned Offset = MRI.createGenericVirtualRegister(LLT::scalar(64));
256 
257       MIRBuilder.buildConstant(Offset, i * NarrowSize / 8);
258       MIRBuilder.buildGEP(SrcReg, MI.getOperand(1).getReg(), Offset);
259       // TODO: This is conservatively correct, but we probably want to split the
260       // memory operands in the future.
261       MIRBuilder.buildLoad(DstReg, SrcReg, **MI.memoperands_begin());
262 
263       DstRegs.push_back(DstReg);
264       Indexes.push_back(i * NarrowSize);
265     }
266     unsigned DstReg = MI.getOperand(0).getReg();
267     MIRBuilder.buildSequence(DstReg, DstRegs, Indexes);
268     MI.eraseFromParent();
269     return Legalized;
270   }
271   case TargetOpcode::G_STORE: {
272     unsigned NarrowSize = NarrowTy.getSizeInBits();
273     int NumParts =
274         MRI.getType(MI.getOperand(0).getReg()).getSizeInBits() / NarrowSize;
275     LLT NarrowPtrTy = LLT::pointer(
276         MRI.getType(MI.getOperand(1).getReg()).getAddressSpace(), NarrowSize);
277 
278     SmallVector<unsigned, 2> SrcRegs;
279     extractParts(MI.getOperand(0).getReg(), NarrowTy, NumParts, SrcRegs);
280 
281     for (int i = 0; i < NumParts; ++i) {
282       unsigned DstReg = MRI.createGenericVirtualRegister(NarrowPtrTy);
283       unsigned Offset = MRI.createGenericVirtualRegister(LLT::scalar(64));
284       MIRBuilder.buildConstant(Offset, i * NarrowSize / 8);
285       MIRBuilder.buildGEP(DstReg, MI.getOperand(1).getReg(), Offset);
286       // TODO: This is conservatively correct, but we probably want to split the
287       // memory operands in the future.
288       MIRBuilder.buildStore(SrcRegs[i], DstReg, **MI.memoperands_begin());
289     }
290     MI.eraseFromParent();
291     return Legalized;
292   }
293   }
294 }
295 
296 LegalizerHelper::LegalizeResult
297 LegalizerHelper::widenScalar(MachineInstr &MI, unsigned TypeIdx, LLT WideTy) {
298   MIRBuilder.setInstr(MI);
299 
300   switch (MI.getOpcode()) {
301   default:
302     return UnableToLegalize;
303   case TargetOpcode::G_ADD:
304   case TargetOpcode::G_AND:
305   case TargetOpcode::G_MUL:
306   case TargetOpcode::G_OR:
307   case TargetOpcode::G_XOR:
308   case TargetOpcode::G_SUB:
309   case TargetOpcode::G_SHL: {
310     // Perform operation at larger width (any extension is fine here, high bits
311     // don't affect the result) and then truncate the result back to the
312     // original type.
313     unsigned Src1Ext = MRI.createGenericVirtualRegister(WideTy);
314     unsigned Src2Ext = MRI.createGenericVirtualRegister(WideTy);
315     MIRBuilder.buildAnyExt(Src1Ext, MI.getOperand(1).getReg());
316     MIRBuilder.buildAnyExt(Src2Ext, MI.getOperand(2).getReg());
317 
318     unsigned DstExt = MRI.createGenericVirtualRegister(WideTy);
319     MIRBuilder.buildInstr(MI.getOpcode())
320         .addDef(DstExt)
321         .addUse(Src1Ext)
322         .addUse(Src2Ext);
323 
324     MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), DstExt);
325     MI.eraseFromParent();
326     return Legalized;
327   }
328   case TargetOpcode::G_SDIV:
329   case TargetOpcode::G_UDIV:
330   case TargetOpcode::G_ASHR:
331   case TargetOpcode::G_LSHR: {
332     unsigned ExtOp = MI.getOpcode() == TargetOpcode::G_SDIV ||
333                              MI.getOpcode() == TargetOpcode::G_ASHR
334                          ? TargetOpcode::G_SEXT
335                          : TargetOpcode::G_ZEXT;
336 
337     unsigned LHSExt = MRI.createGenericVirtualRegister(WideTy);
338     MIRBuilder.buildInstr(ExtOp).addDef(LHSExt).addUse(
339         MI.getOperand(1).getReg());
340 
341     unsigned RHSExt = MRI.createGenericVirtualRegister(WideTy);
342     MIRBuilder.buildInstr(ExtOp).addDef(RHSExt).addUse(
343         MI.getOperand(2).getReg());
344 
345     unsigned ResExt = MRI.createGenericVirtualRegister(WideTy);
346     MIRBuilder.buildInstr(MI.getOpcode())
347         .addDef(ResExt)
348         .addUse(LHSExt)
349         .addUse(RHSExt);
350 
351     MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), ResExt);
352     MI.eraseFromParent();
353     return Legalized;
354   }
355   case TargetOpcode::G_SELECT: {
356     if (TypeIdx != 0)
357       return UnableToLegalize;
358 
359     // Perform operation at larger width (any extension is fine here, high bits
360     // don't affect the result) and then truncate the result back to the
361     // original type.
362     unsigned Src1Ext = MRI.createGenericVirtualRegister(WideTy);
363     unsigned Src2Ext = MRI.createGenericVirtualRegister(WideTy);
364     MIRBuilder.buildAnyExt(Src1Ext, MI.getOperand(2).getReg());
365     MIRBuilder.buildAnyExt(Src2Ext, MI.getOperand(3).getReg());
366 
367     unsigned DstExt = MRI.createGenericVirtualRegister(WideTy);
368     MIRBuilder.buildInstr(TargetOpcode::G_SELECT)
369         .addDef(DstExt)
370         .addReg(MI.getOperand(1).getReg())
371         .addUse(Src1Ext)
372         .addUse(Src2Ext);
373 
374     MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), DstExt);
375     MI.eraseFromParent();
376     return Legalized;
377   }
378   case TargetOpcode::G_FPTOSI:
379   case TargetOpcode::G_FPTOUI: {
380     if (TypeIdx != 0)
381       return UnableToLegalize;
382 
383     unsigned DstExt = MRI.createGenericVirtualRegister(WideTy);
384     MIRBuilder.buildInstr(MI.getOpcode())
385         .addDef(DstExt)
386         .addUse(MI.getOperand(1).getReg());
387 
388     MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), DstExt);
389     MI.eraseFromParent();
390     return Legalized;
391   }
392   case TargetOpcode::G_SITOFP:
393   case TargetOpcode::G_UITOFP: {
394     if (TypeIdx != 1)
395       return UnableToLegalize;
396 
397     unsigned Src = MI.getOperand(1).getReg();
398     unsigned SrcExt = MRI.createGenericVirtualRegister(WideTy);
399 
400     if (MI.getOpcode() == TargetOpcode::G_SITOFP) {
401       MIRBuilder.buildSExt(SrcExt, Src);
402     } else {
403       assert(MI.getOpcode() == TargetOpcode::G_UITOFP && "Unexpected conv op");
404       MIRBuilder.buildZExt(SrcExt, Src);
405     }
406 
407     MIRBuilder.buildInstr(MI.getOpcode())
408         .addDef(MI.getOperand(0).getReg())
409         .addUse(SrcExt);
410 
411     MI.eraseFromParent();
412     return Legalized;
413   }
414   case TargetOpcode::G_INSERT: {
415     if (TypeIdx != 0)
416       return UnableToLegalize;
417 
418     unsigned Src = MI.getOperand(1).getReg();
419     unsigned SrcExt = MRI.createGenericVirtualRegister(WideTy);
420     MIRBuilder.buildAnyExt(SrcExt, Src);
421 
422     unsigned DstExt = MRI.createGenericVirtualRegister(WideTy);
423     auto MIB = MIRBuilder.buildInsert(DstExt, SrcExt, MI.getOperand(2).getReg(),
424                                       MI.getOperand(3).getImm());
425     for (unsigned OpNum = 4; OpNum < MI.getNumOperands(); OpNum += 2) {
426       MIB.addReg(MI.getOperand(OpNum).getReg());
427       MIB.addImm(MI.getOperand(OpNum + 1).getImm());
428     }
429 
430     MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), DstExt);
431     MI.eraseFromParent();
432     return Legalized;
433   }
434   case TargetOpcode::G_LOAD: {
435     assert(alignTo(MRI.getType(MI.getOperand(0).getReg()).getSizeInBits(), 8) ==
436                WideTy.getSizeInBits() &&
437            "illegal to increase number of bytes loaded");
438 
439     unsigned DstExt = MRI.createGenericVirtualRegister(WideTy);
440     MIRBuilder.buildLoad(DstExt, MI.getOperand(1).getReg(),
441                          **MI.memoperands_begin());
442     MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), DstExt);
443     MI.eraseFromParent();
444     return Legalized;
445   }
446   case TargetOpcode::G_STORE: {
447     assert(alignTo(MRI.getType(MI.getOperand(0).getReg()).getSizeInBits(), 8) ==
448                WideTy.getSizeInBits() &&
449            "illegal to increase number of bytes modified by a store");
450 
451     unsigned SrcExt = MRI.createGenericVirtualRegister(WideTy);
452     MIRBuilder.buildAnyExt(SrcExt, MI.getOperand(0).getReg());
453     MIRBuilder.buildStore(SrcExt, MI.getOperand(1).getReg(),
454                           **MI.memoperands_begin());
455     MI.eraseFromParent();
456     return Legalized;
457   }
458   case TargetOpcode::G_CONSTANT: {
459     unsigned DstExt = MRI.createGenericVirtualRegister(WideTy);
460     MIRBuilder.buildConstant(DstExt, *MI.getOperand(1).getCImm());
461     MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), DstExt);
462     MI.eraseFromParent();
463     return Legalized;
464   }
465   case TargetOpcode::G_FCONSTANT: {
466     unsigned DstExt = MRI.createGenericVirtualRegister(WideTy);
467     MIRBuilder.buildFConstant(DstExt, *MI.getOperand(1).getFPImm());
468     MIRBuilder.buildFPTrunc(MI.getOperand(0).getReg(), DstExt);
469     MI.eraseFromParent();
470     return Legalized;
471   }
472   case TargetOpcode::G_BRCOND: {
473     unsigned TstExt = MRI.createGenericVirtualRegister(WideTy);
474     MIRBuilder.buildAnyExt(TstExt, MI.getOperand(0).getReg());
475     MIRBuilder.buildBrCond(TstExt, *MI.getOperand(1).getMBB());
476     MI.eraseFromParent();
477     return Legalized;
478   }
479   case TargetOpcode::G_ICMP: {
480     assert(TypeIdx == 1 && "unable to legalize predicate");
481     bool IsSigned = CmpInst::isSigned(
482         static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate()));
483     unsigned Op0Ext = MRI.createGenericVirtualRegister(WideTy);
484     unsigned Op1Ext = MRI.createGenericVirtualRegister(WideTy);
485     if (IsSigned) {
486       MIRBuilder.buildSExt(Op0Ext, MI.getOperand(2).getReg());
487       MIRBuilder.buildSExt(Op1Ext, MI.getOperand(3).getReg());
488     } else {
489       MIRBuilder.buildZExt(Op0Ext, MI.getOperand(2).getReg());
490       MIRBuilder.buildZExt(Op1Ext, MI.getOperand(3).getReg());
491     }
492     MIRBuilder.buildICmp(
493         static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate()),
494         MI.getOperand(0).getReg(), Op0Ext, Op1Ext);
495     MI.eraseFromParent();
496     return Legalized;
497   }
498   case TargetOpcode::G_GEP: {
499     assert(TypeIdx == 1 && "unable to legalize pointer of GEP");
500     unsigned OffsetExt = MRI.createGenericVirtualRegister(WideTy);
501     MIRBuilder.buildSExt(OffsetExt, MI.getOperand(2).getReg());
502     MI.getOperand(2).setReg(OffsetExt);
503     return Legalized;
504   }
505   }
506 }
507 
508 LegalizerHelper::LegalizeResult
509 LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT Ty) {
510   using namespace TargetOpcode;
511   MIRBuilder.setInstr(MI);
512 
513   switch(MI.getOpcode()) {
514   default:
515     return UnableToLegalize;
516   case TargetOpcode::G_SREM:
517   case TargetOpcode::G_UREM: {
518     unsigned QuotReg = MRI.createGenericVirtualRegister(Ty);
519     MIRBuilder.buildInstr(MI.getOpcode() == G_SREM ? G_SDIV : G_UDIV)
520         .addDef(QuotReg)
521         .addUse(MI.getOperand(1).getReg())
522         .addUse(MI.getOperand(2).getReg());
523 
524     unsigned ProdReg = MRI.createGenericVirtualRegister(Ty);
525     MIRBuilder.buildMul(ProdReg, QuotReg, MI.getOperand(2).getReg());
526     MIRBuilder.buildSub(MI.getOperand(0).getReg(), MI.getOperand(1).getReg(),
527                         ProdReg);
528     MI.eraseFromParent();
529     return Legalized;
530   }
531   case TargetOpcode::G_SMULO:
532   case TargetOpcode::G_UMULO: {
533     // Generate G_UMULH/G_SMULH to check for overflow and a normal G_MUL for the
534     // result.
535     unsigned Res = MI.getOperand(0).getReg();
536     unsigned Overflow = MI.getOperand(1).getReg();
537     unsigned LHS = MI.getOperand(2).getReg();
538     unsigned RHS = MI.getOperand(3).getReg();
539 
540     MIRBuilder.buildMul(Res, LHS, RHS);
541 
542     unsigned Opcode = MI.getOpcode() == TargetOpcode::G_SMULO
543                           ? TargetOpcode::G_SMULH
544                           : TargetOpcode::G_UMULH;
545 
546     unsigned HiPart = MRI.createGenericVirtualRegister(Ty);
547     MIRBuilder.buildInstr(Opcode)
548       .addDef(HiPart)
549       .addUse(LHS)
550       .addUse(RHS);
551 
552     unsigned Zero = MRI.createGenericVirtualRegister(Ty);
553     MIRBuilder.buildConstant(Zero, 0);
554     MIRBuilder.buildICmp(CmpInst::ICMP_NE, Overflow, HiPart, Zero);
555     MI.eraseFromParent();
556     return Legalized;
557   }
558   }
559 }
560 
561 LegalizerHelper::LegalizeResult
562 LegalizerHelper::fewerElementsVector(MachineInstr &MI, unsigned TypeIdx,
563                                      LLT NarrowTy) {
564   // FIXME: Don't know how to handle secondary types yet.
565   if (TypeIdx != 0)
566     return UnableToLegalize;
567   switch (MI.getOpcode()) {
568   default:
569     return UnableToLegalize;
570   case TargetOpcode::G_ADD: {
571     unsigned NarrowSize = NarrowTy.getSizeInBits();
572     unsigned DstReg = MI.getOperand(0).getReg();
573     int NumParts = MRI.getType(DstReg).getSizeInBits() / NarrowSize;
574 
575     MIRBuilder.setInstr(MI);
576 
577     SmallVector<unsigned, 2> Src1Regs, Src2Regs, DstRegs;
578     SmallVector<uint64_t, 2> Indexes;
579     extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, Src1Regs);
580     extractParts(MI.getOperand(2).getReg(), NarrowTy, NumParts, Src2Regs);
581 
582     for (int i = 0; i < NumParts; ++i) {
583       unsigned DstReg = MRI.createGenericVirtualRegister(NarrowTy);
584       MIRBuilder.buildAdd(DstReg, Src1Regs[i], Src2Regs[i]);
585       DstRegs.push_back(DstReg);
586       Indexes.push_back(i * NarrowSize);
587     }
588 
589     MIRBuilder.buildSequence(DstReg, DstRegs, Indexes);
590     MI.eraseFromParent();
591     return Legalized;
592   }
593   }
594 }
595