Chromium Code Reviews| 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...) Expand 10 before | Expand all | Expand 10 after 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() ? -1 : 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 an Variable, it returns true if this instruction ends | |
|
jvoung (off chromium)
2014/05/28 17:48:15
"is a Variable"?
Jim Stichnoth
2014/05/29 01:39:46
Fixed this and several other instances. :) (This
| |
| 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 SizeT VarIndex = 0; | |
|
jvoung (off chromium)
2014/05/28 17:48:15
VarIndex unused here (just incremented)? Looks lik
Jim Stichnoth
2014/05/29 01:39:46
Done.
| |
| 101 SizeT Mask = LiveRangesEnded; | |
|
JF
2014/05/25 22:50:50
You should use the same typedef for LiveRangesEnde
Jim Stichnoth
2014/05/29 01:39:46
Done.
| |
| 102 for (SizeT I = 0; I < getSrcSize(); ++I) { | |
| 103 Operand *Src = getSrc(I); | |
| 104 SizeT NumVars = Src->getNumVars(); | |
| 105 for (SizeT J = 0; J < NumVars; ++J, ++VarIndex) { | |
| 106 const Variable *Var = Src->getVar(J); | |
| 107 if (Var == TestVar) { | |
| 108 // We've found where the variable is used in the instruction. | |
| 109 return Mask & 1; | |
| 110 } | |
| 111 Mask >>= 1; | |
| 112 if (Mask == 0) | |
| 113 return false; // another early-exit optimization | |
| 114 } | |
| 115 } | |
| 116 } | |
| 117 return false; | |
| 118 } | |
| 80 | 119 |
| 81 void Inst::updateVars(CfgNode *Node) { | 120 void Inst::updateVars(CfgNode *Node) { |
| 82 if (Dest) | 121 if (Dest) |
| 83 Dest->setDefinition(this, Node); | 122 Dest->setDefinition(this, Node); |
| 84 | 123 |
| 85 SizeT VarIndex = 0; | 124 SizeT VarIndex = 0; |
|
jvoung (off chromium)
2014/05/28 17:48:15
VarIndex also unused here (just incremented)?
Jim Stichnoth
2014/05/29 01:39:46
Done.
| |
| 86 for (SizeT I = 0; I < getSrcSize(); ++I) { | 125 for (SizeT I = 0; I < getSrcSize(); ++I) { |
| 87 Operand *Src = getSrc(I); | 126 Operand *Src = getSrc(I); |
| 88 SizeT NumVars = Src->getNumVars(); | 127 SizeT NumVars = Src->getNumVars(); |
| 89 for (SizeT J = 0; J < NumVars; ++J, ++VarIndex) { | 128 for (SizeT J = 0; J < NumVars; ++J, ++VarIndex) { |
| 90 Variable *Var = Src->getVar(J); | 129 Variable *Var = Src->getVar(J); |
| 91 Var->setUse(this, Node); | 130 Var->setUse(this, Node); |
| 92 } | 131 } |
| 93 } | 132 } |
| 94 } | 133 } |
| 95 | 134 |
| 135 void Inst::liveness(LivenessMode Mode, int32_t InstNumber, | |
| 136 llvm::BitVector &Live, Liveness *Liveness, | |
| 137 const CfgNode *Node) { | |
| 138 if (isDeleted()) | |
| 139 return; | |
| 140 if (llvm::isa<InstFakeKill>(this)) | |
| 141 return; | |
| 142 | |
| 143 // For lightweight liveness, do the simple calculation and return. | |
| 144 if (Mode == Liveness_LREndLightweight) { | |
| 145 resetLastUses(); | |
| 146 SizeT VarIndex = 0; | |
| 147 for (SizeT I = 0; I < getSrcSize(); ++I) { | |
| 148 Operand *Src = getSrc(I); | |
| 149 SizeT NumVars = Src->getNumVars(); | |
| 150 for (SizeT J = 0; J < NumVars; ++J, ++VarIndex) { | |
| 151 const Variable *Var = Src->getVar(J); | |
| 152 if (Var->isMultiblockLife()) | |
| 153 continue; | |
| 154 SizeT Index = Var->getIndex(); | |
| 155 if (Live[Index]) | |
| 156 continue; | |
| 157 Live[Index] = true; | |
| 158 setLastUse(VarIndex); | |
|
jvoung (off chromium)
2014/05/28 17:48:15
I see... so VarIndex is an optimized, different nu
Jim Stichnoth
2014/05/29 01:39:46
OK, it looks like I never properly documented VarI
| |
| 159 } | |
| 160 } | |
| 161 return; | |
| 162 } | |
| 163 | |
| 164 std::vector<int32_t> &LiveBegin = Liveness->getLiveBegin(Node); | |
| 165 std::vector<int32_t> &LiveEnd = Liveness->getLiveEnd(Node); | |
| 166 Dead = false; | |
| 167 if (Dest) { | |
| 168 SizeT VarNum = Liveness->getLiveIndex(Dest); | |
| 169 if (Live[VarNum]) { | |
| 170 Live[VarNum] = false; | |
| 171 LiveBegin[VarNum] = InstNumber; | |
| 172 } else { | |
| 173 if (!hasSideEffects()) | |
| 174 Dead = true; | |
| 175 } | |
| 176 } | |
| 177 if (Dead) | |
| 178 return; | |
| 179 // Phi arguments only get added to Live in the predecessor node, but | |
| 180 // we still need to update LiveRangesEnded. | |
| 181 bool IsPhi = llvm::isa<InstPhi>(this); | |
| 182 resetLastUses(); | |
| 183 SizeT VarIndex = 0; | |
| 184 for (SizeT I = 0; I < getSrcSize(); ++I) { | |
| 185 Operand *Src = getSrc(I); | |
| 186 SizeT NumVars = Src->getNumVars(); | |
| 187 for (SizeT J = 0; J < NumVars; ++J, ++VarIndex) { | |
| 188 const Variable *Var = Src->getVar(J); | |
| 189 SizeT VarNum = Liveness->getLiveIndex(Var); | |
| 190 if (!Live[VarNum]) { | |
| 191 setLastUse(VarIndex); | |
| 192 if (!IsPhi) { | |
| 193 Live[VarNum] = true; | |
| 194 // For a variable in SSA form, its live range can end at | |
| 195 // most once in a basic block. However, after lowering to | |
| 196 // two-address instructions, we end up with sequences like | |
| 197 // "t=b;t+=c;a=t" where t's live range begins and ends | |
| 198 // twice. ICE only allows a variable to have a single | |
| 199 // liveness interval in a basic block (except for blocks | |
| 200 // where a variable is live-in and live-out but there is a | |
| 201 // gap in the middle, and except for the special | |
| 202 // InstFakeKill instruction that can appear multiple | |
| 203 // times in the same block). Therefore, this lowered | |
| 204 // sequence needs to represent a single conservative live | |
| 205 // range for t. Since the instructions are being traversed | |
| 206 // backwards, we make sure LiveEnd is only set once by | |
| 207 // setting it only when LiveEnd[VarNum]==0 (sentinel value). | |
| 208 // Note that it's OK to set LiveBegin multiple times because | |
| 209 // of the backwards traversal. | |
| 210 if (LiveEnd[VarNum] == 0) { | |
| 211 LiveEnd[VarNum] = InstNumber; | |
| 212 } | |
| 213 } | |
| 214 } | |
| 215 } | |
| 216 } | |
| 217 } | |
| 218 | |
| 96 InstAlloca::InstAlloca(Cfg *Func, Operand *ByteCount, uint32_t AlignInBytes, | 219 InstAlloca::InstAlloca(Cfg *Func, Operand *ByteCount, uint32_t AlignInBytes, |
| 97 Variable *Dest) | 220 Variable *Dest) |
| 98 : Inst(Func, Inst::Alloca, 1, Dest), AlignInBytes(AlignInBytes) { | 221 : Inst(Func, Inst::Alloca, 1, Dest), AlignInBytes(AlignInBytes) { |
| 99 // Verify AlignInBytes is 0 or a power of 2. | 222 // Verify AlignInBytes is 0 or a power of 2. |
| 100 assert(AlignInBytes == 0 || llvm::isPowerOf2_32(AlignInBytes)); | 223 assert(AlignInBytes == 0 || llvm::isPowerOf2_32(AlignInBytes)); |
| 101 addSource(ByteCount); | 224 addSource(ByteCount); |
| 102 } | 225 } |
| 103 | 226 |
| 104 InstArithmetic::InstArithmetic(Cfg *Func, OpKind Op, Variable *Dest, | 227 InstArithmetic::InstArithmetic(Cfg *Func, OpKind Op, Variable *Dest, |
| 105 Operand *Source1, Operand *Source2) | 228 Operand *Source1, Operand *Source2) |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 185 // improved if it becomes a problem. | 308 // improved if it becomes a problem. |
| 186 Operand *InstPhi::getOperandForTarget(CfgNode *Target) const { | 309 Operand *InstPhi::getOperandForTarget(CfgNode *Target) const { |
| 187 for (SizeT I = 0; I < getSrcSize(); ++I) { | 310 for (SizeT I = 0; I < getSrcSize(); ++I) { |
| 188 if (Labels[I] == Target) | 311 if (Labels[I] == Target) |
| 189 return getSrc(I); | 312 return getSrc(I); |
| 190 } | 313 } |
| 191 llvm_unreachable("Phi target not found"); | 314 llvm_unreachable("Phi target not found"); |
| 192 return NULL; | 315 return NULL; |
| 193 } | 316 } |
| 194 | 317 |
| 318 // Updates liveness for a particular operand based on the given | |
| 319 // predecessor edge. Doesn't mark the operand as live if the Phi | |
| 320 // instruction is dead or deleted. | |
| 321 void InstPhi::livenessPhiOperand(llvm::BitVector &Live, CfgNode *Target, | |
| 322 Liveness *Liveness) { | |
| 323 if (isDeleted() || Dead) | |
| 324 return; | |
| 325 for (SizeT I = 0; I < getSrcSize(); ++I) { | |
| 326 if (Labels[I] == Target) { | |
| 327 if (Variable *Var = llvm::dyn_cast<Variable>(getSrc(I))) { | |
| 328 SizeT SrcIndex = Liveness->getLiveIndex(Var); | |
| 329 if (!Live[SrcIndex]) { | |
| 330 setLastUse(I); | |
| 331 Live[SrcIndex] = true; | |
| 332 } | |
| 333 } | |
| 334 return; | |
| 335 } | |
| 336 } | |
| 337 llvm_unreachable("Phi operand not found for specified target node"); | |
| 338 } | |
| 339 | |
| 195 // Change "a=phi(...)" to "a_phi=phi(...)" and return a new | 340 // Change "a=phi(...)" to "a_phi=phi(...)" and return a new |
| 196 // instruction "a=a_phi". | 341 // instruction "a=a_phi". |
| 197 Inst *InstPhi::lower(Cfg *Func, CfgNode *Node) { | 342 Inst *InstPhi::lower(Cfg *Func, CfgNode *Node) { |
| 198 Variable *Dest = getDest(); | 343 Variable *Dest = getDest(); |
| 199 assert(Dest); | 344 assert(Dest); |
| 200 IceString PhiName = Dest->getName() + "_phi"; | 345 IceString PhiName = Dest->getName() + "_phi"; |
| 201 Variable *NewSrc = Func->makeVariable(Dest->getType(), Node, PhiName); | 346 Variable *NewSrc = Func->makeVariable(Dest->getType(), Node, PhiName); |
| 202 this->Dest = NewSrc; | 347 this->Dest = NewSrc; |
| 203 InstAssign *NewInst = InstAssign::create(Func, Dest, NewSrc); | 348 InstAssign *NewInst = InstAssign::create(Func, Dest, NewSrc); |
| 204 // Set Dest and NewSrc to have affinity with each other, as a hint | 349 // Set Dest and NewSrc to have affinity with each other, as a hint |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 298 if (Number < 0) | 443 if (Number < 0) |
| 299 snprintf(buf, llvm::array_lengthof(buf), "[XXX]"); | 444 snprintf(buf, llvm::array_lengthof(buf), "[XXX]"); |
| 300 else | 445 else |
| 301 snprintf(buf, llvm::array_lengthof(buf), "[%3d]", Number); | 446 snprintf(buf, llvm::array_lengthof(buf), "[%3d]", Number); |
| 302 Str << buf; | 447 Str << buf; |
| 303 } | 448 } |
| 304 Str << " "; | 449 Str << " "; |
| 305 if (isDeleted()) | 450 if (isDeleted()) |
| 306 Str << " //"; | 451 Str << " //"; |
| 307 dump(Func); | 452 dump(Func); |
| 453 dumpExtras(Func); | |
| 308 Str << "\n"; | 454 Str << "\n"; |
| 309 } | 455 } |
| 310 | 456 |
| 311 void Inst::emit(const Cfg * /*Func*/) const { | 457 void Inst::emit(const Cfg * /*Func*/) const { |
| 312 llvm_unreachable("emit() called on a non-lowered instruction"); | 458 llvm_unreachable("emit() called on a non-lowered instruction"); |
| 313 } | 459 } |
| 314 | 460 |
| 315 void Inst::dump(const Cfg *Func) const { | 461 void Inst::dump(const Cfg *Func) const { |
| 316 Ostream &Str = Func->getContext()->getStrDump(); | 462 Ostream &Str = Func->getContext()->getStrDump(); |
| 317 dumpDest(Func); | 463 dumpDest(Func); |
| 318 Str << " =~ "; | 464 Str << " =~ "; |
| 319 dumpSources(Func); | 465 dumpSources(Func); |
| 320 } | 466 } |
| 321 | 467 |
| 468 void Inst::dumpExtras(const Cfg *Func) const { | |
| 469 Ostream &Str = Func->getContext()->getStrDump(); | |
| 470 bool First = true; | |
| 471 // Print "LIVEEND={a,b,c}" for all source operands whose live ranges | |
| 472 // are known to end at this instruction. | |
| 473 if (Func->getContext()->isVerbose(IceV_Liveness)) { | |
| 474 SizeT VarIndex = 0; | |
|
jvoung (off chromium)
2014/05/28 17:48:15
VarIndex unused?
Jim Stichnoth
2014/05/29 01:39:46
Done.
| |
| 475 for (SizeT I = 0; I < getSrcSize(); ++I) { | |
| 476 Operand *Src = getSrc(I); | |
| 477 SizeT NumVars = Src->getNumVars(); | |
| 478 for (SizeT J = 0; J < NumVars; ++J, ++VarIndex) { | |
| 479 const Variable *Var = Src->getVar(J); | |
| 480 if (isLastUse(Var)) { | |
| 481 if (First) | |
| 482 Str << " // LIVEEND={"; | |
| 483 else | |
| 484 Str << ","; | |
| 485 Var->dump(Func); | |
| 486 First = false; | |
| 487 } | |
| 488 } | |
| 489 } | |
| 490 if (!First) | |
| 491 Str << "}"; | |
| 492 } | |
| 493 } | |
| 494 | |
| 322 void Inst::dumpSources(const Cfg *Func) const { | 495 void Inst::dumpSources(const Cfg *Func) const { |
| 323 Ostream &Str = Func->getContext()->getStrDump(); | 496 Ostream &Str = Func->getContext()->getStrDump(); |
| 324 for (SizeT I = 0; I < getSrcSize(); ++I) { | 497 for (SizeT I = 0; I < getSrcSize(); ++I) { |
| 325 if (I > 0) | 498 if (I > 0) |
| 326 Str << ", "; | 499 Str << ", "; |
| 327 getSrc(I)->dump(Func); | 500 getSrc(I)->dump(Func); |
| 328 } | 501 } |
| 329 } | 502 } |
| 330 | 503 |
| 331 void Inst::emitSources(const Cfg *Func) const { | 504 void Inst::emitSources(const Cfg *Func) const { |
| (...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 546 Str << "kill.pseudo "; | 719 Str << "kill.pseudo "; |
| 547 dumpSources(Func); | 720 dumpSources(Func); |
| 548 } | 721 } |
| 549 | 722 |
| 550 void InstTarget::dump(const Cfg *Func) const { | 723 void InstTarget::dump(const Cfg *Func) const { |
| 551 Ostream &Str = Func->getContext()->getStrDump(); | 724 Ostream &Str = Func->getContext()->getStrDump(); |
| 552 Str << "[TARGET] "; | 725 Str << "[TARGET] "; |
| 553 Inst::dump(Func); | 726 Inst::dump(Func); |
| 554 } | 727 } |
| 555 | 728 |
| 729 void InstTarget::dumpExtras(const Cfg *Func) const { Inst::dumpExtras(Func); } | |
| 730 | |
| 556 } // end of namespace Ice | 731 } // end of namespace Ice |
| OLD | NEW |