OLD | NEW |
1 //===- subzero/src/IceInst.cpp - High-level instruction implementation ----===// | 1 //===- subzero/src/IceInst.cpp - High-level instruction implementation ----===// |
2 // | 2 // |
3 // The Subzero Code Generator | 3 // The Subzero Code Generator |
4 // | 4 // |
5 // This file is distributed under the University of Illinois Open Source | 5 // This file is distributed under the University of Illinois Open Source |
6 // License. See LICENSE.TXT for details. | 6 // License. See LICENSE.TXT for details. |
7 // | 7 // |
8 //===----------------------------------------------------------------------===// | 8 //===----------------------------------------------------------------------===// |
9 // | 9 // |
10 // This file implements the Inst class, primarily the various | 10 // This file implements the Inst class, primarily the various |
11 // subclass constructors and dump routines. | 11 // subclass constructors and dump routines. |
12 // | 12 // |
13 //===----------------------------------------------------------------------===// | 13 //===----------------------------------------------------------------------===// |
14 | 14 |
15 #include "IceCfg.h" | 15 #include "IceCfg.h" |
16 #include "IceCfgNode.h" | 16 #include "IceCfgNode.h" |
17 #include "IceInst.h" | 17 #include "IceInst.h" |
| 18 #include "IceLiveness.h" |
18 #include "IceOperand.h" | 19 #include "IceOperand.h" |
19 | 20 |
20 namespace Ice { | 21 namespace Ice { |
21 | 22 |
22 namespace { | 23 namespace { |
23 | 24 |
24 // Using non-anonymous struct so that array_lengthof works. | 25 // Using non-anonymous struct so that array_lengthof works. |
25 const struct InstArithmeticAttributes_ { | 26 const struct InstArithmeticAttributes_ { |
26 const char *DisplayString; | 27 const char *DisplayString; |
27 bool IsCommutative; | 28 bool IsCommutative; |
(...skipping 39 matching lines...) Loading... |
67 { str } \ | 68 { str } \ |
68 , | 69 , |
69 ICEINSTICMP_TABLE | 70 ICEINSTICMP_TABLE |
70 #undef X | 71 #undef X |
71 }; | 72 }; |
72 const size_t InstIcmpAttributesSize = llvm::array_lengthof(InstIcmpAttributes); | 73 const size_t InstIcmpAttributesSize = llvm::array_lengthof(InstIcmpAttributes); |
73 | 74 |
74 } // end of anonymous namespace | 75 } // end of anonymous namespace |
75 | 76 |
76 Inst::Inst(Cfg *Func, InstKind Kind, SizeT MaxSrcs, Variable *Dest) | 77 Inst::Inst(Cfg *Func, InstKind Kind, SizeT MaxSrcs, Variable *Dest) |
77 : Kind(Kind), Number(Func->newInstNumber()), Deleted(false), | 78 : Kind(Kind), Number(Func->newInstNumber()), Deleted(false), Dead(false), |
78 HasSideEffects(false), Dest(Dest), MaxSrcs(MaxSrcs), NumSrcs(0), | 79 HasSideEffects(false), Dest(Dest), MaxSrcs(MaxSrcs), NumSrcs(0), |
79 Srcs(Func->allocateArrayOf<Operand *>(MaxSrcs)) {} | 80 Srcs(Func->allocateArrayOf<Operand *>(MaxSrcs)), LiveRangesEnded(0) {} |
| 81 |
| 82 // Assign the instruction a new number. |
| 83 void Inst::renumber(Cfg *Func) { |
| 84 Number = isDeleted() ? NumberDeleted : Func->newInstNumber(); |
| 85 } |
| 86 |
| 87 // Delete the instruction if its tentative Dead flag is still set |
| 88 // after liveness analysis. |
| 89 void Inst::deleteIfDead() { |
| 90 if (Dead) |
| 91 setDeleted(); |
| 92 } |
| 93 |
| 94 // If Src is a Variable, it returns true if this instruction ends |
| 95 // Src's live range. Otherwise, returns false. |
| 96 bool Inst::isLastUse(const Operand *TestSrc) const { |
| 97 if (LiveRangesEnded == 0) |
| 98 return false; // early-exit optimization |
| 99 if (const Variable *TestVar = llvm::dyn_cast<const Variable>(TestSrc)) { |
| 100 LREndedBits Mask = LiveRangesEnded; |
| 101 for (SizeT I = 0; I < getSrcSize(); ++I) { |
| 102 Operand *Src = getSrc(I); |
| 103 SizeT NumVars = Src->getNumVars(); |
| 104 for (SizeT J = 0; J < NumVars; ++J) { |
| 105 const Variable *Var = Src->getVar(J); |
| 106 if (Var == TestVar) { |
| 107 // We've found where the variable is used in the instruction. |
| 108 return Mask & 1; |
| 109 } |
| 110 Mask >>= 1; |
| 111 if (Mask == 0) |
| 112 return false; // another early-exit optimization |
| 113 } |
| 114 } |
| 115 } |
| 116 return false; |
| 117 } |
80 | 118 |
81 void Inst::updateVars(CfgNode *Node) { | 119 void Inst::updateVars(CfgNode *Node) { |
82 if (Dest) | 120 if (Dest) |
83 Dest->setDefinition(this, Node); | 121 Dest->setDefinition(this, Node); |
84 | 122 |
| 123 for (SizeT I = 0; I < getSrcSize(); ++I) { |
| 124 Operand *Src = getSrc(I); |
| 125 SizeT NumVars = Src->getNumVars(); |
| 126 for (SizeT J = 0; J < NumVars; ++J) { |
| 127 Variable *Var = Src->getVar(J); |
| 128 Var->setUse(this, Node); |
| 129 } |
| 130 } |
| 131 } |
| 132 |
| 133 void Inst::livenessLightweight(llvm::BitVector &Live) { |
| 134 assert(!isDeleted()); |
| 135 if (llvm::isa<InstFakeKill>(this)) |
| 136 return; |
| 137 resetLastUses(); |
85 SizeT VarIndex = 0; | 138 SizeT VarIndex = 0; |
86 for (SizeT I = 0; I < getSrcSize(); ++I) { | 139 for (SizeT I = 0; I < getSrcSize(); ++I) { |
87 Operand *Src = getSrc(I); | 140 Operand *Src = getSrc(I); |
88 SizeT NumVars = Src->getNumVars(); | 141 SizeT NumVars = Src->getNumVars(); |
89 for (SizeT J = 0; J < NumVars; ++J, ++VarIndex) { | 142 for (SizeT J = 0; J < NumVars; ++J, ++VarIndex) { |
90 Variable *Var = Src->getVar(J); | 143 const Variable *Var = Src->getVar(J); |
91 Var->setUse(this, Node); | 144 if (Var->isMultiblockLife()) |
| 145 continue; |
| 146 SizeT Index = Var->getIndex(); |
| 147 if (Live[Index]) |
| 148 continue; |
| 149 Live[Index] = true; |
| 150 setLastUse(VarIndex); |
| 151 } |
| 152 } |
| 153 } |
| 154 |
| 155 void Inst::liveness(InstNumberT InstNumber, llvm::BitVector &Live, |
| 156 Liveness *Liveness, const CfgNode *Node) { |
| 157 assert(!isDeleted()); |
| 158 if (llvm::isa<InstFakeKill>(this)) |
| 159 return; |
| 160 |
| 161 std::vector<InstNumberT> &LiveBegin = Liveness->getLiveBegin(Node); |
| 162 std::vector<InstNumberT> &LiveEnd = Liveness->getLiveEnd(Node); |
| 163 Dead = false; |
| 164 if (Dest) { |
| 165 SizeT VarNum = Liveness->getLiveIndex(Dest); |
| 166 if (Live[VarNum]) { |
| 167 Live[VarNum] = false; |
| 168 LiveBegin[VarNum] = InstNumber; |
| 169 } else { |
| 170 if (!hasSideEffects()) |
| 171 Dead = true; |
| 172 } |
| 173 } |
| 174 if (Dead) |
| 175 return; |
| 176 // Phi arguments only get added to Live in the predecessor node, but |
| 177 // we still need to update LiveRangesEnded. |
| 178 bool IsPhi = llvm::isa<InstPhi>(this); |
| 179 resetLastUses(); |
| 180 SizeT VarIndex = 0; |
| 181 for (SizeT I = 0; I < getSrcSize(); ++I) { |
| 182 Operand *Src = getSrc(I); |
| 183 SizeT NumVars = Src->getNumVars(); |
| 184 for (SizeT J = 0; J < NumVars; ++J, ++VarIndex) { |
| 185 const Variable *Var = Src->getVar(J); |
| 186 SizeT VarNum = Liveness->getLiveIndex(Var); |
| 187 if (!Live[VarNum]) { |
| 188 setLastUse(VarIndex); |
| 189 if (!IsPhi) { |
| 190 Live[VarNum] = true; |
| 191 // For a variable in SSA form, its live range can end at |
| 192 // most once in a basic block. However, after lowering to |
| 193 // two-address instructions, we end up with sequences like |
| 194 // "t=b;t+=c;a=t" where t's live range begins and ends |
| 195 // twice. ICE only allows a variable to have a single |
| 196 // liveness interval in a basic block (except for blocks |
| 197 // where a variable is live-in and live-out but there is a |
| 198 // gap in the middle, and except for the special |
| 199 // InstFakeKill instruction that can appear multiple |
| 200 // times in the same block). Therefore, this lowered |
| 201 // sequence needs to represent a single conservative live |
| 202 // range for t. Since the instructions are being traversed |
| 203 // backwards, we make sure LiveEnd is only set once by |
| 204 // setting it only when LiveEnd[VarNum]==0 (sentinel value). |
| 205 // Note that it's OK to set LiveBegin multiple times because |
| 206 // of the backwards traversal. |
| 207 if (LiveEnd[VarNum] == 0) { |
| 208 LiveEnd[VarNum] = InstNumber; |
| 209 } |
| 210 } |
| 211 } |
92 } | 212 } |
93 } | 213 } |
94 } | 214 } |
95 | 215 |
96 InstAlloca::InstAlloca(Cfg *Func, Operand *ByteCount, uint32_t AlignInBytes, | 216 InstAlloca::InstAlloca(Cfg *Func, Operand *ByteCount, uint32_t AlignInBytes, |
97 Variable *Dest) | 217 Variable *Dest) |
98 : Inst(Func, Inst::Alloca, 1, Dest), AlignInBytes(AlignInBytes) { | 218 : Inst(Func, Inst::Alloca, 1, Dest), AlignInBytes(AlignInBytes) { |
99 // Verify AlignInBytes is 0 or a power of 2. | 219 // Verify AlignInBytes is 0 or a power of 2. |
100 assert(AlignInBytes == 0 || llvm::isPowerOf2_32(AlignInBytes)); | 220 assert(AlignInBytes == 0 || llvm::isPowerOf2_32(AlignInBytes)); |
101 addSource(ByteCount); | 221 addSource(ByteCount); |
(...skipping 83 matching lines...) Loading... |
185 // improved if it becomes a problem. | 305 // improved if it becomes a problem. |
186 Operand *InstPhi::getOperandForTarget(CfgNode *Target) const { | 306 Operand *InstPhi::getOperandForTarget(CfgNode *Target) const { |
187 for (SizeT I = 0; I < getSrcSize(); ++I) { | 307 for (SizeT I = 0; I < getSrcSize(); ++I) { |
188 if (Labels[I] == Target) | 308 if (Labels[I] == Target) |
189 return getSrc(I); | 309 return getSrc(I); |
190 } | 310 } |
191 llvm_unreachable("Phi target not found"); | 311 llvm_unreachable("Phi target not found"); |
192 return NULL; | 312 return NULL; |
193 } | 313 } |
194 | 314 |
| 315 // Updates liveness for a particular operand based on the given |
| 316 // predecessor edge. Doesn't mark the operand as live if the Phi |
| 317 // instruction is dead or deleted. |
| 318 void InstPhi::livenessPhiOperand(llvm::BitVector &Live, CfgNode *Target, |
| 319 Liveness *Liveness) { |
| 320 if (isDeleted() || Dead) |
| 321 return; |
| 322 for (SizeT I = 0; I < getSrcSize(); ++I) { |
| 323 if (Labels[I] == Target) { |
| 324 if (Variable *Var = llvm::dyn_cast<Variable>(getSrc(I))) { |
| 325 SizeT SrcIndex = Liveness->getLiveIndex(Var); |
| 326 if (!Live[SrcIndex]) { |
| 327 setLastUse(I); |
| 328 Live[SrcIndex] = true; |
| 329 } |
| 330 } |
| 331 return; |
| 332 } |
| 333 } |
| 334 llvm_unreachable("Phi operand not found for specified target node"); |
| 335 } |
| 336 |
195 // Change "a=phi(...)" to "a_phi=phi(...)" and return a new | 337 // Change "a=phi(...)" to "a_phi=phi(...)" and return a new |
196 // instruction "a=a_phi". | 338 // instruction "a=a_phi". |
197 Inst *InstPhi::lower(Cfg *Func, CfgNode *Node) { | 339 Inst *InstPhi::lower(Cfg *Func, CfgNode *Node) { |
198 Variable *Dest = getDest(); | 340 Variable *Dest = getDest(); |
199 assert(Dest); | 341 assert(Dest); |
200 IceString PhiName = Dest->getName() + "_phi"; | 342 IceString PhiName = Dest->getName() + "_phi"; |
201 Variable *NewSrc = Func->makeVariable(Dest->getType(), Node, PhiName); | 343 Variable *NewSrc = Func->makeVariable(Dest->getType(), Node, PhiName); |
202 this->Dest = NewSrc; | 344 this->Dest = NewSrc; |
203 InstAssign *NewInst = InstAssign::create(Func, Dest, NewSrc); | 345 InstAssign *NewInst = InstAssign::create(Func, Dest, NewSrc); |
204 // Set Dest and NewSrc to have affinity with each other, as a hint | 346 // Set Dest and NewSrc to have affinity with each other, as a hint |
(...skipping 82 matching lines...) Loading... |
287 | 429 |
288 // ======================== Dump routines ======================== // | 430 // ======================== Dump routines ======================== // |
289 | 431 |
290 void Inst::dumpDecorated(const Cfg *Func) const { | 432 void Inst::dumpDecorated(const Cfg *Func) const { |
291 Ostream &Str = Func->getContext()->getStrDump(); | 433 Ostream &Str = Func->getContext()->getStrDump(); |
292 if (!Func->getContext()->isVerbose(IceV_Deleted) && | 434 if (!Func->getContext()->isVerbose(IceV_Deleted) && |
293 (isDeleted() || isRedundantAssign())) | 435 (isDeleted() || isRedundantAssign())) |
294 return; | 436 return; |
295 if (Func->getContext()->isVerbose(IceV_InstNumbers)) { | 437 if (Func->getContext()->isVerbose(IceV_InstNumbers)) { |
296 char buf[30]; | 438 char buf[30]; |
297 int32_t Number = getNumber(); | 439 InstNumberT Number = getNumber(); |
298 if (Number < 0) | 440 if (Number == NumberDeleted) |
299 snprintf(buf, llvm::array_lengthof(buf), "[XXX]"); | 441 snprintf(buf, llvm::array_lengthof(buf), "[XXX]"); |
300 else | 442 else |
301 snprintf(buf, llvm::array_lengthof(buf), "[%3d]", Number); | 443 snprintf(buf, llvm::array_lengthof(buf), "[%3d]", Number); |
302 Str << buf; | 444 Str << buf; |
303 } | 445 } |
304 Str << " "; | 446 Str << " "; |
305 if (isDeleted()) | 447 if (isDeleted()) |
306 Str << " //"; | 448 Str << " //"; |
307 dump(Func); | 449 dump(Func); |
| 450 dumpExtras(Func); |
308 Str << "\n"; | 451 Str << "\n"; |
309 } | 452 } |
310 | 453 |
311 void Inst::emit(const Cfg * /*Func*/) const { | 454 void Inst::emit(const Cfg * /*Func*/) const { |
312 llvm_unreachable("emit() called on a non-lowered instruction"); | 455 llvm_unreachable("emit() called on a non-lowered instruction"); |
313 } | 456 } |
314 | 457 |
315 void Inst::dump(const Cfg *Func) const { | 458 void Inst::dump(const Cfg *Func) const { |
316 Ostream &Str = Func->getContext()->getStrDump(); | 459 Ostream &Str = Func->getContext()->getStrDump(); |
317 dumpDest(Func); | 460 dumpDest(Func); |
318 Str << " =~ "; | 461 Str << " =~ "; |
319 dumpSources(Func); | 462 dumpSources(Func); |
320 } | 463 } |
321 | 464 |
| 465 void Inst::dumpExtras(const Cfg *Func) const { |
| 466 Ostream &Str = Func->getContext()->getStrDump(); |
| 467 bool First = true; |
| 468 // Print "LIVEEND={a,b,c}" for all source operands whose live ranges |
| 469 // are known to end at this instruction. |
| 470 if (Func->getContext()->isVerbose(IceV_Liveness)) { |
| 471 for (SizeT I = 0; I < getSrcSize(); ++I) { |
| 472 Operand *Src = getSrc(I); |
| 473 SizeT NumVars = Src->getNumVars(); |
| 474 for (SizeT J = 0; J < NumVars; ++J) { |
| 475 const Variable *Var = Src->getVar(J); |
| 476 if (isLastUse(Var)) { |
| 477 if (First) |
| 478 Str << " // LIVEEND={"; |
| 479 else |
| 480 Str << ","; |
| 481 Var->dump(Func); |
| 482 First = false; |
| 483 } |
| 484 } |
| 485 } |
| 486 if (!First) |
| 487 Str << "}"; |
| 488 } |
| 489 } |
| 490 |
322 void Inst::dumpSources(const Cfg *Func) const { | 491 void Inst::dumpSources(const Cfg *Func) const { |
323 Ostream &Str = Func->getContext()->getStrDump(); | 492 Ostream &Str = Func->getContext()->getStrDump(); |
324 for (SizeT I = 0; I < getSrcSize(); ++I) { | 493 for (SizeT I = 0; I < getSrcSize(); ++I) { |
325 if (I > 0) | 494 if (I > 0) |
326 Str << ", "; | 495 Str << ", "; |
327 getSrc(I)->dump(Func); | 496 getSrc(I)->dump(Func); |
328 } | 497 } |
329 } | 498 } |
330 | 499 |
331 void Inst::emitSources(const Cfg *Func) const { | 500 void Inst::emitSources(const Cfg *Func) const { |
(...skipping 214 matching lines...) Loading... |
546 Str << "kill.pseudo "; | 715 Str << "kill.pseudo "; |
547 dumpSources(Func); | 716 dumpSources(Func); |
548 } | 717 } |
549 | 718 |
550 void InstTarget::dump(const Cfg *Func) const { | 719 void InstTarget::dump(const Cfg *Func) const { |
551 Ostream &Str = Func->getContext()->getStrDump(); | 720 Ostream &Str = Func->getContext()->getStrDump(); |
552 Str << "[TARGET] "; | 721 Str << "[TARGET] "; |
553 Inst::dump(Func); | 722 Inst::dump(Func); |
554 } | 723 } |
555 | 724 |
| 725 void InstTarget::dumpExtras(const Cfg *Func) const { Inst::dumpExtras(Func); } |
| 726 |
556 } // end of namespace Ice | 727 } // end of namespace Ice |
OLD | NEW |