| 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 |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after 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 static TimerIdT IDtranslate = GlobalContext::getTimerID("translate"); |
| 73 TimerMarker T(IDtranslate, getContext()); |
| 72 | 74 |
| 73 dump("Initial CFG"); | 75 dump("Initial CFG"); |
| 74 | 76 |
| 75 Timer T_translate; | |
| 76 // The set of translation passes and their order are determined by | 77 // The set of translation passes and their order are determined by |
| 77 // the target. | 78 // the target. |
| 78 getTarget()->translate(); | 79 getTarget()->translate(); |
| 79 T_translate.printElapsedUs(getContext(), "translate()"); | |
| 80 | 80 |
| 81 dump("Final output"); | 81 dump("Final output"); |
| 82 } | 82 } |
| 83 | 83 |
| 84 void Cfg::computePredecessors() { | 84 void Cfg::computePredecessors() { |
| 85 for (NodeList::iterator I = Nodes.begin(), E = Nodes.end(); I != E; ++I) { | 85 for (NodeList::iterator I = Nodes.begin(), E = Nodes.end(); I != E; ++I) { |
| 86 (*I)->computePredecessors(); | 86 (*I)->computePredecessors(); |
| 87 } | 87 } |
| 88 } | 88 } |
| 89 | 89 |
| 90 void Cfg::renumberInstructions() { | 90 void Cfg::renumberInstructions() { |
| 91 static TimerIdT IDrenumberInstructions = |
| 92 GlobalContext::getTimerID("renumberInstructions"); |
| 93 TimerMarker T(IDrenumberInstructions, getContext()); |
| 91 NextInstNumber = 1; | 94 NextInstNumber = 1; |
| 92 for (NodeList::iterator I = Nodes.begin(), E = Nodes.end(); I != E; ++I) { | 95 for (NodeList::iterator I = Nodes.begin(), E = Nodes.end(); I != E; ++I) { |
| 93 (*I)->renumberInstructions(); | 96 (*I)->renumberInstructions(); |
| 94 } | 97 } |
| 95 } | 98 } |
| 96 | 99 |
| 97 // placePhiLoads() must be called before placePhiStores(). | 100 // placePhiLoads() must be called before placePhiStores(). |
| 98 void Cfg::placePhiLoads() { | 101 void Cfg::placePhiLoads() { |
| 102 static TimerIdT IDplacePhiLoads = GlobalContext::getTimerID("placePhiLoads"); |
| 103 TimerMarker T(IDplacePhiLoads, getContext()); |
| 99 for (NodeList::iterator I = Nodes.begin(), E = Nodes.end(); I != E; ++I) { | 104 for (NodeList::iterator I = Nodes.begin(), E = Nodes.end(); I != E; ++I) { |
| 100 (*I)->placePhiLoads(); | 105 (*I)->placePhiLoads(); |
| 101 } | 106 } |
| 102 } | 107 } |
| 103 | 108 |
| 104 // placePhiStores() must be called after placePhiLoads(). | 109 // placePhiStores() must be called after placePhiLoads(). |
| 105 void Cfg::placePhiStores() { | 110 void Cfg::placePhiStores() { |
| 111 static TimerIdT IDplacePhiStores = |
| 112 GlobalContext::getTimerID("placePhiStores"); |
| 113 TimerMarker T(IDplacePhiStores, getContext()); |
| 106 for (NodeList::iterator I = Nodes.begin(), E = Nodes.end(); I != E; ++I) { | 114 for (NodeList::iterator I = Nodes.begin(), E = Nodes.end(); I != E; ++I) { |
| 107 (*I)->placePhiStores(); | 115 (*I)->placePhiStores(); |
| 108 } | 116 } |
| 109 } | 117 } |
| 110 | 118 |
| 111 void Cfg::deletePhis() { | 119 void Cfg::deletePhis() { |
| 120 static TimerIdT IDdeletePhis = GlobalContext::getTimerID("deletePhis"); |
| 121 TimerMarker T(IDdeletePhis, getContext()); |
| 112 for (NodeList::iterator I = Nodes.begin(), E = Nodes.end(); I != E; ++I) { | 122 for (NodeList::iterator I = Nodes.begin(), E = Nodes.end(); I != E; ++I) { |
| 113 (*I)->deletePhis(); | 123 (*I)->deletePhis(); |
| 114 } | 124 } |
| 115 } | 125 } |
| 116 | 126 |
| 117 void Cfg::doArgLowering() { | 127 void Cfg::doArgLowering() { |
| 128 static TimerIdT IDdoArgLowering = GlobalContext::getTimerID("doArgLowering"); |
| 129 TimerMarker T(IDdoArgLowering, getContext()); |
| 118 getTarget()->lowerArguments(); | 130 getTarget()->lowerArguments(); |
| 119 } | 131 } |
| 120 | 132 |
| 121 void Cfg::doAddressOpt() { | 133 void Cfg::doAddressOpt() { |
| 134 static TimerIdT IDdoAddressOpt = GlobalContext::getTimerID("doAddressOpt"); |
| 135 TimerMarker T(IDdoAddressOpt, getContext()); |
| 122 for (NodeList::iterator I = Nodes.begin(), E = Nodes.end(); I != E; ++I) { | 136 for (NodeList::iterator I = Nodes.begin(), E = Nodes.end(); I != E; ++I) { |
| 123 (*I)->doAddressOpt(); | 137 (*I)->doAddressOpt(); |
| 124 } | 138 } |
| 125 } | 139 } |
| 126 | 140 |
| 127 void Cfg::doNopInsertion() { | 141 void Cfg::doNopInsertion() { |
| 142 static TimerIdT IDdoNopInsertion = |
| 143 GlobalContext::getTimerID("doNopInsertion"); |
| 144 TimerMarker T(IDdoNopInsertion, getContext()); |
| 128 for (NodeList::iterator I = Nodes.begin(), E = Nodes.end(); I != E; ++I) { | 145 for (NodeList::iterator I = Nodes.begin(), E = Nodes.end(); I != E; ++I) { |
| 129 (*I)->doNopInsertion(); | 146 (*I)->doNopInsertion(); |
| 130 } | 147 } |
| 131 } | 148 } |
| 132 | 149 |
| 133 void Cfg::genCode() { | 150 void Cfg::genCode() { |
| 151 static TimerIdT IDgenCode = GlobalContext::getTimerID("genCode"); |
| 152 TimerMarker T(IDgenCode, getContext()); |
| 134 for (NodeList::iterator I = Nodes.begin(), E = Nodes.end(); I != E; ++I) { | 153 for (NodeList::iterator I = Nodes.begin(), E = Nodes.end(); I != E; ++I) { |
| 135 (*I)->genCode(); | 154 (*I)->genCode(); |
| 136 } | 155 } |
| 137 } | 156 } |
| 138 | 157 |
| 139 // Compute the stack frame layout. | 158 // Compute the stack frame layout. |
| 140 void Cfg::genFrame() { | 159 void Cfg::genFrame() { |
| 160 static TimerIdT IDgenFrame = GlobalContext::getTimerID("genFrame"); |
| 161 TimerMarker T(IDgenFrame, getContext()); |
| 141 getTarget()->addProlog(Entry); | 162 getTarget()->addProlog(Entry); |
| 142 // TODO: Consider folding epilog generation into the final | 163 // TODO: Consider folding epilog generation into the final |
| 143 // emission/assembly pass to avoid an extra iteration over the node | 164 // emission/assembly pass to avoid an extra iteration over the node |
| 144 // list. Or keep a separate list of exit nodes. | 165 // list. Or keep a separate list of exit nodes. |
| 145 for (NodeList::iterator I = Nodes.begin(), E = Nodes.end(); I != E; ++I) { | 166 for (NodeList::iterator I = Nodes.begin(), E = Nodes.end(); I != E; ++I) { |
| 146 CfgNode *Node = *I; | 167 CfgNode *Node = *I; |
| 147 if (Node->getHasReturn()) | 168 if (Node->getHasReturn()) |
| 148 getTarget()->addEpilog(Node); | 169 getTarget()->addEpilog(Node); |
| 149 } | 170 } |
| 150 } | 171 } |
| 151 | 172 |
| 152 // This is a lightweight version of live-range-end calculation. Marks | 173 // This is a lightweight version of live-range-end calculation. Marks |
| 153 // the last use of only those variables whose definition and uses are | 174 // the last use of only those variables whose definition and uses are |
| 154 // completely with a single block. It is a quick single pass and | 175 // completely with a single block. It is a quick single pass and |
| 155 // doesn't need to iterate until convergence. | 176 // doesn't need to iterate until convergence. |
| 156 void Cfg::livenessLightweight() { | 177 void Cfg::livenessLightweight() { |
| 178 static TimerIdT IDlivenessLightweight = |
| 179 GlobalContext::getTimerID("livenessLightweight"); |
| 180 TimerMarker T(IDlivenessLightweight, getContext()); |
| 157 getVMetadata()->init(); | 181 getVMetadata()->init(); |
| 158 for (NodeList::iterator I = Nodes.begin(), E = Nodes.end(); I != E; ++I) { | 182 for (NodeList::iterator I = Nodes.begin(), E = Nodes.end(); I != E; ++I) { |
| 159 (*I)->livenessLightweight(); | 183 (*I)->livenessLightweight(); |
| 160 } | 184 } |
| 161 } | 185 } |
| 162 | 186 |
| 163 void Cfg::liveness(LivenessMode Mode) { | 187 void Cfg::liveness(LivenessMode Mode) { |
| 188 static TimerIdT IDliveness = GlobalContext::getTimerID("liveness"); |
| 189 TimerMarker T(IDliveness, getContext()); |
| 164 Live.reset(new Liveness(this, Mode)); | 190 Live.reset(new Liveness(this, Mode)); |
| 165 getVMetadata()->init(); | 191 getVMetadata()->init(); |
| 166 Live->init(); | 192 Live->init(); |
| 167 // Initialize with all nodes needing to be processed. | 193 // Initialize with all nodes needing to be processed. |
| 168 llvm::BitVector NeedToProcess(Nodes.size(), true); | 194 llvm::BitVector NeedToProcess(Nodes.size(), true); |
| 169 while (NeedToProcess.any()) { | 195 while (NeedToProcess.any()) { |
| 170 // Iterate in reverse topological order to speed up convergence. | 196 // Iterate in reverse topological order to speed up convergence. |
| 171 for (NodeList::reverse_iterator I = Nodes.rbegin(), E = Nodes.rend(); | 197 for (NodeList::reverse_iterator I = Nodes.rbegin(), E = Nodes.rend(); |
| 172 I != E; ++I) { | 198 I != E; ++I) { |
| 173 CfgNode *Node = *I; | 199 CfgNode *Node = *I; |
| (...skipping 18 matching lines...) Expand all Loading... |
| 192 // Reset each variable's live range. | 218 // Reset each variable's live range. |
| 193 for (VarList::const_iterator I = Variables.begin(), E = Variables.end(); | 219 for (VarList::const_iterator I = Variables.begin(), E = Variables.end(); |
| 194 I != E; ++I) { | 220 I != E; ++I) { |
| 195 if (Variable *Var = *I) | 221 if (Variable *Var = *I) |
| 196 Var->resetLiveRange(); | 222 Var->resetLiveRange(); |
| 197 } | 223 } |
| 198 } | 224 } |
| 199 // Collect timing for just the portion that constructs the live | 225 // Collect timing for just the portion that constructs the live |
| 200 // range intervals based on the end-of-live-range computation, for a | 226 // range intervals based on the end-of-live-range computation, for a |
| 201 // finer breakdown of the cost. | 227 // finer breakdown of the cost. |
| 202 Timer T_liveRange; | |
| 203 // Make a final pass over instructions to delete dead instructions | 228 // Make a final pass over instructions to delete dead instructions |
| 204 // and build each Variable's live range. | 229 // and build each Variable's live range. |
| 230 static TimerIdT IDliveRange = GlobalContext::getTimerID("liveRange"); |
| 231 TimerMarker T1(IDliveRange, getContext()); |
| 205 for (NodeList::iterator I = Nodes.begin(), E = Nodes.end(); I != E; ++I) { | 232 for (NodeList::iterator I = Nodes.begin(), E = Nodes.end(); I != E; ++I) { |
| 206 (*I)->livenessPostprocess(Mode, getLiveness()); | 233 (*I)->livenessPostprocess(Mode, getLiveness()); |
| 207 } | 234 } |
| 208 if (Mode == Liveness_Intervals) { | 235 if (Mode == Liveness_Intervals) { |
| 209 // Special treatment for live in-args. Their liveness needs to | 236 // Special treatment for live in-args. Their liveness needs to |
| 210 // extend beyond the beginning of the function, otherwise an arg | 237 // extend beyond the beginning of the function, otherwise an arg |
| 211 // whose only use is in the first instruction will end up having | 238 // whose only use is in the first instruction will end up having |
| 212 // the trivial live range [1,1) and will *not* interfere with | 239 // the trivial live range [1,1) and will *not* interfere with |
| 213 // other arguments. So if the first instruction of the method is | 240 // other arguments. So if the first instruction of the method is |
| 214 // "r=arg1+arg2", both args may be assigned the same register. | 241 // "r=arg1+arg2", both args may be assigned the same register. |
| (...skipping 19 matching lines...) Expand all Loading... |
| 234 // Remove Variable::LiveRange and redirect to | 261 // Remove Variable::LiveRange and redirect to |
| 235 // Liveness::LiveRanges. TODO: make sure Variable weights | 262 // Liveness::LiveRanges. TODO: make sure Variable weights |
| 236 // are applied properly. | 263 // are applied properly. |
| 237 SizeT NumVars = Variables.size(); | 264 SizeT NumVars = Variables.size(); |
| 238 for (SizeT i = 0; i < NumVars; ++i) { | 265 for (SizeT i = 0; i < NumVars; ++i) { |
| 239 Variable *Var = Variables[i]; | 266 Variable *Var = Variables[i]; |
| 240 Var->setLiveRange(Live->getLiveRange(Var)); | 267 Var->setLiveRange(Live->getLiveRange(Var)); |
| 241 if (Var->getWeight().isInf()) | 268 if (Var->getWeight().isInf()) |
| 242 Var->setLiveRangeInfiniteWeight(); | 269 Var->setLiveRangeInfiniteWeight(); |
| 243 } | 270 } |
| 244 T_liveRange.printElapsedUs(getContext(), "live range construction"); | |
| 245 dump(); | 271 dump(); |
| 246 } | 272 } |
| 247 } | 273 } |
| 248 | 274 |
| 249 // Traverse every Variable of every Inst and verify that it | 275 // Traverse every Variable of every Inst and verify that it |
| 250 // appears within the Variable's computed live range. | 276 // appears within the Variable's computed live range. |
| 251 bool Cfg::validateLiveness() const { | 277 bool Cfg::validateLiveness() const { |
| 278 static TimerIdT IDvalidateLiveness = |
| 279 GlobalContext::getTimerID("validateLiveness"); |
| 280 TimerMarker T(IDvalidateLiveness, getContext()); |
| 252 bool Valid = true; | 281 bool Valid = true; |
| 253 Ostream &Str = Ctx->getStrDump(); | 282 Ostream &Str = Ctx->getStrDump(); |
| 254 for (NodeList::const_iterator I1 = Nodes.begin(), E1 = Nodes.end(); I1 != E1; | 283 for (NodeList::const_iterator I1 = Nodes.begin(), E1 = Nodes.end(); I1 != E1; |
| 255 ++I1) { | 284 ++I1) { |
| 256 CfgNode *Node = *I1; | 285 CfgNode *Node = *I1; |
| 257 InstList &Insts = Node->getInsts(); | 286 InstList &Insts = Node->getInsts(); |
| 258 for (InstList::const_iterator I2 = Insts.begin(), E2 = Insts.end(); | 287 for (InstList::const_iterator I2 = Insts.begin(), E2 = Insts.end(); |
| 259 I2 != E2; ++I2) { | 288 I2 != E2; ++I2) { |
| 260 Inst *Inst = *I2; | 289 Inst *Inst = *I2; |
| 261 if (Inst->isDeleted()) | 290 if (Inst->isDeleted()) |
| (...skipping 27 matching lines...) Expand all Loading... |
| 289 Str << " live range " << Var->getLiveRange() << "\n"; | 318 Str << " live range " << Var->getLiveRange() << "\n"; |
| 290 } | 319 } |
| 291 } | 320 } |
| 292 } | 321 } |
| 293 } | 322 } |
| 294 } | 323 } |
| 295 return Valid; | 324 return Valid; |
| 296 } | 325 } |
| 297 | 326 |
| 298 void Cfg::doBranchOpt() { | 327 void Cfg::doBranchOpt() { |
| 328 static TimerIdT IDdoBranchOpt = GlobalContext::getTimerID("doBranchOpt"); |
| 329 TimerMarker T(IDdoBranchOpt, getContext()); |
| 299 for (NodeList::iterator I = Nodes.begin(), E = Nodes.end(); I != E; ++I) { | 330 for (NodeList::iterator I = Nodes.begin(), E = Nodes.end(); I != E; ++I) { |
| 300 NodeList::iterator NextNode = I; | 331 NodeList::iterator NextNode = I; |
| 301 ++NextNode; | 332 ++NextNode; |
| 302 (*I)->doBranchOpt(*NextNode); | 333 (*I)->doBranchOpt(NextNode == E ? NULL : *NextNode); |
| 303 } | 334 } |
| 304 } | 335 } |
| 305 | 336 |
| 306 // ======================== Dump routines ======================== // | 337 // ======================== Dump routines ======================== // |
| 307 | 338 |
| 308 void Cfg::emit() { | 339 void Cfg::emit() { |
| 340 static TimerIdT IDemit = GlobalContext::getTimerID("emit"); |
| 341 TimerMarker T(IDemit, getContext()); |
| 309 Ostream &Str = Ctx->getStrEmit(); | 342 Ostream &Str = Ctx->getStrEmit(); |
| 310 Timer T_emit; | |
| 311 if (!Ctx->testAndSetHasEmittedFirstMethod()) { | 343 if (!Ctx->testAndSetHasEmittedFirstMethod()) { |
| 312 // Print a helpful command for assembling the output. | 344 // Print a helpful command for assembling the output. |
| 313 // TODO: have the Target emit the header | 345 // TODO: have the Target emit the header |
| 314 // TODO: need a per-file emit in addition to per-CFG | 346 // TODO: need a per-file emit in addition to per-CFG |
| 315 Str << "# $LLVM_BIN_PATH/llvm-mc" | 347 Str << "# $LLVM_BIN_PATH/llvm-mc" |
| 316 << " -arch=x86" | 348 << " -arch=x86" |
| 317 << " -x86-asm-syntax=intel" | 349 << " -x86-asm-syntax=intel" |
| 318 << " -filetype=obj" | 350 << " -filetype=obj" |
| 319 << " -o=MyObj.o" | 351 << " -o=MyObj.o" |
| 320 << "\n\n"; | 352 << "\n\n"; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 332 for (llvm::ArrayRef<uint8_t>::iterator I = Pad.begin(), E = Pad.end(); | 364 for (llvm::ArrayRef<uint8_t>::iterator I = Pad.begin(), E = Pad.end(); |
| 333 I != E; ++I) { | 365 I != E; ++I) { |
| 334 Str.write_hex(*I); | 366 Str.write_hex(*I); |
| 335 } | 367 } |
| 336 Str << "\n"; | 368 Str << "\n"; |
| 337 for (NodeList::const_iterator I = Nodes.begin(), E = Nodes.end(); I != E; | 369 for (NodeList::const_iterator I = Nodes.begin(), E = Nodes.end(); I != E; |
| 338 ++I) { | 370 ++I) { |
| 339 (*I)->emit(this); | 371 (*I)->emit(this); |
| 340 } | 372 } |
| 341 Str << "\n"; | 373 Str << "\n"; |
| 342 T_emit.printElapsedUs(Ctx, "emit()"); | |
| 343 } | 374 } |
| 344 | 375 |
| 345 // Dumps the IR with an optional introductory message. | 376 // Dumps the IR with an optional introductory message. |
| 346 void Cfg::dump(const IceString &Message) { | 377 void Cfg::dump(const IceString &Message) { |
| 347 if (!Ctx->isVerbose()) | 378 if (!Ctx->isVerbose()) |
| 348 return; | 379 return; |
| 349 Ostream &Str = Ctx->getStrDump(); | 380 Ostream &Str = Ctx->getStrDump(); |
| 350 if (!Message.empty()) | 381 if (!Message.empty()) |
| 351 Str << "================ " << Message << " ================\n"; | 382 Str << "================ " << Message << " ================\n"; |
| 352 setCurrentNode(getEntryNode()); | 383 setCurrentNode(getEntryNode()); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 384 for (NodeList::const_iterator I = Nodes.begin(), E = Nodes.end(); I != E; | 415 for (NodeList::const_iterator I = Nodes.begin(), E = Nodes.end(); I != E; |
| 385 ++I) { | 416 ++I) { |
| 386 (*I)->dump(this); | 417 (*I)->dump(this); |
| 387 } | 418 } |
| 388 if (getContext()->isVerbose(IceV_Instructions)) { | 419 if (getContext()->isVerbose(IceV_Instructions)) { |
| 389 Str << "}\n"; | 420 Str << "}\n"; |
| 390 } | 421 } |
| 391 } | 422 } |
| 392 | 423 |
| 393 } // end of namespace Ice | 424 } // end of namespace Ice |
| OLD | NEW |