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