| Index: runtime/vm/intermediate_language.cc
|
| diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
|
| index fa9a5eda03d338f8a79dce05f1fd3e2c7043a454..ed4036a5a46496334e6e3874079d3ee9f2389df7 100644
|
| --- a/runtime/vm/intermediate_language.cc
|
| +++ b/runtime/vm/intermediate_language.cc
|
| @@ -312,6 +312,15 @@ bool BinarySmiOpInstr::AttributesEqual(Instruction* other) const {
|
| }
|
|
|
|
|
| +bool BinaryInt32OpInstr::AttributesEqual(Instruction* other) const {
|
| + BinaryInt32OpInstr* other_op = other->AsBinaryInt32Op();
|
| + ASSERT(other_op != NULL);
|
| + return (op_kind() == other_op->op_kind()) &&
|
| + (overflow_ == other_op->overflow_) &&
|
| + (is_truncating_ == other_op->is_truncating_);
|
| +}
|
| +
|
| +
|
| EffectSet LoadFieldInstr::Dependencies() const {
|
| return immutable_ ? EffectSet::None() : EffectSet::All();
|
| }
|
| @@ -388,12 +397,16 @@ bool ConstantInstr::AttributesEqual(Instruction* other) const {
|
| }
|
|
|
|
|
| -UnboxedConstantInstr::UnboxedConstantInstr(const Object& value)
|
| - : ConstantInstr(value), constant_address_(0) {
|
| - // Only doubles supported for now.
|
| - ASSERT(value.IsDouble());
|
| - constant_address_ =
|
| - FlowGraphBuilder::FindDoubleConstant(Double::Cast(value).value());
|
| +UnboxedConstantInstr::UnboxedConstantInstr(const Object& value,
|
| + Representation representation)
|
| + : ConstantInstr(value),
|
| + representation_(representation),
|
| + constant_address_(0) {
|
| + if (representation_ == kUnboxedDouble) {
|
| + ASSERT(value.IsDouble());
|
| + constant_address_ =
|
| + FlowGraphBuilder::FindDoubleConstant(Double::Cast(value).value());
|
| + }
|
| }
|
|
|
|
|
| @@ -678,7 +691,9 @@ void Value::RemoveFromUseList() {
|
| // True if the definition has a single input use and is used only in
|
| // environments at the same instruction as that input use.
|
| bool Definition::HasOnlyUse(Value* use) const {
|
| - if ((input_use_list() != use) || (use->next_use() != NULL)) return false;
|
| + if (!HasOnlyInputUse(use)) {
|
| + return false;
|
| + }
|
|
|
| Instruction* target = use->instruction();
|
| for (Value::Iterator it(env_use_list()); !it.Done(); it.Advance()) {
|
| @@ -688,6 +703,11 @@ bool Definition::HasOnlyUse(Value* use) const {
|
| }
|
|
|
|
|
| +bool Definition::HasOnlyInputUse(Value* use) const {
|
| + return (input_use_list() == use) && (use->next_use() == NULL);
|
| +}
|
| +
|
| +
|
| void Definition::ReplaceUsesWith(Definition* other) {
|
| ASSERT(other != NULL);
|
| ASSERT(this != other);
|
| @@ -1149,6 +1169,49 @@ void Instruction::Goto(JoinEntryInstr* entry) {
|
| }
|
|
|
|
|
| +bool UnboxedIntConverterInstr::CanDeoptimize() const {
|
| + return (to() == kUnboxedInt32) &&
|
| + !Range::Fits(value()->definition()->range(),
|
| + RangeBoundary::kRangeBoundaryInt32);
|
| +}
|
| +
|
| +
|
| +bool UnboxInt32Instr::CanDeoptimize() const {
|
| + const intptr_t value_cid = value()->Type()->ToCid();
|
| + if (value_cid == kSmiCid) {
|
| + return false;
|
| + } else if (value_cid == kMintCid) {
|
| + return !Range::Fits(value()->definition()->range(),
|
| + RangeBoundary::kRangeBoundaryInt32);
|
| + } else {
|
| + return true;
|
| + }
|
| +}
|
| +
|
| +
|
| +bool BinaryInt32OpInstr::CanDeoptimize() const {
|
| + switch (op_kind()) {
|
| + case Token::kBIT_AND:
|
| + case Token::kBIT_OR:
|
| + case Token::kBIT_XOR:
|
| + return false;
|
| +
|
| + case Token::kSHR:
|
| + return false;
|
| +
|
| + case Token::kSHL:
|
| + return true;
|
| +
|
| + case Token::kMOD: {
|
| + UNREACHABLE();
|
| + }
|
| +
|
| + default:
|
| + return overflow_;
|
| + }
|
| +}
|
| +
|
| +
|
| bool BinarySmiOpInstr::CanDeoptimize() const {
|
| if (FLAG_throw_on_javascript_int_overflow && (Smi::kBits > 32)) {
|
| // If Smi's are bigger than 32-bits, then the instruction could deoptimize
|
| @@ -1425,6 +1488,29 @@ Definition* BinaryUint32OpInstr::Canonicalize(FlowGraph* flow_graph) {
|
| }
|
|
|
|
|
| +Definition* BinaryInt32OpInstr::Canonicalize(FlowGraph* flow_graph) {
|
| + Definition* result = NULL;
|
| +
|
| + result = CanonicalizeCommutativeArithmetic(op_kind(),
|
| + kSmiCid,
|
| + left(),
|
| + right());
|
| + if (result != NULL) {
|
| + return result;
|
| + }
|
| +
|
| + result = CanonicalizeCommutativeArithmetic(op_kind(),
|
| + kSmiCid,
|
| + right(),
|
| + left());
|
| + if (result != NULL) {
|
| + return result;
|
| + }
|
| +
|
| + return this;
|
| +}
|
| +
|
| +
|
| // Optimizations that eliminate or simplify individual instructions.
|
| Instruction* Instruction::Canonicalize(FlowGraph* flow_graph) {
|
| return this;
|
| @@ -1623,6 +1709,103 @@ Definition* BoxDoubleInstr::Canonicalize(FlowGraph* flow_graph) {
|
| }
|
|
|
|
|
| +bool BoxIntNInstr::ValueFitsSmi() const {
|
| + Range* range = value()->definition()->range();
|
| + return Range::Fits(range, RangeBoundary::kRangeBoundarySmi);
|
| +}
|
| +
|
| +
|
| +Definition* BoxIntNInstr::Canonicalize(FlowGraph* flow_graph) {
|
| + if ((input_use_list() == NULL) && !HasTryBlockUse(env_use_list())) {
|
| + // Environments can accomodate any representation. No need to box.
|
| + return value()->definition();
|
| + }
|
| +
|
| + return this;
|
| +}
|
| +
|
| +
|
| +Definition* UnboxIntNInstr::Canonicalize(FlowGraph* flow_graph) {
|
| + if (!HasUses()) return NULL;
|
| +
|
| + // Fold away UnboxInt<N>Instr(BoxInt<N>Instr(v)).
|
| + BoxIntNInstr* box_defn = value()->definition()->AsBoxIntN();
|
| + if (box_defn != NULL) {
|
| + if (box_defn->value()->definition()->representation() == representation()) {
|
| + return box_defn->value()->definition();
|
| + } else {
|
| + UnboxedIntConverterInstr* converter = new UnboxedIntConverterInstr(
|
| + box_defn->value()->definition()->representation(),
|
| + representation(),
|
| + box_defn->value()->CopyWithType(),
|
| + representation() == kUnboxedInt32 ? deopt_id_ : Isolate::kNoDeoptId);
|
| + flow_graph->InsertBefore(this, converter, env(), FlowGraph::kValue);
|
| + return converter;
|
| + }
|
| + }
|
| +
|
| + return this;
|
| +}
|
| +
|
| +
|
| +Definition* UnboxedIntConverterInstr::Canonicalize(FlowGraph* flow_graph) {
|
| + if (!HasUses()) return NULL;
|
| +
|
| + UnboxedIntConverterInstr* box_defn =
|
| + value()->definition()->AsUnboxedIntConverter();
|
| + if ((box_defn != NULL) && (box_defn->representation() == from())) {
|
| + if (box_defn->from() == to()) {
|
| + return box_defn->value()->definition();
|
| + }
|
| +
|
| + UnboxedIntConverterInstr* converter = new UnboxedIntConverterInstr(
|
| + box_defn->from(),
|
| + representation(),
|
| + box_defn->value()->CopyWithType(),
|
| + to() == kUnboxedInt32 ? deopt_id_ : NULL);
|
| + flow_graph->InsertBefore(this, converter, env(), FlowGraph::kValue);
|
| + return converter;
|
| + }
|
| +
|
| + UnboxIntegerInstr* unbox_defn = value()->definition()->AsUnboxInteger();
|
| + if (unbox_defn != NULL &&
|
| + (from() == kUnboxedMint) &&
|
| + (to() == kUnboxedInt32) &&
|
| + unbox_defn->HasOnlyInputUse(value())) {
|
| + // TODO(vegorov): there is a duplication of code between UnboxedIntCoverter
|
| + // and code path that unboxes Mint into Int32. We should just schedule
|
| + // these instructions close to each other instead of fusing them.
|
| + Definition* replacement =
|
| + new UnboxInt32Instr(unbox_defn->value()->CopyWithType(), deopt_id_);
|
| + flow_graph->InsertBefore(this,
|
| + replacement,
|
| + env(),
|
| + FlowGraph::kValue);
|
| + return replacement;
|
| + }
|
| +
|
| + return this;
|
| +}
|
| +
|
| +
|
| +Definition* UnboxInt32Instr::Canonicalize(FlowGraph* flow_graph) {
|
| + Definition* replacement = UnboxIntNInstr::Canonicalize(flow_graph);
|
| + if (replacement != this) {
|
| + return replacement;
|
| + }
|
| +
|
| + ConstantInstr* c = value()->definition()->AsConstant();
|
| + if ((c != NULL) && c->value().IsSmi()) {
|
| + UnboxedConstantInstr* uc =
|
| + new UnboxedConstantInstr(c->value(), kUnboxedInt32);
|
| + flow_graph->InsertBefore(this, uc, NULL, FlowGraph::kValue);
|
| + return uc;
|
| + }
|
| +
|
| + return this;
|
| +}
|
| +
|
| +
|
| Definition* UnboxDoubleInstr::Canonicalize(FlowGraph* flow_graph) {
|
| if (!HasUses()) return NULL;
|
| // Fold away UnboxDouble(BoxDouble(v)).
|
| @@ -1633,7 +1816,8 @@ Definition* UnboxDoubleInstr::Canonicalize(FlowGraph* flow_graph) {
|
|
|
| ConstantInstr* c = value()->definition()->AsConstant();
|
| if ((c != NULL) && c->value().IsDouble()) {
|
| - UnboxedConstantInstr* uc = new UnboxedConstantInstr(c->value());
|
| + UnboxedConstantInstr* uc =
|
| + new UnboxedConstantInstr(c->value(), kUnboxedDouble);
|
| flow_graph->InsertBefore(this, uc, NULL, FlowGraph::kValue);
|
| return uc;
|
| }
|
| @@ -1642,6 +1826,49 @@ Definition* UnboxDoubleInstr::Canonicalize(FlowGraph* flow_graph) {
|
| }
|
|
|
|
|
| +Definition* BoxIntegerInstr::Canonicalize(FlowGraph* flow_graph) {
|
| + if ((input_use_list() == NULL) && !HasTryBlockUse(env_use_list())) {
|
| + // Environments can accomodate any representation. No need to box.
|
| + return value()->definition();
|
| + }
|
| +
|
| + UnboxedIntConverterInstr* conv =
|
| + value()->definition()->AsUnboxedIntConverter();
|
| + if (conv != NULL) {
|
| + Definition* replacement = this;
|
| +
|
| + switch (conv->from()) {
|
| + case kUnboxedInt32:
|
| + replacement = new BoxInt32Instr(conv->value()->CopyWithType());
|
| + break;
|
| + case kUnboxedUint32:
|
| + replacement = new BoxUint32Instr(conv->value()->CopyWithType());
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + break;
|
| + }
|
| +
|
| + if (replacement != this) {
|
| + flow_graph->InsertBefore(this,
|
| + replacement,
|
| + NULL,
|
| + FlowGraph::kValue);
|
| + }
|
| +
|
| + return replacement;
|
| + }
|
| +
|
| + return this;
|
| +}
|
| +
|
| +
|
| +Definition* UnboxIntegerInstr::Canonicalize(FlowGraph* flow_graph) {
|
| + if (!HasUses()) return NULL;
|
| + return this;
|
| +}
|
| +
|
| +
|
| Definition* BoxFloat32x4Instr::Canonicalize(FlowGraph* flow_graph) {
|
| if ((input_use_list() == NULL) && !HasTryBlockUse(env_use_list())) {
|
| // Environments can accomodate any representation. No need to box.
|
|
|