Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 import '../compiler.dart'; | |
|
Siggi Cherem (dart-lang)
2016/09/01 23:51:22
+ copyright
Harry Terkelsen
2016/09/02 17:52:28
Done.
| |
| 2 import '../io/source_information.dart'; | |
| 3 import '../js_backend/js_backend.dart'; | |
| 4 import '../tree/tree.dart' as ast; | |
| 5 | |
| 6 import 'graph_builder.dart'; | |
| 7 import 'locals_handler.dart'; | |
| 8 import 'nodes.dart'; | |
| 9 | |
| 10 class SsaBranch { | |
| 11 final SsaBranchBuilder branchBuilder; | |
| 12 final HBasicBlock block; | |
| 13 LocalsHandler startLocals; | |
| 14 LocalsHandler exitLocals; | |
| 15 SubGraph graph; | |
| 16 | |
| 17 SsaBranch(this.branchBuilder) : block = new HBasicBlock(); | |
| 18 } | |
| 19 | |
| 20 class SsaBranchBuilder { | |
| 21 final GraphBuilder builder; | |
| 22 final Compiler compiler; | |
| 23 final ast.Node diagnosticNode; | |
| 24 | |
| 25 SsaBranchBuilder(this.builder, this.compiler, [this.diagnosticNode]); | |
| 26 | |
| 27 void checkNotAborted() { | |
| 28 if (builder.isAborted()) { | |
| 29 compiler.unimplemented(diagnosticNode, "aborted control flow"); | |
| 30 } | |
| 31 } | |
| 32 | |
| 33 void buildCondition( | |
| 34 void visitCondition(), | |
| 35 SsaBranch conditionBranch, | |
| 36 SsaBranch thenBranch, | |
| 37 SsaBranch elseBranch, | |
| 38 SourceInformation sourceInformation) { | |
| 39 startBranch(conditionBranch); | |
| 40 visitCondition(); | |
| 41 checkNotAborted(); | |
| 42 assert(identical(builder.current, builder.lastOpenedBlock)); | |
| 43 HInstruction conditionValue = builder.popBoolified(); | |
| 44 HIf branch = new HIf(conditionValue)..sourceInformation = sourceInformation; | |
| 45 HBasicBlock conditionExitBlock = builder.current; | |
| 46 builder.close(branch); | |
| 47 conditionBranch.exitLocals = builder.localsHandler; | |
| 48 conditionExitBlock.addSuccessor(thenBranch.block); | |
| 49 conditionExitBlock.addSuccessor(elseBranch.block); | |
| 50 bool conditionBranchLocalsCanBeReused = | |
| 51 mergeLocals(conditionBranch, thenBranch, mayReuseFromLocals: true); | |
| 52 mergeLocals(conditionBranch, elseBranch, | |
| 53 mayReuseFromLocals: conditionBranchLocalsCanBeReused); | |
| 54 | |
| 55 conditionBranch.graph = | |
| 56 new SubExpression(conditionBranch.block, conditionExitBlock); | |
| 57 } | |
| 58 | |
| 59 /** | |
| 60 * Returns true if the locals of the [fromBranch] may be reused. A [:true:] | |
| 61 * return value implies that [mayReuseFromLocals] was set to [:true:]. | |
| 62 */ | |
| 63 bool mergeLocals(SsaBranch fromBranch, SsaBranch toBranch, | |
| 64 {bool mayReuseFromLocals}) { | |
| 65 LocalsHandler fromLocals = fromBranch.exitLocals; | |
| 66 if (toBranch.startLocals == null) { | |
| 67 if (mayReuseFromLocals) { | |
| 68 toBranch.startLocals = fromLocals; | |
| 69 return false; | |
| 70 } else { | |
| 71 toBranch.startLocals = new LocalsHandler.from(fromLocals); | |
| 72 return true; | |
| 73 } | |
| 74 } else { | |
| 75 toBranch.startLocals.mergeWith(fromLocals, toBranch.block); | |
| 76 return true; | |
| 77 } | |
| 78 } | |
| 79 | |
| 80 void startBranch(SsaBranch branch) { | |
| 81 builder.graph.addBlock(branch.block); | |
| 82 builder.localsHandler = branch.startLocals; | |
| 83 builder.open(branch.block); | |
| 84 } | |
| 85 | |
| 86 HInstruction buildBranch(SsaBranch branch, void visitBranch(), | |
| 87 SsaBranch joinBranch, bool isExpression) { | |
| 88 startBranch(branch); | |
| 89 visitBranch(); | |
| 90 branch.graph = new SubGraph(branch.block, builder.lastOpenedBlock); | |
| 91 branch.exitLocals = builder.localsHandler; | |
| 92 if (!builder.isAborted()) { | |
| 93 builder.goto(builder.current, joinBranch.block); | |
| 94 mergeLocals(branch, joinBranch, mayReuseFromLocals: true); | |
| 95 } | |
| 96 if (isExpression) { | |
| 97 checkNotAborted(); | |
| 98 return builder.pop(); | |
| 99 } | |
| 100 return null; | |
| 101 } | |
| 102 | |
| 103 handleIf(void visitCondition(), void visitThen(), void visitElse(), | |
| 104 {SourceInformation sourceInformation}) { | |
| 105 if (visitElse == null) { | |
| 106 // Make sure to have an else part to avoid a critical edge. A | |
| 107 // critical edge is an edge that connects a block with multiple | |
| 108 // successors to a block with multiple predecessors. We avoid | |
| 109 // such edges because they prevent inserting copies during code | |
| 110 // generation of phi instructions. | |
| 111 visitElse = () {}; | |
| 112 } | |
| 113 | |
| 114 _handleDiamondBranch(visitCondition, visitThen, visitElse, | |
| 115 isExpression: false, sourceInformation: sourceInformation); | |
| 116 } | |
| 117 | |
| 118 handleConditional(void visitCondition(), void visitThen(), void visitElse()) { | |
| 119 assert(visitElse != null); | |
| 120 _handleDiamondBranch(visitCondition, visitThen, visitElse, | |
| 121 isExpression: true); | |
| 122 } | |
| 123 | |
| 124 handleIfNull(void left(), void right()) { | |
| 125 // x ?? y is transformed into: x == null ? y : x | |
| 126 HInstruction leftExpression; | |
| 127 handleConditional(() { | |
| 128 left(); | |
| 129 leftExpression = builder.pop(); | |
| 130 builder.pushCheckNull(leftExpression); | |
| 131 }, right, () => builder.stack.add(leftExpression)); | |
| 132 } | |
| 133 | |
| 134 void handleLogicalAndOr(void left(), void right(), {bool isAnd}) { | |
|
Siggi Cherem (dart-lang)
2016/09/01 23:51:22
consider making this private and exposing 2 public
Harry Terkelsen
2016/09/02 17:52:27
Seems good, but if I do this then I will have to c
Siggi Cherem (dart-lang)
2016/09/02 17:56:37
Good point - now that we refactored the other, it
| |
| 135 // x && y is transformed into: | |
| 136 // t0 = boolify(x); | |
| 137 // if (t0) { | |
| 138 // t1 = boolify(y); | |
| 139 // } | |
| 140 // result = phi(t1, false); | |
| 141 // | |
| 142 // x || y is transformed into: | |
| 143 // t0 = boolify(x); | |
| 144 // if (not(t0)) { | |
| 145 // t1 = boolify(y); | |
| 146 // } | |
| 147 // result = phi(t1, true); | |
| 148 HInstruction boolifiedLeft; | |
| 149 HInstruction boolifiedRight; | |
| 150 | |
| 151 void visitCondition() { | |
| 152 left(); | |
| 153 boolifiedLeft = builder.popBoolified(); | |
| 154 builder.stack.add(boolifiedLeft); | |
| 155 if (!isAnd) { | |
| 156 JavaScriptBackend backend = compiler.backend; | |
| 157 builder.push(new HNot(builder.pop(), backend.boolType)); | |
| 158 } | |
| 159 } | |
| 160 | |
| 161 void visitThen() { | |
| 162 right(); | |
| 163 boolifiedRight = builder.popBoolified(); | |
| 164 } | |
| 165 | |
| 166 handleIf(visitCondition, visitThen, null); | |
| 167 HConstant notIsAnd = builder.graph.addConstantBool(!isAnd, compiler); | |
| 168 JavaScriptBackend backend = compiler.backend; | |
| 169 HPhi result = new HPhi.manyInputs( | |
| 170 null, <HInstruction>[boolifiedRight, notIsAnd], backend.dynamicType); | |
| 171 builder.current.addPhi(result); | |
| 172 builder.stack.add(result); | |
| 173 } | |
| 174 | |
| 175 void _handleDiamondBranch( | |
| 176 void visitCondition(), void visitThen(), void visitElse(), | |
| 177 {bool isExpression, SourceInformation sourceInformation}) { | |
| 178 SsaBranch conditionBranch = new SsaBranch(this); | |
| 179 SsaBranch thenBranch = new SsaBranch(this); | |
| 180 SsaBranch elseBranch = new SsaBranch(this); | |
| 181 SsaBranch joinBranch = new SsaBranch(this); | |
| 182 | |
| 183 conditionBranch.startLocals = builder.localsHandler; | |
| 184 builder.goto(builder.current, conditionBranch.block); | |
| 185 | |
| 186 buildCondition(visitCondition, conditionBranch, thenBranch, elseBranch, | |
| 187 sourceInformation); | |
| 188 HInstruction thenValue = | |
| 189 buildBranch(thenBranch, visitThen, joinBranch, isExpression); | |
| 190 HInstruction elseValue = | |
| 191 buildBranch(elseBranch, visitElse, joinBranch, isExpression); | |
| 192 | |
| 193 if (isExpression) { | |
| 194 assert(thenValue != null && elseValue != null); | |
| 195 JavaScriptBackend backend = compiler.backend; | |
| 196 HPhi phi = new HPhi.manyInputs( | |
| 197 null, <HInstruction>[thenValue, elseValue], backend.dynamicType); | |
| 198 joinBranch.block.addPhi(phi); | |
| 199 builder.stack.add(phi); | |
| 200 } | |
| 201 | |
| 202 HBasicBlock joinBlock; | |
| 203 // If at least one branch did not abort, open the joinBranch. | |
| 204 if (!joinBranch.block.predecessors.isEmpty) { | |
| 205 startBranch(joinBranch); | |
| 206 joinBlock = joinBranch.block; | |
| 207 } | |
| 208 | |
| 209 HIfBlockInformation info = new HIfBlockInformation( | |
| 210 new HSubExpressionBlockInformation(conditionBranch.graph), | |
| 211 new HSubGraphBlockInformation(thenBranch.graph), | |
| 212 new HSubGraphBlockInformation(elseBranch.graph)); | |
| 213 | |
| 214 HBasicBlock conditionStartBlock = conditionBranch.block; | |
| 215 conditionStartBlock.setBlockFlow(info, joinBlock); | |
| 216 SubGraph conditionGraph = conditionBranch.graph; | |
| 217 HIf branch = conditionGraph.end.last; | |
| 218 assert(branch is HIf); | |
| 219 branch.blockInformation = conditionStartBlock.blockFlow; | |
| 220 } | |
| 221 } | |
| OLD | NEW |