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