Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 //===- subzero/src/IceCfg.cpp - Control flow graph implementation ---------===// | 1 //===- subzero/src/IceCfg.cpp - Control flow graph 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 Cfg class, including constant pool | 10 // This file implements the Cfg class, including constant pool |
| 11 // management. | 11 // management. |
| 12 // | 12 // |
| 13 //===----------------------------------------------------------------------===// | 13 //===----------------------------------------------------------------------===// |
| 14 | 14 |
| 15 #include "IceCfg.h" | 15 #include "IceCfg.h" |
| 16 #include "IceCfgNode.h" | 16 #include "IceCfgNode.h" |
| 17 #include "IceClFlags.h" | 17 #include "IceClFlags.h" |
| 18 #include "IceDefs.h" | 18 #include "IceDefs.h" |
| 19 #include "IceInst.h" | 19 #include "IceInst.h" |
| 20 #include "IceLiveness.h" | 20 #include "IceLiveness.h" |
| 21 #include "IceOperand.h" | 21 #include "IceOperand.h" |
| 22 #include "IceTargetLowering.h" | 22 #include "IceTargetLowering.h" |
| 23 | 23 |
| 24 namespace Ice { | 24 namespace Ice { |
| 25 | 25 |
| 26 Cfg::Cfg(GlobalContext *Ctx) | 26 Cfg::Cfg(GlobalContext *Ctx) |
| 27 : Ctx(Ctx), FunctionName(""), ReturnType(IceType_void), | 27 : Ctx(Ctx), FunctionName(""), ReturnType(IceType_void), |
| 28 IsInternalLinkage(false), HasError(false), ErrorMessage(""), Entry(NULL), | 28 IsInternalLinkage(false), HasError(false), FocusedTiming(false), |
| 29 NextInstNumber(1), Live(nullptr), | 29 ErrorMessage(""), Entry(NULL), NextInstNumber(1), Live(nullptr), |
| 30 Target(TargetLowering::createLowering(Ctx->getTargetArch(), this)), | 30 Target(TargetLowering::createLowering(Ctx->getTargetArch(), this)), |
| 31 VMetadata(new VariablesMetadata(this)), | 31 VMetadata(new VariablesMetadata(this)), |
| 32 TargetAssembler( | 32 TargetAssembler( |
| 33 TargetLowering::createAssembler(Ctx->getTargetArch(), this)), | 33 TargetLowering::createAssembler(Ctx->getTargetArch(), this)), |
| 34 CurrentNode(NULL) {} | 34 CurrentNode(NULL) {} |
| 35 | 35 |
| 36 Cfg::~Cfg() {} | 36 Cfg::~Cfg() {} |
| 37 | 37 |
| 38 void Cfg::setError(const IceString &Message) { | 38 void Cfg::setError(const IceString &Message) { |
| 39 HasError = true; | 39 HasError = true; |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 62 ImplicitArgs.push_back(Arg); | 62 ImplicitArgs.push_back(Arg); |
| 63 } | 63 } |
| 64 | 64 |
| 65 // Returns whether the stack frame layout has been computed yet. This | 65 // Returns whether the stack frame layout has been computed yet. This |
| 66 // is used for dumping the stack frame location of Variables. | 66 // is used for dumping the stack frame location of Variables. |
| 67 bool Cfg::hasComputedFrame() const { return getTarget()->hasComputedFrame(); } | 67 bool Cfg::hasComputedFrame() const { return getTarget()->hasComputedFrame(); } |
| 68 | 68 |
| 69 void Cfg::translate() { | 69 void Cfg::translate() { |
| 70 if (hasError()) | 70 if (hasError()) |
| 71 return; | 71 return; |
| 72 VerboseMask OldVerboseMask = getContext()->getVerbose(); | |
| 73 const IceString &TimingFocusOn = getContext()->getFlags().TimingFocusOn; | |
| 74 if (TimingFocusOn == "*" || TimingFocusOn == getFunctionName()) | |
| 75 setFocusedTiming(); | |
| 76 bool VerboseFocus = (getContext()->getFlags().VerboseFocusOn == getFunctionNam e()); | |
|
jvoung (off chromium)
2014/10/06 16:30:56
80 col ?
Jim Stichnoth
2014/10/06 21:29:57
Done.
| |
| 77 if (VerboseFocus) | |
| 78 getContext()->setVerbose(IceV_All); | |
| 72 static TimerIdT IDtranslate = GlobalContext::getTimerID("translate"); | 79 static TimerIdT IDtranslate = GlobalContext::getTimerID("translate"); |
| 73 TimerMarker T(IDtranslate, getContext()); | 80 TimerMarker T(IDtranslate, this); |
| 74 | 81 |
| 75 dump("Initial CFG"); | 82 dump("Initial CFG"); |
| 76 | 83 |
| 77 // The set of translation passes and their order are determined by | 84 // The set of translation passes and their order are determined by |
| 78 // the target. | 85 // the target. |
| 79 getTarget()->translate(); | 86 getTarget()->translate(); |
| 80 | 87 |
| 81 dump("Final output"); | 88 dump("Final output"); |
| 89 if (getFocusedTiming()) | |
| 90 getContext()->dumpTimers(); | |
| 91 if (VerboseFocus) | |
| 92 getContext()->setVerbose(OldVerboseMask); | |
| 82 } | 93 } |
| 83 | 94 |
| 84 void Cfg::computePredecessors() { | 95 void Cfg::computePredecessors() { |
| 85 for (CfgNode *Node : Nodes) | 96 for (CfgNode *Node : Nodes) |
| 86 Node->computePredecessors(); | 97 Node->computePredecessors(); |
| 87 } | 98 } |
| 88 | 99 |
| 89 void Cfg::renumberInstructions() { | 100 void Cfg::renumberInstructions() { |
| 90 static TimerIdT IDrenumberInstructions = | 101 static TimerIdT IDrenumberInstructions = |
| 91 GlobalContext::getTimerID("renumberInstructions"); | 102 GlobalContext::getTimerID("renumberInstructions"); |
| 92 TimerMarker T(IDrenumberInstructions, getContext()); | 103 TimerMarker T(IDrenumberInstructions, this); |
| 93 NextInstNumber = 1; | 104 NextInstNumber = 1; |
| 94 for (CfgNode *Node : Nodes) | 105 for (CfgNode *Node : Nodes) |
| 95 Node->renumberInstructions(); | 106 Node->renumberInstructions(); |
| 96 } | 107 } |
| 97 | 108 |
| 98 // placePhiLoads() must be called before placePhiStores(). | 109 // placePhiLoads() must be called before placePhiStores(). |
| 99 void Cfg::placePhiLoads() { | 110 void Cfg::placePhiLoads() { |
| 100 static TimerIdT IDplacePhiLoads = GlobalContext::getTimerID("placePhiLoads"); | 111 static TimerIdT IDplacePhiLoads = GlobalContext::getTimerID("placePhiLoads"); |
| 101 TimerMarker T(IDplacePhiLoads, getContext()); | 112 TimerMarker T(IDplacePhiLoads, this); |
| 102 for (CfgNode *Node : Nodes) | 113 for (CfgNode *Node : Nodes) |
| 103 Node->placePhiLoads(); | 114 Node->placePhiLoads(); |
| 104 } | 115 } |
| 105 | 116 |
| 106 // placePhiStores() must be called after placePhiLoads(). | 117 // placePhiStores() must be called after placePhiLoads(). |
| 107 void Cfg::placePhiStores() { | 118 void Cfg::placePhiStores() { |
| 108 static TimerIdT IDplacePhiStores = | 119 static TimerIdT IDplacePhiStores = |
| 109 GlobalContext::getTimerID("placePhiStores"); | 120 GlobalContext::getTimerID("placePhiStores"); |
| 110 TimerMarker T(IDplacePhiStores, getContext()); | 121 TimerMarker T(IDplacePhiStores, this); |
| 111 for (CfgNode *Node : Nodes) | 122 for (CfgNode *Node : Nodes) |
| 112 Node->placePhiStores(); | 123 Node->placePhiStores(); |
| 113 } | 124 } |
| 114 | 125 |
| 115 void Cfg::deletePhis() { | 126 void Cfg::deletePhis() { |
| 116 static TimerIdT IDdeletePhis = GlobalContext::getTimerID("deletePhis"); | 127 static TimerIdT IDdeletePhis = GlobalContext::getTimerID("deletePhis"); |
| 117 TimerMarker T(IDdeletePhis, getContext()); | 128 TimerMarker T(IDdeletePhis, this); |
| 118 for (CfgNode *Node : Nodes) | 129 for (CfgNode *Node : Nodes) |
| 119 Node->deletePhis(); | 130 Node->deletePhis(); |
| 120 } | 131 } |
| 121 | 132 |
| 122 void Cfg::doArgLowering() { | 133 void Cfg::doArgLowering() { |
| 123 static TimerIdT IDdoArgLowering = GlobalContext::getTimerID("doArgLowering"); | 134 static TimerIdT IDdoArgLowering = GlobalContext::getTimerID("doArgLowering"); |
| 124 TimerMarker T(IDdoArgLowering, getContext()); | 135 TimerMarker T(IDdoArgLowering, this); |
| 125 getTarget()->lowerArguments(); | 136 getTarget()->lowerArguments(); |
| 126 } | 137 } |
| 127 | 138 |
| 128 void Cfg::doAddressOpt() { | 139 void Cfg::doAddressOpt() { |
| 129 static TimerIdT IDdoAddressOpt = GlobalContext::getTimerID("doAddressOpt"); | 140 static TimerIdT IDdoAddressOpt = GlobalContext::getTimerID("doAddressOpt"); |
| 130 TimerMarker T(IDdoAddressOpt, getContext()); | 141 TimerMarker T(IDdoAddressOpt, this); |
| 131 for (CfgNode *Node : Nodes) | 142 for (CfgNode *Node : Nodes) |
| 132 Node->doAddressOpt(); | 143 Node->doAddressOpt(); |
| 133 } | 144 } |
| 134 | 145 |
| 135 void Cfg::doNopInsertion() { | 146 void Cfg::doNopInsertion() { |
| 136 static TimerIdT IDdoNopInsertion = | 147 static TimerIdT IDdoNopInsertion = |
| 137 GlobalContext::getTimerID("doNopInsertion"); | 148 GlobalContext::getTimerID("doNopInsertion"); |
| 138 TimerMarker T(IDdoNopInsertion, getContext()); | 149 TimerMarker T(IDdoNopInsertion, this); |
| 139 for (CfgNode *Node : Nodes) | 150 for (CfgNode *Node : Nodes) |
| 140 Node->doNopInsertion(); | 151 Node->doNopInsertion(); |
| 141 } | 152 } |
| 142 | 153 |
| 143 void Cfg::genCode() { | 154 void Cfg::genCode() { |
| 144 static TimerIdT IDgenCode = GlobalContext::getTimerID("genCode"); | 155 static TimerIdT IDgenCode = GlobalContext::getTimerID("genCode"); |
| 145 TimerMarker T(IDgenCode, getContext()); | 156 TimerMarker T(IDgenCode, this); |
| 146 for (CfgNode *Node : Nodes) | 157 for (CfgNode *Node : Nodes) |
| 147 Node->genCode(); | 158 Node->genCode(); |
| 148 } | 159 } |
| 149 | 160 |
| 150 // Compute the stack frame layout. | 161 // Compute the stack frame layout. |
| 151 void Cfg::genFrame() { | 162 void Cfg::genFrame() { |
| 152 static TimerIdT IDgenFrame = GlobalContext::getTimerID("genFrame"); | 163 static TimerIdT IDgenFrame = GlobalContext::getTimerID("genFrame"); |
| 153 TimerMarker T(IDgenFrame, getContext()); | 164 TimerMarker T(IDgenFrame, this); |
| 154 getTarget()->addProlog(Entry); | 165 getTarget()->addProlog(Entry); |
| 155 // TODO: Consider folding epilog generation into the final | 166 // TODO: Consider folding epilog generation into the final |
| 156 // emission/assembly pass to avoid an extra iteration over the node | 167 // emission/assembly pass to avoid an extra iteration over the node |
| 157 // list. Or keep a separate list of exit nodes. | 168 // list. Or keep a separate list of exit nodes. |
| 158 for (CfgNode *Node : Nodes) | 169 for (CfgNode *Node : Nodes) |
| 159 if (Node->getHasReturn()) | 170 if (Node->getHasReturn()) |
| 160 getTarget()->addEpilog(Node); | 171 getTarget()->addEpilog(Node); |
| 161 } | 172 } |
| 162 | 173 |
| 163 // This is a lightweight version of live-range-end calculation. Marks | 174 // This is a lightweight version of live-range-end calculation. Marks |
| 164 // the last use of only those variables whose definition and uses are | 175 // the last use of only those variables whose definition and uses are |
| 165 // completely with a single block. It is a quick single pass and | 176 // completely with a single block. It is a quick single pass and |
| 166 // doesn't need to iterate until convergence. | 177 // doesn't need to iterate until convergence. |
| 167 void Cfg::livenessLightweight() { | 178 void Cfg::livenessLightweight() { |
| 168 static TimerIdT IDlivenessLightweight = | 179 static TimerIdT IDlivenessLightweight = |
| 169 GlobalContext::getTimerID("livenessLightweight"); | 180 GlobalContext::getTimerID("livenessLightweight"); |
| 170 TimerMarker T(IDlivenessLightweight, getContext()); | 181 TimerMarker T(IDlivenessLightweight, this); |
| 171 getVMetadata()->init(); | 182 getVMetadata()->init(); |
| 172 for (CfgNode *Node : Nodes) | 183 for (CfgNode *Node : Nodes) |
| 173 Node->livenessLightweight(); | 184 Node->livenessLightweight(); |
| 174 } | 185 } |
| 175 | 186 |
| 176 void Cfg::liveness(LivenessMode Mode) { | 187 void Cfg::liveness(LivenessMode Mode) { |
| 177 static TimerIdT IDliveness = GlobalContext::getTimerID("liveness"); | 188 static TimerIdT IDliveness = GlobalContext::getTimerID("liveness"); |
| 178 TimerMarker T(IDliveness, getContext()); | 189 TimerMarker T(IDliveness, this); |
| 179 Live.reset(new Liveness(this, Mode)); | 190 Live.reset(new Liveness(this, Mode)); |
| 180 getVMetadata()->init(); | 191 getVMetadata()->init(); |
| 181 Live->init(); | 192 Live->init(); |
| 182 // Initialize with all nodes needing to be processed. | 193 // Initialize with all nodes needing to be processed. |
| 183 llvm::BitVector NeedToProcess(Nodes.size(), true); | 194 llvm::BitVector NeedToProcess(Nodes.size(), true); |
| 184 while (NeedToProcess.any()) { | 195 while (NeedToProcess.any()) { |
| 185 // Iterate in reverse topological order to speed up convergence. | 196 // Iterate in reverse topological order to speed up convergence. |
| 186 // TODO(stichnot): Use llvm::make_range with LLVM 3.5. | 197 // TODO(stichnot): Use llvm::make_range with LLVM 3.5. |
| 187 for (auto I = Nodes.rbegin(), E = Nodes.rend(); I != E; ++I) { | 198 for (auto I = Nodes.rbegin(), E = Nodes.rend(); I != E; ++I) { |
| 188 CfgNode *Node = *I; | 199 CfgNode *Node = *I; |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 202 // Reset each variable's live range. | 213 // Reset each variable's live range. |
| 203 for (Variable *Var : Variables) | 214 for (Variable *Var : Variables) |
| 204 Var->resetLiveRange(); | 215 Var->resetLiveRange(); |
| 205 } | 216 } |
| 206 // Collect timing for just the portion that constructs the live | 217 // Collect timing for just the portion that constructs the live |
| 207 // range intervals based on the end-of-live-range computation, for a | 218 // range intervals based on the end-of-live-range computation, for a |
| 208 // finer breakdown of the cost. | 219 // finer breakdown of the cost. |
| 209 // Make a final pass over instructions to delete dead instructions | 220 // Make a final pass over instructions to delete dead instructions |
| 210 // and build each Variable's live range. | 221 // and build each Variable's live range. |
| 211 static TimerIdT IDliveRange = GlobalContext::getTimerID("liveRange"); | 222 static TimerIdT IDliveRange = GlobalContext::getTimerID("liveRange"); |
| 212 TimerMarker T1(IDliveRange, getContext()); | 223 TimerMarker T1(IDliveRange, this); |
| 213 for (CfgNode *Node : Nodes) | 224 for (CfgNode *Node : Nodes) |
| 214 Node->livenessPostprocess(Mode, getLiveness()); | 225 Node->livenessPostprocess(Mode, getLiveness()); |
| 215 if (Mode == Liveness_Intervals) { | 226 if (Mode == Liveness_Intervals) { |
| 216 // Special treatment for live in-args. Their liveness needs to | 227 // Special treatment for live in-args. Their liveness needs to |
| 217 // extend beyond the beginning of the function, otherwise an arg | 228 // extend beyond the beginning of the function, otherwise an arg |
| 218 // whose only use is in the first instruction will end up having | 229 // whose only use is in the first instruction will end up having |
| 219 // the trivial live range [1,1) and will *not* interfere with | 230 // the trivial live range [1,1) and will *not* interfere with |
| 220 // other arguments. So if the first instruction of the method is | 231 // other arguments. So if the first instruction of the method is |
| 221 // "r=arg1+arg2", both args may be assigned the same register. | 232 // "r=arg1+arg2", both args may be assigned the same register. |
| 222 for (SizeT I = 0; I < Args.size(); ++I) { | 233 for (SizeT I = 0; I < Args.size(); ++I) { |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 250 } | 261 } |
| 251 dump(); | 262 dump(); |
| 252 } | 263 } |
| 253 } | 264 } |
| 254 | 265 |
| 255 // Traverse every Variable of every Inst and verify that it | 266 // Traverse every Variable of every Inst and verify that it |
| 256 // appears within the Variable's computed live range. | 267 // appears within the Variable's computed live range. |
| 257 bool Cfg::validateLiveness() const { | 268 bool Cfg::validateLiveness() const { |
| 258 static TimerIdT IDvalidateLiveness = | 269 static TimerIdT IDvalidateLiveness = |
| 259 GlobalContext::getTimerID("validateLiveness"); | 270 GlobalContext::getTimerID("validateLiveness"); |
| 260 TimerMarker T(IDvalidateLiveness, getContext()); | 271 TimerMarker T(IDvalidateLiveness, this); |
| 261 bool Valid = true; | 272 bool Valid = true; |
| 262 Ostream &Str = Ctx->getStrDump(); | 273 Ostream &Str = Ctx->getStrDump(); |
| 263 for (CfgNode *Node : Nodes) { | 274 for (CfgNode *Node : Nodes) { |
| 264 for (Inst *Inst : Node->getInsts()) { | 275 for (Inst *Inst : Node->getInsts()) { |
| 265 if (Inst->isDeleted()) | 276 if (Inst->isDeleted()) |
| 266 continue; | 277 continue; |
| 267 if (llvm::isa<InstFakeKill>(Inst)) | 278 if (llvm::isa<InstFakeKill>(Inst)) |
| 268 continue; | 279 continue; |
| 269 InstNumberT InstNumber = Inst->getNumber(); | 280 InstNumberT InstNumber = Inst->getNumber(); |
| 270 Variable *Dest = Inst->getDest(); | 281 Variable *Dest = Inst->getDest(); |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 294 } | 305 } |
| 295 } | 306 } |
| 296 } | 307 } |
| 297 } | 308 } |
| 298 } | 309 } |
| 299 return Valid; | 310 return Valid; |
| 300 } | 311 } |
| 301 | 312 |
| 302 void Cfg::doBranchOpt() { | 313 void Cfg::doBranchOpt() { |
| 303 static TimerIdT IDdoBranchOpt = GlobalContext::getTimerID("doBranchOpt"); | 314 static TimerIdT IDdoBranchOpt = GlobalContext::getTimerID("doBranchOpt"); |
| 304 TimerMarker T(IDdoBranchOpt, getContext()); | 315 TimerMarker T(IDdoBranchOpt, this); |
| 305 for (auto I = Nodes.begin(), E = Nodes.end(); I != E; ++I) { | 316 for (auto I = Nodes.begin(), E = Nodes.end(); I != E; ++I) { |
| 306 auto NextNode = I; | 317 auto NextNode = I; |
| 307 ++NextNode; | 318 ++NextNode; |
| 308 (*I)->doBranchOpt(NextNode == E ? NULL : *NextNode); | 319 (*I)->doBranchOpt(NextNode == E ? NULL : *NextNode); |
| 309 } | 320 } |
| 310 } | 321 } |
| 311 | 322 |
| 312 // ======================== Dump routines ======================== // | 323 // ======================== Dump routines ======================== // |
| 313 | 324 |
| 314 void Cfg::emit() { | 325 void Cfg::emit() { |
| 315 static TimerIdT IDemit = GlobalContext::getTimerID("emit"); | 326 static TimerIdT IDemit = GlobalContext::getTimerID("emit"); |
| 316 TimerMarker T(IDemit, getContext()); | 327 TimerMarker T(IDemit, this); |
| 317 Ostream &Str = Ctx->getStrEmit(); | 328 Ostream &Str = Ctx->getStrEmit(); |
| 318 if (!Ctx->testAndSetHasEmittedFirstMethod()) { | 329 if (!Ctx->testAndSetHasEmittedFirstMethod()) { |
| 319 // Print a helpful command for assembling the output. | 330 // Print a helpful command for assembling the output. |
| 320 // TODO: have the Target emit the header | 331 // TODO: have the Target emit the header |
| 321 // TODO: need a per-file emit in addition to per-CFG | 332 // TODO: need a per-file emit in addition to per-CFG |
| 322 Str << "# $LLVM_BIN_PATH/llvm-mc" | 333 Str << "# $LLVM_BIN_PATH/llvm-mc" |
| 323 << " -arch=x86" | 334 << " -arch=x86" |
| 324 << " -x86-asm-syntax=intel" | 335 << " -x86-asm-syntax=intel" |
| 325 << " -filetype=obj" | 336 << " -filetype=obj" |
| 326 << " -o=MyObj.o" | 337 << " -o=MyObj.o" |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 380 } | 391 } |
| 381 } | 392 } |
| 382 // Print each basic block | 393 // Print each basic block |
| 383 for (CfgNode *Node : Nodes) | 394 for (CfgNode *Node : Nodes) |
| 384 Node->dump(this); | 395 Node->dump(this); |
| 385 if (getContext()->isVerbose(IceV_Instructions)) | 396 if (getContext()->isVerbose(IceV_Instructions)) |
| 386 Str << "}\n"; | 397 Str << "}\n"; |
| 387 } | 398 } |
| 388 | 399 |
| 389 } // end of namespace Ice | 400 } // end of namespace Ice |
| OLD | NEW |