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

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: 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 163 matching lines...) Expand 10 before | Expand all | Expand 10 after
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 if (instruction is HPhi && !logicalOperations.containsKey(instruction)) {
182 return false; 182 return false;
183 } 183 }
184 HInstruction previous;
ngeoffray 2012/04/19 12:52:24 Unused variable?
Lasse Reichstein Nielsen 2012/04/19 13:13:07 Yes, removed.
184 while (instruction.previous != null) { 185 while (instruction.previous != null) {
185 instruction = instruction.previous; 186 instruction = instruction.previous;
186 if (!generateAtUseSite.contains(instruction)) { 187 if (!generateAtUseSite.contains(instruction)) {
187 return false; 188 return false;
188 } 189 }
189 } 190 }
190 HBasicBlock block = instruction.block; 191 HBasicBlock block = instruction.block;
191 if (!block.phis.isEmpty()) return false; 192 if (!block.phis.isEmpty()) {
193 if (!generateAtUseSite.contains(instruction)) {
ngeoffray 2012/04/19 12:52:24 So this is the very first instruction of the block
Lasse Reichstein Nielsen 2012/04/19 13:13:07 Done. Also took care of the case when [instruction
194 return false;
195 }
196 instruction = block.phis.last;
197 if (block.phis.first !== instruction) {
ngeoffray 2012/04/19 12:52:24 block.phis.length != 1 reads better
Lasse Reichstein Nielsen 2012/04/19 13:13:07 But runs worse. [block.phis] is a [HInstructionLis
198 return false;
199 }
200 }
192 if (instruction is HPhi && logicalOperations.containsKey(instruction)) { 201 if (instruction is HPhi && logicalOperations.containsKey(instruction)) {
193 return isExpression(instruction.inputs[0], limit); 202 return isExpression(instruction.inputs[0], limit);
194 } 203 }
195 return block.predecessors.length == 1 && block.predecessors[0] == limit; 204 if (block.predecessors.length !== 1) {
205 return false;
206 }
207 HBasicBlock previousBlock = block.predecessors[0];
208 if (previousBlock === limit) return true;
209 if (previousBlock.successors.length !== 1 ||
210 previousBlock.last is! HGoto) {
ngeoffray 2012/04/19 12:52:24 Should that check be isBlockSinglePredecessor inst
Lasse Reichstein Nielsen 2012/04/19 13:13:07 It's more, since it also checks that the HControlF
211 return false;
212 }
213 return isExpression(previousBlock.last, limit);
196 } 214 }
197 215
198 void replaceWithLogicalOperator(HPhi phi, String type) { 216 void replaceWithLogicalOperator(HPhi phi, String type) {
199 if (canGenerateAtUseSite(phi)) generateAtUseSite.add(phi); 217 if (canGenerateAtUseSite(phi)) generateAtUseSite.add(phi);
200 logicalOperations[phi] = type; 218 logicalOperations[phi] = type;
219 // If the phi corresponds to logical control flow, mark the
220 // control-flow instructions as generate-at-use-site.
221 generateAtUseSite.add(phi.block.predecessors[0].last);
222 generateAtUseSite.add(phi.block.predecessors[1].last);
223 // If the first input is only used as branch condition and result, it too
224 // can be generate-at-use-site.
225 if (phi.inputs[0].usedBy.length == 2) {
226 generateAtUseSite.add(phi.inputs[0]);
227 }
228 if (phi.inputs[1].usedBy.length == 1) {
229 generateAtUseSite.add(phi.inputs[1]);
230 }
201 } 231 }
202 232
203 bool canGenerateAtUseSite(HPhi phi) { 233 bool canGenerateAtUseSite(HPhi phi) {
204 if (phi.usedBy.length != 1) return false; 234 if (phi.usedBy.length != 1) {
235 return false;
236 }
205 assert(phi.next == null); 237 assert(phi.next == null);
206 HInstruction use = phi.usedBy[0]; 238 HInstruction use = phi.usedBy[0];
207 239
208 HInstruction current = phi.block.first; 240 HInstruction current = phi.block.first;
209 while (current != use) { 241 while (current != use) {
210 if (!generateAtUseSite.contains(current)) return false; 242 if (current is! HControlFlow && !generateAtUseSite.contains(current)) {
ngeoffray 2012/04/19 12:52:24 Please add a comment on why you check that.
Lasse Reichstein Nielsen 2012/04/19 13:13:07 Done.
243 return false;
244 }
211 if (current.next != null) { 245 if (current.next != null) {
212 current = current.next; 246 current = current.next;
213 } else if (current is HPhi) { 247 } else if (current is HPhi) {
214 current = current.block.first; 248 current = current.block.first;
215 } else { 249 } else {
216 assert(current is HControlFlow); 250 assert(current is HControlFlow);
217 if (current is !HGoto) return false; 251 if (current is !HGoto) {
252 return false;
253 }
218 HBasicBlock nextBlock = current.block.successors[0]; 254 HBasicBlock nextBlock = current.block.successors[0];
219 if (!nextBlock.phis.isEmpty()) { 255 if (!nextBlock.phis.isEmpty()) {
220 current = nextBlock.phis.first; 256 current = nextBlock.phis.first;
221 } else { 257 } else {
222 current = nextBlock.first; 258 current = nextBlock.first;
223 } 259 }
224 } 260 }
225 } 261 }
226 return true; 262 return true;
227 } 263 }
228 264
265 HInstruction previousInstruction(HInstruction instruction) {
266 if (instruction.previous != null) return instruction.previous;
267 HBasicBlock block = instruction.block;
268 if (instruction is! HPhi) {
269 if (block.phis.last != null) return block.phis.last;
270 }
271 if (block.predecessors.length == 1) {
272 HBasicBlock previousBlock = block.predecessors[0];
273 if (previousBlock.last is HGoto) {
ngeoffray 2012/04/19 12:52:24 Use isBlockSinglePredecessor instead?
Lasse Reichstein Nielsen 2012/04/19 13:13:07 Don't have it. I don't think it's worth copying he
274 assert(previousBlock.successors.length == 1);
275 assert(previousBlock.successors[0] === block);
276 return previousInstruction(previousBlock.last);
277 }
278 }
279 return null;
280 }
281
229 void detectLogicControlFlow(HPhi phi) { 282 void detectLogicControlFlow(HPhi phi) {
230 // Check for the most common pattern for a short-circuit logic operation: 283 // 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) 284 // B0 b0 = ...; if (b0) goto B1 else B2 (or: if (!b0) goto B2 else B1)
232 // |\ 285 // |\
233 // | B1 b1 = ...; goto B2 286 // | B1 b1 = ...; goto B2
234 // |/ 287 // |/
235 // B2 b2 = phi(b0,b1); if(b2) ... 288 // B2 b2 = phi(b0,b1); if(b2) ...
236 // TODO(lrn): Also recognize ?:-flow? 289 // TODO(lrn): Also recognize ?:-flow?
237
238 if (phi.inputs.length != 2) return; 290 if (phi.inputs.length != 2) return;
291 HBasicBlock firstBlock = phi.block.predecessors[0];
292 HBasicBlock secondBlock = phi.block.predecessors[1];
ngeoffray 2012/04/19 12:52:24 How it was written before read better for me.
Lasse Reichstein Nielsen 2012/04/19 13:13:07 Reordered.
239 HInstruction first = phi.inputs[0]; 293 HInstruction first = phi.inputs[0];
240 HBasicBlock firstBlock = first.block;
241 HInstruction second = phi.inputs[1]; 294 HInstruction second = phi.inputs[1];
242 HBasicBlock secondBlock = second.block;
243 // Check second input of phi being an expression followed by a goto. 295 // Check second input of phi being an expression followed by a goto.
244 if (second.usedBy.length != 1) return; 296 if (second.usedBy.length != 1) return;
245 HInstruction secondNext = 297 HInstruction secondNext =
246 (second is HPhi) ? secondBlock.first : second.next; 298 (second is HPhi) ? secondBlock.first : second.next;
247 if (secondNext != secondBlock.last) return; 299 if (secondNext != secondBlock.last) return;
248 if (secondBlock.last is !HGoto) return; 300 if (secondBlock.last is !HGoto) return;
249 if (secondBlock.successors[0] != phi.block) return; 301 if (secondBlock.successors[0] != phi.block) return;
250 if (!isExpression(second, firstBlock)) return; 302 if (!isExpression(second, firstBlock)) return;
251 // Check first input of phi being followed by a (possibly negated) 303 // Check first input of phi being followed by a (possibly negated)
252 // conditional branch based on the same value. 304 // conditional branch based on the same value.
253 if (firstBlock != phi.block.dominator) return; 305 if (firstBlock != phi.block.dominator) return;
254 if (firstBlock.last is !HConditionalBranch) return; 306 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; 307 if (firstBlock.successors[1] != phi.block) return;
259 HInstruction firstNext = (first is HPhi) ? firstBlock.first : first.next; 308 HIf firstBranch = firstBlock.last;
260 if (firstNext == firstBranch && 309 HInstruction condition = firstBranch.inputs[0];
261 firstBranch.condition == first) { 310 if (condition === first) {
262 replaceWithLogicalOperator(phi, "&&"); 311 replaceWithLogicalOperator(phi, "&&");
263 } else if (firstNext is HNot && 312 } else if (condition is HNot &&
264 firstNext.inputs[0] == first && 313 condition.inputs[0] == first) {
265 generateAtUseSite.contains(firstNext) &&
266 firstNext.next == firstBlock.last &&
267 firstBranch.condition == firstNext) {
268 replaceWithLogicalOperator(phi, "||"); 314 replaceWithLogicalOperator(phi, "||");
269 } else { 315 // If the negation is only used by this logical operation, or only by
270 return; 316 // logical operators in general, it won't need to be generated.
317 if (!generateAtUseSite.contains(condition)) {
318 for (HInstruction user in condition.usedBy) {
319 if (user is! HIf || !generateAtUseSite.contains(user)) {
320 return;
321 }
322 }
323 generateAtUseSite.add(condition);
324 }
271 } 325 }
272 // Detected as logic control flow. Mark the corresponding 326 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 } 327 }
280 328
281 void visitBasicBlock(HBasicBlock block) { 329 void visitBasicBlock(HBasicBlock block) {
282 if (!block.phis.isEmpty() && 330 if (!block.phis.isEmpty() &&
283 block.phis.first == block.phis.last) { 331 block.phis.first === block.phis.last) {
284 detectLogicControlFlow(block.phis.first); 332 detectLogicControlFlow(block.phis.first);
285 } 333 }
286 } 334 }
287 } 335 }
288 336
289 // Precedence information for JavaScript operators. 337 // Precedence information for JavaScript operators.
290 class JSPrecedence { 338 class JSPrecedence {
291 // Used as precedence for something that's not even an expression. 339 // Used as precedence for something that's not even an expression.
292 static final int STATEMENT_PRECEDENCE = 0; 340 static final int STATEMENT_PRECEDENCE = 0;
293 // Precedences of JS operators. 341 // Precedences of JS operators.
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after
425 // improving the performance of future lookups. 473 // improving the performance of future lookups.
426 T root = getRepresentative(parent); 474 T root = getRepresentative(parent);
427 if (root !== parent) representative[element] = root; 475 if (root !== parent) representative[element] = root;
428 return root; 476 return root;
429 } 477 }
430 478
431 bool areEquivalent(T a, T b) { 479 bool areEquivalent(T a, T b) {
432 return getRepresentative(a) === getRepresentative(b); 480 return getRepresentative(a) === getRepresentative(b);
433 } 481 }
434 } 482 }
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