| 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 + 1; x.f = t2; use(t2) --> ++x.f |
| 144 // t1 = x.f; t2 = t1 op y; x.f = t2; use(t2) --> x.f op= y |
| 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) { |
| 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. Thi
s |
| 155 // could be broadened to allow non-interfering interleaved instructions. |
| 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 return false; |
| 163 } |
| 164 |
| 165 HInstruction noMatchingRead() { |
| 166 // If we have other HFieldSet optimizations, they go here. |
| 167 return null; |
| 168 } |
| 169 |
| 170 HInstruction replaceOp(HInstruction replacement, HInstruction getter) { |
| 171 block.addBefore(setter, replacement); |
| 172 block.remove(setter); |
| 173 block.rewrite(op, replacement); |
| 174 block.remove(op); |
| 175 block.remove(getter); |
| 176 return null; |
| 177 } |
| 178 |
| 179 HInstruction plusOrMinus(String assignOp, String incrementOp) { |
| 180 HInvokeBinary binary = op; |
| 181 HInstruction left = binary.left; |
| 182 HInstruction right = binary.right; |
| 183 if (isMatchingRead(left)) { |
| 184 if (left.usedBy.length == 1) { |
| 185 if (right is HConstant && right.constant.isOne) { |
| 186 HInstruction rmw = new HReadModifyWrite.preOp( |
| 187 setter.element, incrementOp, receiver, op.instructionType); |
| 188 return replaceOp(rmw, left); |
| 189 } else { |
| 190 HInstruction rmw = new HReadModifyWrite.assignOp( |
| 191 setter.element, |
| 192 assignOp, |
| 193 receiver, right, op.instructionType); |
| 194 return replaceOp(rmw, left); |
| 195 } |
| 196 } else if (op.usedBy.length == 1 && |
| 197 right is HConstant && |
| 198 right.constant.isOne) { |
| 199 HInstruction rmw = new HReadModifyWrite.postOp( |
| 200 setter.element, incrementOp, receiver, op.instructionType); |
| 201 block.addAfter(left, rmw); |
| 202 block.remove(setter); |
| 203 block.remove(op); |
| 204 block.rewrite(left, rmw); |
| 205 block.remove(left); |
| 206 return null; |
| 207 } |
| 208 } |
| 209 return noMatchingRead(); |
| 210 } |
| 211 |
| 212 HInstruction simple(String assignOp, |
| 213 HInstruction left, HInstruction right) { |
| 214 if (isMatchingRead(left)) { |
| 215 if (left.usedBy.length == 1) { |
| 216 HInstruction rmw = new HReadModifyWrite.assignOp( |
| 217 setter.element, |
| 218 assignOp, |
| 219 receiver, right, op.instructionType); |
| 220 return replaceOp(rmw, left); |
| 221 } |
| 222 } |
| 223 return noMatchingRead(); |
| 224 } |
| 225 |
| 226 HInstruction simpleBinary(String assignOp) { |
| 227 HInvokeBinary binary = op; |
| 228 return simple(assignOp, binary.left, binary.right); |
| 229 } |
| 230 |
| 231 HInstruction bitop(String assignOp) { |
| 232 // HBitAnd, HBitOr etc. are more difficult because HBitAnd(a.x, y) |
| 233 // sometimes needs to be forced to unsigned: a.x = (a.x & y) >>> 0. |
| 234 if (op.isUInt31(compiler)) return simpleBinary(assignOp); |
| 235 return noMatchingRead(); |
| 236 } |
| 237 |
| 238 if (op is HAdd) return plusOrMinus('+', '++'); |
| 239 if (op is HSubtract) return plusOrMinus('-', '--'); |
| 240 |
| 241 if (op is HStringConcat) return simple('+', op.left, op.right); |
| 242 |
| 243 if (op is HMultiply) return simpleBinary('*'); |
| 244 if (op is HDivide) return simpleBinary('/'); |
| 245 |
| 246 if (op is HBitAnd) return bitop('&'); |
| 247 if (op is HBitOr) return bitop('|'); |
| 248 if (op is HBitXor) return bitop('^'); |
| 249 |
| 250 return noMatchingRead(); |
| 251 } |
| 140 } | 252 } |
| 141 | 253 |
| 142 /** | 254 /** |
| 143 * Remove [HTypeKnown] instructions from the graph, to make codegen | 255 * Remove [HTypeKnown] instructions from the graph, to make codegen |
| 144 * analysis easier. | 256 * analysis easier. |
| 145 */ | 257 */ |
| 146 class SsaTypeKnownRemover extends HBaseVisitor { | 258 class SsaTypeKnownRemover extends HBaseVisitor { |
| 147 | 259 |
| 148 void visitGraph(HGraph graph) { | 260 void visitGraph(HGraph graph) { |
| 149 visitDominatorTree(graph); | 261 visitDominatorTree(graph); |
| (...skipping 436 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 586 } | 698 } |
| 587 | 699 |
| 588 // If [thenInput] is defined in the first predecessor, then it is only used | 700 // If [thenInput] is defined in the first predecessor, then it is only used |
| 589 // by [phi] and can be generated at use site. | 701 // by [phi] and can be generated at use site. |
| 590 if (identical(thenInput.block, end.predecessors[0])) { | 702 if (identical(thenInput.block, end.predecessors[0])) { |
| 591 assert(thenInput.usedBy.length == 1); | 703 assert(thenInput.usedBy.length == 1); |
| 592 markAsGenerateAtUseSite(thenInput); | 704 markAsGenerateAtUseSite(thenInput); |
| 593 } | 705 } |
| 594 } | 706 } |
| 595 } | 707 } |
| OLD | NEW |