| 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 /// \file | 10 /// \file |
| 11 /// This file implements the Inst class, primarily the various | 11 /// This file implements the Inst class, primarily the various |
| 12 /// subclass constructors and dump routines. | 12 /// subclass constructors and dump routines. |
| 13 /// | 13 /// |
| 14 //===----------------------------------------------------------------------===// | 14 //===----------------------------------------------------------------------===// |
| 15 | 15 |
| 16 #include "IceInst.h" | 16 #include "IceInst.h" |
| 17 | 17 |
| 18 #include "IceCfg.h" | 18 #include "IceCfg.h" |
| 19 #include "IceCfgNode.h" | 19 #include "IceCfgNode.h" |
| 20 #include "IceInstVarIter.h" |
| 20 #include "IceLiveness.h" | 21 #include "IceLiveness.h" |
| 21 #include "IceOperand.h" | 22 #include "IceOperand.h" |
| 22 #include "IceTargetLowering.h" | 23 #include "IceTargetLowering.h" |
| 23 | 24 |
| 24 namespace Ice { | 25 namespace Ice { |
| 25 | 26 |
| 26 namespace { | 27 namespace { |
| 27 | 28 |
| 28 // Using non-anonymous struct so that array_lengthof works. | 29 // Using non-anonymous struct so that array_lengthof works. |
| 29 const struct InstArithmeticAttributes_ { | 30 const struct InstArithmeticAttributes_ { |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 88 setDeleted(); | 89 setDeleted(); |
| 89 } | 90 } |
| 90 | 91 |
| 91 // If Src is a Variable, it returns true if this instruction ends | 92 // If Src is a Variable, it returns true if this instruction ends |
| 92 // Src's live range. Otherwise, returns false. | 93 // Src's live range. Otherwise, returns false. |
| 93 bool Inst::isLastUse(const Operand *TestSrc) const { | 94 bool Inst::isLastUse(const Operand *TestSrc) const { |
| 94 if (LiveRangesEnded == 0) | 95 if (LiveRangesEnded == 0) |
| 95 return false; // early-exit optimization | 96 return false; // early-exit optimization |
| 96 if (const Variable *TestVar = llvm::dyn_cast<const Variable>(TestSrc)) { | 97 if (const Variable *TestVar = llvm::dyn_cast<const Variable>(TestSrc)) { |
| 97 LREndedBits Mask = LiveRangesEnded; | 98 LREndedBits Mask = LiveRangesEnded; |
| 98 for (SizeT I = 0; I < getSrcSize(); ++I) { | 99 FOREACH_VAR_IN_INST(Var, *this) { |
| 99 Operand *Src = getSrc(I); | 100 if (Var == TestVar) { |
| 100 SizeT NumVars = Src->getNumVars(); | 101 // We've found where the variable is used in the instruction. |
| 101 for (SizeT J = 0; J < NumVars; ++J) { | 102 return Mask & 1; |
| 102 const Variable *Var = Src->getVar(J); | |
| 103 if (Var == TestVar) { | |
| 104 // We've found where the variable is used in the instruction. | |
| 105 return Mask & 1; | |
| 106 } | |
| 107 Mask >>= 1; | |
| 108 if (Mask == 0) | |
| 109 return false; // another early-exit optimization | |
| 110 } | 103 } |
| 104 Mask >>= 1; |
| 105 if (Mask == 0) |
| 106 return false; // another early-exit optimization |
| 111 } | 107 } |
| 112 } | 108 } |
| 113 return false; | 109 return false; |
| 114 } | 110 } |
| 115 | 111 |
| 116 // Given an instruction like: | 112 // Given an instruction like: |
| 117 // a = b + c + [x,y] + e | 113 // a = b + c + [x,y] + e |
| 118 // which was created from OrigInst: | 114 // which was created from OrigInst: |
| 119 // a = b + c + d + e | 115 // a = b + c + d + e |
| 120 // with SpliceAssn spliced in: | 116 // with SpliceAssn spliced in: |
| (...skipping 27 matching lines...) Expand all Loading... |
| 148 } | 144 } |
| 149 Index += getSrc(I)->getNumVars(); | 145 Index += getSrc(I)->getNumVars(); |
| 150 } | 146 } |
| 151 llvm::report_fatal_error("Failed to find splice operand"); | 147 llvm::report_fatal_error("Failed to find splice operand"); |
| 152 } | 148 } |
| 153 | 149 |
| 154 void Inst::livenessLightweight(Cfg *Func, LivenessBV &Live) { | 150 void Inst::livenessLightweight(Cfg *Func, LivenessBV &Live) { |
| 155 assert(!isDeleted()); | 151 assert(!isDeleted()); |
| 156 resetLastUses(); | 152 resetLastUses(); |
| 157 VariablesMetadata *VMetadata = Func->getVMetadata(); | 153 VariablesMetadata *VMetadata = Func->getVMetadata(); |
| 158 SizeT VarIndex = 0; | 154 FOREACH_VAR_IN_INST(Var, *this) { |
| 159 for (SizeT I = 0; I < getSrcSize(); ++I) { | 155 if (VMetadata->isMultiBlock(Var)) |
| 160 Operand *Src = getSrc(I); | 156 continue; |
| 161 SizeT NumVars = Src->getNumVars(); | 157 SizeT Index = Var->getIndex(); |
| 162 for (SizeT J = 0; J < NumVars; ++J, ++VarIndex) { | 158 if (Live[Index]) |
| 163 const Variable *Var = Src->getVar(J); | 159 continue; |
| 164 if (VMetadata->isMultiBlock(Var)) | 160 Live[Index] = true; |
| 165 continue; | 161 setLastUse(IndexOfVarInInst(Var)); |
| 166 SizeT Index = Var->getIndex(); | |
| 167 if (Live[Index]) | |
| 168 continue; | |
| 169 Live[Index] = true; | |
| 170 setLastUse(VarIndex); | |
| 171 } | |
| 172 } | 162 } |
| 173 } | 163 } |
| 174 | 164 |
| 175 bool Inst::liveness(InstNumberT InstNumber, LivenessBV &Live, | 165 bool Inst::liveness(InstNumberT InstNumber, LivenessBV &Live, |
| 176 Liveness *Liveness, LiveBeginEndMap *LiveBegin, | 166 Liveness *Liveness, LiveBeginEndMap *LiveBegin, |
| 177 LiveBeginEndMap *LiveEnd) { | 167 LiveBeginEndMap *LiveEnd) { |
| 178 assert(!isDeleted()); | 168 assert(!isDeleted()); |
| 179 | 169 |
| 180 Dead = false; | 170 Dead = false; |
| 181 if (Dest) { | 171 if (Dest) { |
| 182 SizeT VarNum = Liveness->getLiveIndex(Dest->getIndex()); | 172 SizeT VarNum = Liveness->getLiveIndex(Dest->getIndex()); |
| 183 if (Live[VarNum]) { | 173 if (Live[VarNum]) { |
| 184 if (!isDestNonKillable()) { | 174 if (!isDestNonKillable()) { |
| 185 Live[VarNum] = false; | 175 Live[VarNum] = false; |
| 186 if (LiveBegin && Liveness->getRangeMask(Dest->getIndex())) { | 176 if (LiveBegin && Liveness->getRangeMask(Dest->getIndex())) { |
| 187 LiveBegin->push_back(std::make_pair(VarNum, InstNumber)); | 177 LiveBegin->push_back(std::make_pair(VarNum, InstNumber)); |
| 188 } | 178 } |
| 189 } | 179 } |
| 190 } else { | 180 } else { |
| 191 if (!hasSideEffects()) | 181 if (!hasSideEffects()) |
| 192 Dead = true; | 182 Dead = true; |
| 193 } | 183 } |
| 194 } | 184 } |
| 195 if (Dead) | 185 if (Dead) |
| 196 return false; | 186 return false; |
| 197 // Phi arguments only get added to Live in the predecessor node, but | 187 // Phi arguments only get added to Live in the predecessor node, but |
| 198 // we still need to update LiveRangesEnded. | 188 // we still need to update LiveRangesEnded. |
| 199 bool IsPhi = llvm::isa<InstPhi>(this); | 189 bool IsPhi = llvm::isa<InstPhi>(this); |
| 200 resetLastUses(); | 190 resetLastUses(); |
| 201 SizeT VarIndex = 0; | 191 FOREACH_VAR_IN_INST(Var, *this) { |
| 202 for (SizeT I = 0; I < getSrcSize(); ++I) { | 192 SizeT VarNum = Liveness->getLiveIndex(Var->getIndex()); |
| 203 Operand *Src = getSrc(I); | 193 if (!Live[VarNum]) { |
| 204 SizeT NumVars = Src->getNumVars(); | 194 setLastUse(IndexOfVarInInst(Var)); |
| 205 for (SizeT J = 0; J < NumVars; ++J, ++VarIndex) { | 195 if (!IsPhi) { |
| 206 const Variable *Var = Src->getVar(J); | 196 Live[VarNum] = true; |
| 207 SizeT VarNum = Liveness->getLiveIndex(Var->getIndex()); | 197 // For a variable in SSA form, its live range can end at most once in a |
| 208 if (!Live[VarNum]) { | 198 // basic block. However, after lowering to two-address instructions, we |
| 209 setLastUse(VarIndex); | 199 // end up with sequences like "t=b;t+=c;a=t" where t's live range begins |
| 210 if (!IsPhi) { | 200 // and ends twice. ICE only allows a variable to have a single liveness |
| 211 Live[VarNum] = true; | 201 // interval in a basic block (except for blocks where a variable is |
| 212 // For a variable in SSA form, its live range can end at | 202 // live-in and live-out but there is a gap in the middle). Therefore, |
| 213 // most once in a basic block. However, after lowering to | 203 // this lowered sequence needs to represent a single conservative live |
| 214 // two-address instructions, we end up with sequences like | 204 // range for t. Since the instructions are being traversed backwards, |
| 215 // "t=b;t+=c;a=t" where t's live range begins and ends | 205 // we make sure LiveEnd is only set once by setting it only when |
| 216 // twice. ICE only allows a variable to have a single | 206 // LiveEnd[VarNum]==0 (sentinel value). Note that it's OK to set |
| 217 // liveness interval in a basic block (except for blocks | 207 // LiveBegin multiple times because of the backwards traversal. |
| 218 // where a variable is live-in and live-out but there is a | 208 if (LiveEnd && Liveness->getRangeMask(Var->getIndex())) { |
| 219 // gap in the middle). Therefore, this lowered sequence | 209 // Ideally, we would verify that VarNum wasn't already added in this |
| 220 // needs to represent a single conservative live range for | 210 // block, but this can't be done very efficiently with LiveEnd as a |
| 221 // t. Since the instructions are being traversed backwards, | 211 // vector. Instead, livenessPostprocess() verifies this after the |
| 222 // we make sure LiveEnd is only set once by setting it only | 212 // vector has been sorted. |
| 223 // when LiveEnd[VarNum]==0 (sentinel value). Note that it's | 213 LiveEnd->push_back(std::make_pair(VarNum, InstNumber)); |
| 224 // OK to set LiveBegin multiple times because of the | |
| 225 // backwards traversal. | |
| 226 if (LiveEnd && Liveness->getRangeMask(Var->getIndex())) { | |
| 227 // Ideally, we would verify that VarNum wasn't already | |
| 228 // added in this block, but this can't be done very | |
| 229 // efficiently with LiveEnd as a vector. Instead, | |
| 230 // livenessPostprocess() verifies this after the vector | |
| 231 // has been sorted. | |
| 232 LiveEnd->push_back(std::make_pair(VarNum, InstNumber)); | |
| 233 } | |
| 234 } | 214 } |
| 235 } | 215 } |
| 236 } | 216 } |
| 237 } | 217 } |
| 238 return true; | 218 return true; |
| 239 } | 219 } |
| 240 | 220 |
| 241 InstAlloca::InstAlloca(Cfg *Func, Operand *ByteCount, uint32_t AlignInBytes, | 221 InstAlloca::InstAlloca(Cfg *Func, Operand *ByteCount, uint32_t AlignInBytes, |
| 242 Variable *Dest) | 222 Variable *Dest) |
| 243 : InstHighLevel(Func, Inst::Alloca, 1, Dest), AlignInBytes(AlignInBytes) { | 223 : InstHighLevel(Func, Inst::Alloca, 1, Dest), AlignInBytes(AlignInBytes) { |
| (...skipping 330 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 574 } | 554 } |
| 575 | 555 |
| 576 void Inst::dumpExtras(const Cfg *Func) const { | 556 void Inst::dumpExtras(const Cfg *Func) const { |
| 577 if (!BuildDefs::dump()) | 557 if (!BuildDefs::dump()) |
| 578 return; | 558 return; |
| 579 Ostream &Str = Func->getContext()->getStrDump(); | 559 Ostream &Str = Func->getContext()->getStrDump(); |
| 580 bool First = true; | 560 bool First = true; |
| 581 // Print "LIVEEND={a,b,c}" for all source operands whose live ranges | 561 // Print "LIVEEND={a,b,c}" for all source operands whose live ranges |
| 582 // are known to end at this instruction. | 562 // are known to end at this instruction. |
| 583 if (Func->isVerbose(IceV_Liveness)) { | 563 if (Func->isVerbose(IceV_Liveness)) { |
| 584 for (SizeT I = 0; I < getSrcSize(); ++I) { | 564 FOREACH_VAR_IN_INST(Var, *this) { |
| 585 Operand *Src = getSrc(I); | 565 if (isLastUse(Var)) { |
| 586 SizeT NumVars = Src->getNumVars(); | 566 if (First) |
| 587 for (SizeT J = 0; J < NumVars; ++J) { | 567 Str << " // LIVEEND={"; |
| 588 const Variable *Var = Src->getVar(J); | 568 else |
| 589 if (isLastUse(Var)) { | 569 Str << ","; |
| 590 if (First) | 570 Var->dump(Func); |
| 591 Str << " // LIVEEND={"; | 571 First = false; |
| 592 else | |
| 593 Str << ","; | |
| 594 Var->dump(Func); | |
| 595 First = false; | |
| 596 } | |
| 597 } | 572 } |
| 598 } | 573 } |
| 599 if (!First) | 574 if (!First) |
| 600 Str << "}"; | 575 Str << "}"; |
| 601 } | 576 } |
| 602 } | 577 } |
| 603 | 578 |
| 604 void Inst::dumpSources(const Cfg *Func) const { | 579 void Inst::dumpSources(const Cfg *Func) const { |
| 605 if (!BuildDefs::dump()) | 580 if (!BuildDefs::dump()) |
| 606 return; | 581 return; |
| (...skipping 367 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 974 // preserve these. | 949 // preserve these. |
| 975 return true; | 950 return true; |
| 976 } | 951 } |
| 977 if (!Dest->hasReg() && !SrcVar->hasReg() && | 952 if (!Dest->hasReg() && !SrcVar->hasReg() && |
| 978 Dest->getStackOffset() == SrcVar->getStackOffset()) | 953 Dest->getStackOffset() == SrcVar->getStackOffset()) |
| 979 return true; | 954 return true; |
| 980 return false; | 955 return false; |
| 981 } | 956 } |
| 982 | 957 |
| 983 } // end of namespace Ice | 958 } // end of namespace Ice |
| OLD | NEW |