| 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 subclass |
| 12 /// subclass constructors and dump routines. | 12 /// 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 "IceInstVarIter.h" |
| 21 #include "IceLiveness.h" | 21 #include "IceLiveness.h" |
| 22 #include "IceOperand.h" | 22 #include "IceOperand.h" |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 75 | 75 |
| 76 Inst::Inst(Cfg *Func, InstKind Kind, SizeT MaxSrcs, Variable *Dest) | 76 Inst::Inst(Cfg *Func, InstKind Kind, SizeT MaxSrcs, Variable *Dest) |
| 77 : Kind(Kind), Number(Func->newInstNumber()), Dest(Dest), MaxSrcs(MaxSrcs), | 77 : Kind(Kind), Number(Func->newInstNumber()), Dest(Dest), MaxSrcs(MaxSrcs), |
| 78 Srcs(Func->allocateArrayOf<Operand *>(MaxSrcs)), LiveRangesEnded(0) {} | 78 Srcs(Func->allocateArrayOf<Operand *>(MaxSrcs)), LiveRangesEnded(0) {} |
| 79 | 79 |
| 80 // Assign the instruction a new number. | 80 // Assign the instruction a new number. |
| 81 void Inst::renumber(Cfg *Func) { | 81 void Inst::renumber(Cfg *Func) { |
| 82 Number = isDeleted() ? NumberDeleted : Func->newInstNumber(); | 82 Number = isDeleted() ? NumberDeleted : Func->newInstNumber(); |
| 83 } | 83 } |
| 84 | 84 |
| 85 // Delete the instruction if its tentative Dead flag is still set | 85 // Delete the instruction if its tentative Dead flag is still set after |
| 86 // after liveness analysis. | 86 // liveness analysis. |
| 87 void Inst::deleteIfDead() { | 87 void Inst::deleteIfDead() { |
| 88 if (Dead) | 88 if (Dead) |
| 89 setDeleted(); | 89 setDeleted(); |
| 90 } | 90 } |
| 91 | 91 |
| 92 // 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 Src's live |
| 93 // Src's live range. Otherwise, returns false. | 93 // range. Otherwise, returns false. |
| 94 bool Inst::isLastUse(const Operand *TestSrc) const { | 94 bool Inst::isLastUse(const Operand *TestSrc) const { |
| 95 if (LiveRangesEnded == 0) | 95 if (LiveRangesEnded == 0) |
| 96 return false; // early-exit optimization | 96 return false; // early-exit optimization |
| 97 if (const Variable *TestVar = llvm::dyn_cast<const Variable>(TestSrc)) { | 97 if (const Variable *TestVar = llvm::dyn_cast<const Variable>(TestSrc)) { |
| 98 LREndedBits Mask = LiveRangesEnded; | 98 LREndedBits Mask = LiveRangesEnded; |
| 99 FOREACH_VAR_IN_INST(Var, *this) { | 99 FOREACH_VAR_IN_INST(Var, *this) { |
| 100 if (Var == TestVar) { | 100 if (Var == TestVar) { |
| 101 // We've found where the variable is used in the instruction. | 101 // We've found where the variable is used in the instruction. |
| 102 return Mask & 1; | 102 return Mask & 1; |
| 103 } | 103 } |
| 104 Mask >>= 1; | 104 Mask >>= 1; |
| 105 if (Mask == 0) | 105 if (Mask == 0) |
| 106 return false; // another early-exit optimization | 106 return false; // another early-exit optimization |
| 107 } | 107 } |
| 108 } | 108 } |
| 109 return false; | 109 return false; |
| 110 } | 110 } |
| 111 | 111 |
| 112 // Given an instruction like: | 112 // Given an instruction like: |
| 113 // a = b + c + [x,y] + e | 113 // a = b + c + [x,y] + e |
| 114 // which was created from OrigInst: | 114 // which was created from OrigInst: |
| 115 // a = b + c + d + e | 115 // a = b + c + d + e |
| 116 // with SpliceAssn spliced in: | 116 // with SpliceAssn spliced in: |
| 117 // d = [x,y] | 117 // d = [x,y] |
| 118 // | 118 // |
| 119 // Reconstruct the LiveRangesEnded bitmask in this instruction by | 119 // Reconstruct the LiveRangesEnded bitmask in this instruction by combining the |
| 120 // combining the LiveRangesEnded values of OrigInst and SpliceAssn. | 120 // LiveRangesEnded values of OrigInst and SpliceAssn. If operands d and [x,y] |
| 121 // If operands d and [x,y] contain a different number of variables, | 121 // contain a different number of variables, then the bitmask position for e may |
| 122 // then the bitmask position for e may be different in OrigInst and | 122 // be different in OrigInst and the current instruction, requiring extra shifts |
| 123 // the current instruction, requiring extra shifts and masks in the | 123 // and masks in the computation. In the example above, OrigInst has variable e |
| 124 // computation. In the example above, OrigInst has variable e in bit | 124 // in bit position 3, whereas the current instruction has e in bit position 4 |
| 125 // position 3, whereas the current instruction has e in bit position 4 | |
| 126 // because [x,y] consumes 2 bitmask slots while d only consumed 1. | 125 // because [x,y] consumes 2 bitmask slots while d only consumed 1. |
| 127 // | 126 // |
| 128 // Additionally, set HasSideEffects if either OrigInst or SpliceAssn | 127 // Additionally, set HasSideEffects if either OrigInst or SpliceAssn have |
| 129 // have HasSideEffects set. | 128 // HasSideEffects set. |
| 130 void Inst::spliceLivenessInfo(Inst *OrigInst, Inst *SpliceAssn) { | 129 void Inst::spliceLivenessInfo(Inst *OrigInst, Inst *SpliceAssn) { |
| 131 HasSideEffects |= OrigInst->HasSideEffects; | 130 HasSideEffects |= OrigInst->HasSideEffects; |
| 132 HasSideEffects |= SpliceAssn->HasSideEffects; | 131 HasSideEffects |= SpliceAssn->HasSideEffects; |
| 133 // Find the bitmask index of SpliceAssn's dest within OrigInst. | 132 // Find the bitmask index of SpliceAssn's dest within OrigInst. |
| 134 Variable *SpliceDest = SpliceAssn->getDest(); | 133 Variable *SpliceDest = SpliceAssn->getDest(); |
| 135 SizeT Index = 0; | 134 SizeT Index = 0; |
| 136 for (SizeT I = 0; I < OrigInst->getSrcSize(); ++I) { | 135 for (SizeT I = 0; I < OrigInst->getSrcSize(); ++I) { |
| 137 Operand *Src = OrigInst->getSrc(I); | 136 Operand *Src = OrigInst->getSrc(I); |
| 138 if (Src == SpliceDest) { | 137 if (Src == SpliceDest) { |
| 139 LREndedBits LeftMask = OrigInst->LiveRangesEnded & ((1 << Index) - 1); | 138 LREndedBits LeftMask = OrigInst->LiveRangesEnded & ((1 << Index) - 1); |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 177 LiveBegin->push_back(std::make_pair(VarNum, InstNumber)); | 176 LiveBegin->push_back(std::make_pair(VarNum, InstNumber)); |
| 178 } | 177 } |
| 179 } | 178 } |
| 180 } else { | 179 } else { |
| 181 if (!hasSideEffects()) | 180 if (!hasSideEffects()) |
| 182 Dead = true; | 181 Dead = true; |
| 183 } | 182 } |
| 184 } | 183 } |
| 185 if (Dead) | 184 if (Dead) |
| 186 return false; | 185 return false; |
| 187 // Phi arguments only get added to Live in the predecessor node, but | 186 // Phi arguments only get added to Live in the predecessor node, but we still |
| 188 // we still need to update LiveRangesEnded. | 187 // need to update LiveRangesEnded. |
| 189 bool IsPhi = llvm::isa<InstPhi>(this); | 188 bool IsPhi = llvm::isa<InstPhi>(this); |
| 190 resetLastUses(); | 189 resetLastUses(); |
| 191 FOREACH_VAR_IN_INST(Var, *this) { | 190 FOREACH_VAR_IN_INST(Var, *this) { |
| 192 SizeT VarNum = Liveness->getLiveIndex(Var->getIndex()); | 191 SizeT VarNum = Liveness->getLiveIndex(Var->getIndex()); |
| 193 if (!Live[VarNum]) { | 192 if (!Live[VarNum]) { |
| 194 setLastUse(IndexOfVarInInst(Var)); | 193 setLastUse(IndexOfVarInInst(Var)); |
| 195 if (!IsPhi) { | 194 if (!IsPhi) { |
| 196 Live[VarNum] = true; | 195 Live[VarNum] = true; |
| 197 // For a variable in SSA form, its live range can end at most once in a | 196 // For a variable in SSA form, its live range can end at most once in a |
| 198 // basic block. However, after lowering to two-address instructions, we | 197 // basic block. However, after lowering to two-address instructions, we |
| 199 // end up with sequences like "t=b;t+=c;a=t" where t's live range begins | 198 // end up with sequences like "t=b;t+=c;a=t" where t's live range |
| 200 // and ends twice. ICE only allows a variable to have a single liveness | 199 // begins and ends twice. ICE only allows a variable to have a single |
| 201 // interval in a basic block (except for blocks where a variable is | 200 // liveness interval in a basic block (except for blocks where a |
| 202 // live-in and live-out but there is a gap in the middle). Therefore, | 201 // variable is live-in and live-out but there is a gap in the middle). |
| 203 // this lowered sequence needs to represent a single conservative live | 202 // Therefore, this lowered sequence needs to represent a single |
| 204 // range for t. Since the instructions are being traversed backwards, | 203 // conservative live range for t. Since the instructions are being |
| 205 // we make sure LiveEnd is only set once by setting it only when | 204 // traversed backwards, we make sure LiveEnd is only set once by |
| 206 // LiveEnd[VarNum]==0 (sentinel value). Note that it's OK to set | 205 // setting it only when LiveEnd[VarNum]==0 (sentinel value). Note that |
| 207 // LiveBegin multiple times because of the backwards traversal. | 206 // it's OK to set LiveBegin multiple times because of the backwards |
| 207 // traversal. |
| 208 if (LiveEnd && Liveness->getRangeMask(Var->getIndex())) { | 208 if (LiveEnd && Liveness->getRangeMask(Var->getIndex())) { |
| 209 // Ideally, we would verify that VarNum wasn't already added in this | 209 // Ideally, we would verify that VarNum wasn't already added in this |
| 210 // block, but this can't be done very efficiently with LiveEnd as a | 210 // block, but this can't be done very efficiently with LiveEnd as a |
| 211 // vector. Instead, livenessPostprocess() verifies this after the | 211 // vector. Instead, livenessPostprocess() verifies this after the |
| 212 // vector has been sorted. | 212 // vector has been sorted. |
| 213 LiveEnd->push_back(std::make_pair(VarNum, InstNumber)); | 213 LiveEnd->push_back(std::make_pair(VarNum, InstNumber)); |
| 214 } | 214 } |
| 215 } | 215 } |
| 216 } | 216 } |
| 217 } | 217 } |
| 218 return true; | 218 return true; |
| 219 } | 219 } |
| 220 | 220 |
| 221 InstAlloca::InstAlloca(Cfg *Func, Operand *ByteCount, uint32_t AlignInBytes, | 221 InstAlloca::InstAlloca(Cfg *Func, Operand *ByteCount, uint32_t AlignInBytes, |
| (...skipping 20 matching lines...) Expand all Loading... |
| 242 | 242 |
| 243 bool InstArithmetic::isCommutative() const { | 243 bool InstArithmetic::isCommutative() const { |
| 244 return InstArithmeticAttributes[getOp()].IsCommutative; | 244 return InstArithmeticAttributes[getOp()].IsCommutative; |
| 245 } | 245 } |
| 246 | 246 |
| 247 InstAssign::InstAssign(Cfg *Func, Variable *Dest, Operand *Source) | 247 InstAssign::InstAssign(Cfg *Func, Variable *Dest, Operand *Source) |
| 248 : InstHighLevel(Func, Inst::Assign, 1, Dest) { | 248 : InstHighLevel(Func, Inst::Assign, 1, Dest) { |
| 249 addSource(Source); | 249 addSource(Source); |
| 250 } | 250 } |
| 251 | 251 |
| 252 // If TargetTrue==TargetFalse, we turn it into an unconditional | 252 // If TargetTrue==TargetFalse, we turn it into an unconditional branch. This |
| 253 // branch. This ensures that, along with the 'switch' instruction | 253 // ensures that, along with the 'switch' instruction semantics, there is at |
| 254 // semantics, there is at most one edge from one node to another. | 254 // most one edge from one node to another. |
| 255 InstBr::InstBr(Cfg *Func, Operand *Source, CfgNode *TargetTrue_, | 255 InstBr::InstBr(Cfg *Func, Operand *Source, CfgNode *TargetTrue_, |
| 256 CfgNode *TargetFalse_) | 256 CfgNode *TargetFalse_) |
| 257 : InstHighLevel(Func, Inst::Br, 1, nullptr), TargetFalse(TargetFalse_), | 257 : InstHighLevel(Func, Inst::Br, 1, nullptr), TargetFalse(TargetFalse_), |
| 258 TargetTrue(TargetTrue_) { | 258 TargetTrue(TargetTrue_) { |
| 259 if (TargetTrue == TargetFalse) { | 259 if (TargetTrue == TargetFalse) { |
| 260 TargetTrue = nullptr; // turn into unconditional version | 260 TargetTrue = nullptr; // turn into unconditional version |
| 261 } else { | 261 } else { |
| 262 addSource(Source); | 262 addSource(Source); |
| 263 } | 263 } |
| 264 } | 264 } |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 327 InstLoad::InstLoad(Cfg *Func, Variable *Dest, Operand *SourceAddr) | 327 InstLoad::InstLoad(Cfg *Func, Variable *Dest, Operand *SourceAddr) |
| 328 : InstHighLevel(Func, Inst::Load, 1, Dest) { | 328 : InstHighLevel(Func, Inst::Load, 1, Dest) { |
| 329 addSource(SourceAddr); | 329 addSource(SourceAddr); |
| 330 } | 330 } |
| 331 | 331 |
| 332 InstPhi::InstPhi(Cfg *Func, SizeT MaxSrcs, Variable *Dest) | 332 InstPhi::InstPhi(Cfg *Func, SizeT MaxSrcs, Variable *Dest) |
| 333 : InstHighLevel(Func, Phi, MaxSrcs, Dest) { | 333 : InstHighLevel(Func, Phi, MaxSrcs, Dest) { |
| 334 Labels = Func->allocateArrayOf<CfgNode *>(MaxSrcs); | 334 Labels = Func->allocateArrayOf<CfgNode *>(MaxSrcs); |
| 335 } | 335 } |
| 336 | 336 |
| 337 // TODO: A Switch instruction (and maybe others) can add duplicate | 337 // TODO: A Switch instruction (and maybe others) can add duplicate edges. We |
| 338 // edges. We may want to de-dup Phis and validate consistency (i.e., | 338 // may want to de-dup Phis and validate consistency (i.e., the source operands |
| 339 // the source operands are the same for duplicate edges), though it | 339 // are the same for duplicate edges), though it seems the current lowering code |
| 340 // seems the current lowering code is OK with this situation. | 340 // is OK with this situation. |
| 341 void InstPhi::addArgument(Operand *Source, CfgNode *Label) { | 341 void InstPhi::addArgument(Operand *Source, CfgNode *Label) { |
| 342 Labels[getSrcSize()] = Label; | 342 Labels[getSrcSize()] = Label; |
| 343 addSource(Source); | 343 addSource(Source); |
| 344 } | 344 } |
| 345 | 345 |
| 346 // Find the source operand corresponding to the incoming edge for the | 346 // Find the source operand corresponding to the incoming edge for the given |
| 347 // given node. TODO: This uses a linear-time search, which could be | 347 // node. TODO: This uses a linear-time search, which could be improved if it |
| 348 // improved if it becomes a problem. | 348 // becomes a problem. |
| 349 Operand *InstPhi::getOperandForTarget(CfgNode *Target) const { | 349 Operand *InstPhi::getOperandForTarget(CfgNode *Target) const { |
| 350 for (SizeT I = 0; I < getSrcSize(); ++I) { | 350 for (SizeT I = 0; I < getSrcSize(); ++I) { |
| 351 if (Labels[I] == Target) | 351 if (Labels[I] == Target) |
| 352 return getSrc(I); | 352 return getSrc(I); |
| 353 } | 353 } |
| 354 llvm_unreachable("Phi target not found"); | 354 llvm_unreachable("Phi target not found"); |
| 355 return nullptr; | 355 return nullptr; |
| 356 } | 356 } |
| 357 | 357 |
| 358 // Updates liveness for a particular operand based on the given | 358 // Updates liveness for a particular operand based on the given predecessor |
| 359 // predecessor edge. Doesn't mark the operand as live if the Phi | 359 // edge. Doesn't mark the operand as live if the Phi instruction is dead or |
| 360 // instruction is dead or deleted. | 360 // deleted. |
| 361 void InstPhi::livenessPhiOperand(LivenessBV &Live, CfgNode *Target, | 361 void InstPhi::livenessPhiOperand(LivenessBV &Live, CfgNode *Target, |
| 362 Liveness *Liveness) { | 362 Liveness *Liveness) { |
| 363 if (isDeleted() || Dead) | 363 if (isDeleted() || Dead) |
| 364 return; | 364 return; |
| 365 for (SizeT I = 0; I < getSrcSize(); ++I) { | 365 for (SizeT I = 0; I < getSrcSize(); ++I) { |
| 366 if (Labels[I] == Target) { | 366 if (Labels[I] == Target) { |
| 367 if (Variable *Var = llvm::dyn_cast<Variable>(getSrc(I))) { | 367 if (Variable *Var = llvm::dyn_cast<Variable>(getSrc(I))) { |
| 368 SizeT SrcIndex = Liveness->getLiveIndex(Var->getIndex()); | 368 SizeT SrcIndex = Liveness->getLiveIndex(Var->getIndex()); |
| 369 if (!Live[SrcIndex]) { | 369 if (!Live[SrcIndex]) { |
| 370 setLastUse(I); | 370 setLastUse(I); |
| 371 Live[SrcIndex] = true; | 371 Live[SrcIndex] = true; |
| 372 } | 372 } |
| 373 } | 373 } |
| 374 return; | 374 return; |
| 375 } | 375 } |
| 376 } | 376 } |
| 377 llvm_unreachable("Phi operand not found for specified target node"); | 377 llvm_unreachable("Phi operand not found for specified target node"); |
| 378 } | 378 } |
| 379 | 379 |
| 380 // Change "a=phi(...)" to "a_phi=phi(...)" and return a new | 380 // Change "a=phi(...)" to "a_phi=phi(...)" and return a new instruction |
| 381 // instruction "a=a_phi". | 381 // "a=a_phi". |
| 382 Inst *InstPhi::lower(Cfg *Func) { | 382 Inst *InstPhi::lower(Cfg *Func) { |
| 383 Variable *Dest = getDest(); | 383 Variable *Dest = getDest(); |
| 384 assert(Dest); | 384 assert(Dest); |
| 385 Variable *NewSrc = Func->makeVariable(Dest->getType()); | 385 Variable *NewSrc = Func->makeVariable(Dest->getType()); |
| 386 if (BuildDefs::dump()) | 386 if (BuildDefs::dump()) |
| 387 NewSrc->setName(Func, Dest->getName(Func) + "_phi"); | 387 NewSrc->setName(Func, Dest->getName(Func) + "_phi"); |
| 388 this->Dest = NewSrc; | 388 this->Dest = NewSrc; |
| 389 return InstAssign::create(Func, Dest, NewSrc); | 389 return InstAssign::create(Func, Dest, NewSrc); |
| 390 } | 390 } |
| 391 | 391 |
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 555 dumpDest(Func); | 555 dumpDest(Func); |
| 556 Str << " =~ "; | 556 Str << " =~ "; |
| 557 dumpSources(Func); | 557 dumpSources(Func); |
| 558 } | 558 } |
| 559 | 559 |
| 560 void Inst::dumpExtras(const Cfg *Func) const { | 560 void Inst::dumpExtras(const Cfg *Func) const { |
| 561 if (!BuildDefs::dump()) | 561 if (!BuildDefs::dump()) |
| 562 return; | 562 return; |
| 563 Ostream &Str = Func->getContext()->getStrDump(); | 563 Ostream &Str = Func->getContext()->getStrDump(); |
| 564 bool First = true; | 564 bool First = true; |
| 565 // Print "LIVEEND={a,b,c}" for all source operands whose live ranges | 565 // Print "LIVEEND={a,b,c}" for all source operands whose live ranges are |
| 566 // are known to end at this instruction. | 566 // known to end at this instruction. |
| 567 if (Func->isVerbose(IceV_Liveness)) { | 567 if (Func->isVerbose(IceV_Liveness)) { |
| 568 FOREACH_VAR_IN_INST(Var, *this) { | 568 FOREACH_VAR_IN_INST(Var, *this) { |
| 569 if (isLastUse(Var)) { | 569 if (isLastUse(Var)) { |
| 570 if (First) | 570 if (First) |
| 571 Str << " // LIVEEND={"; | 571 Str << " // LIVEEND={"; |
| 572 else | 572 else |
| 573 Str << ","; | 573 Str << ","; |
| 574 Var->dump(Func); | 574 Var->dump(Func); |
| 575 First = false; | 575 First = false; |
| 576 } | 576 } |
| (...skipping 302 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 879 void InstBundleUnlock::dump(const Cfg *Func) const { | 879 void InstBundleUnlock::dump(const Cfg *Func) const { |
| 880 if (!BuildDefs::dump()) | 880 if (!BuildDefs::dump()) |
| 881 return; | 881 return; |
| 882 Ostream &Str = Func->getContext()->getStrDump(); | 882 Ostream &Str = Func->getContext()->getStrDump(); |
| 883 Str << "bundle_unlock"; | 883 Str << "bundle_unlock"; |
| 884 } | 884 } |
| 885 | 885 |
| 886 void InstFakeDef::emit(const Cfg *Func) const { | 886 void InstFakeDef::emit(const Cfg *Func) const { |
| 887 if (!BuildDefs::dump()) | 887 if (!BuildDefs::dump()) |
| 888 return; | 888 return; |
| 889 // Go ahead and "emit" these for now, since they are relatively | 889 // Go ahead and "emit" these for now, since they are relatively rare. |
| 890 // rare. | |
| 891 Ostream &Str = Func->getContext()->getStrEmit(); | 890 Ostream &Str = Func->getContext()->getStrEmit(); |
| 892 Str << "\t# "; | 891 Str << "\t# "; |
| 893 getDest()->emit(Func); | 892 getDest()->emit(Func); |
| 894 Str << " = def.pseudo "; | 893 Str << " = def.pseudo "; |
| 895 emitSources(Func); | 894 emitSources(Func); |
| 896 } | 895 } |
| 897 | 896 |
| 898 void InstFakeDef::dump(const Cfg *Func) const { | 897 void InstFakeDef::dump(const Cfg *Func) const { |
| 899 if (!BuildDefs::dump()) | 898 if (!BuildDefs::dump()) |
| 900 return; | 899 return; |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 941 Ostream &Str = Func->getContext()->getStrDump(); | 940 Ostream &Str = Func->getContext()->getStrDump(); |
| 942 Str << "[TARGET] "; | 941 Str << "[TARGET] "; |
| 943 Inst::dump(Func); | 942 Inst::dump(Func); |
| 944 } | 943 } |
| 945 | 944 |
| 946 bool checkForRedundantAssign(const Variable *Dest, const Operand *Source) { | 945 bool checkForRedundantAssign(const Variable *Dest, const Operand *Source) { |
| 947 const auto SrcVar = llvm::dyn_cast<const Variable>(Source); | 946 const auto SrcVar = llvm::dyn_cast<const Variable>(Source); |
| 948 if (!SrcVar) | 947 if (!SrcVar) |
| 949 return false; | 948 return false; |
| 950 if (Dest->hasReg() && Dest->getRegNum() == SrcVar->getRegNum()) { | 949 if (Dest->hasReg() && Dest->getRegNum() == SrcVar->getRegNum()) { |
| 951 // TODO: On x86-64, instructions like "mov eax, eax" are used to | 950 // TODO: On x86-64, instructions like "mov eax, eax" are used to clear the |
| 952 // clear the upper 32 bits of rax. We need to recognize and | 951 // upper 32 bits of rax. We need to recognize and preserve these. |
| 953 // preserve these. | |
| 954 return true; | 952 return true; |
| 955 } | 953 } |
| 956 if (!Dest->hasReg() && !SrcVar->hasReg() && | 954 if (!Dest->hasReg() && !SrcVar->hasReg() && |
| 957 Dest->getStackOffset() == SrcVar->getStackOffset()) | 955 Dest->getStackOffset() == SrcVar->getStackOffset()) |
| 958 return true; | 956 return true; |
| 959 return false; | 957 return false; |
| 960 } | 958 } |
| 961 | 959 |
| 962 } // end of namespace Ice | 960 } // end of namespace Ice |
| OLD | NEW |