Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 part of ssa; | 5 part of ssa; |
| 6 | 6 |
| 7 /** | 7 /** |
| 8 * Replaces some instructions with specialized versions to make codegen easier. | 8 * Replaces some instructions with specialized versions to make codegen easier. |
| 9 * Caches codegen information on nodes. | 9 * Caches codegen information on nodes. |
| 10 */ | 10 */ |
| 11 class SsaInstructionSelection extends HBaseVisitor { | 11 class SsaInstructionSelection extends HBaseVisitor { |
| 12 final Compiler compiler; | 12 final Compiler compiler; |
| 13 HGraph graph; | 13 HGraph graph; |
| 14 | 14 |
| 15 SsaInstructionSelection(this.compiler); | 15 SsaInstructionSelection(this.compiler); |
| 16 | 16 |
| 17 JavaScriptBackend get backend => compiler.backend; | 17 JavaScriptBackend get backend => compiler.backend; |
| 18 | 18 |
| 19 void visitGraph(HGraph graph) { | 19 void visitGraph(HGraph graph) { |
| 20 this.graph = graph; | 20 this.graph = graph; |
| 21 visitDominatorTree(graph); | 21 visitDominatorTree(graph); |
| 22 } | 22 } |
| 23 | 23 |
| 24 visitBasicBlock(HBasicBlock block) { | 24 visitBasicBlock(HBasicBlock block) { |
| 25 HInstruction instruction = block.first; | 25 HInstruction instruction = block.first; |
| 26 while (instruction != null) { | 26 while (instruction != null) { |
| 27 HInstruction next = instruction.next; | 27 HInstruction next = instruction.next; |
| 28 HInstruction replacement = instruction.accept(this); | 28 HInstruction replacement = instruction.accept(this); |
| 29 if (replacement != instruction) { | 29 if (replacement != instruction && replacement != null) { |
| 30 block.rewrite(instruction, replacement); | 30 block.rewrite(instruction, replacement); |
| 31 | 31 |
| 32 // If the replacement instruction does not know its source element, use | 32 // If the replacement instruction does not know its source element, use |
| 33 // the source element of the instruction. | 33 // the source element of the instruction. |
| 34 if (replacement.sourceElement == null) { | 34 if (replacement.sourceElement == null) { |
| 35 replacement.sourceElement = instruction.sourceElement; | 35 replacement.sourceElement = instruction.sourceElement; |
| 36 } | 36 } |
| 37 if (replacement.sourcePosition == null) { | 37 if (replacement.sourcePosition == null) { |
| 38 replacement.sourcePosition = instruction.sourcePosition; | 38 replacement.sourcePosition = instruction.sourcePosition; |
| 39 } | 39 } |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 130 receiverArgument.usedBy.remove(node); | 130 receiverArgument.usedBy.remove(node); |
| 131 node.inputs[1] = dummy; | 131 node.inputs[1] = dummy; |
| 132 dummy.usedBy.add(node); | 132 dummy.usedBy.add(node); |
| 133 } | 133 } |
| 134 } | 134 } |
| 135 } | 135 } |
| 136 } | 136 } |
| 137 | 137 |
| 138 return node; | 138 return node; |
| 139 } | 139 } |
| 140 | |
| 141 HInstruction visitFieldSet(HFieldSet setter) { | |
| 142 // Pattern match | |
| 143 // t1 = x.f; t2 = t1 op y; x.f = t2; use(t2) --> x.f op= y | |
| 144 // t1 = x.f; t2 = t1 + 1; x.f = t2; use(t2) --> ++x.f | |
|
floitsch
2014/04/01 17:28:58
Move that line first. Otherwise the x.f op= y alwa
sra1
2014/04/01 19:51:59
Done.
| |
| 145 // t1 = x.f; t2 = t1 + 1; x.f = t2; use(t1) --> x.f++ | |
| 146 HBasicBlock block = setter.block; | |
| 147 HInstruction op = setter.value; | |
| 148 HInstruction receiver = setter.receiver; | |
| 149 | |
| 150 bool isMatchingRead(HInstruction candidate) { | |
| 151 if (candidate is! HFieldGet) return false; | |
| 152 if (candidate.element != setter.element) return false; | |
| 153 if (candidate.receiver != setter.receiver) return false; | |
| 154 // Recognize only three instructions in sequence in the same block. This | |
| 155 // could be broadened to allow non-interfereing interleaved instructions. | |
|
floitsch
2014/04/01 17:28:58
interfering
sra1
2014/04/01 19:51:59
Done.
| |
| 156 if (op.block != block) return false; | |
| 157 if (candidate.block != block) return false; | |
| 158 if (setter.previous != op) return false; | |
| 159 if (op.previous != candidate) return false; | |
| 160 return true; | |
| 161 } | |
| 162 | |
| 163 HInstruction noMatchingRead() { | |
| 164 // If we have other HFieldSet optimizations, they go here. | |
| 165 return null; | |
| 166 } | |
| 167 | |
| 168 HInstruction replaceOp(HInstruction replacement, HInstruction getter) { | |
| 169 block.addBefore(setter, replacement); | |
| 170 block.remove(setter); | |
| 171 block.rewrite(op, replacement); | |
| 172 block.remove(op); | |
| 173 block.remove(getter); | |
| 174 return null; | |
| 175 } | |
| 176 | |
| 177 HInstruction plusOrMinus(String assignOp, String incrementOp) { | |
| 178 if (isMatchingRead(op.left)) { | |
| 179 HFieldGet getter = op.left; | |
| 180 HInstruction right = op.right; | |
| 181 if (getter.usedBy.length == 1) { | |
| 182 if (right is HConstant && right.constant.isOne) { | |
| 183 HInstruction rmw = new HReadModifyWrite.preOp( | |
| 184 setter.element, incrementOp, receiver, op.instructionType); | |
| 185 return replaceOp(rmw, getter); | |
| 186 } else { | |
| 187 HInstruction rmw = new HReadModifyWrite.assignOp( | |
| 188 setter.element, | |
| 189 assignOp, | |
| 190 receiver, right, op.instructionType); | |
| 191 return replaceOp(rmw, getter); | |
| 192 } | |
| 193 } else if (op.usedBy.length == 1 && | |
| 194 right is HConstant && | |
| 195 right.constant.isOne) { | |
| 196 HInstruction rmw = new HReadModifyWrite.postOp( | |
| 197 setter.element, incrementOp, receiver, op.instructionType); | |
| 198 block.addAfter(getter, rmw); | |
| 199 block.remove(setter); | |
| 200 block.remove(op); | |
| 201 block.rewrite(getter, rmw); | |
| 202 block.remove(getter); | |
| 203 return null; | |
| 204 } | |
| 205 } | |
| 206 return noMatchingRead(); | |
| 207 } | |
| 208 | |
| 209 HInstruction simple(String assignOp) { | |
| 210 if (isMatchingRead(op.left)) { | |
| 211 HFieldGet getter = op.left; | |
| 212 if (getter.usedBy.length == 1) { | |
| 213 HInstruction rmw = new HReadModifyWrite.assignOp( | |
| 214 setter.element, | |
| 215 assignOp, | |
| 216 receiver, op.right, op.instructionType); | |
| 217 return replaceOp(rmw, getter); | |
| 218 } | |
| 219 } | |
| 220 return noMatchingRead(); | |
| 221 } | |
| 222 | |
| 223 HInstruction bitop(String assignOp) { | |
| 224 // HBitAnd, HBitOr etc. are more difficult because HBitAnd(a.x, y) | |
| 225 // sometimes needs to be forced to unsigned: a.x = (a.x & y) >>> 0. | |
| 226 if (op.isUInt31(compiler)) return simple(assignOp); | |
| 227 return noMatchingRead(); | |
| 228 } | |
| 229 | |
| 230 if (op is HAdd) return plusOrMinus('+', '++'); | |
| 231 if (op is HSubtract) return plusOrMinus('-', '--'); | |
| 232 | |
| 233 if (op is HStringConcat) return simple('+'); | |
| 234 if (op is HMultiply) return simple('*'); | |
| 235 if (op is HDivide) return simple('/'); | |
| 236 | |
| 237 if (op is HBitAnd) return bitop('&'); | |
| 238 if (op is HBitOr) return bitop('|'); | |
| 239 if (op is HBitXor) return bitop('^'); | |
| 240 | |
| 241 return noMatchingRead(); | |
| 242 } | |
| 140 } | 243 } |
| 141 | 244 |
| 142 /** | 245 /** |
| 143 * Remove [HTypeKnown] instructions from the graph, to make codegen | 246 * Remove [HTypeKnown] instructions from the graph, to make codegen |
| 144 * analysis easier. | 247 * analysis easier. |
| 145 */ | 248 */ |
| 146 class SsaTypeKnownRemover extends HBaseVisitor { | 249 class SsaTypeKnownRemover extends HBaseVisitor { |
| 147 | 250 |
| 148 void visitGraph(HGraph graph) { | 251 void visitGraph(HGraph graph) { |
| 149 visitDominatorTree(graph); | 252 visitDominatorTree(graph); |
| (...skipping 436 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 586 } | 689 } |
| 587 | 690 |
| 588 // If [thenInput] is defined in the first predecessor, then it is only used | 691 // If [thenInput] is defined in the first predecessor, then it is only used |
| 589 // by [phi] and can be generated at use site. | 692 // by [phi] and can be generated at use site. |
| 590 if (identical(thenInput.block, end.predecessors[0])) { | 693 if (identical(thenInput.block, end.predecessors[0])) { |
| 591 assert(thenInput.usedBy.length == 1); | 694 assert(thenInput.usedBy.length == 1); |
| 592 markAsGenerateAtUseSite(thenInput); | 695 markAsGenerateAtUseSite(thenInput); |
| 593 } | 696 } |
| 594 } | 697 } |
| 595 } | 698 } |
| OLD | NEW |