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

Side by Side Diff: lib/compiler/implementation/ssa/codegen_helpers.dart

Issue 10126005: Better detection of logical and/or inlining opportunities. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Address review comments. Created 8 years, 8 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 /** 5 /**
6 * Instead of emitting each SSA instruction with a temporary variable 6 * Instead of emitting each SSA instruction with a temporary variable
7 * mark instructions that can be emitted at their use-site. 7 * mark instructions that can be emitted at their use-site.
8 * For example, in: 8 * For example, in:
9 * t0 = 4; 9 * t0 = 4;
10 * t1 = 3; 10 * t1 = 3;
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after
171 171
172 /** 172 /**
173 * Returns true if the given instruction is an expression that uses up all 173 * Returns true if the given instruction is an expression that uses up all
174 * instructions up to the given [limit]. 174 * instructions up to the given [limit].
175 * 175 *
176 * That is, all instructions starting after the [limit] block (at the branch 176 * That is, all instructions starting after the [limit] block (at the branch
177 * leading to the [instruction]) down to the given [instruction] can be 177 * leading to the [instruction]) down to the given [instruction] can be
178 * generated at use-site. 178 * generated at use-site.
179 */ 179 */
180 bool isExpression(HInstruction instruction, HBasicBlock limit) { 180 bool isExpression(HInstruction instruction, HBasicBlock limit) {
181 if (instruction is HPhi && !logicalOperations.containsKey(instruction)) { 181 HBasicBlock block = instruction.block;
182 if (instruction is HPhi) {
183 if (!logicalOperations.containsKey(instruction)) {
184 return false;
185 }
186 } else {
187 while (instruction.previous != null) {
188 instruction = instruction.previous;
189 if (!generateAtUseSite.contains(instruction)) {
190 return false;
191 }
192 }
193 // Now [instruction] is the first instruction of the block
194 // (aka [block.first]). If there are also a phi, check the current
195 // [instruction] normally and make [instruction] be the phi.
196 if (!block.phis.isEmpty()) {
197 if (!generateAtUseSite.contains(instruction)) {
198 return false;
199 }
200 instruction = block.phis.last;
201 if (block.phis.first !== instruction) {
202 // If there is more than one phi, don't try to undestand it.
203 return false;
204 }
205 if (!logicalOperations.containsKey(instruction)) {
206 return false;
207 }
208 }
209 }
210 if (instruction is HPhi) {
211 assert(logicalOperations.containsKey(instruction));
212 return isExpression(instruction.inputs[0], limit);
213 }
214 if (block.predecessors.length !== 1) {
182 return false; 215 return false;
183 } 216 }
184 while (instruction.previous != null) { 217 HBasicBlock previousBlock = block.predecessors[0];
185 instruction = instruction.previous; 218 if (previousBlock === limit) return true;
186 if (!generateAtUseSite.contains(instruction)) { 219 if (previousBlock.successors.length !== 1 ||
187 return false; 220 previousBlock.last is! HGoto) {
188 } 221 return false;
189 } 222 }
190 HBasicBlock block = instruction.block; 223 return isExpression(previousBlock.last, limit);
191 if (!block.phis.isEmpty()) return false;
192 if (instruction is HPhi && logicalOperations.containsKey(instruction)) {
193 return isExpression(instruction.inputs[0], limit);
194 }
195 return block.predecessors.length == 1 && block.predecessors[0] == limit;
196 } 224 }
197 225
198 void replaceWithLogicalOperator(HPhi phi, String type) { 226 void replaceWithLogicalOperator(HPhi phi, String type) {
199 if (canGenerateAtUseSite(phi)) generateAtUseSite.add(phi); 227 if (canGenerateAtUseSite(phi)) generateAtUseSite.add(phi);
200 logicalOperations[phi] = type; 228 logicalOperations[phi] = type;
229 // If the phi corresponds to logical control flow, mark the
230 // control-flow instructions as generate-at-use-site.
231 generateAtUseSite.add(phi.block.predecessors[0].last);
232 generateAtUseSite.add(phi.block.predecessors[1].last);
233 // If the first input is only used as branch condition and result, it too
234 // can be generate-at-use-site.
235 if (phi.inputs[0].usedBy.length == 2) {
236 generateAtUseSite.add(phi.inputs[0]);
237 }
238 if (phi.inputs[1].usedBy.length == 1) {
239 generateAtUseSite.add(phi.inputs[1]);
240 }
201 } 241 }
202 242
203 bool canGenerateAtUseSite(HPhi phi) { 243 bool canGenerateAtUseSite(HPhi phi) {
204 if (phi.usedBy.length != 1) return false; 244 if (phi.usedBy.length != 1) {
245 return false;
246 }
205 assert(phi.next == null); 247 assert(phi.next == null);
206 HInstruction use = phi.usedBy[0]; 248 HInstruction use = phi.usedBy[0];
207 249
208 HInstruction current = phi.block.first; 250 HInstruction current = phi.block.first;
209 while (current != use) { 251 while (current != use) {
210 if (!generateAtUseSite.contains(current)) return false; 252 // Check that every instruction between the start of the block and the
253 // use of the phi (i.e., every instruction between the phi and the use)
254 // is itself generated at use site. That means that the phi can be
255 // moved to its use site without crossing any other code, because those
256 // instructions (if any) are moved too.
257 if (current is! HControlFlow && !generateAtUseSite.contains(current)) {
258 return false;
259 }
211 if (current.next != null) { 260 if (current.next != null) {
212 current = current.next; 261 current = current.next;
213 } else if (current is HPhi) { 262 } else if (current is HPhi) {
214 current = current.block.first; 263 current = current.block.first;
215 } else { 264 } else {
216 assert(current is HControlFlow); 265 assert(current is HControlFlow);
217 if (current is !HGoto) return false; 266 if (current is !HGoto) {
267 return false;
268 }
218 HBasicBlock nextBlock = current.block.successors[0]; 269 HBasicBlock nextBlock = current.block.successors[0];
219 if (!nextBlock.phis.isEmpty()) { 270 if (!nextBlock.phis.isEmpty()) {
220 current = nextBlock.phis.first; 271 current = nextBlock.phis.first;
221 } else { 272 } else {
222 current = nextBlock.first; 273 current = nextBlock.first;
223 } 274 }
224 } 275 }
225 } 276 }
226 return true; 277 return true;
227 } 278 }
228 279
280 HInstruction previousInstruction(HInstruction instruction) {
281 if (instruction.previous != null) return instruction.previous;
282 HBasicBlock block = instruction.block;
283 if (instruction is! HPhi) {
284 if (block.phis.last != null) return block.phis.last;
285 }
286 if (block.predecessors.length == 1) {
287 HBasicBlock previousBlock = block.predecessors[0];
288 if (previousBlock.last is HGoto) {
289 assert(previousBlock.successors.length == 1);
290 assert(previousBlock.successors[0] === block);
291 return previousInstruction(previousBlock.last);
292 }
293 }
294 return null;
295 }
296
229 void detectLogicControlFlow(HPhi phi) { 297 void detectLogicControlFlow(HPhi phi) {
230 // Check for the most common pattern for a short-circuit logic operation: 298 // Check for the most common pattern for a short-circuit logic operation:
231 // B0 b0 = ...; if (b0) goto B1 else B2 (or: if (!b0) goto B2 else B1) 299 // B0 b0 = ...; if (b0) goto B1 else B2 (or: if (!b0) goto B2 else B1)
232 // |\ 300 // |\
233 // | B1 b1 = ...; goto B2 301 // | B1 b1 = ...; goto B2
234 // |/ 302 // |/
235 // B2 b2 = phi(b0,b1); if(b2) ... 303 // B2 b2 = phi(b0,b1); if(b2) ...
236 // TODO(lrn): Also recognize ?:-flow? 304 // TODO(lrn): Also recognize ?:-flow?
237
238 if (phi.inputs.length != 2) return; 305 if (phi.inputs.length != 2) return;
239 HInstruction first = phi.inputs[0]; 306 HInstruction first = phi.inputs[0];
240 HBasicBlock firstBlock = first.block; 307 HBasicBlock firstBlock = phi.block.predecessors[0];
241 HInstruction second = phi.inputs[1]; 308 HInstruction second = phi.inputs[1];
242 HBasicBlock secondBlock = second.block; 309 HBasicBlock secondBlock = phi.block.predecessors[1];
243 // Check second input of phi being an expression followed by a goto. 310 // Check second input of phi being an expression followed by a goto.
244 if (second.usedBy.length != 1) return; 311 if (second.usedBy.length != 1) return;
245 HInstruction secondNext = 312 HInstruction secondNext =
246 (second is HPhi) ? secondBlock.first : second.next; 313 (second is HPhi) ? secondBlock.first : second.next;
247 if (secondNext != secondBlock.last) return; 314 if (secondNext != secondBlock.last) return;
248 if (secondBlock.last is !HGoto) return; 315 if (secondBlock.last is !HGoto) return;
249 if (secondBlock.successors[0] != phi.block) return; 316 if (secondBlock.successors[0] != phi.block) return;
250 if (!isExpression(second, firstBlock)) return; 317 if (!isExpression(second, firstBlock)) return;
251 // Check first input of phi being followed by a (possibly negated) 318 // Check first input of phi being followed by a (possibly negated)
252 // conditional branch based on the same value. 319 // conditional branch based on the same value.
253 if (firstBlock != phi.block.dominator) return; 320 if (firstBlock != phi.block.dominator) return;
254 if (firstBlock.last is !HConditionalBranch) return; 321 if (firstBlock.last is! HIf) return;
255 HConditionalBranch firstBranch = firstBlock.last;
256 // Must be used both for value and for control to avoid the second branch.
257 if (first.usedBy.length != 2) return;
258 if (firstBlock.successors[1] != phi.block) return; 322 if (firstBlock.successors[1] != phi.block) return;
259 HInstruction firstNext = (first is HPhi) ? firstBlock.first : first.next; 323 HIf firstBranch = firstBlock.last;
260 if (firstNext == firstBranch && 324 HInstruction condition = firstBranch.inputs[0];
261 firstBranch.condition == first) { 325 if (condition === first) {
262 replaceWithLogicalOperator(phi, "&&"); 326 replaceWithLogicalOperator(phi, "&&");
263 } else if (firstNext is HNot && 327 } else if (condition is HNot &&
264 firstNext.inputs[0] == first && 328 condition.inputs[0] == first) {
265 generateAtUseSite.contains(firstNext) &&
266 firstNext.next == firstBlock.last &&
267 firstBranch.condition == firstNext) {
268 replaceWithLogicalOperator(phi, "||"); 329 replaceWithLogicalOperator(phi, "||");
269 } else { 330 // If the negation is only used by this logical operation, or only by
270 return; 331 // logical operators in general, it won't need to be generated.
332 if (!generateAtUseSite.contains(condition)) {
333 for (HInstruction user in condition.usedBy) {
334 if (user is! HIf || !generateAtUseSite.contains(user)) {
335 return;
336 }
337 }
338 generateAtUseSite.add(condition);
339 }
271 } 340 }
272 // Detected as logic control flow. Mark the corresponding 341 return;
273 // inputs as generated at use site. These will now be generated
274 // as part of an expression.
275 generateAtUseSite.add(first);
276 generateAtUseSite.add(firstBlock.last);
277 generateAtUseSite.add(second);
278 generateAtUseSite.add(secondBlock.last);
279 } 342 }
280 343
281 void visitBasicBlock(HBasicBlock block) { 344 void visitBasicBlock(HBasicBlock block) {
282 if (!block.phis.isEmpty() && 345 if (!block.phis.isEmpty() &&
283 block.phis.first == block.phis.last) { 346 block.phis.first === block.phis.last) {
284 detectLogicControlFlow(block.phis.first); 347 detectLogicControlFlow(block.phis.first);
285 } 348 }
286 } 349 }
287 } 350 }
288 351
289 // Precedence information for JavaScript operators. 352 // Precedence information for JavaScript operators.
290 class JSPrecedence { 353 class JSPrecedence {
291 // Used as precedence for something that's not even an expression. 354 // Used as precedence for something that's not even an expression.
292 static final int STATEMENT_PRECEDENCE = 0; 355 static final int STATEMENT_PRECEDENCE = 0;
293 // Precedences of JS operators. 356 // Precedences of JS operators.
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after
425 // improving the performance of future lookups. 488 // improving the performance of future lookups.
426 T root = getRepresentative(parent); 489 T root = getRepresentative(parent);
427 if (root !== parent) representative[element] = root; 490 if (root !== parent) representative[element] = root;
428 return root; 491 return root;
429 } 492 }
430 493
431 bool areEquivalent(T a, T b) { 494 bool areEquivalent(T a, T b) {
432 return getRepresentative(a) === getRepresentative(b); 495 return getRepresentative(a) === getRepresentative(b);
433 } 496 }
434 } 497 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698