| 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 /// \file | 10 /// \file |
| 11 /// This file implements the Cfg class, including constant pool | 11 /// This file implements the Cfg class, including constant pool management. |
| 12 /// management. | |
| 13 /// | 12 /// |
| 14 //===----------------------------------------------------------------------===// | 13 //===----------------------------------------------------------------------===// |
| 15 | 14 |
| 16 #include "IceCfg.h" | 15 #include "IceCfg.h" |
| 17 | 16 |
| 18 #include "IceAssembler.h" | 17 #include "IceAssembler.h" |
| 19 #include "IceCfgNode.h" | 18 #include "IceCfgNode.h" |
| 20 #include "IceClFlags.h" | 19 #include "IceClFlags.h" |
| 21 #include "IceDefs.h" | 20 #include "IceDefs.h" |
| 22 #include "IceELFObjectWriter.h" | 21 #include "IceELFObjectWriter.h" |
| (...skipping 16 matching lines...) Expand all Loading... |
| 39 Cfg::Cfg(GlobalContext *Ctx, uint32_t SequenceNumber) | 38 Cfg::Cfg(GlobalContext *Ctx, uint32_t SequenceNumber) |
| 40 : Ctx(Ctx), SequenceNumber(SequenceNumber), | 39 : Ctx(Ctx), SequenceNumber(SequenceNumber), |
| 41 VMask(Ctx->getFlags().getVerbose()), NextInstNumber(Inst::NumberInitial), | 40 VMask(Ctx->getFlags().getVerbose()), NextInstNumber(Inst::NumberInitial), |
| 42 Allocator(new ArenaAllocator<>()), Live(nullptr), | 41 Allocator(new ArenaAllocator<>()), Live(nullptr), |
| 43 Target(TargetLowering::createLowering(Ctx->getFlags().getTargetArch(), | 42 Target(TargetLowering::createLowering(Ctx->getFlags().getTargetArch(), |
| 44 this)), | 43 this)), |
| 45 VMetadata(new VariablesMetadata(this)), | 44 VMetadata(new VariablesMetadata(this)), |
| 46 TargetAssembler(TargetLowering::createAssembler( | 45 TargetAssembler(TargetLowering::createAssembler( |
| 47 Ctx->getFlags().getTargetArch(), this)) { | 46 Ctx->getFlags().getTargetArch(), this)) { |
| 48 if (Ctx->getFlags().getRandomizeAndPoolImmediatesOption() == RPI_Randomize) { | 47 if (Ctx->getFlags().getRandomizeAndPoolImmediatesOption() == RPI_Randomize) { |
| 49 // If -randomize-pool-immediates=randomize, create a random number generator | 48 // If -randomize-pool-immediates=randomize, create a random number |
| 50 // to generate a cookie for constant blinding. | 49 // generator to generate a cookie for constant blinding. |
| 51 RandomNumberGenerator RNG(Ctx->getFlags().getRandomSeed(), | 50 RandomNumberGenerator RNG(Ctx->getFlags().getRandomSeed(), |
| 52 RPE_ConstantBlinding, this->SequenceNumber); | 51 RPE_ConstantBlinding, this->SequenceNumber); |
| 53 ConstantBlindingCookie = | 52 ConstantBlindingCookie = |
| 54 (uint32_t)RNG.next((uint64_t)std::numeric_limits<uint32_t>::max() + 1); | 53 (uint32_t)RNG.next((uint64_t)std::numeric_limits<uint32_t>::max() + 1); |
| 55 } | 54 } |
| 56 } | 55 } |
| 57 | 56 |
| 58 Cfg::~Cfg() { assert(ICE_TLS_GET_FIELD(CurrentCfg) == nullptr); } | 57 Cfg::~Cfg() { assert(ICE_TLS_GET_FIELD(CurrentCfg) == nullptr); } |
| 59 | 58 |
| 60 void Cfg::setError(const IceString &Message) { | 59 void Cfg::setError(const IceString &Message) { |
| (...skipping 17 matching lines...) Expand all Loading... |
| 78 void Cfg::addArg(Variable *Arg) { | 77 void Cfg::addArg(Variable *Arg) { |
| 79 Arg->setIsArg(); | 78 Arg->setIsArg(); |
| 80 Args.push_back(Arg); | 79 Args.push_back(Arg); |
| 81 } | 80 } |
| 82 | 81 |
| 83 void Cfg::addImplicitArg(Variable *Arg) { | 82 void Cfg::addImplicitArg(Variable *Arg) { |
| 84 Arg->setIsImplicitArg(); | 83 Arg->setIsImplicitArg(); |
| 85 ImplicitArgs.push_back(Arg); | 84 ImplicitArgs.push_back(Arg); |
| 86 } | 85 } |
| 87 | 86 |
| 88 // Returns whether the stack frame layout has been computed yet. This | 87 // Returns whether the stack frame layout has been computed yet. This is used |
| 89 // is used for dumping the stack frame location of Variables. | 88 // for dumping the stack frame location of Variables. |
| 90 bool Cfg::hasComputedFrame() const { return getTarget()->hasComputedFrame(); } | 89 bool Cfg::hasComputedFrame() const { return getTarget()->hasComputedFrame(); } |
| 91 | 90 |
| 92 namespace { | 91 namespace { |
| 93 constexpr char BlockNameGlobalPrefix[] = ".L$profiler$block_name$"; | 92 constexpr char BlockNameGlobalPrefix[] = ".L$profiler$block_name$"; |
| 94 constexpr char BlockStatsGlobalPrefix[] = ".L$profiler$block_info$"; | 93 constexpr char BlockStatsGlobalPrefix[] = ".L$profiler$block_info$"; |
| 95 | 94 |
| 96 VariableDeclaration *nodeNameDeclaration(GlobalContext *Ctx, | 95 VariableDeclaration *nodeNameDeclaration(GlobalContext *Ctx, |
| 97 const IceString &NodeAsmName) { | 96 const IceString &NodeAsmName) { |
| 98 VariableDeclaration *Var = VariableDeclaration::create(Ctx); | 97 VariableDeclaration *Var = VariableDeclaration::create(Ctx); |
| 99 Var->setName(BlockNameGlobalPrefix + NodeAsmName); | 98 Var->setName(BlockNameGlobalPrefix + NodeAsmName); |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 149 constexpr Variable *Void = nullptr; | 148 constexpr Variable *Void = nullptr; |
| 150 constexpr bool HasTailCall = false; | 149 constexpr bool HasTailCall = false; |
| 151 auto *Call = | 150 auto *Call = |
| 152 InstCall::create(this, NumArgs, Void, ProfileSummarySym, HasTailCall); | 151 InstCall::create(this, NumArgs, Void, ProfileSummarySym, HasTailCall); |
| 153 getEntryNode()->getInsts().push_front(Call); | 152 getEntryNode()->getInsts().push_front(Call); |
| 154 } | 153 } |
| 155 | 154 |
| 156 void Cfg::translate() { | 155 void Cfg::translate() { |
| 157 if (hasError()) | 156 if (hasError()) |
| 158 return; | 157 return; |
| 159 // FunctionTimer conditionally pushes/pops a TimerMarker if | 158 // FunctionTimer conditionally pushes/pops a TimerMarker if TimeEachFunction |
| 160 // TimeEachFunction is enabled. | 159 // is enabled. |
| 161 std::unique_ptr<TimerMarker> FunctionTimer; | 160 std::unique_ptr<TimerMarker> FunctionTimer; |
| 162 if (BuildDefs::dump()) { | 161 if (BuildDefs::dump()) { |
| 163 const IceString &TimingFocusOn = | 162 const IceString &TimingFocusOn = |
| 164 getContext()->getFlags().getTimingFocusOn(); | 163 getContext()->getFlags().getTimingFocusOn(); |
| 165 const IceString &Name = getFunctionName(); | 164 const IceString &Name = getFunctionName(); |
| 166 if (TimingFocusOn == "*" || TimingFocusOn == Name) { | 165 if (TimingFocusOn == "*" || TimingFocusOn == Name) { |
| 167 setFocusedTiming(); | 166 setFocusedTiming(); |
| 168 getContext()->resetTimer(GlobalContext::TSK_Default); | 167 getContext()->resetTimer(GlobalContext::TSK_Default); |
| 169 getContext()->setTimerName(GlobalContext::TSK_Default, Name); | 168 getContext()->setTimerName(GlobalContext::TSK_Default, Name); |
| 170 } | 169 } |
| 171 if (getContext()->getFlags().getTimeEachFunction()) | 170 if (getContext()->getFlags().getTimeEachFunction()) |
| 172 FunctionTimer.reset(new TimerMarker( | 171 FunctionTimer.reset(new TimerMarker( |
| 173 getContext()->getTimerID(GlobalContext::TSK_Funcs, Name), | 172 getContext()->getTimerID(GlobalContext::TSK_Funcs, Name), |
| 174 getContext(), GlobalContext::TSK_Funcs)); | 173 getContext(), GlobalContext::TSK_Funcs)); |
| 175 } | 174 } |
| 176 TimerMarker T(TimerStack::TT_translate, this); | 175 TimerMarker T(TimerStack::TT_translate, this); |
| 177 | 176 |
| 178 dump("Initial CFG"); | 177 dump("Initial CFG"); |
| 179 | 178 |
| 180 if (getContext()->getFlags().getEnableBlockProfile()) { | 179 if (getContext()->getFlags().getEnableBlockProfile()) { |
| 181 profileBlocks(); | 180 profileBlocks(); |
| 182 // TODO(jpp): this is fragile, at best. Figure out a better way of detecting | 181 // TODO(jpp): this is fragile, at best. Figure out a better way of |
| 183 // exit functions. | 182 // detecting exit functions. |
| 184 if (GlobalContext::matchSymbolName(getFunctionName(), "exit")) { | 183 if (GlobalContext::matchSymbolName(getFunctionName(), "exit")) { |
| 185 addCallToProfileSummary(); | 184 addCallToProfileSummary(); |
| 186 } | 185 } |
| 187 dump("Profiled CFG"); | 186 dump("Profiled CFG"); |
| 188 } | 187 } |
| 189 | 188 |
| 190 // The set of translation passes and their order are determined by | 189 // The set of translation passes and their order are determined by the |
| 191 // the target. | 190 // target. |
| 192 getTarget()->translate(); | 191 getTarget()->translate(); |
| 193 | 192 |
| 194 dump("Final output"); | 193 dump("Final output"); |
| 195 if (getFocusedTiming()) | 194 if (getFocusedTiming()) |
| 196 getContext()->dumpTimers(); | 195 getContext()->dumpTimers(); |
| 197 } | 196 } |
| 198 | 197 |
| 199 void Cfg::computeInOutEdges() { | 198 void Cfg::computeInOutEdges() { |
| 200 // Compute the out-edges. | 199 // Compute the out-edges. |
| 201 for (CfgNode *Node : Nodes) | 200 for (CfgNode *Node : Nodes) |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 261 } | 260 } |
| 262 | 261 |
| 263 void Cfg::advancedPhiLowering() { | 262 void Cfg::advancedPhiLowering() { |
| 264 TimerMarker T(TimerStack::TT_advancedPhiLowering, this); | 263 TimerMarker T(TimerStack::TT_advancedPhiLowering, this); |
| 265 // Clear all previously computed live ranges (but not live-in/live-out bit | 264 // Clear all previously computed live ranges (but not live-in/live-out bit |
| 266 // vectors or last-use markers), because the follow-on register allocation is | 265 // vectors or last-use markers), because the follow-on register allocation is |
| 267 // only concerned with live ranges across the newly created blocks. | 266 // only concerned with live ranges across the newly created blocks. |
| 268 for (Variable *Var : Variables) { | 267 for (Variable *Var : Variables) { |
| 269 Var->getLiveRange().reset(); | 268 Var->getLiveRange().reset(); |
| 270 } | 269 } |
| 271 // This splits edges and appends new nodes to the end of the node | 270 // This splits edges and appends new nodes to the end of the node list. This |
| 272 // list. This can invalidate iterators, so don't use an iterator. | 271 // can invalidate iterators, so don't use an iterator. |
| 273 SizeT NumNodes = getNumNodes(); | 272 SizeT NumNodes = getNumNodes(); |
| 274 SizeT NumVars = getNumVariables(); | 273 SizeT NumVars = getNumVariables(); |
| 275 for (SizeT I = 0; I < NumNodes; ++I) | 274 for (SizeT I = 0; I < NumNodes; ++I) |
| 276 Nodes[I]->advancedPhiLowering(); | 275 Nodes[I]->advancedPhiLowering(); |
| 277 | 276 |
| 278 TimerMarker TT(TimerStack::TT_lowerPhiAssignments, this); | 277 TimerMarker TT(TimerStack::TT_lowerPhiAssignments, this); |
| 279 if (true) { | 278 if (true) { |
| 280 // The following code does an in-place update of liveness and live ranges as | 279 // The following code does an in-place update of liveness and live ranges |
| 281 // a result of adding the new phi edge split nodes. | 280 // as a result of adding the new phi edge split nodes. |
| 282 getLiveness()->initPhiEdgeSplits(Nodes.begin() + NumNodes, | 281 getLiveness()->initPhiEdgeSplits(Nodes.begin() + NumNodes, |
| 283 Variables.begin() + NumVars); | 282 Variables.begin() + NumVars); |
| 284 TimerMarker TTT(TimerStack::TT_liveness, this); | 283 TimerMarker TTT(TimerStack::TT_liveness, this); |
| 285 // Iterate over the newly added nodes to add their liveness info. | 284 // Iterate over the newly added nodes to add their liveness info. |
| 286 for (auto I = Nodes.begin() + NumNodes, E = Nodes.end(); I != E; ++I) { | 285 for (auto I = Nodes.begin() + NumNodes, E = Nodes.end(); I != E; ++I) { |
| 287 InstNumberT FirstInstNum = getNextInstNumber(); | 286 InstNumberT FirstInstNum = getNextInstNumber(); |
| 288 (*I)->renumberInstructions(); | 287 (*I)->renumberInstructions(); |
| 289 InstNumberT LastInstNum = getNextInstNumber() - 1; | 288 InstNumberT LastInstNum = getNextInstNumber() - 1; |
| 290 (*I)->liveness(getLiveness()); | 289 (*I)->liveness(getLiveness()); |
| 291 (*I)->livenessAddIntervals(getLiveness(), FirstInstNum, LastInstNum); | 290 (*I)->livenessAddIntervals(getLiveness(), FirstInstNum, LastInstNum); |
| 292 } | 291 } |
| 293 } else { | 292 } else { |
| 294 // The following code does a brute-force recalculation of live ranges as a | 293 // The following code does a brute-force recalculation of live ranges as a |
| 295 // result of adding the new phi edge split nodes. The liveness calculation | 294 // result of adding the new phi edge split nodes. The liveness calculation |
| 296 // is particularly expensive because the new nodes are not yet in a proper | 295 // is particularly expensive because the new nodes are not yet in a proper |
| 297 // topological order and so convergence is slower. | 296 // topological order and so convergence is slower. |
| 298 // | 297 // |
| 299 // This code is kept here for reference and can be temporarily enabled in | 298 // This code is kept here for reference and can be temporarily enabled in |
| 300 // case the incremental code is under suspicion. | 299 // case the incremental code is under suspicion. |
| 301 renumberInstructions(); | 300 renumberInstructions(); |
| 302 liveness(Liveness_Intervals); | 301 liveness(Liveness_Intervals); |
| 303 getVMetadata()->init(VMK_All); | 302 getVMetadata()->init(VMK_All); |
| 304 } | 303 } |
| 305 Target->regAlloc(RAK_Phi); | 304 Target->regAlloc(RAK_Phi); |
| 306 } | 305 } |
| 307 | 306 |
| 308 // Find a reasonable placement for nodes that have not yet been | 307 // Find a reasonable placement for nodes that have not yet been placed, while |
| 309 // placed, while maintaining the same relative ordering among already | 308 // maintaining the same relative ordering among already placed nodes. |
| 310 // placed nodes. | |
| 311 void Cfg::reorderNodes() { | 309 void Cfg::reorderNodes() { |
| 312 // TODO(ascull): it would be nice if the switch tests were always followed | 310 // TODO(ascull): it would be nice if the switch tests were always followed by |
| 313 // by the default case to allow for fall through. | 311 // the default case to allow for fall through. |
| 314 using PlacedList = std::list<CfgNode *>; | 312 using PlacedList = std::list<CfgNode *>; |
| 315 PlacedList Placed; // Nodes with relative placement locked down | 313 PlacedList Placed; // Nodes with relative placement locked down |
| 316 PlacedList Unreachable; // Unreachable nodes | 314 PlacedList Unreachable; // Unreachable nodes |
| 317 PlacedList::iterator NoPlace = Placed.end(); | 315 PlacedList::iterator NoPlace = Placed.end(); |
| 318 // Keep track of where each node has been tentatively placed so that | 316 // Keep track of where each node has been tentatively placed so that we can |
| 319 // we can manage insertions into the middle. | 317 // manage insertions into the middle. |
| 320 std::vector<PlacedList::iterator> PlaceIndex(Nodes.size(), NoPlace); | 318 std::vector<PlacedList::iterator> PlaceIndex(Nodes.size(), NoPlace); |
| 321 for (CfgNode *Node : Nodes) { | 319 for (CfgNode *Node : Nodes) { |
| 322 // The "do ... while(0);" construct is to factor out the | 320 // The "do ... while(0);" construct is to factor out the --PlaceIndex and |
| 323 // --PlaceIndex and assert() statements before moving to the next | 321 // assert() statements before moving to the next node. |
| 324 // node. | |
| 325 do { | 322 do { |
| 326 if (Node != getEntryNode() && Node->getInEdges().empty()) { | 323 if (Node != getEntryNode() && Node->getInEdges().empty()) { |
| 327 // The node has essentially been deleted since it is not a | 324 // The node has essentially been deleted since it is not a successor of |
| 328 // successor of any other node. | 325 // any other node. |
| 329 Unreachable.push_back(Node); | 326 Unreachable.push_back(Node); |
| 330 PlaceIndex[Node->getIndex()] = Unreachable.end(); | 327 PlaceIndex[Node->getIndex()] = Unreachable.end(); |
| 331 Node->setNeedsPlacement(false); | 328 Node->setNeedsPlacement(false); |
| 332 continue; | 329 continue; |
| 333 } | 330 } |
| 334 if (!Node->needsPlacement()) { | 331 if (!Node->needsPlacement()) { |
| 335 // Add to the end of the Placed list. | 332 // Add to the end of the Placed list. |
| 336 Placed.push_back(Node); | 333 Placed.push_back(Node); |
| 337 PlaceIndex[Node->getIndex()] = Placed.end(); | 334 PlaceIndex[Node->getIndex()] = Placed.end(); |
| 338 continue; | 335 continue; |
| 339 } | 336 } |
| 340 Node->setNeedsPlacement(false); | 337 Node->setNeedsPlacement(false); |
| 341 // Assume for now that the unplaced node is from edge-splitting | 338 // Assume for now that the unplaced node is from edge-splitting and |
| 342 // and therefore has 1 in-edge and 1 out-edge (actually, possibly | 339 // therefore has 1 in-edge and 1 out-edge (actually, possibly more than 1 |
| 343 // more than 1 in-edge if the predecessor node was contracted). | 340 // in-edge if the predecessor node was contracted). If this changes in |
| 344 // If this changes in the future, rethink the strategy. | 341 // the future, rethink the strategy. |
| 345 assert(Node->getInEdges().size() >= 1); | 342 assert(Node->getInEdges().size() >= 1); |
| 346 assert(Node->getOutEdges().size() == 1); | 343 assert(Node->getOutEdges().size() == 1); |
| 347 | 344 |
| 348 // If it's a (non-critical) edge where the successor has a single | 345 // If it's a (non-critical) edge where the successor has a single |
| 349 // in-edge, then place it before the successor. | 346 // in-edge, then place it before the successor. |
| 350 CfgNode *Succ = Node->getOutEdges().front(); | 347 CfgNode *Succ = Node->getOutEdges().front(); |
| 351 if (Succ->getInEdges().size() == 1 && | 348 if (Succ->getInEdges().size() == 1 && |
| 352 PlaceIndex[Succ->getIndex()] != NoPlace) { | 349 PlaceIndex[Succ->getIndex()] != NoPlace) { |
| 353 Placed.insert(PlaceIndex[Succ->getIndex()], Node); | 350 Placed.insert(PlaceIndex[Succ->getIndex()], Node); |
| 354 PlaceIndex[Node->getIndex()] = PlaceIndex[Succ->getIndex()]; | 351 PlaceIndex[Node->getIndex()] = PlaceIndex[Succ->getIndex()]; |
| 355 continue; | 352 continue; |
| 356 } | 353 } |
| 357 | 354 |
| 358 // Otherwise, place it after the (first) predecessor. | 355 // Otherwise, place it after the (first) predecessor. |
| 359 CfgNode *Pred = Node->getInEdges().front(); | 356 CfgNode *Pred = Node->getInEdges().front(); |
| 360 auto PredPosition = PlaceIndex[Pred->getIndex()]; | 357 auto PredPosition = PlaceIndex[Pred->getIndex()]; |
| 361 // It shouldn't be the case that PredPosition==NoPlace, but if | 358 // It shouldn't be the case that PredPosition==NoPlace, but if that |
| 362 // that somehow turns out to be true, we just insert Node before | 359 // somehow turns out to be true, we just insert Node before |
| 363 // PredPosition=NoPlace=Placed.end() . | 360 // PredPosition=NoPlace=Placed.end() . |
| 364 if (PredPosition != NoPlace) | 361 if (PredPosition != NoPlace) |
| 365 ++PredPosition; | 362 ++PredPosition; |
| 366 Placed.insert(PredPosition, Node); | 363 Placed.insert(PredPosition, Node); |
| 367 PlaceIndex[Node->getIndex()] = PredPosition; | 364 PlaceIndex[Node->getIndex()] = PredPosition; |
| 368 } while (0); | 365 } while (0); |
| 369 | 366 |
| 370 --PlaceIndex[Node->getIndex()]; | 367 --PlaceIndex[Node->getIndex()]; |
| 371 assert(*PlaceIndex[Node->getIndex()] == Node); | 368 assert(*PlaceIndex[Node->getIndex()] == Node); |
| 372 } | 369 } |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 463 if (Node->getHasReturn()) | 460 if (Node->getHasReturn()) |
| 464 getTarget()->addEpilog(Node); | 461 getTarget()->addEpilog(Node); |
| 465 } | 462 } |
| 466 | 463 |
| 467 void Cfg::computeLoopNestDepth() { | 464 void Cfg::computeLoopNestDepth() { |
| 468 TimerMarker T(TimerStack::TT_computeLoopNestDepth, this); | 465 TimerMarker T(TimerStack::TT_computeLoopNestDepth, this); |
| 469 LoopAnalyzer LA(this); | 466 LoopAnalyzer LA(this); |
| 470 LA.computeLoopNestDepth(); | 467 LA.computeLoopNestDepth(); |
| 471 } | 468 } |
| 472 | 469 |
| 473 // This is a lightweight version of live-range-end calculation. Marks the last | 470 // This is a lightweight version of live-range-end calculation. Marks the last |
| 474 // use of only those variables whose definition and uses are completely with a | 471 // use of only those variables whose definition and uses are completely with a |
| 475 // single block. It is a quick single pass and doesn't need to iterate until | 472 // single block. It is a quick single pass and doesn't need to iterate until |
| 476 // convergence. | 473 // convergence. |
| 477 void Cfg::livenessLightweight() { | 474 void Cfg::livenessLightweight() { |
| 478 TimerMarker T(TimerStack::TT_livenessLightweight, this); | 475 TimerMarker T(TimerStack::TT_livenessLightweight, this); |
| 479 getVMetadata()->init(VMK_Uses); | 476 getVMetadata()->init(VMK_Uses); |
| 480 for (CfgNode *Node : Nodes) | 477 for (CfgNode *Node : Nodes) |
| 481 Node->livenessLightweight(); | 478 Node->livenessLightweight(); |
| 482 } | 479 } |
| 483 | 480 |
| 484 void Cfg::liveness(LivenessMode Mode) { | 481 void Cfg::liveness(LivenessMode Mode) { |
| 485 TimerMarker T(TimerStack::TT_liveness, this); | 482 TimerMarker T(TimerStack::TT_liveness, this); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 501 NeedToProcess[Pred->getIndex()] = true; | 498 NeedToProcess[Pred->getIndex()] = true; |
| 502 } | 499 } |
| 503 } | 500 } |
| 504 } | 501 } |
| 505 } | 502 } |
| 506 if (Mode == Liveness_Intervals) { | 503 if (Mode == Liveness_Intervals) { |
| 507 // Reset each variable's live range. | 504 // Reset each variable's live range. |
| 508 for (Variable *Var : Variables) | 505 for (Variable *Var : Variables) |
| 509 Var->resetLiveRange(); | 506 Var->resetLiveRange(); |
| 510 } | 507 } |
| 511 // Make a final pass over each node to delete dead instructions, | 508 // Make a final pass over each node to delete dead instructions, collect the |
| 512 // collect the first and last instruction numbers, and add live | 509 // first and last instruction numbers, and add live range segments for that |
| 513 // range segments for that node. | 510 // node. |
| 514 for (CfgNode *Node : Nodes) { | 511 for (CfgNode *Node : Nodes) { |
| 515 InstNumberT FirstInstNum = Inst::NumberSentinel; | 512 InstNumberT FirstInstNum = Inst::NumberSentinel; |
| 516 InstNumberT LastInstNum = Inst::NumberSentinel; | 513 InstNumberT LastInstNum = Inst::NumberSentinel; |
| 517 for (Inst &I : Node->getPhis()) { | 514 for (Inst &I : Node->getPhis()) { |
| 518 I.deleteIfDead(); | 515 I.deleteIfDead(); |
| 519 if (Mode == Liveness_Intervals && !I.isDeleted()) { | 516 if (Mode == Liveness_Intervals && !I.isDeleted()) { |
| 520 if (FirstInstNum == Inst::NumberSentinel) | 517 if (FirstInstNum == Inst::NumberSentinel) |
| 521 FirstInstNum = I.getNumber(); | 518 FirstInstNum = I.getNumber(); |
| 522 assert(I.getNumber() > LastInstNum); | 519 assert(I.getNumber() > LastInstNum); |
| 523 LastInstNum = I.getNumber(); | 520 LastInstNum = I.getNumber(); |
| 524 } | 521 } |
| 525 } | 522 } |
| 526 for (Inst &I : Node->getInsts()) { | 523 for (Inst &I : Node->getInsts()) { |
| 527 I.deleteIfDead(); | 524 I.deleteIfDead(); |
| 528 if (Mode == Liveness_Intervals && !I.isDeleted()) { | 525 if (Mode == Liveness_Intervals && !I.isDeleted()) { |
| 529 if (FirstInstNum == Inst::NumberSentinel) | 526 if (FirstInstNum == Inst::NumberSentinel) |
| 530 FirstInstNum = I.getNumber(); | 527 FirstInstNum = I.getNumber(); |
| 531 assert(I.getNumber() > LastInstNum); | 528 assert(I.getNumber() > LastInstNum); |
| 532 LastInstNum = I.getNumber(); | 529 LastInstNum = I.getNumber(); |
| 533 } | 530 } |
| 534 } | 531 } |
| 535 if (Mode == Liveness_Intervals) { | 532 if (Mode == Liveness_Intervals) { |
| 536 // Special treatment for live in-args. Their liveness needs to | 533 // Special treatment for live in-args. Their liveness needs to extend |
| 537 // extend beyond the beginning of the function, otherwise an arg | 534 // beyond the beginning of the function, otherwise an arg whose only use |
| 538 // whose only use is in the first instruction will end up having | 535 // is in the first instruction will end up having the trivial live range |
| 539 // the trivial live range [2,2) and will *not* interfere with | 536 // [2,2) and will *not* interfere with other arguments. So if the first |
| 540 // other arguments. So if the first instruction of the method | 537 // instruction of the method is "r=arg1+arg2", both args may be assigned |
| 541 // is "r=arg1+arg2", both args may be assigned the same | 538 // the same register. This is accomplished by extending the entry block's |
| 542 // register. This is accomplished by extending the entry | 539 // instruction range from [2,n) to [1,n) which will transform the |
| 543 // block's instruction range from [2,n) to [1,n) which will | 540 // problematic [2,2) live ranges into [1,2). |
| 544 // transform the problematic [2,2) live ranges into [1,2). | |
| 545 if (Node == getEntryNode()) { | 541 if (Node == getEntryNode()) { |
| 546 // TODO(stichnot): Make it a strict requirement that the entry | 542 // TODO(stichnot): Make it a strict requirement that the entry node |
| 547 // node gets the lowest instruction numbers, so that extending | 543 // gets the lowest instruction numbers, so that extending the live |
| 548 // the live range for in-args is guaranteed to work. | 544 // range for in-args is guaranteed to work. |
| 549 FirstInstNum = Inst::NumberExtended; | 545 FirstInstNum = Inst::NumberExtended; |
| 550 } | 546 } |
| 551 Node->livenessAddIntervals(getLiveness(), FirstInstNum, LastInstNum); | 547 Node->livenessAddIntervals(getLiveness(), FirstInstNum, LastInstNum); |
| 552 } | 548 } |
| 553 } | 549 } |
| 554 } | 550 } |
| 555 | 551 |
| 556 // Traverse every Variable of every Inst and verify that it | 552 // Traverse every Variable of every Inst and verify that it appears within the |
| 557 // appears within the Variable's computed live range. | 553 // Variable's computed live range. |
| 558 bool Cfg::validateLiveness() const { | 554 bool Cfg::validateLiveness() const { |
| 559 TimerMarker T(TimerStack::TT_validateLiveness, this); | 555 TimerMarker T(TimerStack::TT_validateLiveness, this); |
| 560 bool Valid = true; | 556 bool Valid = true; |
| 561 OstreamLocker L(Ctx); | 557 OstreamLocker L(Ctx); |
| 562 Ostream &Str = Ctx->getStrDump(); | 558 Ostream &Str = Ctx->getStrDump(); |
| 563 for (CfgNode *Node : Nodes) { | 559 for (CfgNode *Node : Nodes) { |
| 564 Inst *FirstInst = nullptr; | 560 Inst *FirstInst = nullptr; |
| 565 for (Inst &Inst : Node->getInsts()) { | 561 for (Inst &Inst : Node->getInsts()) { |
| 566 if (Inst.isDeleted()) | 562 if (Inst.isDeleted()) |
| 567 continue; | 563 continue; |
| 568 if (FirstInst == nullptr) | 564 if (FirstInst == nullptr) |
| 569 FirstInst = &Inst; | 565 FirstInst = &Inst; |
| 570 InstNumberT InstNumber = Inst.getNumber(); | 566 InstNumberT InstNumber = Inst.getNumber(); |
| 571 if (Variable *Dest = Inst.getDest()) { | 567 if (Variable *Dest = Inst.getDest()) { |
| 572 if (!Dest->getIgnoreLiveness()) { | 568 if (!Dest->getIgnoreLiveness()) { |
| 573 bool Invalid = false; | 569 bool Invalid = false; |
| 574 const bool IsDest = true; | 570 const bool IsDest = true; |
| 575 if (!Dest->getLiveRange().containsValue(InstNumber, IsDest)) | 571 if (!Dest->getLiveRange().containsValue(InstNumber, IsDest)) |
| 576 Invalid = true; | 572 Invalid = true; |
| 577 // Check that this instruction actually *begins* Dest's live | 573 // Check that this instruction actually *begins* Dest's live range, |
| 578 // range, by checking that Dest is not live in the previous | 574 // by checking that Dest is not live in the previous instruction. As |
| 579 // instruction. As a special exception, we don't check this | 575 // a special exception, we don't check this for the first instruction |
| 580 // for the first instruction of the block, because a Phi | 576 // of the block, because a Phi temporary may be live at the end of |
| 581 // temporary may be live at the end of the previous block, | 577 // the previous block, and if it is also assigned in the first |
| 582 // and if it is also assigned in the first instruction of | 578 // instruction of this block, the adjacent live ranges get merged. |
| 583 // this block, the adjacent live ranges get merged. | |
| 584 if (static_cast<class Inst *>(&Inst) != FirstInst && | 579 if (static_cast<class Inst *>(&Inst) != FirstInst && |
| 585 !Inst.isDestNonKillable() && | 580 !Inst.isDestNonKillable() && |
| 586 Dest->getLiveRange().containsValue(InstNumber - 1, IsDest)) | 581 Dest->getLiveRange().containsValue(InstNumber - 1, IsDest)) |
| 587 Invalid = true; | 582 Invalid = true; |
| 588 if (Invalid) { | 583 if (Invalid) { |
| 589 Valid = false; | 584 Valid = false; |
| 590 Str << "Liveness error: inst " << Inst.getNumber() << " dest "; | 585 Str << "Liveness error: inst " << Inst.getNumber() << " dest "; |
| 591 Dest->dump(this); | 586 Dest->dump(this); |
| 592 Str << " live range " << Dest->getLiveRange() << "\n"; | 587 Str << " live range " << Dest->getLiveRange() << "\n"; |
| 593 } | 588 } |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 630 } | 625 } |
| 631 | 626 |
| 632 void Cfg::markNodesForSandboxing() { | 627 void Cfg::markNodesForSandboxing() { |
| 633 for (const InstJumpTable *JT : JumpTables) | 628 for (const InstJumpTable *JT : JumpTables) |
| 634 for (SizeT I = 0; I < JT->getNumTargets(); ++I) | 629 for (SizeT I = 0; I < JT->getNumTargets(); ++I) |
| 635 JT->getTarget(I)->setNeedsAlignment(); | 630 JT->getTarget(I)->setNeedsAlignment(); |
| 636 } | 631 } |
| 637 | 632 |
| 638 // ======================== Dump routines ======================== // | 633 // ======================== Dump routines ======================== // |
| 639 | 634 |
| 640 // emitTextHeader() is not target-specific (apart from what is | 635 // emitTextHeader() is not target-specific (apart from what is abstracted by |
| 641 // abstracted by the Assembler), so it is defined here rather than in | 636 // the Assembler), so it is defined here rather than in the target lowering |
| 642 // the target lowering class. | 637 // class. |
| 643 void Cfg::emitTextHeader(const IceString &MangledName, GlobalContext *Ctx, | 638 void Cfg::emitTextHeader(const IceString &MangledName, GlobalContext *Ctx, |
| 644 const Assembler *Asm) { | 639 const Assembler *Asm) { |
| 645 if (!BuildDefs::dump()) | 640 if (!BuildDefs::dump()) |
| 646 return; | 641 return; |
| 647 Ostream &Str = Ctx->getStrEmit(); | 642 Ostream &Str = Ctx->getStrEmit(); |
| 648 Str << "\t.text\n"; | 643 Str << "\t.text\n"; |
| 649 if (Ctx->getFlags().getFunctionSections()) | 644 if (Ctx->getFlags().getFunctionSections()) |
| 650 Str << "\t.section\t.text." << MangledName << ",\"ax\",@progbits\n"; | 645 Str << "\t.section\t.text." << MangledName << ",\"ax\",@progbits\n"; |
| 651 if (!Asm->getInternal() || Ctx->getFlags().getDisableInternal()) { | 646 if (!Asm->getInternal() || Ctx->getFlags().getDisableInternal()) { |
| 652 Str << "\t.globl\t" << MangledName << "\n"; | 647 Str << "\t.globl\t" << MangledName << "\n"; |
| 653 Str << "\t.type\t" << MangledName << ",%function\n"; | 648 Str << "\t.type\t" << MangledName << ",%function\n"; |
| 654 } | 649 } |
| 655 Str << "\t" << Asm->getAlignDirective() << " " | 650 Str << "\t" << Asm->getAlignDirective() << " " |
| 656 << Asm->getBundleAlignLog2Bytes() << ",0x"; | 651 << Asm->getBundleAlignLog2Bytes() << ",0x"; |
| 657 for (uint8_t I : Asm->getNonExecBundlePadding()) | 652 for (uint8_t I : Asm->getNonExecBundlePadding()) |
| 658 Str.write_hex(I); | 653 Str.write_hex(I); |
| 659 Str << "\n"; | 654 Str << "\n"; |
| 660 Str << MangledName << ":\n"; | 655 Str << MangledName << ":\n"; |
| 661 } | 656 } |
| 662 | 657 |
| 663 void Cfg::deleteJumpTableInsts() { | 658 void Cfg::deleteJumpTableInsts() { |
| 664 for (InstJumpTable *JumpTable : JumpTables) | 659 for (InstJumpTable *JumpTable : JumpTables) |
| 665 JumpTable->setDeleted(); | 660 JumpTable->setDeleted(); |
| 666 } | 661 } |
| 667 | 662 |
| 668 void Cfg::emitJumpTables() { | 663 void Cfg::emitJumpTables() { |
| 669 switch (Ctx->getFlags().getOutFileType()) { | 664 switch (Ctx->getFlags().getOutFileType()) { |
| 670 case FT_Elf: | 665 case FT_Elf: |
| 671 case FT_Iasm: { | 666 case FT_Iasm: { |
| 672 // The emission needs to be delayed until the after the text section so save | 667 // The emission needs to be delayed until the after the text section so |
| 673 // the offsets in the global context. | 668 // save the offsets in the global context. |
| 674 IceString MangledName = Ctx->mangleName(getFunctionName()); | 669 IceString MangledName = Ctx->mangleName(getFunctionName()); |
| 675 for (const InstJumpTable *JumpTable : JumpTables) { | 670 for (const InstJumpTable *JumpTable : JumpTables) { |
| 676 SizeT NumTargets = JumpTable->getNumTargets(); | 671 SizeT NumTargets = JumpTable->getNumTargets(); |
| 677 JumpTableData &JT = | 672 JumpTableData &JT = |
| 678 Ctx->addJumpTable(MangledName, JumpTable->getId(), NumTargets); | 673 Ctx->addJumpTable(MangledName, JumpTable->getId(), NumTargets); |
| 679 for (SizeT I = 0; I < NumTargets; ++I) { | 674 for (SizeT I = 0; I < NumTargets; ++I) { |
| 680 SizeT Index = JumpTable->getTarget(I)->getIndex(); | 675 SizeT Index = JumpTable->getTarget(I)->getIndex(); |
| 681 JT.pushTarget(getAssembler()->getCfgNodeLabel(Index)->getPosition()); | 676 JT.pushTarget(getAssembler()->getCfgNodeLabel(Index)->getPosition()); |
| 682 } | 677 } |
| 683 } | 678 } |
| (...skipping 30 matching lines...) Expand all Loading... |
| 714 << Asm->getBundleAlignLog2Bytes() << "\n"; | 709 << Asm->getBundleAlignLog2Bytes() << "\n"; |
| 715 } | 710 } |
| 716 Node->emit(this); | 711 Node->emit(this); |
| 717 } | 712 } |
| 718 emitJumpTables(); | 713 emitJumpTables(); |
| 719 Str << "\n"; | 714 Str << "\n"; |
| 720 } | 715 } |
| 721 | 716 |
| 722 void Cfg::emitIAS() { | 717 void Cfg::emitIAS() { |
| 723 TimerMarker T(TimerStack::TT_emit, this); | 718 TimerMarker T(TimerStack::TT_emit, this); |
| 724 // The emitIAS() routines emit into the internal assembler buffer, | 719 // The emitIAS() routines emit into the internal assembler buffer, so there's |
| 725 // so there's no need to lock the streams. | 720 // no need to lock the streams. |
| 726 deleteJumpTableInsts(); | 721 deleteJumpTableInsts(); |
| 727 const bool NeedSandboxing = Ctx->getFlags().getUseSandboxing(); | 722 const bool NeedSandboxing = Ctx->getFlags().getUseSandboxing(); |
| 728 for (CfgNode *Node : Nodes) { | 723 for (CfgNode *Node : Nodes) { |
| 729 if (NeedSandboxing && Node->needsAlignment()) | 724 if (NeedSandboxing && Node->needsAlignment()) |
| 730 getAssembler()->alignCfgNode(); | 725 getAssembler()->alignCfgNode(); |
| 731 Node->emitIAS(this); | 726 Node->emitIAS(this); |
| 732 } | 727 } |
| 733 emitJumpTables(); | 728 emitJumpTables(); |
| 734 } | 729 } |
| 735 | 730 |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 773 } | 768 } |
| 774 } | 769 } |
| 775 // Print each basic block | 770 // Print each basic block |
| 776 for (CfgNode *Node : Nodes) | 771 for (CfgNode *Node : Nodes) |
| 777 Node->dump(this); | 772 Node->dump(this); |
| 778 if (isVerbose(IceV_Instructions)) | 773 if (isVerbose(IceV_Instructions)) |
| 779 Str << "}\n"; | 774 Str << "}\n"; |
| 780 } | 775 } |
| 781 | 776 |
| 782 } // end of namespace Ice | 777 } // end of namespace Ice |
| OLD | NEW |