| OLD | NEW |
| 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 233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 244 BinarySmiOpInstr* smi_op = new BinarySmiOpInstr( | 244 BinarySmiOpInstr* smi_op = new BinarySmiOpInstr( |
| 245 Token::kBIT_AND, | 245 Token::kBIT_AND, |
| 246 new Value(left_instr), | 246 new Value(left_instr), |
| 247 new Value(right_instr), | 247 new Value(right_instr), |
| 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 |
| 255 // Used by TryMergeDivMod. |
| 256 // Inserts a load-indexed instruction between a TRUNCDIV or MOD instruction, |
| 257 // and the using instruction. This is an intermediate step before merging. |
| 258 static void DivModAppendLoadIndexed(BinarySmiOpInstr* instr, |
| 259 FlowGraph* flow_graph) { |
| 260 const intptr_t index_scale = FlowGraphCompiler::ElementSizeFor(kArrayCid); |
| 261 const intptr_t ix = (instr->op_kind() == Token::kTRUNCDIV) ? 0 : 1; |
| 262 ConstantInstr* index_instr = new ConstantInstr(Smi::Handle(Smi::New(ix))); |
| 263 flow_graph->InsertAfter(instr, index_instr, NULL, Definition::kValue); |
| 264 LoadIndexedInstr* load = new LoadIndexedInstr(new Value(instr), |
| 265 new Value(index_instr), |
| 266 index_scale, |
| 267 kArrayCid, |
| 268 Isolate::kNoDeoptId); |
| 269 instr->ReplaceUsesWith(load); |
| 270 flow_graph->InsertAfter(index_instr, load, NULL, Definition::kValue); |
| 271 } |
| 272 |
| 273 |
| 274 // Dart: |
| 275 // var x = d % 10; |
| 276 // var y = d ~/ 10; |
| 277 // var z = x + y; |
| 278 // |
| 279 // IL: |
| 280 // v4 <- %(v2, v3) |
| 281 // v5 <- ~/(v2, v3) |
| 282 // v6 <- +(v4, v5) |
| 283 // |
| 284 // IL optimized: |
| 285 // v4 <- DIVMOD(v2, v3); |
| 286 // v5 <- LoadIndexed(v4, 0); // ~/ result |
| 287 // v6 <- LoadIndexed(v4, 1); // % result |
| 288 // v7 <- +(v5, v6) |
| 289 // Because of the environment it is important that merged instruction replaces |
| 290 // first original instruction encountered. |
| 291 void FlowGraphOptimizer::TryMergeTruncDivMod( |
| 292 GrowableArray<BinarySmiOpInstr*>* merge_candidates) { |
| 293 if (merge_candidates->length() < 2) { |
| 294 // Need at least a TRUNCDIV and a MOD. |
| 295 return; |
| 296 } |
| 297 for (intptr_t i = 0; i < merge_candidates->length(); i++) { |
| 298 BinarySmiOpInstr* curr_instr = (*merge_candidates)[i]; |
| 299 if (curr_instr == NULL) { |
| 300 // Instructions was merged already. |
| 301 continue; |
| 302 } |
| 303 ASSERT((curr_instr->op_kind() == Token::kTRUNCDIV) || |
| 304 (curr_instr->op_kind() == Token::kMOD)); |
| 305 // Check if there is kMOD/kTRUNDIV binop with same inputs. |
| 306 const intptr_t other_kind = (curr_instr->op_kind() == Token::kTRUNCDIV) ? |
| 307 Token::kMOD : Token::kTRUNCDIV; |
| 308 Definition* left_def = curr_instr->left()->definition(); |
| 309 Definition* right_def = curr_instr->right()->definition(); |
| 310 for (intptr_t k = i + 1; k < merge_candidates->length(); k++) { |
| 311 BinarySmiOpInstr* other_binop = (*merge_candidates)[k]; |
| 312 // 'other_binop' can be NULL if it was already merged. |
| 313 if ((other_binop != NULL) && |
| 314 (other_binop->op_kind() == other_kind) && |
| 315 (other_binop->left()->definition() == left_def) && |
| 316 (other_binop->right()->definition() == right_def)) { |
| 317 (*merge_candidates)[k] = NULL; // Clear it. |
| 318 // Append a LoadIndexed behind TRUNC_DIV and MOD. |
| 319 DivModAppendLoadIndexed(curr_instr, flow_graph_); |
| 320 DivModAppendLoadIndexed(other_binop, flow_graph_); |
| 321 |
| 322 ZoneGrowableArray<Value*>* args = new ZoneGrowableArray<Value*>(2); |
| 323 args->Add(new Value(curr_instr->left()->definition())); |
| 324 args->Add(new Value(curr_instr->right()->definition())); |
| 325 |
| 326 // Replace with TruncDivMod. |
| 327 MergedMathInstr* div_mod = new MergedMathInstr( |
| 328 args, |
| 329 curr_instr->deopt_id(), |
| 330 MergedMathInstr::kTruncDivMod); |
| 331 curr_instr->ReplaceWith(div_mod, current_iterator()); |
| 332 other_binop->ReplaceUsesWith(div_mod); |
| 333 other_binop->RemoveFromGraph(); |
| 334 } |
| 335 } |
| 336 } |
| 337 } |
| 338 |
| 339 |
| 254 // Optimize (a << b) & c pattern: if c is a positive Smi or zero, then the | 340 // Optimize (a << b) & c pattern: if c is a positive Smi or zero, then the |
| 255 // shift can be a truncating Smi shift-left and result is always Smi. | 341 // shift can be a truncating Smi shift-left and result is always Smi. |
| 256 void FlowGraphOptimizer::TryOptimizeLeftShiftWithBitAndPattern() { | 342 // Merging occurs only per basic-block. |
| 343 void FlowGraphOptimizer::TryOptimizePatterns() { |
| 257 if (!FLAG_truncating_left_shift) return; | 344 if (!FLAG_truncating_left_shift) return; |
| 258 ASSERT(current_iterator_ == NULL); | 345 ASSERT(current_iterator_ == NULL); |
| 346 GrowableArray<BinarySmiOpInstr*> for_merge; |
| 259 for (intptr_t i = 0; i < block_order_.length(); ++i) { | 347 for (intptr_t i = 0; i < block_order_.length(); ++i) { |
| 348 // Merging only per basic-block. |
| 349 for_merge.Clear(); |
| 260 BlockEntryInstr* entry = block_order_[i]; | 350 BlockEntryInstr* entry = block_order_[i]; |
| 261 ForwardInstructionIterator it(entry); | 351 ForwardInstructionIterator it(entry); |
| 262 current_iterator_ = ⁢ | 352 current_iterator_ = ⁢ |
| 263 for (; !it.Done(); it.Advance()) { | 353 for (; !it.Done(); it.Advance()) { |
| 264 if (it.Current()->IsBinarySmiOp()) { | 354 if (it.Current()->IsBinarySmiOp()) { |
| 265 BinarySmiOpInstr* binop = it.Current()->AsBinarySmiOp(); | 355 BinarySmiOpInstr* binop = it.Current()->AsBinarySmiOp(); |
| 266 if (binop->op_kind() == Token::kBIT_AND) { | 356 if (binop->op_kind() == Token::kBIT_AND) { |
| 267 OptimizeLeftShiftBitAndSmiOp(binop, | 357 OptimizeLeftShiftBitAndSmiOp(binop, |
| 268 binop->left()->definition(), | 358 binop->left()->definition(), |
| 269 binop->right()->definition()); | 359 binop->right()->definition()); |
| 360 } else if ((binop->op_kind() == Token::kTRUNCDIV) || |
| 361 (binop->op_kind() == Token::kMOD)) { |
| 362 for_merge.Add(binop); |
| 270 } | 363 } |
| 271 } else if (it.Current()->IsBinaryMintOp()) { | 364 } else if (it.Current()->IsBinaryMintOp()) { |
| 272 BinaryMintOpInstr* mintop = it.Current()->AsBinaryMintOp(); | 365 BinaryMintOpInstr* mintop = it.Current()->AsBinaryMintOp(); |
| 273 if (mintop->op_kind() == Token::kBIT_AND) { | 366 if (mintop->op_kind() == Token::kBIT_AND) { |
| 274 OptimizeLeftShiftBitAndSmiOp(mintop, | 367 OptimizeLeftShiftBitAndSmiOp(mintop, |
| 275 mintop->left()->definition(), | 368 mintop->left()->definition(), |
| 276 mintop->right()->definition()); | 369 mintop->right()->definition()); |
| 277 } | 370 } |
| 278 } | 371 } |
| 279 } | 372 } |
| 373 TryMergeTruncDivMod(&for_merge); |
| 280 current_iterator_ = NULL; | 374 current_iterator_ = NULL; |
| 281 } | 375 } |
| 282 } | 376 } |
| 283 | 377 |
| 284 | 378 |
| 285 static void EnsureSSATempIndex(FlowGraph* graph, | 379 static void EnsureSSATempIndex(FlowGraph* graph, |
| 286 Definition* defn, | 380 Definition* defn, |
| 287 Definition* replacement) { | 381 Definition* replacement) { |
| 288 if ((replacement->ssa_temp_index() == -1) && | 382 if ((replacement->ssa_temp_index() == -1) && |
| 289 (defn->ssa_temp_index() != -1)) { | 383 (defn->ssa_temp_index() != -1)) { |
| (...skipping 6533 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6823 SetValue(instr, non_constant_); | 6917 SetValue(instr, non_constant_); |
| 6824 } | 6918 } |
| 6825 | 6919 |
| 6826 | 6920 |
| 6827 void ConstantPropagator::VisitInvokeMathCFunction( | 6921 void ConstantPropagator::VisitInvokeMathCFunction( |
| 6828 InvokeMathCFunctionInstr* instr) { | 6922 InvokeMathCFunctionInstr* instr) { |
| 6829 // TODO(kmillikin): Handle conversion. | 6923 // TODO(kmillikin): Handle conversion. |
| 6830 SetValue(instr, non_constant_); | 6924 SetValue(instr, non_constant_); |
| 6831 } | 6925 } |
| 6832 | 6926 |
| 6927 |
| 6928 void ConstantPropagator::VisitMergedMath(MergedMathInstr* instr) { |
| 6929 // TODO(srdjan): Handle merged instruction. |
| 6930 SetValue(instr, non_constant_); |
| 6931 } |
| 6932 |
| 6933 |
| 6833 void ConstantPropagator::VisitConstant(ConstantInstr* instr) { | 6934 void ConstantPropagator::VisitConstant(ConstantInstr* instr) { |
| 6834 SetValue(instr, instr->value()); | 6935 SetValue(instr, instr->value()); |
| 6835 } | 6936 } |
| 6836 | 6937 |
| 6837 | 6938 |
| 6838 void ConstantPropagator::VisitConstraint(ConstraintInstr* instr) { | 6939 void ConstantPropagator::VisitConstraint(ConstraintInstr* instr) { |
| 6839 // Should not be used outside of range analysis. | 6940 // Should not be used outside of range analysis. |
| 6840 UNREACHABLE(); | 6941 UNREACHABLE(); |
| 6841 } | 6942 } |
| 6842 | 6943 |
| (...skipping 1069 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7912 } | 8013 } |
| 7913 | 8014 |
| 7914 // Insert materializations at environment uses. | 8015 // Insert materializations at environment uses. |
| 7915 for (intptr_t i = 0; i < exits.length(); i++) { | 8016 for (intptr_t i = 0; i < exits.length(); i++) { |
| 7916 CreateMaterializationAt(exits[i], alloc, alloc->cls(), *fields); | 8017 CreateMaterializationAt(exits[i], alloc, alloc->cls(), *fields); |
| 7917 } | 8018 } |
| 7918 } | 8019 } |
| 7919 | 8020 |
| 7920 | 8021 |
| 7921 } // namespace dart | 8022 } // namespace dart |
| OLD | NEW |