• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===- subzero/src/IceInst.cpp - High-level instruction implementation ----===//
2 //
3 //                        The Subzero Code Generator
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
11 /// \brief Implements the Inst class, primarily the various subclass
12 /// constructors and dump routines.
13 ///
14 //===----------------------------------------------------------------------===//
15 
16 #include "IceInst.h"
17 
18 #include "IceCfg.h"
19 #include "IceCfgNode.h"
20 #include "IceInstVarIter.h"
21 #include "IceLiveness.h"
22 #include "IceOperand.h"
23 #include "IceTargetLowering.h"
24 
25 #include "llvm/Support/Format.h"
26 
27 namespace Ice {
28 
29 namespace {
30 
31 // Using non-anonymous struct so that array_lengthof works.
32 const struct InstArithmeticAttributes_ {
33   const char *DisplayString;
34   bool IsCommutative;
35 } InstArithmeticAttributes[] = {
36 #define X(tag, str, commutative) {str, commutative},
37     ICEINSTARITHMETIC_TABLE
38 #undef X
39 };
40 
41 // Using non-anonymous struct so that array_lengthof works.
42 const struct InstCastAttributes_ {
43   const char *DisplayString;
44 } InstCastAttributes[] = {
45 #define X(tag, str) {str},
46     ICEINSTCAST_TABLE
47 #undef X
48 };
49 
50 // Using non-anonymous struct so that array_lengthof works.
51 const struct InstFcmpAttributes_ {
52   const char *DisplayString;
53 } InstFcmpAttributes[] = {
54 #define X(tag, str) {str},
55     ICEINSTFCMP_TABLE
56 #undef X
57 };
58 
59 // Using non-anonymous struct so that array_lengthof works.
60 const struct InstIcmpAttributes_ {
61   const char *DisplayString;
62   InstIcmp::ICond Reverse;
63 } InstIcmpAttributes[] = {
64 #define X(tag, reverse, str) {str, InstIcmp::ICond::reverse},
65     ICEINSTICMP_TABLE
66 #undef X
67 };
68 
69 } // end of anonymous namespace
70 
Inst(Cfg * Func,InstKind Kind,SizeT MaxSrcs,Variable * Dest)71 Inst::Inst(Cfg *Func, InstKind Kind, SizeT MaxSrcs, Variable *Dest)
72     : Kind(Kind), Number(Func->newInstNumber()), Dest(Dest), MaxSrcs(MaxSrcs),
73       LiveRangesEnded(0) {
74   Srcs.reserve(MaxSrcs);
75 }
76 
getInstName() const77 const char *Inst::getInstName() const {
78   if (!BuildDefs::dump())
79     return "???";
80 
81   switch (Kind) {
82 #define X(InstrKind, name)                                                     \
83   case InstrKind:                                                              \
84     return name
85     X(Unreachable, "unreachable");
86     X(Alloca, "alloca");
87     X(Arithmetic, "arithmetic");
88     X(Br, "br");
89     X(Call, "call");
90     X(Cast, "cast");
91     X(ExtractElement, "extractelement");
92     X(Fcmp, "fcmp");
93     X(Icmp, "icmp");
94     X(Intrinsic, "intrinsic");
95     X(InsertElement, "insertelement");
96     X(Load, "load");
97     X(Phi, "phi");
98     X(Ret, "ret");
99     X(Select, "select");
100     X(Store, "store");
101     X(Switch, "switch");
102     X(Assign, "assign");
103     X(Breakpoint, "break");
104     X(FakeDef, "fakedef");
105     X(FakeUse, "fakeuse");
106     X(FakeKill, "fakekill");
107     X(JumpTable, "jumptable");
108     X(ShuffleVector, "shufflevector");
109 #undef X
110   default:
111     assert(Kind >= Target);
112     return "target";
113   }
114 }
115 
116 // Assign the instruction a new number.
renumber(Cfg * Func)117 void Inst::renumber(Cfg *Func) {
118   Number = isDeleted() ? NumberDeleted : Func->newInstNumber();
119 }
120 
121 // Delete the instruction if its tentative Dead flag is still set after
122 // liveness analysis.
deleteIfDead()123 void Inst::deleteIfDead() {
124   if (Dead)
125     setDeleted();
126 }
127 
128 // If Src is a Variable, it returns true if this instruction ends Src's live
129 // range. Otherwise, returns false.
isLastUse(const Operand * TestSrc) const130 bool Inst::isLastUse(const Operand *TestSrc) const {
131   if (LiveRangesEnded == 0)
132     return false; // early-exit optimization
133   if (auto *TestVar = llvm::dyn_cast<const Variable>(TestSrc)) {
134     LREndedBits Mask = LiveRangesEnded;
135     FOREACH_VAR_IN_INST(Var, *this) {
136       if (Var == TestVar) {
137         // We've found where the variable is used in the instruction.
138         return Mask & 1;
139       }
140       Mask >>= 1;
141       if (Mask == 0)
142         return false; // another early-exit optimization
143     }
144   }
145   return false;
146 }
147 
148 // Given an instruction like:
149 //   a = b + c + [x,y] + e
150 // which was created from OrigInst:
151 //   a = b + c + d + e
152 // with SpliceAssn spliced in:
153 //   d = [x,y]
154 //
155 // Reconstruct the LiveRangesEnded bitmask in this instruction by combining the
156 // LiveRangesEnded values of OrigInst and SpliceAssn. If operands d and [x,y]
157 // contain a different number of variables, then the bitmask position for e may
158 // be different in OrigInst and the current instruction, requiring extra shifts
159 // and masks in the computation. In the example above, OrigInst has variable e
160 // in bit position 3, whereas the current instruction has e in bit position 4
161 // because [x,y] consumes 2 bitmask slots while d only consumed 1.
162 //
163 // Additionally, set HasSideEffects if either OrigInst or SpliceAssn have
164 // HasSideEffects set.
spliceLivenessInfo(Inst * OrigInst,Inst * SpliceAssn)165 void Inst::spliceLivenessInfo(Inst *OrigInst, Inst *SpliceAssn) {
166   HasSideEffects |= OrigInst->HasSideEffects;
167   HasSideEffects |= SpliceAssn->HasSideEffects;
168   // Find the bitmask index of SpliceAssn's dest within OrigInst.
169   Variable *SpliceDest = SpliceAssn->getDest();
170   SizeT Index = 0;
171   for (SizeT I = 0; I < OrigInst->getSrcSize(); ++I) {
172     Operand *Src = OrigInst->getSrc(I);
173     if (Src == SpliceDest) {
174       LREndedBits LeftMask = OrigInst->LiveRangesEnded & ((1 << Index) - 1);
175       LREndedBits RightMask = OrigInst->LiveRangesEnded >> (Index + 1);
176       LiveRangesEnded = LeftMask | (SpliceAssn->LiveRangesEnded << Index) |
177                         (RightMask << (Index + getSrc(I)->getNumVars()));
178       return;
179     }
180     Index += getSrc(I)->getNumVars();
181   }
182   llvm::report_fatal_error("Failed to find splice operand");
183 }
184 
isMemoryWrite() const185 bool Inst::isMemoryWrite() const {
186   llvm::report_fatal_error("Attempt to call base Inst::isMemoryWrite() method");
187 }
188 
livenessLightweight(Cfg * Func,LivenessBV & Live)189 void Inst::livenessLightweight(Cfg *Func, LivenessBV &Live) {
190   assert(!isDeleted());
191   resetLastUses();
192   VariablesMetadata *VMetadata = Func->getVMetadata();
193   FOREACH_VAR_IN_INST(Var, *this) {
194     if (VMetadata->isMultiBlock(Var))
195       continue;
196     SizeT Index = Var->getIndex();
197     if (Live[Index])
198       continue;
199     Live[Index] = true;
200     setLastUse(IndexOfVarInInst(Var));
201   }
202 }
203 
liveness(InstNumberT InstNumber,LivenessBV & Live,Liveness * Liveness,LiveBeginEndMap * LiveBegin,LiveBeginEndMap * LiveEnd)204 bool Inst::liveness(InstNumberT InstNumber, LivenessBV &Live,
205                     Liveness *Liveness, LiveBeginEndMap *LiveBegin,
206                     LiveBeginEndMap *LiveEnd) {
207   assert(!isDeleted());
208 
209   Dead = false;
210   if (Dest && !Dest->isRematerializable()) {
211     SizeT VarNum = Liveness->getLiveIndex(Dest->getIndex());
212     if (Live[VarNum]) {
213       if (!isDestRedefined()) {
214         Live[VarNum] = false;
215         if (LiveBegin && Liveness->getRangeMask(Dest->getIndex())) {
216           LiveBegin->push_back(std::make_pair(VarNum, InstNumber));
217         }
218       }
219     } else {
220       if (!hasSideEffects())
221         Dead = true;
222     }
223   }
224   if (Dead)
225     return false;
226   // Phi arguments only get added to Live in the predecessor node, but we still
227   // need to update LiveRangesEnded.
228   bool IsPhi = llvm::isa<InstPhi>(this);
229   resetLastUses();
230   FOREACH_VAR_IN_INST(Var, *this) {
231     if (Var->isRematerializable())
232       continue;
233     SizeT VarNum = Liveness->getLiveIndex(Var->getIndex());
234     if (!Live[VarNum]) {
235       setLastUse(IndexOfVarInInst(Var));
236       if (!IsPhi) {
237         Live[VarNum] = true;
238         // For a variable in SSA form, its live range can end at most once in a
239         // basic block. However, after lowering to two-address instructions, we
240         // end up with sequences like "t=b;t+=c;a=t" where t's live range
241         // begins and ends twice. ICE only allows a variable to have a single
242         // liveness interval in a basic block (except for blocks where a
243         // variable is live-in and live-out but there is a gap in the middle).
244         // Therefore, this lowered sequence needs to represent a single
245         // conservative live range for t. Since the instructions are being
246         // traversed backwards, we make sure LiveEnd is only set once by
247         // setting it only when LiveEnd[VarNum]==0 (sentinel value). Note that
248         // it's OK to set LiveBegin multiple times because of the backwards
249         // traversal.
250         if (LiveEnd && Liveness->getRangeMask(Var->getIndex())) {
251           // Ideally, we would verify that VarNum wasn't already added in this
252           // block, but this can't be done very efficiently with LiveEnd as a
253           // vector. Instead, livenessPostprocess() verifies this after the
254           // vector has been sorted.
255           LiveEnd->push_back(std::make_pair(VarNum, InstNumber));
256         }
257       }
258     }
259   }
260   return true;
261 }
262 
InstAlloca(Cfg * Func,Variable * Dest,Operand * ByteCount,uint32_t AlignInBytes)263 InstAlloca::InstAlloca(Cfg *Func, Variable *Dest, Operand *ByteCount,
264                        uint32_t AlignInBytes)
265     : InstHighLevel(Func, Inst::Alloca, 1, Dest), AlignInBytes(AlignInBytes) {
266   // Verify AlignInBytes is 0 or a power of 2.
267   assert(AlignInBytes == 0 || llvm::isPowerOf2_32(AlignInBytes));
268   addSource(ByteCount);
269 }
270 
InstArithmetic(Cfg * Func,OpKind Op,Variable * Dest,Operand * Source1,Operand * Source2)271 InstArithmetic::InstArithmetic(Cfg *Func, OpKind Op, Variable *Dest,
272                                Operand *Source1, Operand *Source2)
273     : InstHighLevel(Func, Inst::Arithmetic, 2, Dest), Op(Op) {
274   addSource(Source1);
275   addSource(Source2);
276 }
277 
getInstName() const278 const char *InstArithmetic::getInstName() const {
279   if (!BuildDefs::dump())
280     return "???";
281 
282   return InstArithmeticAttributes[getOp()].DisplayString;
283 }
284 
getOpName(OpKind Op)285 const char *InstArithmetic::getOpName(OpKind Op) {
286   return Op < InstArithmetic::_num ? InstArithmeticAttributes[Op].DisplayString
287                                    : "???";
288 }
289 
isCommutative() const290 bool InstArithmetic::isCommutative() const {
291   return InstArithmeticAttributes[getOp()].IsCommutative;
292 }
293 
InstAssign(Cfg * Func,Variable * Dest,Operand * Source)294 InstAssign::InstAssign(Cfg *Func, Variable *Dest, Operand *Source)
295     : InstHighLevel(Func, Inst::Assign, 1, Dest) {
296   addSource(Source);
297 }
298 
isVarAssign() const299 bool InstAssign::isVarAssign() const { return llvm::isa<Variable>(getSrc(0)); }
300 
301 // If TargetTrue==TargetFalse, we turn it into an unconditional branch. This
302 // ensures that, along with the 'switch' instruction semantics, there is at
303 // most one edge from one node to another.
InstBr(Cfg * Func,Operand * Source,CfgNode * TargetTrue_,CfgNode * TargetFalse_)304 InstBr::InstBr(Cfg *Func, Operand *Source, CfgNode *TargetTrue_,
305                CfgNode *TargetFalse_)
306     : InstHighLevel(Func, Inst::Br, 1, nullptr), TargetFalse(TargetFalse_),
307       TargetTrue(TargetTrue_) {
308   if (auto *Constant = llvm::dyn_cast<ConstantInteger32>(Source)) {
309     int32_t C32 = Constant->getValue();
310     if (C32 != 0) {
311       TargetFalse = TargetTrue;
312     }
313     TargetTrue = nullptr; // turn into unconditional version
314   } else if (TargetTrue == TargetFalse) {
315     TargetTrue = nullptr; // turn into unconditional version
316   } else {
317     addSource(Source);
318   }
319 }
320 
InstBr(Cfg * Func,CfgNode * Target)321 InstBr::InstBr(Cfg *Func, CfgNode *Target)
322     : InstHighLevel(Func, Inst::Br, 0, nullptr), TargetFalse(Target),
323       TargetTrue(nullptr) {}
324 
getTerminatorEdges() const325 NodeList InstBr::getTerminatorEdges() const {
326   NodeList OutEdges;
327   OutEdges.reserve(TargetTrue ? 2 : 1);
328   OutEdges.push_back(TargetFalse);
329   if (TargetTrue)
330     OutEdges.push_back(TargetTrue);
331   return OutEdges;
332 }
333 
repointEdges(CfgNode * OldNode,CfgNode * NewNode)334 bool InstBr::repointEdges(CfgNode *OldNode, CfgNode *NewNode) {
335   bool Found = false;
336   if (TargetFalse == OldNode) {
337     TargetFalse = NewNode;
338     Found = true;
339   }
340   if (TargetTrue == OldNode) {
341     TargetTrue = NewNode;
342     Found = true;
343   }
344   return Found;
345 }
346 
InstCast(Cfg * Func,OpKind CastKind,Variable * Dest,Operand * Source)347 InstCast::InstCast(Cfg *Func, OpKind CastKind, Variable *Dest, Operand *Source)
348     : InstHighLevel(Func, Inst::Cast, 1, Dest), CastKind(CastKind) {
349   addSource(Source);
350 }
351 
InstExtractElement(Cfg * Func,Variable * Dest,Operand * Source1,Operand * Source2)352 InstExtractElement::InstExtractElement(Cfg *Func, Variable *Dest,
353                                        Operand *Source1, Operand *Source2)
354     : InstHighLevel(Func, Inst::ExtractElement, 2, Dest) {
355   addSource(Source1);
356   addSource(Source2);
357 }
358 
InstFcmp(Cfg * Func,FCond Condition,Variable * Dest,Operand * Source1,Operand * Source2)359 InstFcmp::InstFcmp(Cfg *Func, FCond Condition, Variable *Dest, Operand *Source1,
360                    Operand *Source2)
361     : InstHighLevel(Func, Inst::Fcmp, 2, Dest), Condition(Condition) {
362   addSource(Source1);
363   addSource(Source2);
364 }
365 
InstIcmp(Cfg * Func,ICond Condition,Variable * Dest,Operand * Source1,Operand * Source2)366 InstIcmp::InstIcmp(Cfg *Func, ICond Condition, Variable *Dest, Operand *Source1,
367                    Operand *Source2)
368     : InstHighLevel(Func, Inst::Icmp, 2, Dest), Condition(Condition) {
369   addSource(Source1);
370   addSource(Source2);
371 }
372 
InstInsertElement(Cfg * Func,Variable * Dest,Operand * Source1,Operand * Source2,Operand * Source3)373 InstInsertElement::InstInsertElement(Cfg *Func, Variable *Dest,
374                                      Operand *Source1, Operand *Source2,
375                                      Operand *Source3)
376     : InstHighLevel(Func, Inst::InsertElement, 3, Dest) {
377   addSource(Source1);
378   addSource(Source2);
379   addSource(Source3);
380 }
381 
InstLoad(Cfg * Func,Variable * Dest,Operand * SourceAddr)382 InstLoad::InstLoad(Cfg *Func, Variable *Dest, Operand *SourceAddr)
383     : InstHighLevel(Func, Inst::Load, 1, Dest) {
384   addSource(SourceAddr);
385 }
386 
InstPhi(Cfg * Func,SizeT MaxSrcs,Variable * Dest)387 InstPhi::InstPhi(Cfg *Func, SizeT MaxSrcs, Variable *Dest)
388     : InstHighLevel(Func, Phi, MaxSrcs, Dest) {
389   Labels.reserve(MaxSrcs);
390 }
391 
392 // TODO: A Switch instruction (and maybe others) can add duplicate edges. We
393 // may want to de-dup Phis and validate consistency (i.e., the source operands
394 // are the same for duplicate edges), though it seems the current lowering code
395 // is OK with this situation.
addArgument(Operand * Source,CfgNode * Label)396 void InstPhi::addArgument(Operand *Source, CfgNode *Label) {
397   assert(Label);
398   Labels.push_back(Label);
399   addSource(Source);
400 }
401 
402 // Find the source operand corresponding to the incoming edge for the given
403 // node.
getOperandForTarget(CfgNode * Target) const404 Operand *InstPhi::getOperandForTarget(CfgNode *Target) const {
405   for (SizeT I = 0; I < getSrcSize(); ++I) {
406     if (Labels[I] == Target)
407       return getSrc(I);
408   }
409   llvm_unreachable("Phi target not found");
410   return nullptr;
411 }
412 
413 // Replace the source operand corresponding to the incoming edge for the given
414 // node by a zero of the appropriate type.
clearOperandForTarget(CfgNode * Target)415 void InstPhi::clearOperandForTarget(CfgNode *Target) {
416   for (SizeT I = 0; I < getSrcSize(); ++I) {
417     if (getLabel(I) == Target) {
418       Type Ty = Dest->getType();
419       Srcs[I] = Target->getCfg()->getContext()->getConstantZero(Ty);
420       return;
421     }
422   }
423   llvm_unreachable("Phi target not found");
424 }
425 
426 // Updates liveness for a particular operand based on the given predecessor
427 // edge. Doesn't mark the operand as live if the Phi instruction is dead or
428 // deleted.
livenessPhiOperand(LivenessBV & Live,CfgNode * Target,Liveness * Liveness)429 void InstPhi::livenessPhiOperand(LivenessBV &Live, CfgNode *Target,
430                                  Liveness *Liveness) {
431   if (isDeleted() || Dead)
432     return;
433   for (SizeT I = 0; I < getSrcSize(); ++I) {
434     if (Labels[I] == Target) {
435       if (auto *Var = llvm::dyn_cast<Variable>(getSrc(I))) {
436         if (!Var->isRematerializable()) {
437           SizeT SrcIndex = Liveness->getLiveIndex(Var->getIndex());
438           if (!Live[SrcIndex]) {
439             setLastUse(I);
440             Live[SrcIndex] = true;
441           }
442         }
443       }
444       return;
445     }
446   }
447   llvm_unreachable("Phi operand not found for specified target node");
448 }
449 
450 // Change "a=phi(...)" to "a_phi=phi(...)" and return a new instruction
451 // "a=a_phi".
lower(Cfg * Func)452 Inst *InstPhi::lower(Cfg *Func) {
453   Variable *Dest = getDest();
454   assert(Dest);
455   Variable *NewSrc = Func->makeVariable(Dest->getType());
456   if (BuildDefs::dump())
457     NewSrc->setName(Func, Dest->getName() + "_phi");
458   if (auto *NewSrc64On32 = llvm::dyn_cast<Variable64On32>(NewSrc))
459     NewSrc64On32->initHiLo(Func);
460   this->Dest = NewSrc;
461   return InstAssign::create(Func, Dest, NewSrc);
462 }
463 
InstRet(Cfg * Func,Operand * RetValue)464 InstRet::InstRet(Cfg *Func, Operand *RetValue)
465     : InstHighLevel(Func, Ret, RetValue ? 1 : 0, nullptr) {
466   if (RetValue)
467     addSource(RetValue);
468 }
469 
InstSelect(Cfg * Func,Variable * Dest,Operand * Condition,Operand * SourceTrue,Operand * SourceFalse)470 InstSelect::InstSelect(Cfg *Func, Variable *Dest, Operand *Condition,
471                        Operand *SourceTrue, Operand *SourceFalse)
472     : InstHighLevel(Func, Inst::Select, 3, Dest) {
473   assert(typeElementType(Condition->getType()) == IceType_i1);
474   addSource(Condition);
475   addSource(SourceTrue);
476   addSource(SourceFalse);
477 }
478 
InstStore(Cfg * Func,Operand * Data,Operand * Addr)479 InstStore::InstStore(Cfg *Func, Operand *Data, Operand *Addr)
480     : InstHighLevel(Func, Inst::Store, 3, nullptr) {
481   addSource(Data);
482   addSource(Addr);
483   // The 3rd operand is a dummy placeholder for the RMW beacon.
484   addSource(Data);
485 }
486 
getRmwBeacon() const487 Variable *InstStore::getRmwBeacon() const {
488   return llvm::dyn_cast<Variable>(getSrc(2));
489 }
490 
setRmwBeacon(Variable * Beacon)491 void InstStore::setRmwBeacon(Variable *Beacon) {
492   Dest = llvm::dyn_cast<Variable>(getData());
493   Srcs[2] = Beacon;
494 }
495 
InstSwitch(Cfg * Func,SizeT NumCases,Operand * Source,CfgNode * LabelDefault)496 InstSwitch::InstSwitch(Cfg *Func, SizeT NumCases, Operand *Source,
497                        CfgNode *LabelDefault)
498     : InstHighLevel(Func, Inst::Switch, 1, nullptr), LabelDefault(LabelDefault),
499       NumCases(NumCases) {
500   addSource(Source);
501   Values = Func->allocateArrayOf<uint64_t>(NumCases);
502   Labels = Func->allocateArrayOf<CfgNode *>(NumCases);
503   // Initialize in case buggy code doesn't set all entries
504   for (SizeT I = 0; I < NumCases; ++I) {
505     Values[I] = 0;
506     Labels[I] = nullptr;
507   }
508 }
509 
addBranch(SizeT CaseIndex,uint64_t Value,CfgNode * Label)510 void InstSwitch::addBranch(SizeT CaseIndex, uint64_t Value, CfgNode *Label) {
511   assert(CaseIndex < NumCases);
512   Values[CaseIndex] = Value;
513   Labels[CaseIndex] = Label;
514 }
515 
getTerminatorEdges() const516 NodeList InstSwitch::getTerminatorEdges() const {
517   NodeList OutEdges;
518   OutEdges.reserve(NumCases + 1);
519   assert(LabelDefault);
520   OutEdges.push_back(LabelDefault);
521   for (SizeT I = 0; I < NumCases; ++I) {
522     assert(Labels[I]);
523     OutEdges.push_back(Labels[I]);
524   }
525   std::sort(OutEdges.begin(), OutEdges.end(),
526             [](const CfgNode *x, const CfgNode *y) {
527               return x->getIndex() < y->getIndex();
528             });
529   auto Last = std::unique(OutEdges.begin(), OutEdges.end());
530   OutEdges.erase(Last, OutEdges.end());
531   return OutEdges;
532 }
533 
repointEdges(CfgNode * OldNode,CfgNode * NewNode)534 bool InstSwitch::repointEdges(CfgNode *OldNode, CfgNode *NewNode) {
535   bool Found = false;
536   if (LabelDefault == OldNode) {
537     LabelDefault = NewNode;
538     Found = true;
539   }
540   for (SizeT I = 0; I < NumCases; ++I) {
541     if (Labels[I] == OldNode) {
542       Labels[I] = NewNode;
543       Found = true;
544     }
545   }
546   return Found;
547 }
548 
InstUnreachable(Cfg * Func)549 InstUnreachable::InstUnreachable(Cfg *Func)
550     : InstHighLevel(Func, Inst::Unreachable, 0, nullptr) {}
551 
InstFakeDef(Cfg * Func,Variable * Dest,Variable * Src)552 InstFakeDef::InstFakeDef(Cfg *Func, Variable *Dest, Variable *Src)
553     : InstHighLevel(Func, Inst::FakeDef, Src ? 1 : 0, Dest) {
554   assert(Dest);
555   if (Src)
556     addSource(Src);
557 }
558 
InstFakeUse(Cfg * Func,Variable * Src,uint32_t Weight)559 InstFakeUse::InstFakeUse(Cfg *Func, Variable *Src, uint32_t Weight)
560     : InstHighLevel(Func, Inst::FakeUse, Weight, nullptr) {
561   assert(Src);
562   for (uint32_t i = 0; i < Weight; ++i)
563     addSource(Src);
564 }
565 
InstFakeKill(Cfg * Func,const Inst * Linked)566 InstFakeKill::InstFakeKill(Cfg *Func, const Inst *Linked)
567     : InstHighLevel(Func, Inst::FakeKill, 0, nullptr), Linked(Linked) {}
568 
InstShuffleVector(Cfg * Func,Variable * Dest,Operand * Src0,Operand * Src1)569 InstShuffleVector::InstShuffleVector(Cfg *Func, Variable *Dest, Operand *Src0,
570                                      Operand *Src1)
571     : InstHighLevel(Func, Inst::ShuffleVector, 2, Dest),
572       NumIndexes(typeNumElements(Dest->getType())) {
573   addSource(Src0);
574   addSource(Src1);
575   Indexes = Func->allocateArrayOf<ConstantInteger32 *>(NumIndexes);
576 }
577 
578 namespace {
makeName(Cfg * Func,const SizeT Id)579 GlobalString makeName(Cfg *Func, const SizeT Id) {
580   const auto FuncName = Func->getFunctionName();
581   auto *Ctx = Func->getContext();
582   if (FuncName.hasStdString())
583     return GlobalString::createWithString(
584         Ctx, ".L" + FuncName.toString() + "$jumptable$__" + std::to_string(Id));
585   return GlobalString::createWithString(
586       Ctx, "$J" + std::to_string(FuncName.getID()) + "_" + std::to_string(Id));
587 }
588 } // end of anonymous namespace
589 
InstJumpTable(Cfg * Func,SizeT NumTargets,CfgNode * Default)590 InstJumpTable::InstJumpTable(Cfg *Func, SizeT NumTargets, CfgNode *Default)
591     : InstHighLevel(Func, Inst::JumpTable, 1, nullptr),
592       Id(Func->getTarget()->makeNextJumpTableNumber()), NumTargets(NumTargets),
593       Name(makeName(Func, Id)), FuncName(Func->getFunctionName()) {
594   Targets = Func->allocateArrayOf<CfgNode *>(NumTargets);
595   for (SizeT I = 0; I < NumTargets; ++I) {
596     Targets[I] = Default;
597   }
598 }
599 
repointEdges(CfgNode * OldNode,CfgNode * NewNode)600 bool InstJumpTable::repointEdges(CfgNode *OldNode, CfgNode *NewNode) {
601   bool Found = false;
602   for (SizeT I = 0; I < NumTargets; ++I) {
603     if (Targets[I] == OldNode) {
604       Targets[I] = NewNode;
605       Found = true;
606     }
607   }
608   return Found;
609 }
610 
toJumpTableData(Assembler * Asm) const611 JumpTableData InstJumpTable::toJumpTableData(Assembler *Asm) const {
612   JumpTableData::TargetList TargetList(NumTargets);
613   for (SizeT i = 0; i < NumTargets; ++i) {
614     const SizeT Index = Targets[i]->getIndex();
615     TargetList[i] = Asm->getCfgNodeLabel(Index)->getPosition();
616   }
617   return JumpTableData(Name, FuncName, Id, TargetList);
618 }
619 
getReturnType() const620 Type InstCall::getReturnType() const {
621   if (Dest == nullptr)
622     return IceType_void;
623   return Dest->getType();
624 }
625 
626 // ======================== Dump routines ======================== //
627 
dumpDecorated(const Cfg * Func) const628 void Inst::dumpDecorated(const Cfg *Func) const {
629   if (!BuildDefs::dump())
630     return;
631   Ostream &Str = Func->getContext()->getStrDump();
632   if (!Func->isVerbose(IceV_Deleted) && (isDeleted() || isRedundantAssign()))
633     return;
634   if (Func->isVerbose(IceV_InstNumbers)) {
635     InstNumberT Number = getNumber();
636     if (Number == NumberDeleted)
637       Str << "[XXX]";
638     else
639       Str << llvm::format("[%3d]", Number);
640   }
641   Str << "  ";
642   if (isDeleted())
643     Str << "  //";
644   dump(Func);
645   dumpExtras(Func);
646   Str << "\n";
647 }
648 
dump(const Cfg * Func) const649 void Inst::dump(const Cfg *Func) const {
650   if (!BuildDefs::dump())
651     return;
652   Ostream &Str = Func->getContext()->getStrDump();
653   dumpDest(Func);
654   Str << " =~ " << getInstName() << " ";
655   dumpSources(Func);
656 }
657 
dumpExtras(const Cfg * Func) const658 void Inst::dumpExtras(const Cfg *Func) const {
659   if (!BuildDefs::dump())
660     return;
661   Ostream &Str = Func->getContext()->getStrDump();
662   bool First = true;
663   // Print "LIVEEND={a,b,c}" for all source operands whose live ranges are
664   // known to end at this instruction.
665   if (Func->isVerbose(IceV_Liveness)) {
666     FOREACH_VAR_IN_INST(Var, *this) {
667       if (isLastUse(Var)) {
668         if (First)
669           Str << " // LIVEEND={";
670         else
671           Str << ",";
672         Var->dump(Func);
673         First = false;
674       }
675     }
676     if (!First)
677       Str << "}";
678   }
679 }
680 
dumpSources(const Cfg * Func) const681 void Inst::dumpSources(const Cfg *Func) const {
682   if (!BuildDefs::dump())
683     return;
684   Ostream &Str = Func->getContext()->getStrDump();
685   for (SizeT I = 0; I < getSrcSize(); ++I) {
686     if (I > 0)
687       Str << ", ";
688     getSrc(I)->dump(Func);
689   }
690 }
691 
emitSources(const Cfg * Func) const692 void Inst::emitSources(const Cfg *Func) const {
693   if (!BuildDefs::dump())
694     return;
695   Ostream &Str = Func->getContext()->getStrEmit();
696   for (SizeT I = 0; I < getSrcSize(); ++I) {
697     if (I > 0)
698       Str << ", ";
699     getSrc(I)->emit(Func);
700   }
701 }
702 
dumpDest(const Cfg * Func) const703 void Inst::dumpDest(const Cfg *Func) const {
704   if (!BuildDefs::dump())
705     return;
706   if (getDest())
707     getDest()->dump(Func);
708 }
709 
dump(const Cfg * Func) const710 void InstAlloca::dump(const Cfg *Func) const {
711   if (!BuildDefs::dump())
712     return;
713   Ostream &Str = Func->getContext()->getStrDump();
714   dumpDest(Func);
715   Str << " = alloca i8, i32 ";
716   getSizeInBytes()->dump(Func);
717   if (getAlignInBytes())
718     Str << ", align " << getAlignInBytes();
719 }
720 
dump(const Cfg * Func) const721 void InstArithmetic::dump(const Cfg *Func) const {
722   if (!BuildDefs::dump())
723     return;
724   Ostream &Str = Func->getContext()->getStrDump();
725   dumpDest(Func);
726   Str << " = " << getInstName() << " " << getDest()->getType() << " ";
727   dumpSources(Func);
728 }
729 
dump(const Cfg * Func) const730 void InstAssign::dump(const Cfg *Func) const {
731   if (!BuildDefs::dump())
732     return;
733   Ostream &Str = Func->getContext()->getStrDump();
734   dumpDest(Func);
735   Str << " = " << getDest()->getType() << " ";
736   dumpSources(Func);
737 }
738 
dump(const Cfg * Func) const739 void InstBr::dump(const Cfg *Func) const {
740   if (!BuildDefs::dump())
741     return;
742   Ostream &Str = Func->getContext()->getStrDump();
743   dumpDest(Func);
744   Str << "br ";
745   if (!isUnconditional()) {
746     Str << "i1 ";
747     getCondition()->dump(Func);
748     Str << ", label %" << getTargetTrue()->getName() << ", ";
749   }
750   Str << "label %" << getTargetFalse()->getName();
751 }
752 
dump(const Cfg * Func) const753 void InstCall::dump(const Cfg *Func) const {
754   if (!BuildDefs::dump())
755     return;
756   Ostream &Str = Func->getContext()->getStrDump();
757   if (getDest()) {
758     dumpDest(Func);
759     Str << " = ";
760   }
761   Str << "call ";
762   if (getDest())
763     Str << getDest()->getType();
764   else
765     Str << "void";
766   Str << " ";
767   getCallTarget()->dump(Func);
768   Str << "(";
769   for (SizeT I = 0; I < getNumArgs(); ++I) {
770     if (I > 0)
771       Str << ", ";
772     Str << getArg(I)->getType() << " ";
773     getArg(I)->dump(Func);
774   }
775   Str << ")";
776 }
777 
getCastName(InstCast::OpKind Kind)778 const char *InstCast::getCastName(InstCast::OpKind Kind) {
779   if (Kind < InstCast::OpKind::_num)
780     return InstCastAttributes[Kind].DisplayString;
781   llvm_unreachable("Invalid InstCast::OpKind");
782   return "???";
783 }
784 
dump(const Cfg * Func) const785 void InstCast::dump(const Cfg *Func) const {
786   if (!BuildDefs::dump())
787     return;
788   Ostream &Str = Func->getContext()->getStrDump();
789   dumpDest(Func);
790   Str << " = " << getCastName(getCastKind()) << " " << getSrc(0)->getType()
791       << " ";
792   dumpSources(Func);
793   Str << " to " << getDest()->getType();
794 }
795 
dump(const Cfg * Func) const796 void InstIcmp::dump(const Cfg *Func) const {
797   if (!BuildDefs::dump())
798     return;
799   Ostream &Str = Func->getContext()->getStrDump();
800   dumpDest(Func);
801   Str << " = icmp " << InstIcmpAttributes[getCondition()].DisplayString << " "
802       << getSrc(0)->getType() << " ";
803   dumpSources(Func);
804 }
805 
dump(const Cfg * Func) const806 void InstExtractElement::dump(const Cfg *Func) const {
807   if (!BuildDefs::dump())
808     return;
809   Ostream &Str = Func->getContext()->getStrDump();
810   dumpDest(Func);
811   Str << " = extractelement ";
812   Str << getSrc(0)->getType() << " ";
813   getSrc(0)->dump(Func);
814   Str << ", ";
815   Str << getSrc(1)->getType() << " ";
816   getSrc(1)->dump(Func);
817 }
818 
dump(const Cfg * Func) const819 void InstInsertElement::dump(const Cfg *Func) const {
820   if (!BuildDefs::dump())
821     return;
822   Ostream &Str = Func->getContext()->getStrDump();
823   dumpDest(Func);
824   Str << " = insertelement ";
825   Str << getSrc(0)->getType() << " ";
826   getSrc(0)->dump(Func);
827   Str << ", ";
828   Str << getSrc(1)->getType() << " ";
829   getSrc(1)->dump(Func);
830   Str << ", ";
831   Str << getSrc(2)->getType() << " ";
832   getSrc(2)->dump(Func);
833 }
834 
dump(const Cfg * Func) const835 void InstFcmp::dump(const Cfg *Func) const {
836   if (!BuildDefs::dump())
837     return;
838   Ostream &Str = Func->getContext()->getStrDump();
839   dumpDest(Func);
840   Str << " = fcmp " << InstFcmpAttributes[getCondition()].DisplayString << " "
841       << getSrc(0)->getType() << " ";
842   dumpSources(Func);
843 }
844 
dump(const Cfg * Func) const845 void InstLoad::dump(const Cfg *Func) const {
846   if (!BuildDefs::dump())
847     return;
848   Ostream &Str = Func->getContext()->getStrDump();
849   dumpDest(Func);
850   Type Ty = getDest()->getType();
851   Str << " = load " << Ty << ", " << Ty << "* ";
852   dumpSources(Func);
853   Str << ", align " << typeAlignInBytes(Ty);
854 }
855 
dump(const Cfg * Func) const856 void InstStore::dump(const Cfg *Func) const {
857   if (!BuildDefs::dump())
858     return;
859   Ostream &Str = Func->getContext()->getStrDump();
860   Type Ty = getData()->getType();
861   dumpDest(Func);
862   if (Dest)
863     Str << " = ";
864   Str << "store " << Ty << " ";
865   getData()->dump(Func);
866   Str << ", " << Ty << "* ";
867   getStoreAddress()->dump(Func);
868   Str << ", align " << typeAlignInBytes(Ty);
869   if (getRmwBeacon()) {
870     Str << ", beacon ";
871     getRmwBeacon()->dump(Func);
872   }
873 }
874 
dump(const Cfg * Func) const875 void InstSwitch::dump(const Cfg *Func) const {
876   if (!BuildDefs::dump())
877     return;
878   Ostream &Str = Func->getContext()->getStrDump();
879   Type Ty = getComparison()->getType();
880   Str << "switch " << Ty << " ";
881   getSrc(0)->dump(Func);
882   Str << ", label %" << getLabelDefault()->getName() << " [\n";
883   for (SizeT I = 0; I < getNumCases(); ++I) {
884     Str << "    " << Ty << " " << static_cast<int64_t>(getValue(I))
885         << ", label %" << getLabel(I)->getName() << "\n";
886   }
887   Str << "  ]";
888 }
889 
dump(const Cfg * Func) const890 void InstPhi::dump(const Cfg *Func) const {
891   if (!BuildDefs::dump())
892     return;
893   Ostream &Str = Func->getContext()->getStrDump();
894   dumpDest(Func);
895   Str << " = phi " << getDest()->getType() << " ";
896   for (SizeT I = 0; I < getSrcSize(); ++I) {
897     if (I > 0)
898       Str << ", ";
899     Str << "[ ";
900     getSrc(I)->dump(Func);
901     Str << ", %" << Labels[I]->getName() << " ]";
902   }
903 }
904 
dump(const Cfg * Func) const905 void InstRet::dump(const Cfg *Func) const {
906   if (!BuildDefs::dump())
907     return;
908   Ostream &Str = Func->getContext()->getStrDump();
909   Type Ty = hasRetValue() ? getRetValue()->getType() : IceType_void;
910   Str << "ret " << Ty;
911   if (hasRetValue()) {
912     Str << " ";
913     dumpSources(Func);
914   }
915 }
916 
dump(const Cfg * Func) const917 void InstSelect::dump(const Cfg *Func) const {
918   if (!BuildDefs::dump())
919     return;
920   Ostream &Str = Func->getContext()->getStrDump();
921   dumpDest(Func);
922   Operand *Condition = getCondition();
923   Operand *TrueOp = getTrueOperand();
924   Operand *FalseOp = getFalseOperand();
925   Str << " = select " << Condition->getType() << " ";
926   Condition->dump(Func);
927   Str << ", " << TrueOp->getType() << " ";
928   TrueOp->dump(Func);
929   Str << ", " << FalseOp->getType() << " ";
930   FalseOp->dump(Func);
931 }
932 
dump(const Cfg * Func) const933 void InstUnreachable::dump(const Cfg *Func) const {
934   if (!BuildDefs::dump())
935     return;
936   Ostream &Str = Func->getContext()->getStrDump();
937   Str << "unreachable";
938 }
939 
emit(const Cfg * Func) const940 void InstFakeDef::emit(const Cfg *Func) const {
941   if (!BuildDefs::dump())
942     return;
943   // Go ahead and "emit" these for now, since they are relatively rare.
944   Ostream &Str = Func->getContext()->getStrEmit();
945   Str << "\t# ";
946   getDest()->emit(Func);
947   Str << " = def.pseudo";
948   if (getSrcSize() > 0)
949     Str << " ";
950   emitSources(Func);
951   Str << "\n";
952 }
953 
dump(const Cfg * Func) const954 void InstFakeDef::dump(const Cfg *Func) const {
955   if (!BuildDefs::dump())
956     return;
957   Ostream &Str = Func->getContext()->getStrDump();
958   dumpDest(Func);
959   Str << " = def.pseudo ";
960   dumpSources(Func);
961 }
962 
emit(const Cfg * Func) const963 void InstFakeUse::emit(const Cfg *Func) const { (void)Func; }
964 
dump(const Cfg * Func) const965 void InstFakeUse::dump(const Cfg *Func) const {
966   if (!BuildDefs::dump())
967     return;
968   Ostream &Str = Func->getContext()->getStrDump();
969   Str << "use.pseudo ";
970   dumpSources(Func);
971 }
972 
emit(const Cfg * Func) const973 void InstFakeKill::emit(const Cfg *Func) const { (void)Func; }
974 
dump(const Cfg * Func) const975 void InstFakeKill::dump(const Cfg *Func) const {
976   if (!BuildDefs::dump())
977     return;
978   Ostream &Str = Func->getContext()->getStrDump();
979   if (Linked->isDeleted())
980     Str << "// ";
981   Str << "kill.pseudo scratch_regs";
982 }
983 
dump(const Cfg * Func) const984 void InstShuffleVector::dump(const Cfg *Func) const {
985   if (!BuildDefs::dump())
986     return;
987   Ostream &Str = Func->getContext()->getStrDump();
988   Str << "shufflevector ";
989   dumpDest(Func);
990   Str << " = ";
991   dumpSources(Func);
992   for (SizeT I = 0; I < NumIndexes; ++I) {
993     Str << ", ";
994     Indexes[I]->dump(Func);
995   }
996   Str << "\n";
997 }
998 
dump(const Cfg * Func) const999 void InstJumpTable::dump(const Cfg *Func) const {
1000   if (!BuildDefs::dump())
1001     return;
1002   Ostream &Str = Func->getContext()->getStrDump();
1003   Str << "jump table [";
1004   for (SizeT I = 0; I < NumTargets; ++I)
1005     Str << "\n    " << Targets[I]->getName();
1006   Str << "\n  ]";
1007 }
1008 
dump(const Cfg * Func) const1009 void InstTarget::dump(const Cfg *Func) const {
1010   if (!BuildDefs::dump())
1011     return;
1012   Ostream &Str = Func->getContext()->getStrDump();
1013   Str << "[TARGET] ";
1014   Inst::dump(Func);
1015 }
1016 
InstBreakpoint(Cfg * Func)1017 InstBreakpoint::InstBreakpoint(Cfg *Func)
1018     : InstHighLevel(Func, Inst::Breakpoint, 0, nullptr) {}
1019 
reverseConditionAndOperands()1020 void InstIcmp::reverseConditionAndOperands() {
1021   Condition = InstIcmpAttributes[Condition].Reverse;
1022   std::swap(Srcs[0], Srcs[1]);
1023 }
1024 
checkForRedundantAssign(const Variable * Dest,const Operand * Source)1025 bool checkForRedundantAssign(const Variable *Dest, const Operand *Source) {
1026   const auto *SrcVar = llvm::dyn_cast<const Variable>(Source);
1027   if (SrcVar == nullptr)
1028     return false;
1029   if (Dest->hasReg() && Dest->getRegNum() == SrcVar->getRegNum()) {
1030     // TODO: On x86-64, instructions like "mov eax, eax" are used to clear the
1031     // upper 32 bits of rax. We need to recognize and preserve these.
1032     return true;
1033   }
1034   if (!Dest->hasReg() && !SrcVar->hasReg()) {
1035     if (!Dest->hasStackOffset() || !SrcVar->hasStackOffset()) {
1036       // If called before stack slots have been assigned (i.e. as part of the
1037       // dump() routine), conservatively return false.
1038       return false;
1039     }
1040     if (Dest->getStackOffset() != SrcVar->getStackOffset()) {
1041       return false;
1042     }
1043     return true;
1044   }
1045   // For a "v=t" assignment where t has a register, v has a stack slot, and v
1046   // has a LinkedTo stack root, and v and t share the same LinkedTo root, return
1047   // true.  This is because this assignment is effectively reassigning the same
1048   // value to the original LinkedTo stack root.
1049   if (SrcVar->hasReg() && Dest->hasStackOffset() &&
1050       Dest->getLinkedToStackRoot() != nullptr &&
1051       Dest->getLinkedToRoot() == SrcVar->getLinkedToRoot()) {
1052     return true;
1053   }
1054   return false;
1055 }
1056 
1057 } // end of namespace Ice
1058