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

Side by Side Diff: runtime/vm/flow_graph_optimizer.cc

Issue 92433002: Merge sin(a), cos(a) into one instruction. TODO: Implement for ARM and MIPS. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years 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
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, 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 #include "vm/flow_graph_optimizer.h" 5 #include "vm/flow_graph_optimizer.h"
6 6
7 #include "vm/bit_vector.h" 7 #include "vm/bit_vector.h"
8 #include "vm/cha.h" 8 #include "vm/cha.h"
9 #include "vm/dart_entry.h" 9 #include "vm/dart_entry.h"
10 #include "vm/flow_graph_builder.h" 10 #include "vm/flow_graph_builder.h"
(...skipping 237 matching lines...) Expand 10 before | Expand all | Expand 10 after
248 Isolate::kNoDeoptId); // BIT_AND cannot deoptimize. 248 Isolate::kNoDeoptId); // BIT_AND cannot deoptimize.
249 bit_and_instr->ReplaceWith(smi_op, current_iterator()); 249 bit_and_instr->ReplaceWith(smi_op, current_iterator());
250 } 250 }
251 } 251 }
252 252
253 253
254 254
255 // Used by TryMergeDivMod. 255 // Used by TryMergeDivMod.
256 // Inserts a load-indexed instruction between a TRUNCDIV or MOD instruction, 256 // Inserts a load-indexed instruction between a TRUNCDIV or MOD instruction,
257 // and the using instruction. This is an intermediate step before merging. 257 // and the using instruction. This is an intermediate step before merging.
258 static void DivModAppendLoadIndexed(BinarySmiOpInstr* instr, 258 void FlowGraphOptimizer::AppendLoadIndexedForMerged(Definition* instr,
259 FlowGraph* flow_graph) { 259 intptr_t ix,
260 const intptr_t index_scale = FlowGraphCompiler::ElementSizeFor(kArrayCid); 260 intptr_t cid) {
261 const intptr_t ix = (instr->op_kind() == Token::kTRUNCDIV) ? 0 : 1; 261 const intptr_t index_scale = FlowGraphCompiler::ElementSizeFor(cid);
262 ConstantInstr* index_instr = new ConstantInstr(Smi::Handle(Smi::New(ix))); 262 ConstantInstr* index_instr = new ConstantInstr(Smi::Handle(Smi::New(ix)));
263 flow_graph->InsertAfter(instr, index_instr, NULL, Definition::kValue); 263 flow_graph()->InsertAfter(instr, index_instr, NULL, Definition::kValue);
264 LoadIndexedInstr* load = new LoadIndexedInstr(new Value(instr), 264 LoadIndexedInstr* load = new LoadIndexedInstr(new Value(instr),
265 new Value(index_instr), 265 new Value(index_instr),
266 index_scale, 266 index_scale,
267 kArrayCid, 267 cid,
268 Isolate::kNoDeoptId); 268 Isolate::kNoDeoptId);
269 instr->ReplaceUsesWith(load); 269 instr->ReplaceUsesWith(load);
270 flow_graph->InsertAfter(index_instr, load, NULL, Definition::kValue); 270 flow_graph()->InsertAfter(index_instr, load, NULL, Definition::kValue);
271 } 271 }
272 272
273 273
274 // Dart: 274 // Dart:
275 // var x = d % 10; 275 // var x = d % 10;
276 // var y = d ~/ 10; 276 // var y = d ~/ 10;
277 // var z = x + y; 277 // var z = x + y;
278 // 278 //
279 // IL: 279 // IL:
280 // v4 <- %(v2, v3) 280 // v4 <- %(v2, v3)
281 // v5 <- ~/(v2, v3) 281 // v5 <- ~/(v2, v3)
282 // v6 <- +(v4, v5) 282 // v6 <- +(v4, v5)
283 // 283 //
284 // IL optimized: 284 // IL optimized:
285 // v4 <- DIVMOD(v2, v3); 285 // v4 <- DIVMOD(v2, v3);
286 // v5 <- LoadIndexed(v4, 0); // ~/ result 286 // v5 <- LoadIndexed(v4, 0); // ~/ result
287 // v6 <- LoadIndexed(v4, 1); // % result 287 // v6 <- LoadIndexed(v4, 1); // % result
288 // v7 <- +(v5, v6) 288 // v7 <- +(v5, v6)
289 // Because of the environment it is important that merged instruction replaces 289 // Because of the environment it is important that merged instruction replaces
290 // first original instruction encountered. 290 // first original instruction encountered.
291 void FlowGraphOptimizer::TryMergeTruncDivMod( 291 void FlowGraphOptimizer::TryMergeTruncDivMod(
292 GrowableArray<BinarySmiOpInstr*>* merge_candidates) { 292 GrowableArray<BinarySmiOpInstr*>* merge_candidates) {
293 if (merge_candidates->length() < 2) { 293 if (merge_candidates->length() < 2) {
294 // Need at least a TRUNCDIV and a MOD. 294 // Need at least a TRUNCDIV and a MOD.
295 return; 295 return;
296 } 296 }
297 for (intptr_t i = 0; i < merge_candidates->length(); i++) { 297 for (intptr_t i = 0; i < merge_candidates->length(); i++) {
298 BinarySmiOpInstr* curr_instr = (*merge_candidates)[i]; 298 BinarySmiOpInstr* curr_instr = (*merge_candidates)[i];
299 if (curr_instr == NULL) { 299 if (curr_instr == NULL) {
300 // Instructions was merged already. 300 // Instruction was merged already.
301 continue; 301 continue;
302 } 302 }
303 ASSERT((curr_instr->op_kind() == Token::kTRUNCDIV) || 303 ASSERT((curr_instr->op_kind() == Token::kTRUNCDIV) ||
304 (curr_instr->op_kind() == Token::kMOD)); 304 (curr_instr->op_kind() == Token::kMOD));
305 // Check if there is kMOD/kTRUNDIV binop with same inputs. 305 // Check if there is kMOD/kTRUNDIV binop with same inputs.
306 const intptr_t other_kind = (curr_instr->op_kind() == Token::kTRUNCDIV) ? 306 const intptr_t other_kind = (curr_instr->op_kind() == Token::kTRUNCDIV) ?
307 Token::kMOD : Token::kTRUNCDIV; 307 Token::kMOD : Token::kTRUNCDIV;
308 Definition* left_def = curr_instr->left()->definition(); 308 Definition* left_def = curr_instr->left()->definition();
309 Definition* right_def = curr_instr->right()->definition(); 309 Definition* right_def = curr_instr->right()->definition();
310 for (intptr_t k = i + 1; k < merge_candidates->length(); k++) { 310 for (intptr_t k = i + 1; k < merge_candidates->length(); k++) {
311 BinarySmiOpInstr* other_binop = (*merge_candidates)[k]; 311 BinarySmiOpInstr* other_binop = (*merge_candidates)[k];
312 // 'other_binop' can be NULL if it was already merged. 312 // 'other_binop' can be NULL if it was already merged.
313 if ((other_binop != NULL) && 313 if ((other_binop != NULL) &&
314 (other_binop->op_kind() == other_kind) && 314 (other_binop->op_kind() == other_kind) &&
315 (other_binop->left()->definition() == left_def) && 315 (other_binop->left()->definition() == left_def) &&
316 (other_binop->right()->definition() == right_def)) { 316 (other_binop->right()->definition() == right_def)) {
317 (*merge_candidates)[k] = NULL; // Clear it. 317 (*merge_candidates)[k] = NULL; // Clear it.
318 // Append a LoadIndexed behind TRUNC_DIV and MOD. 318 // Append a LoadIndexed behind TRUNC_DIV and MOD.
319 DivModAppendLoadIndexed(curr_instr, flow_graph_); 319 const intptr_t curr_result_ix =
320 DivModAppendLoadIndexed(other_binop, flow_graph_); 320 (curr_instr->op_kind() == Token::kTRUNCDIV) ? 0 : 1;
321 AppendLoadIndexedForMerged(curr_instr, curr_result_ix, kArrayCid);
322 const intptr_t other_result_ix =
Florian Schneider 2013/12/03 14:12:04 Equivalent, but shorter: const intptr_t other_res
323 (other_binop->op_kind() == Token::kTRUNCDIV) ? 0 : 1;
324 AppendLoadIndexedForMerged(other_binop, other_result_ix, kArrayCid);
321 325
322 ZoneGrowableArray<Value*>* args = new ZoneGrowableArray<Value*>(2); 326 ZoneGrowableArray<Value*>* args = new ZoneGrowableArray<Value*>(2);
323 args->Add(new Value(curr_instr->left()->definition())); 327 args->Add(new Value(curr_instr->left()->definition()));
324 args->Add(new Value(curr_instr->right()->definition())); 328 args->Add(new Value(curr_instr->right()->definition()));
325 329
326 // Replace with TruncDivMod. 330 // Replace with TruncDivMod.
327 MergedMathInstr* div_mod = new MergedMathInstr( 331 MergedMathInstr* div_mod = new MergedMathInstr(
328 args, 332 args,
329 curr_instr->deopt_id(), 333 curr_instr->deopt_id(),
330 MergedMathInstr::kTruncDivMod); 334 MergedMathInstr::kTruncDivMod);
331 curr_instr->ReplaceWith(div_mod, current_iterator()); 335 curr_instr->ReplaceWith(div_mod, current_iterator());
332 other_binop->ReplaceUsesWith(div_mod); 336 other_binop->ReplaceUsesWith(div_mod);
333 other_binop->RemoveFromGraph(); 337 other_binop->RemoveFromGraph();
334 } 338 }
335 } 339 }
336 } 340 }
337 } 341 }
338 342
339 343
344 void FlowGraphOptimizer::TryMergeMathUnary(
345 GrowableArray<MathUnaryInstr*>* merge_candidates) {
346 if (!FlowGraphCompiler::SupportsSinCos()) {
347 return;
348 }
349 if (merge_candidates->length() < 2) {
350 // Need at least a SIN and a COS.
351 return;
352 }
353 for (intptr_t i = 0; i < merge_candidates->length(); i++) {
354 MathUnaryInstr* curr_instr = (*merge_candidates)[i];
355 if (curr_instr == NULL) {
356 // Instruction was merged already.
357 continue;
358 }
359 ASSERT((curr_instr->kind() == MethodRecognizer::kMathSin) ||
360 (curr_instr->kind() == MethodRecognizer::kMathCos));
361 // Check if there is sin/cos binop with same inputs.
362 const intptr_t other_kind =
363 (curr_instr->kind() == MethodRecognizer::kMathSin) ?
364 MethodRecognizer::kMathCos : MethodRecognizer::kMathSin;
365 Definition* def = curr_instr->value()->definition();
366 for (intptr_t k = i + 1; k < merge_candidates->length(); k++) {
367 MathUnaryInstr* other_op = (*merge_candidates)[k];
368 // 'other_op' can be NULL if it was already merged.
369 if ((other_op != NULL) && (other_op->kind() == other_kind) &&
370 (other_op->value()->definition() == def)) {
371 (*merge_candidates)[k] = NULL; // Clear it.
372 // Append a LoadIndexed behind SIN and COS.
373 const intptr_t curr_result_ix =
374 (curr_instr->kind() == MethodRecognizer::kMathSin) ? 0 : 1;
375 AppendLoadIndexedForMerged(
376 curr_instr, curr_result_ix, kTypedDataFloat64ArrayCid);
377 const intptr_t other_result_ix =
378 (other_op->kind() == MethodRecognizer::kMathSin) ? 0 : 1;
Florian Schneider 2013/12/03 14:12:04 Equivalent, but shorter: const intptr_t other_res
srdjan 2013/12/03 18:10:01 I used to have that, but found it harder to read.
379 AppendLoadIndexedForMerged(
380 other_op, other_result_ix, kTypedDataFloat64ArrayCid);
381 ZoneGrowableArray<Value*>* args = new ZoneGrowableArray<Value*>(2);
Florian Schneider 2013/12/03 14:12:04 s/2/1/ because only one argument is added below.
srdjan 2013/12/03 18:10:01 Done.
382 args->Add(new Value(curr_instr->value()->definition()));
383
384 // Replace with TruncDivMod.
385 MergedMathInstr* div_mod = new MergedMathInstr(
386 args,
387 curr_instr->DeoptimizationTarget(),
388 MergedMathInstr::kSinCos);
389 curr_instr->ReplaceWith(div_mod, current_iterator());
390 other_op->ReplaceUsesWith(div_mod);
391 other_op->RemoveFromGraph();
392 }
393 }
394 }
395 }
396
397
340 // Optimize (a << b) & c pattern: if c is a positive Smi or zero, then the 398 // Optimize (a << b) & c pattern: if c is a positive Smi or zero, then the
341 // shift can be a truncating Smi shift-left and result is always Smi. 399 // shift can be a truncating Smi shift-left and result is always Smi.
342 // Merging occurs only per basic-block. 400 // Merging occurs only per basic-block.
343 void FlowGraphOptimizer::TryOptimizePatterns() { 401 void FlowGraphOptimizer::TryOptimizePatterns() {
344 if (!FLAG_truncating_left_shift) return; 402 if (!FLAG_truncating_left_shift) return;
345 ASSERT(current_iterator_ == NULL); 403 ASSERT(current_iterator_ == NULL);
346 GrowableArray<BinarySmiOpInstr*> for_merge; 404 GrowableArray<BinarySmiOpInstr*> div_mod_merge;
405 GrowableArray<MathUnaryInstr*> sin_cos_merge;
347 for (intptr_t i = 0; i < block_order_.length(); ++i) { 406 for (intptr_t i = 0; i < block_order_.length(); ++i) {
348 // Merging only per basic-block. 407 // Merging only per basic-block.
349 for_merge.Clear(); 408 div_mod_merge.Clear();
409 sin_cos_merge.Clear();
350 BlockEntryInstr* entry = block_order_[i]; 410 BlockEntryInstr* entry = block_order_[i];
351 ForwardInstructionIterator it(entry); 411 ForwardInstructionIterator it(entry);
352 current_iterator_ = &it; 412 current_iterator_ = &it;
353 for (; !it.Done(); it.Advance()) { 413 for (; !it.Done(); it.Advance()) {
354 if (it.Current()->IsBinarySmiOp()) { 414 if (it.Current()->IsBinarySmiOp()) {
355 BinarySmiOpInstr* binop = it.Current()->AsBinarySmiOp(); 415 BinarySmiOpInstr* binop = it.Current()->AsBinarySmiOp();
356 if (binop->op_kind() == Token::kBIT_AND) { 416 if (binop->op_kind() == Token::kBIT_AND) {
357 OptimizeLeftShiftBitAndSmiOp(binop, 417 OptimizeLeftShiftBitAndSmiOp(binop,
358 binop->left()->definition(), 418 binop->left()->definition(),
359 binop->right()->definition()); 419 binop->right()->definition());
360 } else if ((binop->op_kind() == Token::kTRUNCDIV) || 420 } else if ((binop->op_kind() == Token::kTRUNCDIV) ||
361 (binop->op_kind() == Token::kMOD)) { 421 (binop->op_kind() == Token::kMOD)) {
362 for_merge.Add(binop); 422 div_mod_merge.Add(binop);
363 } 423 }
364 } else if (it.Current()->IsBinaryMintOp()) { 424 } else if (it.Current()->IsBinaryMintOp()) {
365 BinaryMintOpInstr* mintop = it.Current()->AsBinaryMintOp(); 425 BinaryMintOpInstr* mintop = it.Current()->AsBinaryMintOp();
366 if (mintop->op_kind() == Token::kBIT_AND) { 426 if (mintop->op_kind() == Token::kBIT_AND) {
367 OptimizeLeftShiftBitAndSmiOp(mintop, 427 OptimizeLeftShiftBitAndSmiOp(mintop,
368 mintop->left()->definition(), 428 mintop->left()->definition(),
369 mintop->right()->definition()); 429 mintop->right()->definition());
370 } 430 }
431 } else if (it.Current()->IsMathUnary()) {
432 MathUnaryInstr* math_unary = it.Current()->AsMathUnary();
433 if ((math_unary->kind() == MethodRecognizer::kMathSin) ||
434 (math_unary->kind() == MethodRecognizer::kMathCos)) {
435 sin_cos_merge.Add(math_unary);
436 }
371 } 437 }
372 } 438 }
373 TryMergeTruncDivMod(&for_merge); 439 TryMergeTruncDivMod(&div_mod_merge);
440 TryMergeMathUnary(&sin_cos_merge);
374 current_iterator_ = NULL; 441 current_iterator_ = NULL;
375 } 442 }
376 } 443 }
377 444
378 445
379 static void EnsureSSATempIndex(FlowGraph* graph, 446 static void EnsureSSATempIndex(FlowGraph* graph,
380 Definition* defn, 447 Definition* defn,
381 Definition* replacement) { 448 Definition* replacement) {
382 if ((replacement->ssa_temp_index() == -1) && 449 if ((replacement->ssa_temp_index() == -1) &&
383 (defn->ssa_temp_index() != -1)) { 450 (defn->ssa_temp_index() != -1)) {
(...skipping 7592 matching lines...) Expand 10 before | Expand all | Expand 10 after
7976 } 8043 }
7977 8044
7978 // Insert materializations at environment uses. 8045 // Insert materializations at environment uses.
7979 for (intptr_t i = 0; i < exits.length(); i++) { 8046 for (intptr_t i = 0; i < exits.length(); i++) {
7980 CreateMaterializationAt(exits[i], alloc, alloc->cls(), *fields); 8047 CreateMaterializationAt(exits[i], alloc, alloc->cls(), *fields);
7981 } 8048 }
7982 } 8049 }
7983 8050
7984 8051
7985 } // namespace dart 8052 } // namespace dart
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698