| 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 | 
|---|