Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(14)

Side by Side Diff: src/IceVariableSplitting.cpp

Issue 2177033002: Subzero: Local variable splitting. (Closed) Base URL: https://chromium.googlesource.com/native_client/pnacl-subzero.git@master
Patch Set: Break up the big function into smaller helpers. Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/IceVariableSplitting.h ('k') | tests_lit/assembler/x86/opcode_register_encodings.ll » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 //===- subzero/src/IceVariableSplitting.cpp - Local variable splitting ----===//
2 //
3 // The Subzero Code Generator
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 ///
10 /// \file
11 /// \brief Aggressive block-local variable splitting to improve linear-scan
12 /// register allocation.
13 ///
14 //===----------------------------------------------------------------------===//
15
16 #include "IceVariableSplitting.h"
17
18 #include "IceCfg.h"
19 #include "IceCfgNode.h"
20 #include "IceClFlags.h"
21 #include "IceInst.h"
22 #include "IceOperand.h"
23 #include "IceTargetLowering.h"
24
25 namespace Ice {
26
27 namespace {
28
29 /// A Variable is "allocable" if it is a register allocation candidate but
30 /// doesn't already have a register.
31 bool isAllocable(const Variable *Var) {
32 if (Var == nullptr)
33 return false;
34 return !Var->hasReg() && Var->mayHaveReg();
35 }
36
37 /// A Variable is "inf" if it already has a register or is infinite-weight.
38 bool isInf(const Variable *Var) {
39 if (Var == nullptr)
40 return false;
41 return Var->hasReg() || Var->mustHaveReg();
42 }
43
44 /// VariableMap is a simple helper class for splitLocalVars(), that keeps track
45 /// of the latest split version of the original Variables. For each entry, the
46 /// Variable is tagged with the CfgNode that it is valid in, so that we don't
47 /// need to clear the entire Map[] vector for each block.
48 class VariableMap {
49 private:
50 VariableMap() = delete;
51 VariableMap(const VariableMap &) = delete;
52 VariableMap &operator=(const VariableMap &) = delete;
53
54 /// VarNodePair is basically std::pair<Variable*,CfgNode*> .
55 struct VarNodePair {
56 Variable *Var = nullptr;
57 const CfgNode *Node = nullptr;
58 VarNodePair() = default;
59
60 private:
61 VarNodePair(const VarNodePair &) = delete;
62 VarNodePair &operator=(const VarNodePair &) = delete;
63 };
64
65 public:
66 explicit VariableMap(Cfg *Func)
67 : Func(Func), NumVars(Func->getNumVariables()), Map(NumVars) {}
68 /// Reset the mappings at the start of a block.
69 void reset(const CfgNode *CurNode) { Node = CurNode; }
70 /// Get Var's current mapping (or Var itself if it has no mapping yet).
71 Variable *get(Variable *Var) const {
72 const SizeT VarNum = getVarNum(Var);
73 Variable *MappedVar = Map[VarNum].Var;
74 if (MappedVar == nullptr)
75 return Var;
76 if (Map[VarNum].Node != Node)
77 return Var;
78 return MappedVar;
79 }
80 /// Create a new linked Variable in the LinkedTo chain, and set it as Var's
81 /// latest mapping.
82 Variable *makeLinked(Variable *Var) {
83 Variable *NewVar = Func->makeVariable(Var->getType());
84 NewVar->setRegClass(Var->getRegClass());
85 NewVar->setLinkedTo(get(Var));
86 const SizeT VarNum = getVarNum(Var);
87 Map[VarNum].Var = NewVar;
88 Map[VarNum].Node = Node;
89 return NewVar;
90 }
91 /// Given Var that is LinkedTo some other variable, re-splice it into the
92 /// LinkedTo chain so that the chain is ordered by Variable::getIndex().
93 void spliceBlockLocalLinkedToChain(Variable *Var) {
94 Variable *LinkedTo = Var->getLinkedTo();
95 assert(LinkedTo != nullptr);
96 assert(Var->getIndex() > LinkedTo->getIndex());
97 const SizeT VarNum = getVarNum(LinkedTo);
98 Variable *Link = Map[VarNum].Var;
99 if (Link == nullptr || Map[VarNum].Node != Node)
100 return;
101 Variable *LinkParent = Link->getLinkedTo();
102 while (LinkParent != nullptr && LinkParent->getIndex() >= Var->getIndex()) {
103 Link = LinkParent;
104 LinkParent = Link->getLinkedTo();
105 }
106 Var->setLinkedTo(LinkParent);
107 Link->setLinkedTo(Var);
108 }
109
110 private:
111 Cfg *const Func;
112 // NumVars is for the size of the Map array. It can be const because any new
113 // Variables created during the splitting pass don't need to be mapped.
114 const SizeT NumVars;
115 CfgVector<VarNodePair> Map;
116 const CfgNode *Node = nullptr;
117 /// Get Var's VarNum, and do some validation.
118 SizeT getVarNum(Variable *Var) const {
119 const SizeT VarNum = Var->getIndex();
120 assert(VarNum < NumVars);
121 return VarNum;
122 }
123 };
124
125 /// LocalSplittingState tracks the necessary splitting state across
126 /// instructions.
127 class LocalSplittingState {
John 2016/08/01 14:17:32 This is not really a State, it contains the State
Jim Stichnoth 2016/08/01 15:13:50 Changed to "class LocalVariableSplitter Splitter".
128 LocalSplittingState() = delete;
129 LocalSplittingState(const LocalSplittingState &) = delete;
130 LocalSplittingState &operator=(const LocalSplittingState &) = delete;
131
132 public:
133 explicit LocalSplittingState(Cfg *Func)
134 : Target(Func->getTarget()), VarMap(Func) {}
135 /// setNode() is called before processing the instructions of a block.
136 void setNode(CfgNode *CurNode) {
137 Node = CurNode;
138 VarMap.reset(Node);
139 LinkedToFixups.clear();
140 }
141 /// finalizeNode() is called after all instructions in the block are
142 /// processed.
143 void finalizeNode() {
144 // Splice in any preexisting LinkedTo links into the single chain. These
145 // are the ones that were recorded during setInst().
146 for (Variable *Var : LinkedToFixups) {
147 VarMap.spliceBlockLocalLinkedToChain(Var);
148 }
149 }
150 /// setInst() is called before processing the next instruction. The iterators
151 /// are the insertion points for a new instructions, depending on whether the
152 /// new instruction should be inserted before or after the current
153 /// instruction.
154 void setInst(Inst *CurInst, InstList::iterator Cur, InstList::iterator Next) {
John 2016/08/01 14:17:32 isn't it possible to infer CurInst from Cur, and v
Jim Stichnoth 2016/08/01 15:13:51 Not if CurInst is a phi instruction. (I think I h
155 Instr = CurInst;
156 Dest = Instr->getDest();
157 IterCur = Cur;
158 IterNext = Next;
159 ShouldSkipThisInstruction = false;
160 ShouldSkipAllInstructions = false;
161 // Note any preexisting LinkedTo relationships that were created during
162 // target lowering. Record them in LinkedToFixups which is then processed
163 // in finalizeNode().
164 if (Dest != nullptr && Dest->getLinkedTo() != nullptr) {
165 LinkedToFixups.emplace_back(Dest);
166 }
167 }
168 bool shouldSkipThisInstruction() const { return ShouldSkipThisInstruction; }
John 2016/08/01 14:17:32 perhaps this should return ShouldSkipThisInstruct
Jim Stichnoth 2016/08/01 15:13:51 I think I sidestepped this issue with the later pa
169 bool shouldSkipAllInstructions() const { return ShouldSkipAllInstructions; }
170 bool isUnconditionallyExecuted() const { return WaitingForLabel == nullptr; }
171
172 /// Note: the handle*() functions set the ShouldSkipThisInstruction flag to
173 /// indicate that the instruction has now been handled and that the
174 /// instruction loop should continue to the next instruction in the block. In
175 /// addition, they set the ShouldSkipAllInstructions flag to indicate that no
John 2016/08/01 14:17:32 If it indicates that no more instructions should b
Jim Stichnoth 2016/08/01 15:13:51 Done.
176 /// more instructions in the block should be processed.
177
178 /// Process an "unwanted" instruction by setting the ShouldSkipThisInstruction
179 /// flag as necessary.
180 void handleUnwantedInstruction() {
John 2016/08/01 14:17:32 Maybe return bool, and rename this to isUnwantedI
Jim Stichnoth 2016/08/01 15:13:51 I did change all the handle*() functions to return
181 // We can limit the splitting to an arbitrary subset of the instructions,
182 // and still expect correct code. As such, we can do instruction-subset
183 // bisection to help debug any problems in this pass.
184 static constexpr char AnInstructionHasNoName[] = "";
185 if (!BuildDefs::minimal() &&
186 !getFlags().matchSplitInsts(AnInstructionHasNoName,
187 Instr->getNumber())) {
188 ShouldSkipThisInstruction = true;
189 return;
190 }
191 if (!llvm::isa<InstTarget>(Instr)) {
192 // Ignore non-lowered instructions like FakeDef/FakeUse.
193 ShouldSkipThisInstruction = true;
194 return;
195 }
196 }
197
198 /// Process a potential label instruction.
199 void handleLabel() {
John 2016/08/01 14:17:32 Maybe return bool, and rename this to isLabel()
Jim Stichnoth 2016/08/01 15:13:51 Similar to above. I like to keep "handle" because
200 if (!Instr->isLabel())
201 return;
202 ShouldSkipThisInstruction = true;
203 // A Label instruction shouldn't have any operands, so it can be handled
204 // right here and then move on.
205 assert(Dest == nullptr);
206 assert(Instr->getSrcSize() == 0);
207 if (Instr == WaitingForLabel) {
John 2016/08/01 14:17:32 this approach will fail with "deep" short-circuiti
Jim Stichnoth 2016/08/01 19:55:36 By "fail", I assume you mean the entire short-circ
208 // If we found the forward-branch-target Label instruction we're waiting
209 // for, then clear the WaitingForLabel state.
210 WaitingForLabel = nullptr;
211 } else if (WaitingForLabel == nullptr && WaitingForBranchTo == nullptr) {
212 // If we found a new Label instruction while the WaitingFor* state is
213 // clear, then set things up for this being a backward branch target.
214 WaitingForBranchTo = Instr;
215 } else {
216 // We see something we don't understand, so skip to the next block.
217 ShouldSkipAllInstructions = true;
218 }
219 }
220
221 /// Process a potential intra-block branch instruction.
222 void handleIntraBlockBranch() {
John 2016/08/01 14:17:32 Maybe return bool, and rename this to isIntraBloc
Jim Stichnoth 2016/08/01 15:13:51 (same as above with respect to state changes)
223 const Inst *Label = Instr->getIntraBlockBranchTarget();
224 if (Label == nullptr)
225 return;
226 ShouldSkipThisInstruction = true;
227 // An intra-block branch instruction shouldn't have any operands, so it can
228 // be handled right here and then move on.
229 assert(Dest == nullptr);
230 assert(Instr->getSrcSize() == 0);
231 if (WaitingForBranchTo == Label && WaitingForLabel == nullptr) {
232 WaitingForBranchTo = nullptr;
233 } else if (WaitingForBranchTo == nullptr &&
234 (WaitingForLabel == nullptr || WaitingForLabel == Label)) {
235 WaitingForLabel = Label;
236 } else {
237 // We see something we don't understand, so skip to the next block.
238 ShouldSkipAllInstructions = true;
239 }
240 }
241
242 /// Specially process a potential "Variable=Variable" assignment instruction,
243 /// when it conforms to certain patterns.
244 void handleVarAssign() {
John 2016/08/01 14:17:32 Maybe return bool, and rename this to isTrivialVa
Jim Stichnoth 2016/08/01 15:13:51 I still like "handle" because of the possible side
245 if (!Instr->isVarAssign())
246 return;
247 const bool DestIsInf = isInf(Dest);
248 const bool DestIsAllocable = isAllocable(Dest);
249 auto *SrcVar = llvm::cast<Variable>(Instr->getSrc(0));
250 const bool SrcIsInf = isInf(SrcVar);
251 const bool SrcIsAllocable = isAllocable(SrcVar);
252 if (DestIsInf && SrcIsInf) {
253 // The instruction:
254 // t:inf = u:inf
255 // No transformation is needed.
256 ShouldSkipThisInstruction = true;
257 return;
258 }
259 if (DestIsInf && SrcIsAllocable && Dest->getType() == SrcVar->getType()) {
260 // The instruction:
261 // t:inf = v
262 // gets transformed to:
263 // t:inf = v1
264 // v2 = t:inf
265 // where:
266 // v1 := map[v]
267 // v2 := linkTo(v)
268 // map[v] := v2
269 //
270 // If both v2 and its linkedToStackRoot get a stack slot, then "v2=t:inf"
271 // is recognized as a redundant assignment and elided.
272 //
273 // Note that if the dest and src types are different, then this is
274 // actually a truncation operation, which would make "v2=t:inf" an invalid
275 // instruction. In this case, the type test will make it fall through to
276 // the general case below.
277 Variable *OldMapped = VarMap.get(SrcVar);
278 Instr->replaceSource(0, OldMapped);
279 if (isUnconditionallyExecuted()) {
280 // Only create new mapping state if the instruction is unconditionally
281 // executed.
282 Variable *NewMapped = VarMap.makeLinked(SrcVar);
283 Inst *Mov = Target->createLoweredMove(NewMapped, Dest);
284 Node->getInsts().insert(IterNext, Mov);
285 }
286 ShouldSkipThisInstruction = true;
287 return;
288 }
289 if (DestIsAllocable && SrcIsInf) {
290 // The instruction:
291 // v = t:inf
292 // gets transformed to:
293 // v = t:inf
294 // v2 = t:inf
295 // where:
296 // v2 := linkTo(v)
297 // map[v] := v2
298 //
299 // If both v2 and v get a stack slot, then "v2=t:inf" is recognized as a
300 // redundant assignment and elided.
301 if (isUnconditionallyExecuted()) {
302 // Only create new mapping state if the instruction is unconditionally
303 // executed.
304 Variable *NewMapped = VarMap.makeLinked(Dest);
305 Inst *Mov = Target->createLoweredMove(NewMapped, SrcVar);
306 Node->getInsts().insert(IterNext, Mov);
307 } else {
308 // For a conditionally executed instruction, add a redefinition of the
309 // original Dest mapping, without creating a new linked variable.
310 Variable *OldMapped = VarMap.get(Dest);
311 Inst *Mov = Target->createLoweredMove(OldMapped, SrcVar);
312 Mov->setDestRedefined();
313 Node->getInsts().insert(IterNext, Mov);
314 }
315 ShouldSkipThisInstruction = true;
316 return;
317 }
318 assert(!ShouldSkipThisInstruction);
319 assert(!ShouldSkipAllInstructions);
320 }
321
322 /// Process an arbitrary instruction.
323 void handleGeneralInst() {
324 const bool DestIsAllocable = isAllocable(Dest);
325 // The (non-variable-assignment) instruction:
326 // ... = F(v)
327 // where v is not infinite-weight, gets transformed to:
328 // v2 = v1
329 // ... = F(v1)
330 // where:
331 // v1 := map[v]
332 // v2 := linkTo(v)
333 // map[v] := v2
334 // After that, if the "..." dest=u is not infinite-weight, append:
335 // u2 = u
336 // where:
337 // u2 := linkTo(u)
338 // map[u] := u2
339 for (SizeT i = 0; i < Instr->getSrcSize(); ++i) {
340 // Iterate over the top-level src vars. Don't bother to dig into
341 // e.g. MemOperands because their vars should all be infinite-weight.
342 // (This assumption would need to change if the pass were done
343 // pre-lowering.)
344 if (auto *SrcVar = llvm::dyn_cast<Variable>(Instr->getSrc(i))) {
345 const bool SrcIsAllocable = isAllocable(SrcVar);
346 if (SrcIsAllocable) {
347 Variable *OldMapped = VarMap.get(SrcVar);
348 if (isUnconditionallyExecuted()) {
349 Variable *NewMapped = VarMap.makeLinked(SrcVar);
350 Inst *Mov = Target->createLoweredMove(NewMapped, OldMapped);
351 Node->getInsts().insert(IterCur, Mov);
352 }
353 Instr->replaceSource(i, OldMapped);
354 }
355 }
356 }
357 // Transformation of Dest is the same as the "v=t:inf" case above.
358 if (DestIsAllocable) {
359 if (isUnconditionallyExecuted()) {
360 Variable *NewMapped = VarMap.makeLinked(Dest);
361 Inst *Mov = Target->createLoweredMove(NewMapped, Dest);
362 Node->getInsts().insert(IterNext, Mov);
363 } else {
364 Variable *OldMapped = VarMap.get(Dest);
365 Inst *Mov = Target->createLoweredMove(OldMapped, Dest);
366 Mov->setDestRedefined();
367 Node->getInsts().insert(IterNext, Mov);
368 }
369 }
370 }
371
372 private:
373 TargetLowering *Target;
374 CfgNode *Node = nullptr;
375 Inst *Instr = nullptr;
376 Variable *Dest = nullptr;
377 InstList::iterator IterCur;
378 InstList::iterator IterNext;
379 bool ShouldSkipThisInstruction = false;
380 bool ShouldSkipAllInstructions = false;
381 VariableMap VarMap;
382 CfgVector<Variable *> LinkedToFixups;
383 /// WaitingForLabel and WaitingForBranchTo are for tracking intra-block
384 /// control flow.
385 const Inst *WaitingForLabel = nullptr;
386 const Inst *WaitingForBranchTo = nullptr;
387 };
388
389 } // end of anonymous namespace
390
391 /// Within each basic block, rewrite Variable references in terms of chained
392 /// copies of the original Variable. For example:
393 /// A = B + C
394 /// might be rewritten as:
395 /// B1 = B
396 /// C1 = C
397 /// A = B + C
398 /// A1 = A
399 /// and then:
400 /// D = A + B
401 /// might be rewritten as:
402 /// A2 = A1
403 /// B2 = B1
404 /// D = A1 + B1
405 /// D1 = D
406 ///
407 /// The purpose is to present the linear-scan register allocator with smaller
408 /// live ranges, to help mitigate its "all or nothing" allocation strategy,
409 /// while counting on its preference mechanism to keep the split versions in the
410 /// same register when possible.
411 ///
412 /// When creating new Variables, A2 is linked to A1 which is linked to A, and
413 /// similar for the other Variable linked-to chains. Rewrites apply only to
414 /// Variables where mayHaveReg() is true.
415 ///
416 /// At code emission time, redundant linked-to stack assignments will be
417 /// recognized and elided. To illustrate using the above example, if A1 gets a
418 /// register but A and A2 are on the stack, the "A2=A1" store instruction is
419 /// redundant since A and A2 share the same stack slot and A1 originated from A.
420 ///
421 /// Simple assignment instructions are rewritten slightly differently, to take
422 /// maximal advantage of Variables known to have registers.
423 ///
424 /// In general, there may be several valid ways to rewrite an instruction: add
425 /// the new assignment instruction either before or after the original
426 /// instruction, and rewrite the original instruction with either the old or the
427 /// new variable mapping. We try to pick a strategy most likely to avoid
428 /// potential performance problems. For example, try to avoid storing to the
429 /// stack and then immediately reloading from the same location. One
430 /// consequence is that code might be generated that loads a register from a
431 /// stack location, followed almost immediately by another use of the same stack
432 /// location, despite its value already being available in a register as a
433 /// result of the first instruction. However, the performance impact here is
434 /// likely to be negligible, and a simple availability peephole optimization
435 /// could clean it up.
436 ///
437 /// This pass potentially adds a lot of new instructions and variables, and as
438 /// such there are compile-time performance concerns, particularly with liveness
439 /// analysis and register allocation. Note that for liveness analysis, the new
440 /// variables have single-block liveness, so they don't increase the size of the
441 /// liveness bit vectors that need to be merged across blocks. As a result, the
442 /// performance impact is likely to be linearly related to the number of new
443 /// instructions, rather than number of new variables times number of blocks
444 /// which would be the case if they were multi-block variables.
445 void splitBlockLocalVariables(Cfg *Func) {
446 if (!getFlags().getSplitLocalVars())
447 return;
448 TimerMarker _(TimerStack::TT_splitLocalVars, Func);
449 LocalSplittingState State(Func);
450 // TODO(stichnot): Fix this mechanism for LinkedTo variables and stack slot
451 // assignment.
452 //
453 // To work around shortcomings with stack frame mapping, we want to arrange
454 // LinkedTo structure such that within one block, the LinkedTo structure
455 // leading to a root forms a list, not a tree. A LinkedTo root can have
456 // multiple children linking to it, but only one per block. Furthermore,
457 // because stack slot mapping processes variables in numerical order, the
458 // LinkedTo chain needs to be ordered such that when A->getLinkedTo()==B, then
459 // A->getIndex()>B->getIndex().
460 //
461 // To effect this, while processing a block we keep track of preexisting
462 // LinkedTo relationships via the LinkedToFixups vector, and at the end of the
463 // block we splice them in such that the block has a single chain for each
464 // root, ordered by getIndex() value.
465 CfgVector<Variable *> LinkedToFixups;
466 for (CfgNode *Node : Func->getNodes()) {
467 // Clear the VarMap and LinkedToFixups at the start of every block.
468 LinkedToFixups.clear();
469 State.setNode(Node);
470 auto &Insts = Node->getInsts();
471 auto Iter = Insts.begin();
472 auto IterEnd = Insts.end();
473 // TODO(stichnot): Also create assignments/mappings for phi dest variables.
474 InstList::iterator NextIter;
475 for (; Iter != IterEnd && !State.shouldSkipAllInstructions();
476 Iter = NextIter) {
477 NextIter = Iter;
478 ++NextIter;
479 Inst *Instr = iteratorToInst(Iter);
480 if (Instr->isDeleted())
481 continue;
482 State.setInst(Instr, Iter, NextIter);
483
484 // Before doing any transformations, take care of the bookkeeping for
485 // intra-block branching.
486 //
487 // This is tricky because the transformation for one instruction may
488 // depend on a transformation for a previous instruction, but if that
489 // previous instruction is not dynamically executed due to intra-block
490 // control flow, it may lead to an inconsistent state and incorrect code.
491 //
492 // We want to handle some simple cases, and reject some others:
493 //
494 // 1. For something like a select instruction, we could have:
495 // test cond
496 // dest = src_false
497 // branch conditionally to label
498 // dest = src_true
499 // label:
500 //
501 // Between the conditional branch and the label, we need to treat dest and
502 // src variables specially, specifically not creating any new state.
503 //
504 // 2. Some 64-bit atomic instructions may be lowered to a loop:
505 // label:
506 // ...
507 // branch conditionally to label
508 //
509 // No special treatment is needed, but it's worth tracking so that case #1
510 // above can also be handled.
511 //
512 // 3. Advanced switch lowering can create really complex intra-block
513 // control flow, so when we recognize this, we should just stop splitting
514 // for the remainder of the block (which isn't much since a switch
515 // instruction is a terminator).
516 //
517 // 4. Other complex lowering, e.g. an i64 icmp on a 32-bit architecture,
518 // can result in an if/then/else like structure with two labels. One
519 // possibility would be to suspect splitting for the remainder of the
520 // lowered instruction, and then resume for the remainder of the block,
521 // but since we don't have high-level instruction markers, we might as
522 // well just stop splitting for the remainder of the block.
523 State.handleLabel();
John 2016/08/01 14:17:32 if these returned bool, this could be if (State.i
Jim Stichnoth 2016/08/01 15:13:51 Done, in the later patchset.
524 State.handleIntraBlockBranch();
525 State.handleUnwantedInstruction();
526 if (State.shouldSkipThisInstruction())
527 continue;
528
529 // Intra-block bookkeeping is complete, now do the transformations.
530
531 // Determine the transformation based on the kind of instruction, and
532 // whether its Variables are infinite-weight. New instructions can be
John 2016/08/01 14:17:32 ... and you can get rid of the special-case for va
Jim Stichnoth 2016/08/01 15:13:51 I think it's much cleaner now in the later patchse
533 // inserted before the current instruction via Iter, or after the current
534 // instruction via NextIter.
535 if (Instr->isVarAssign()) {
536 State.handleVarAssign();
537 if (State.shouldSkipThisInstruction())
538 continue;
539 }
540 State.handleGeneralInst();
541 // Don't bother checking State.shouldSkipThisInstruction() since this the
542 // end of the loop.
543 }
544 State.finalizeNode();
545 }
546
547 Func->dump("After splitting local variables");
548 }
549
550 } // end of namespace Ice
OLDNEW
« no previous file with comments | « src/IceVariableSplitting.h ('k') | tests_lit/assembler/x86/opcode_register_encodings.ll » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698