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 |