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 |