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 |