| Index: runtime/vm/aot_optimizer.cc
|
| diff --git a/runtime/vm/aot_optimizer.cc b/runtime/vm/aot_optimizer.cc
|
| index 8b279bdc358476984efcc8f54c712f5e2c1070e0..0fce824983e06c8838e640c7a2d3dd695d7b094f 100644
|
| --- a/runtime/vm/aot_optimizer.cc
|
| +++ b/runtime/vm/aot_optimizer.cc
|
| @@ -266,262 +266,6 @@ const ICData& AotOptimizer::TrySpecializeICData(const ICData& ic_data,
|
| }
|
|
|
|
|
| -static BinarySmiOpInstr* AsSmiShiftLeftInstruction(Definition* d) {
|
| - BinarySmiOpInstr* instr = d->AsBinarySmiOp();
|
| - if ((instr != NULL) && (instr->op_kind() == Token::kSHL)) {
|
| - return instr;
|
| - }
|
| - return NULL;
|
| -}
|
| -
|
| -
|
| -static bool IsPositiveOrZeroSmiConst(Definition* d) {
|
| - ConstantInstr* const_instr = d->AsConstant();
|
| - if ((const_instr != NULL) && (const_instr->value().IsSmi())) {
|
| - return Smi::Cast(const_instr->value()).Value() >= 0;
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -
|
| -void AotOptimizer::OptimizeLeftShiftBitAndSmiOp(
|
| - Definition* bit_and_instr,
|
| - Definition* left_instr,
|
| - Definition* right_instr) {
|
| - ASSERT(bit_and_instr != NULL);
|
| - ASSERT((left_instr != NULL) && (right_instr != NULL));
|
| -
|
| - // Check for pattern, smi_shift_left must be single-use.
|
| - bool is_positive_or_zero = IsPositiveOrZeroSmiConst(left_instr);
|
| - if (!is_positive_or_zero) {
|
| - is_positive_or_zero = IsPositiveOrZeroSmiConst(right_instr);
|
| - }
|
| - if (!is_positive_or_zero) return;
|
| -
|
| - BinarySmiOpInstr* smi_shift_left = NULL;
|
| - if (bit_and_instr->InputAt(0)->IsSingleUse()) {
|
| - smi_shift_left = AsSmiShiftLeftInstruction(left_instr);
|
| - }
|
| - if ((smi_shift_left == NULL) && (bit_and_instr->InputAt(1)->IsSingleUse())) {
|
| - smi_shift_left = AsSmiShiftLeftInstruction(right_instr);
|
| - }
|
| - if (smi_shift_left == NULL) return;
|
| -
|
| - // Pattern recognized.
|
| - smi_shift_left->mark_truncating();
|
| - ASSERT(bit_and_instr->IsBinarySmiOp() || bit_and_instr->IsBinaryMintOp());
|
| - if (bit_and_instr->IsBinaryMintOp()) {
|
| - // Replace Mint op with Smi op.
|
| - BinarySmiOpInstr* smi_op = new(Z) BinarySmiOpInstr(
|
| - Token::kBIT_AND,
|
| - new(Z) Value(left_instr),
|
| - new(Z) Value(right_instr),
|
| - Thread::kNoDeoptId); // BIT_AND cannot deoptimize.
|
| - bit_and_instr->ReplaceWith(smi_op, current_iterator());
|
| - }
|
| -}
|
| -
|
| -
|
| -void AotOptimizer::AppendExtractNthOutputForMerged(Definition* instr,
|
| - intptr_t index,
|
| - Representation rep,
|
| - intptr_t cid) {
|
| - ExtractNthOutputInstr* extract =
|
| - new(Z) ExtractNthOutputInstr(new(Z) Value(instr), index, rep, cid);
|
| - instr->ReplaceUsesWith(extract);
|
| - flow_graph()->InsertAfter(instr, extract, NULL, FlowGraph::kValue);
|
| -}
|
| -
|
| -
|
| -// Dart:
|
| -// var x = d % 10;
|
| -// var y = d ~/ 10;
|
| -// var z = x + y;
|
| -//
|
| -// IL:
|
| -// v4 <- %(v2, v3)
|
| -// v5 <- ~/(v2, v3)
|
| -// v6 <- +(v4, v5)
|
| -//
|
| -// IL optimized:
|
| -// v4 <- DIVMOD(v2, v3);
|
| -// v5 <- LoadIndexed(v4, 0); // ~/ result
|
| -// v6 <- LoadIndexed(v4, 1); // % result
|
| -// v7 <- +(v5, v6)
|
| -// Because of the environment it is important that merged instruction replaces
|
| -// first original instruction encountered.
|
| -void AotOptimizer::TryMergeTruncDivMod(
|
| - GrowableArray<BinarySmiOpInstr*>* merge_candidates) {
|
| - if (merge_candidates->length() < 2) {
|
| - // Need at least a TRUNCDIV and a MOD.
|
| - return;
|
| - }
|
| - for (intptr_t i = 0; i < merge_candidates->length(); i++) {
|
| - BinarySmiOpInstr* curr_instr = (*merge_candidates)[i];
|
| - if (curr_instr == NULL) {
|
| - // Instruction was merged already.
|
| - continue;
|
| - }
|
| - ASSERT((curr_instr->op_kind() == Token::kTRUNCDIV) ||
|
| - (curr_instr->op_kind() == Token::kMOD));
|
| - // Check if there is kMOD/kTRUNDIV binop with same inputs.
|
| - const intptr_t other_kind = (curr_instr->op_kind() == Token::kTRUNCDIV) ?
|
| - Token::kMOD : Token::kTRUNCDIV;
|
| - Definition* left_def = curr_instr->left()->definition();
|
| - Definition* right_def = curr_instr->right()->definition();
|
| - for (intptr_t k = i + 1; k < merge_candidates->length(); k++) {
|
| - BinarySmiOpInstr* other_binop = (*merge_candidates)[k];
|
| - // 'other_binop' can be NULL if it was already merged.
|
| - if ((other_binop != NULL) &&
|
| - (other_binop->op_kind() == other_kind) &&
|
| - (other_binop->left()->definition() == left_def) &&
|
| - (other_binop->right()->definition() == right_def)) {
|
| - (*merge_candidates)[k] = NULL; // Clear it.
|
| - ASSERT(curr_instr->HasUses());
|
| - AppendExtractNthOutputForMerged(
|
| - curr_instr,
|
| - MergedMathInstr::OutputIndexOf(curr_instr->op_kind()),
|
| - kTagged, kSmiCid);
|
| - ASSERT(other_binop->HasUses());
|
| - AppendExtractNthOutputForMerged(
|
| - other_binop,
|
| - MergedMathInstr::OutputIndexOf(other_binop->op_kind()),
|
| - kTagged, kSmiCid);
|
| -
|
| - ZoneGrowableArray<Value*>* args = new(Z) ZoneGrowableArray<Value*>(2);
|
| - args->Add(new(Z) Value(curr_instr->left()->definition()));
|
| - args->Add(new(Z) Value(curr_instr->right()->definition()));
|
| -
|
| - // Replace with TruncDivMod.
|
| - MergedMathInstr* div_mod = new(Z) MergedMathInstr(
|
| - args,
|
| - curr_instr->deopt_id(),
|
| - MergedMathInstr::kTruncDivMod);
|
| - curr_instr->ReplaceWith(div_mod, current_iterator());
|
| - other_binop->ReplaceUsesWith(div_mod);
|
| - other_binop->RemoveFromGraph();
|
| - // Only one merge possible. Because canonicalization happens later,
|
| - // more candidates are possible.
|
| - // TODO(srdjan): Allow merging of trunc-div/mod into truncDivMod.
|
| - break;
|
| - }
|
| - }
|
| - }
|
| -}
|
| -
|
| -
|
| -// Tries to merge MathUnary operations, in this case sinus and cosinus.
|
| -void AotOptimizer::TryMergeMathUnary(
|
| - GrowableArray<MathUnaryInstr*>* merge_candidates) {
|
| - if (!FlowGraphCompiler::SupportsSinCos() || !CanUnboxDouble() ||
|
| - !FLAG_merge_sin_cos) {
|
| - return;
|
| - }
|
| - if (merge_candidates->length() < 2) {
|
| - // Need at least a SIN and a COS.
|
| - return;
|
| - }
|
| - for (intptr_t i = 0; i < merge_candidates->length(); i++) {
|
| - MathUnaryInstr* curr_instr = (*merge_candidates)[i];
|
| - if (curr_instr == NULL) {
|
| - // Instruction was merged already.
|
| - continue;
|
| - }
|
| - const intptr_t kind = curr_instr->kind();
|
| - ASSERT((kind == MathUnaryInstr::kSin) ||
|
| - (kind == MathUnaryInstr::kCos));
|
| - // Check if there is sin/cos binop with same inputs.
|
| - const intptr_t other_kind = (kind == MathUnaryInstr::kSin) ?
|
| - MathUnaryInstr::kCos : MathUnaryInstr::kSin;
|
| - Definition* def = curr_instr->value()->definition();
|
| - for (intptr_t k = i + 1; k < merge_candidates->length(); k++) {
|
| - MathUnaryInstr* other_op = (*merge_candidates)[k];
|
| - // 'other_op' can be NULL if it was already merged.
|
| - if ((other_op != NULL) && (other_op->kind() == other_kind) &&
|
| - (other_op->value()->definition() == def)) {
|
| - (*merge_candidates)[k] = NULL; // Clear it.
|
| - ASSERT(curr_instr->HasUses());
|
| - AppendExtractNthOutputForMerged(curr_instr,
|
| - MergedMathInstr::OutputIndexOf(kind),
|
| - kUnboxedDouble, kDoubleCid);
|
| - ASSERT(other_op->HasUses());
|
| - AppendExtractNthOutputForMerged(
|
| - other_op,
|
| - MergedMathInstr::OutputIndexOf(other_kind),
|
| - kUnboxedDouble, kDoubleCid);
|
| - ZoneGrowableArray<Value*>* args = new(Z) ZoneGrowableArray<Value*>(1);
|
| - args->Add(new(Z) Value(curr_instr->value()->definition()));
|
| - // Replace with SinCos.
|
| - MergedMathInstr* sin_cos =
|
| - new(Z) MergedMathInstr(args,
|
| - curr_instr->DeoptimizationTarget(),
|
| - MergedMathInstr::kSinCos);
|
| - curr_instr->ReplaceWith(sin_cos, current_iterator());
|
| - other_op->ReplaceUsesWith(sin_cos);
|
| - other_op->RemoveFromGraph();
|
| - // Only one merge possible. Because canonicalization happens later,
|
| - // more candidates are possible.
|
| - // TODO(srdjan): Allow merging of sin/cos into sincos.
|
| - break;
|
| - }
|
| - }
|
| - }
|
| -}
|
| -
|
| -
|
| -// Optimize (a << b) & c pattern: if c is a positive Smi or zero, then the
|
| -// shift can be a truncating Smi shift-left and result is always Smi.
|
| -// Merging occurs only per basic-block.
|
| -void AotOptimizer::TryOptimizePatterns() {
|
| - if (!FLAG_truncating_left_shift) return;
|
| - ASSERT(current_iterator_ == NULL);
|
| - GrowableArray<BinarySmiOpInstr*> div_mod_merge;
|
| - GrowableArray<MathUnaryInstr*> sin_cos_merge;
|
| - for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator();
|
| - !block_it.Done();
|
| - block_it.Advance()) {
|
| - // Merging only per basic-block.
|
| - div_mod_merge.Clear();
|
| - sin_cos_merge.Clear();
|
| - ForwardInstructionIterator it(block_it.Current());
|
| - current_iterator_ = ⁢
|
| - for (; !it.Done(); it.Advance()) {
|
| - if (it.Current()->IsBinarySmiOp()) {
|
| - BinarySmiOpInstr* binop = it.Current()->AsBinarySmiOp();
|
| - if (binop->op_kind() == Token::kBIT_AND) {
|
| - OptimizeLeftShiftBitAndSmiOp(binop,
|
| - binop->left()->definition(),
|
| - binop->right()->definition());
|
| - } else if ((binop->op_kind() == Token::kTRUNCDIV) ||
|
| - (binop->op_kind() == Token::kMOD)) {
|
| - if (binop->HasUses()) {
|
| - div_mod_merge.Add(binop);
|
| - }
|
| - }
|
| - } else if (it.Current()->IsBinaryMintOp()) {
|
| - BinaryMintOpInstr* mintop = it.Current()->AsBinaryMintOp();
|
| - if (mintop->op_kind() == Token::kBIT_AND) {
|
| - OptimizeLeftShiftBitAndSmiOp(mintop,
|
| - mintop->left()->definition(),
|
| - mintop->right()->definition());
|
| - }
|
| - } else if (it.Current()->IsMathUnary()) {
|
| - MathUnaryInstr* math_unary = it.Current()->AsMathUnary();
|
| - if ((math_unary->kind() == MathUnaryInstr::kSin) ||
|
| - (math_unary->kind() == MathUnaryInstr::kCos)) {
|
| - if (math_unary->HasUses()) {
|
| - sin_cos_merge.Add(math_unary);
|
| - }
|
| - }
|
| - }
|
| - }
|
| - TryMergeTruncDivMod(&div_mod_merge);
|
| - TryMergeMathUnary(&sin_cos_merge);
|
| - current_iterator_ = NULL;
|
| - }
|
| -}
|
| -
|
| -
|
| static bool ClassIdIsOneOf(intptr_t class_id,
|
| const GrowableArray<intptr_t>& class_ids) {
|
| for (intptr_t i = 0; i < class_ids.length(); i++) {
|
|
|