1 //===-- llvm/CodeGen/GlobalISel/MachineIRBuilder.cpp - MIBuilder--*- C++ -*-==//
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 /// \file
10 /// This file implements the MachineIRBuidler class.
11 //===----------------------------------------------------------------------===//
12 #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
13 
14 #include "llvm/CodeGen/MachineFunction.h"
15 #include "llvm/CodeGen/MachineInstr.h"
16 #include "llvm/CodeGen/MachineInstrBuilder.h"
17 #include "llvm/Target/TargetInstrInfo.h"
18 #include "llvm/Target/TargetOpcodes.h"
19 #include "llvm/Target/TargetSubtargetInfo.h"
20 
21 using namespace llvm;
22 
23 void MachineIRBuilder::setMF(MachineFunction &MF) {
24   this->MF = &MF;
25   this->MBB = nullptr;
26   this->TII = MF.getSubtarget().getInstrInfo();
27   this->DL = DebugLoc();
28   this->MI = nullptr;
29   this->InsertedInstr = nullptr;
30 }
31 
32 void MachineIRBuilder::setMBB(MachineBasicBlock &MBB, bool Beginning) {
33   this->MBB = &MBB;
34   Before = Beginning;
35   assert(&getMF() == MBB.getParent() &&
36          "Basic block is in a different function");
37 }
38 
39 void MachineIRBuilder::setInstr(MachineInstr &MI, bool Before) {
40   assert(MI.getParent() && "Instruction is not part of a basic block");
41   setMBB(*MI.getParent());
42   this->MI = &MI;
43   this->Before = Before;
44 }
45 
46 MachineBasicBlock::iterator MachineIRBuilder::getInsertPt() {
47   if (MI) {
48     if (Before)
49       return MI;
50     if (!MI->getNextNode())
51       return getMBB().end();
52     return MI->getNextNode();
53   }
54   return Before ? getMBB().begin() : getMBB().end();
55 }
56 
57 void MachineIRBuilder::recordInsertions(
58     std::function<void(MachineInstr *)> Inserted) {
59   InsertedInstr = Inserted;
60 }
61 
62 void MachineIRBuilder::stopRecordingInsertions() {
63   InsertedInstr = nullptr;
64 }
65 
66 //------------------------------------------------------------------------------
67 // Build instruction variants.
68 //------------------------------------------------------------------------------
69 
70 MachineInstrBuilder MachineIRBuilder::buildInstr(unsigned Opcode,
71                                                   ArrayRef<LLT> Tys) {
72   MachineInstrBuilder MIB = BuildMI(getMF(), DL, getTII().get(Opcode));
73   if (Tys.size() > 0) {
74     assert(isPreISelGenericOpcode(Opcode) &&
75            "Only generic instruction can have a type");
76     for (unsigned i = 0; i < Tys.size(); ++i)
77       MIB->setType(Tys[i], i);
78   } else
79     assert(!isPreISelGenericOpcode(Opcode) &&
80            "Generic instruction must have a type");
81   getMBB().insert(getInsertPt(), MIB);
82   if (InsertedInstr)
83     InsertedInstr(MIB);
84   return MIB;
85 }
86 
87 MachineInstrBuilder MachineIRBuilder::buildFrameIndex(LLT Ty, unsigned Res,
88                                                        int Idx) {
89   return buildInstr(TargetOpcode::G_FRAME_INDEX, Ty)
90       .addDef(Res)
91       .addFrameIndex(Idx);
92 }
93 
94 MachineInstrBuilder MachineIRBuilder::buildAdd(LLT Ty, unsigned Res,
95                                                 unsigned Op0, unsigned Op1) {
96   return buildInstr(TargetOpcode::G_ADD, Ty)
97       .addDef(Res)
98       .addUse(Op0)
99       .addUse(Op1);
100 }
101 
102 MachineInstrBuilder MachineIRBuilder::buildSub(LLT Ty, unsigned Res,
103                                                 unsigned Op0, unsigned Op1) {
104   return buildInstr(TargetOpcode::G_SUB, Ty)
105       .addDef(Res)
106       .addUse(Op0)
107       .addUse(Op1);
108 }
109 
110 MachineInstrBuilder MachineIRBuilder::buildMul(LLT Ty, unsigned Res,
111                                                 unsigned Op0, unsigned Op1) {
112   return buildInstr(TargetOpcode::G_MUL, Ty)
113       .addDef(Res)
114       .addUse(Op0)
115       .addUse(Op1);
116 }
117 
118 MachineInstrBuilder MachineIRBuilder::buildBr(MachineBasicBlock &Dest) {
119   return buildInstr(TargetOpcode::G_BR, LLT::unsized()).addMBB(&Dest);
120 }
121 
122 MachineInstrBuilder MachineIRBuilder::buildCopy(unsigned Res, unsigned Op) {
123   return buildInstr(TargetOpcode::COPY).addDef(Res).addUse(Op);
124 }
125 
126 MachineInstrBuilder MachineIRBuilder::buildConstant(LLT Ty, unsigned Res,
127                                                     int64_t Val) {
128   return buildInstr(TargetOpcode::G_CONSTANT, Ty).addDef(Res).addImm(Val);
129 }
130 
131 MachineInstrBuilder MachineIRBuilder::buildFConstant(LLT Ty, unsigned Res,
132                                                     const ConstantFP &Val) {
133   return buildInstr(TargetOpcode::G_FCONSTANT, Ty).addDef(Res).addFPImm(&Val);
134 }
135 
136 MachineInstrBuilder MachineIRBuilder::buildBrCond(LLT Ty, unsigned Tst,
137                                                   MachineBasicBlock &Dest) {
138   return buildInstr(TargetOpcode::G_BRCOND, Ty).addUse(Tst).addMBB(&Dest);
139 }
140 
141 
142  MachineInstrBuilder MachineIRBuilder::buildLoad(LLT VTy, LLT PTy, unsigned Res,
143                                                  unsigned Addr,
144                                                  MachineMemOperand &MMO) {
145   return buildInstr(TargetOpcode::G_LOAD, {VTy, PTy})
146       .addDef(Res)
147       .addUse(Addr)
148       .addMemOperand(&MMO);
149 }
150 
151 MachineInstrBuilder MachineIRBuilder::buildStore(LLT VTy, LLT PTy,
152                                                   unsigned Val, unsigned Addr,
153                                                   MachineMemOperand &MMO) {
154   return buildInstr(TargetOpcode::G_STORE, {VTy, PTy})
155       .addUse(Val)
156       .addUse(Addr)
157       .addMemOperand(&MMO);
158 }
159 
160 MachineInstrBuilder
161 MachineIRBuilder::buildUAdde(ArrayRef<LLT> Tys, unsigned Res, unsigned CarryOut,
162                              unsigned Op0, unsigned Op1, unsigned CarryIn) {
163   return buildInstr(TargetOpcode::G_UADDE, Tys)
164       .addDef(Res)
165       .addDef(CarryOut)
166       .addUse(Op0)
167       .addUse(Op1)
168       .addUse(CarryIn);
169 }
170 
171 MachineInstrBuilder MachineIRBuilder::buildType(LLT Ty,
172                                                 unsigned Res, unsigned Op) {
173   return buildInstr(TargetOpcode::G_TYPE, Ty).addDef(Res).addUse(Op);
174 }
175 
176 MachineInstrBuilder MachineIRBuilder::buildAnyExt(ArrayRef<LLT> Tys,
177                                                   unsigned Res, unsigned Op) {
178   validateTruncExt(Tys, true);
179   return buildInstr(TargetOpcode::G_ANYEXT, Tys).addDef(Res).addUse(Op);
180 }
181 
182 MachineInstrBuilder MachineIRBuilder::buildSExt(ArrayRef<LLT> Tys, unsigned Res,
183                                                 unsigned Op) {
184   validateTruncExt(Tys, true);
185   return buildInstr(TargetOpcode::G_SEXT, Tys).addDef(Res).addUse(Op);
186 }
187 
188 MachineInstrBuilder MachineIRBuilder::buildZExt(ArrayRef<LLT> Tys, unsigned Res,
189                                                 unsigned Op) {
190   validateTruncExt(Tys, true);
191   return buildInstr(TargetOpcode::G_ZEXT, Tys).addDef(Res).addUse(Op);
192 }
193 
194 MachineInstrBuilder MachineIRBuilder::buildExtract(ArrayRef<LLT> ResTys,
195                                                    ArrayRef<unsigned> Results,
196                                                    ArrayRef<uint64_t> Indices,
197                                                    LLT SrcTy, unsigned Src) {
198   assert(ResTys.size() == Results.size() && Results.size() == Indices.size() &&
199          "inconsistent number of regs");
200   assert(!Results.empty() && "invalid trivial extract");
201   assert(std::is_sorted(Indices.begin(), Indices.end()) &&
202          "extract offsets must be in ascending order");
203 
204   auto MIB = BuildMI(getMF(), DL, getTII().get(TargetOpcode::G_EXTRACT));
205   for (unsigned i = 0; i < ResTys.size(); ++i)
206     MIB->setType(LLT::scalar(ResTys[i].getSizeInBits()), i);
207   MIB->setType(LLT::scalar(SrcTy.getSizeInBits()), ResTys.size());
208 
209   for (auto Res : Results)
210     MIB.addDef(Res);
211 
212   MIB.addUse(Src);
213 
214   for (auto Idx : Indices)
215     MIB.addImm(Idx);
216 
217   getMBB().insert(getInsertPt(), MIB);
218   if (InsertedInstr)
219     InsertedInstr(MIB);
220 
221   return MIB;
222 }
223 
224 MachineInstrBuilder
225 MachineIRBuilder::buildSequence(LLT ResTy, unsigned Res,
226                                 ArrayRef<LLT> OpTys,
227                                 ArrayRef<unsigned> Ops,
228                                 ArrayRef<unsigned> Indices) {
229   assert(OpTys.size() == Ops.size() && Ops.size() == Indices.size() &&
230          "incompatible args");
231   assert(!Ops.empty() && "invalid trivial sequence");
232   assert(std::is_sorted(Indices.begin(), Indices.end()) &&
233          "sequence offsets must be in ascending order");
234 
235   MachineInstrBuilder MIB =
236       buildInstr(TargetOpcode::G_SEQUENCE, LLT::scalar(ResTy.getSizeInBits()));
237   MIB.addDef(Res);
238   for (unsigned i = 0; i < Ops.size(); ++i) {
239     MIB.addUse(Ops[i]);
240     MIB.addImm(Indices[i]);
241     MIB->setType(LLT::scalar(OpTys[i].getSizeInBits()), MIB->getNumTypes());
242   }
243   return MIB;
244 }
245 
246 MachineInstrBuilder MachineIRBuilder::buildIntrinsic(ArrayRef<LLT> Tys,
247                                                      Intrinsic::ID ID,
248                                                      unsigned Res,
249                                                      bool HasSideEffects) {
250   auto MIB =
251       buildInstr(HasSideEffects ? TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS
252                                 : TargetOpcode::G_INTRINSIC,
253                  Tys);
254   if (Res)
255     MIB.addDef(Res);
256   MIB.addIntrinsicID(ID);
257   return MIB;
258 }
259 
260 MachineInstrBuilder MachineIRBuilder::buildTrunc(ArrayRef<LLT> Tys,
261                                                  unsigned Res, unsigned Op) {
262   validateTruncExt(Tys, false);
263   return buildInstr(TargetOpcode::G_TRUNC, Tys).addDef(Res).addUse(Op);
264 }
265 
266 MachineInstrBuilder MachineIRBuilder::buildFPTrunc(ArrayRef<LLT> Tys,
267                                                    unsigned Res, unsigned Op) {
268   validateTruncExt(Tys, false);
269   return buildInstr(TargetOpcode::G_FPTRUNC, Tys).addDef(Res).addUse(Op);
270 }
271 
272 MachineInstrBuilder MachineIRBuilder::buildICmp(ArrayRef<LLT> Tys,
273                                                 CmpInst::Predicate Pred,
274                                                 unsigned Res, unsigned Op0,
275                                                 unsigned Op1) {
276   return buildInstr(TargetOpcode::G_ICMP, Tys)
277       .addDef(Res)
278       .addPredicate(Pred)
279       .addUse(Op0)
280       .addUse(Op1);
281 }
282 
283 MachineInstrBuilder MachineIRBuilder::buildFCmp(ArrayRef<LLT> Tys,
284                                                 CmpInst::Predicate Pred,
285                                                 unsigned Res, unsigned Op0,
286                                                 unsigned Op1) {
287   return buildInstr(TargetOpcode::G_FCMP, Tys)
288       .addDef(Res)
289       .addPredicate(Pred)
290       .addUse(Op0)
291       .addUse(Op1);
292 }
293 
294 MachineInstrBuilder MachineIRBuilder::buildSelect(LLT Ty, unsigned Res,
295                                                   unsigned Tst,
296                                                   unsigned Op0, unsigned Op1) {
297   return buildInstr(TargetOpcode::G_SELECT, {Ty, LLT::scalar(1)})
298       .addDef(Res)
299       .addUse(Tst)
300       .addUse(Op0)
301       .addUse(Op1);
302 }
303 
304 void MachineIRBuilder::validateTruncExt(ArrayRef<LLT> Tys, bool IsExtend) {
305 #ifndef NDEBUG
306   assert(Tys.size() == 2 && "cast should have a source and a dest type");
307   LLT DstTy{Tys[0]}, SrcTy{Tys[1]};
308 
309   if (DstTy.isVector()) {
310     assert(SrcTy.isVector() && "mismatched cast between vecot and non-vector");
311     assert(SrcTy.getNumElements() == DstTy.getNumElements() &&
312            "different number of elements in a trunc/ext");
313   } else
314     assert(DstTy.isScalar() && SrcTy.isScalar() && "invalid extend/trunc");
315 
316   if (IsExtend)
317     assert(DstTy.getSizeInBits() > SrcTy.getSizeInBits() &&
318            "invalid narrowing extend");
319   else
320     assert(DstTy.getSizeInBits() < SrcTy.getSizeInBits() &&
321            "invalid widening trunc");
322 #endif
323 }
324