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