mirror of
https://github.com/dart-lang/sdk
synced 2024-09-20 01:38:14 +00:00
Add a smi-check instruction for arithmetic smi operations.
The flowgraph optimizer inserts smi checks for the inputs of arithmetic smi operations: PushArgument v0 PushArgument v1 v2 <- InstanceCall(+, v0, v1) IC[1: Smi, Smi] becomes CheckSmi(v0) CheckSmi(v1) v2 <- BinarySmiOp(+, v0, v1) Each input operand is checked separately. This avoids using a temp register for a combined smi check. It also allows us to easily eliminate the checks for left and right input separately. There are two ways to eliminate smi checks: 1. By common subexpression elimination: if the value checked is already checked for smi-ness before. 2. By class-id propagation: If the input value is guaranteed to be a smi. Review URL: https://chromiumcodereview.appspot.com//10867012 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@11216 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
parent
5b27429411
commit
e450dfb95a
|
@ -77,7 +77,8 @@ DECLARE_RUNTIME_ENTRY(TraceFunctionExit);
|
|||
V(DeoptNoTypeFeedback) \
|
||||
V(DeoptSAR) \
|
||||
V(DeoptUnaryOp) \
|
||||
V(DeoptCheckClass)
|
||||
V(DeoptCheckClass) \
|
||||
V(DeoptCheckSmi)
|
||||
|
||||
enum DeoptReasonId {
|
||||
#define DEFINE_ENUM_LIST(name) k##name,
|
||||
|
|
|
@ -34,15 +34,18 @@ void FlowGraphOptimizer::OptimizeComputations() {
|
|||
BindInstr* instr = it.Current()->AsBind();
|
||||
if (instr != NULL) {
|
||||
Definition* result = instr->computation()->TryReplace(instr);
|
||||
if (result != NULL) {
|
||||
// Replace uses and remove the current instructions via the iterator.
|
||||
instr->ReplaceUsesWith(result);
|
||||
it.RemoveCurrentFromGraph();
|
||||
if (FLAG_trace_optimization) {
|
||||
OS::Print("Replacing v%d with v%d\n",
|
||||
instr->ssa_temp_index(),
|
||||
result->ssa_temp_index());
|
||||
if (result != instr) {
|
||||
if (result != NULL) {
|
||||
instr->ReplaceUsesWith(result);
|
||||
if (FLAG_trace_optimization) {
|
||||
OS::Print("Replacing v%d with v%d\n",
|
||||
instr->ssa_temp_index(),
|
||||
result->ssa_temp_index());
|
||||
}
|
||||
} else if (FLAG_trace_optimization) {
|
||||
OS::Print("Removing v%d.\n", instr->ssa_temp_index());
|
||||
}
|
||||
it.RemoveCurrentFromGraph();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -194,6 +197,19 @@ static intptr_t ReceiverClassId(Computation* comp) {
|
|||
}
|
||||
|
||||
|
||||
// Insert a check computation before an instruction and set the environment
|
||||
// of the check to the same as the instruction.
|
||||
static void InsertCheckBefore(BindInstr* instr,
|
||||
Computation* check,
|
||||
Environment* env) {
|
||||
BindInstr* check_instr = new BindInstr(BindInstr::kUnused, check);
|
||||
check_instr->InsertBefore(instr);
|
||||
ASSERT(env != NULL);
|
||||
// Attach an environment to the check instruction.
|
||||
check_instr->set_env(env);
|
||||
}
|
||||
|
||||
|
||||
static void AddCheckClass(BindInstr* instr,
|
||||
InstanceCallComp* comp,
|
||||
Value* value) {
|
||||
|
@ -202,11 +218,10 @@ static void AddCheckClass(BindInstr* instr,
|
|||
const ICData& unary_checks =
|
||||
ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecks());
|
||||
check->set_ic_data(&unary_checks);
|
||||
BindInstr* check_instr = new BindInstr(BindInstr::kUnused, check);
|
||||
ASSERT(instr->env() != NULL); // Always the case with SSA.
|
||||
// Attach the original environment to the check instruction.
|
||||
check_instr->set_env(instr->env());
|
||||
check_instr->InsertBefore(instr);
|
||||
InsertCheckBefore(instr, check, instr->env());
|
||||
// Detach environment from the original instruction because it can't
|
||||
// deoptimize.
|
||||
instr->set_env(NULL);
|
||||
}
|
||||
|
||||
|
||||
|
@ -317,6 +332,14 @@ bool FlowGraphOptimizer::TryReplaceWithBinaryOp(BindInstr* instr,
|
|||
ASSERT(operands_type == kSmiCid);
|
||||
Value* left = comp->ArgumentAt(0)->value();
|
||||
Value* right = comp->ArgumentAt(1)->value();
|
||||
// Insert two smi checks and attach a copy of the original
|
||||
// environment because the smi operation can still deoptimize.
|
||||
InsertCheckBefore(instr,
|
||||
new CheckSmiComp(left, comp),
|
||||
instr->env()->Copy());
|
||||
InsertCheckBefore(instr,
|
||||
new CheckSmiComp(right, comp),
|
||||
instr->env()->Copy());
|
||||
BinarySmiOpComp* bin_op = new BinarySmiOpComp(op_kind,
|
||||
comp,
|
||||
left,
|
||||
|
@ -391,8 +414,8 @@ bool FlowGraphOptimizer::TryInlineInstanceGetter(BindInstr* instr,
|
|||
String::Handle(Field::NameFromGetter(comp->function_name()));
|
||||
const Field& field = Field::Handle(GetField(class_ids[0], field_name));
|
||||
ASSERT(!field.IsNull());
|
||||
|
||||
AddCheckClass(instr, comp, comp->ArgumentAt(0)->value());
|
||||
instr->set_env(NULL);
|
||||
LoadInstanceFieldComp* load =
|
||||
new LoadInstanceFieldComp(field,
|
||||
comp->ArgumentAt(0)->value(),
|
||||
|
@ -573,7 +596,6 @@ bool FlowGraphOptimizer::TryInlineInstanceSetter(BindInstr* instr,
|
|||
ASSERT(!field.IsNull());
|
||||
|
||||
AddCheckClass(instr, comp, comp->ArgumentAt(0)->value());
|
||||
instr->set_env(NULL);
|
||||
StoreInstanceFieldComp* store = new StoreInstanceFieldComp(
|
||||
field,
|
||||
comp->ArgumentAt(0)->value(),
|
||||
|
|
|
@ -408,6 +408,16 @@ void UnarySmiOpComp::PrintOperandsTo(BufferFormatter* f) const {
|
|||
}
|
||||
|
||||
|
||||
void CheckClassComp::PrintOperandsTo(BufferFormatter* f) const {
|
||||
value()->PrintTo(f);
|
||||
f->Print(", cid={");
|
||||
for (intptr_t i = 0; i < ic_data()->NumberOfChecks(); i++) {
|
||||
f->Print("%d ", ic_data()->GetReceiverClassIdAt(i));
|
||||
}
|
||||
f->Print("}");
|
||||
}
|
||||
|
||||
|
||||
void GraphEntryInstr::PrintTo(BufferFormatter* f) const {
|
||||
f->Print("%2d: [graph]", block_id());
|
||||
if (start_env_ != NULL) {
|
||||
|
|
|
@ -1000,6 +1000,18 @@ intptr_t BinarySmiOpComp::ResultCid() const {
|
|||
}
|
||||
|
||||
|
||||
bool BinarySmiOpComp::CanDeoptimize() const {
|
||||
switch (op_kind()) {
|
||||
case Token::kBIT_AND:
|
||||
case Token::kBIT_OR:
|
||||
case Token::kBIT_XOR:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
RawAbstractType* BinaryMintOpComp::CompileType() const {
|
||||
ObjectStore* object_store = Isolate::Current()->object_store();
|
||||
return object_store->mint_type();
|
||||
|
@ -1047,33 +1059,52 @@ RawAbstractType* CheckClassComp::CompileType() const {
|
|||
}
|
||||
|
||||
|
||||
RawAbstractType* CheckSmiComp::CompileType() const {
|
||||
return AbstractType::null();
|
||||
}
|
||||
|
||||
|
||||
// Optimizations that eliminate or simplify individual computations.
|
||||
Definition* Computation::TryReplace(BindInstr* instr) const {
|
||||
return instr;
|
||||
}
|
||||
|
||||
|
||||
Definition* StrictCompareComp::TryReplace(BindInstr* instr) const {
|
||||
UseVal* left_use = left()->AsUse();
|
||||
UseVal* right_use = right()->AsUse();
|
||||
if ((right_use == NULL) || (left_use == NULL)) return instr;
|
||||
if (!right_use->BindsToConstant()) return instr;
|
||||
const Object& right_constant = right_use->BoundConstant();
|
||||
Definition* left = left_use->definition();
|
||||
// TODO(fschneider): Handle other cases: e === false and e !== true/false.
|
||||
// Handles e === true.
|
||||
if ((kind() == Token::kEQ_STRICT) &&
|
||||
(right_constant.raw() == Bool::True()) &&
|
||||
(left_use->ResultCid() == kBoolCid)) {
|
||||
// Remove the constant from the graph.
|
||||
BindInstr* right = right_use->definition()->AsBind();
|
||||
if (right != NULL) {
|
||||
right->set_use_list(NULL);
|
||||
right->RemoveFromGraph();
|
||||
}
|
||||
// Return left subexpression as the replacement for this instruction.
|
||||
return left;
|
||||
}
|
||||
return instr;
|
||||
}
|
||||
|
||||
|
||||
Definition* CheckSmiComp::TryReplace(BindInstr* instr) const {
|
||||
return (value()->ResultCid() == kSmiCid) ? NULL : instr;
|
||||
}
|
||||
|
||||
|
||||
// Shared code generation methods (EmitNativeCode, MakeLocationSummary, and
|
||||
// PrepareEntry). Only assembly code that can be shared across all architectures
|
||||
// can be used. Machine specific register allocation and code generation
|
||||
// is located in intermediate_language_<arch>.cc
|
||||
|
||||
|
||||
// True iff. the arguments to a call will be properly pushed and can
|
||||
// be popped after the call.
|
||||
template <typename T> static bool VerifyCallComputation(T* comp) {
|
||||
// Argument values should be consecutive temps.
|
||||
//
|
||||
// TODO(kmillikin): implement stack height tracking so we can also assert
|
||||
// they are on top of the stack.
|
||||
intptr_t previous = -1;
|
||||
for (int i = 0; i < comp->ArgumentCount(); ++i) {
|
||||
Value* val = comp->ArgumentAt(i);
|
||||
if (!val->IsUse()) return false;
|
||||
intptr_t current = val->AsUse()->definition()->temp_index();
|
||||
if (i != 0) {
|
||||
if (current != (previous + 1)) return false;
|
||||
}
|
||||
previous = current;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#define __ compiler->assembler()->
|
||||
|
||||
void GraphEntryInstr::PrepareEntry(FlowGraphCompiler* compiler) {
|
||||
|
@ -1248,31 +1279,6 @@ void StoreContextComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
}
|
||||
|
||||
|
||||
Definition* StrictCompareComp::TryReplace(BindInstr* instr) {
|
||||
UseVal* left_use = left()->AsUse();
|
||||
UseVal* right_use = right()->AsUse();
|
||||
if ((right_use == NULL) || (left_use == NULL)) return NULL;
|
||||
if (!right_use->BindsToConstant()) return NULL;
|
||||
const Object& right_constant = right_use->BoundConstant();
|
||||
Definition* left = left_use->definition();
|
||||
// TODO(fschneider): Handle other cases: e === false and e !== true/false.
|
||||
// Handles e === true.
|
||||
if ((kind() == Token::kEQ_STRICT) &&
|
||||
(right_constant.raw() == Bool::True()) &&
|
||||
(left_use->ResultCid() == kBoolCid)) {
|
||||
// Remove the constant from the graph.
|
||||
BindInstr* right = right_use->definition()->AsBind();
|
||||
if (right != NULL) {
|
||||
right->set_use_list(NULL);
|
||||
right->RemoveFromGraph();
|
||||
}
|
||||
// Return left subexpression as the replacement for this instruction.
|
||||
return left;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
LocationSummary* StrictCompareComp::MakeLocationSummary() const {
|
||||
return LocationSummary::Make(2,
|
||||
Location::SameAsFirstInput(),
|
||||
|
@ -1528,6 +1534,20 @@ Environment::Environment(const GrowableArray<Definition*>& definitions,
|
|||
}
|
||||
|
||||
|
||||
Environment* Environment::Copy() const {
|
||||
Environment* copy = new Environment(values().length(),
|
||||
fixed_parameter_count());
|
||||
GrowableArray<Value*>* values_copy = copy->values_ptr();
|
||||
for (intptr_t i = 0; i < values().length(); ++i) {
|
||||
Value* val = values()[i];
|
||||
values_copy->Add(val->IsUse()
|
||||
? UseDefinition(values()[i]->AsUse()->definition())
|
||||
: val);
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
|
||||
#undef __
|
||||
|
||||
} // namespace dart
|
||||
|
|
|
@ -103,6 +103,7 @@ class LocalVariable;
|
|||
M(DoubleToDouble, DoubleToDoubleComp) \
|
||||
M(SmiToDouble, SmiToDoubleComp) \
|
||||
M(CheckClass, CheckClassComp) \
|
||||
M(CheckSmi, CheckSmiComp) \
|
||||
M(Materialize, MaterializeComp)
|
||||
|
||||
|
||||
|
@ -152,9 +153,10 @@ class Computation : public ZoneAllocated {
|
|||
// Returns true, if this computation can deoptimize.
|
||||
virtual bool CanDeoptimize() const = 0;
|
||||
|
||||
// Optimize this computation. Returns a replacement for the instruction
|
||||
// that wraps this computation or NULL if nothing to replace.
|
||||
virtual Definition* TryReplace(BindInstr* instr) { return NULL; }
|
||||
// Returns a replacement for the instruction that wraps this computation.
|
||||
// Returns NULL if instr can be eliminated.
|
||||
// By default returns instr (input parameter) which means no change.
|
||||
virtual Definition* TryReplace(BindInstr* instr) const;
|
||||
|
||||
// Compares two computations. Returns true, if:
|
||||
// 1. They are of the same kind.
|
||||
|
@ -772,7 +774,8 @@ class StrictCompareComp : public ComparisonComp {
|
|||
|
||||
virtual bool CanDeoptimize() const { return false; }
|
||||
|
||||
virtual Definition* TryReplace(BindInstr* instr);
|
||||
virtual Definition* TryReplace(BindInstr* instr) const;
|
||||
|
||||
virtual intptr_t ResultCid() const { return kBoolCid; }
|
||||
|
||||
private:
|
||||
|
@ -1675,7 +1678,8 @@ class BinarySmiOpComp : public TemplateComputation<2> {
|
|||
|
||||
DECLARE_COMPUTATION(BinarySmiOp)
|
||||
|
||||
virtual bool CanDeoptimize() const { return true; }
|
||||
virtual bool CanDeoptimize() const;
|
||||
|
||||
virtual intptr_t ResultCid() const;
|
||||
|
||||
private:
|
||||
|
@ -1890,6 +1894,8 @@ class CheckClassComp : public TemplateComputation<1> {
|
|||
intptr_t deopt_id() const { return original_->deopt_id(); }
|
||||
intptr_t try_index() const { return original_->try_index(); }
|
||||
|
||||
virtual void PrintOperandsTo(BufferFormatter* f) const;
|
||||
|
||||
private:
|
||||
InstanceCallComp* original_;
|
||||
|
||||
|
@ -1897,6 +1903,36 @@ class CheckClassComp : public TemplateComputation<1> {
|
|||
};
|
||||
|
||||
|
||||
class CheckSmiComp : public TemplateComputation<1> {
|
||||
public:
|
||||
CheckSmiComp(Value* value, InstanceCallComp* original)
|
||||
: original_(original) {
|
||||
ASSERT(value != NULL);
|
||||
inputs_[0] = value;
|
||||
}
|
||||
|
||||
DECLARE_COMPUTATION(CheckSmi)
|
||||
|
||||
virtual bool CanDeoptimize() const { return true; }
|
||||
|
||||
virtual bool AttributesEqual(Computation* other) const { return true; }
|
||||
|
||||
virtual bool HasSideEffect() const { return false; }
|
||||
|
||||
virtual Definition* TryReplace(BindInstr* instr) const;
|
||||
|
||||
Value* value() const { return inputs_[0]; }
|
||||
|
||||
intptr_t deopt_id() const { return original_->deopt_id(); }
|
||||
intptr_t try_index() const { return original_->try_index(); }
|
||||
|
||||
private:
|
||||
InstanceCallComp* original_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(CheckSmiComp);
|
||||
};
|
||||
|
||||
|
||||
#undef DECLARE_COMPUTATION
|
||||
|
||||
|
||||
|
@ -3063,9 +3099,16 @@ class Environment : public ZoneAllocated {
|
|||
return fixed_parameter_count_;
|
||||
}
|
||||
|
||||
Environment* Copy() const;
|
||||
|
||||
void PrintTo(BufferFormatter* f) const;
|
||||
|
||||
private:
|
||||
Environment(intptr_t length, intptr_t fixed_parameter_count)
|
||||
: values_(length),
|
||||
locations_(NULL),
|
||||
fixed_parameter_count_(fixed_parameter_count) { }
|
||||
|
||||
GrowableArray<Value*> values_;
|
||||
Location* locations_;
|
||||
const intptr_t fixed_parameter_count_;
|
||||
|
|
|
@ -1422,13 +1422,12 @@ LocationSummary* BinarySmiOpComp::MakeLocationSummary() const {
|
|||
summary->set_temp(2, Location::RequiresRegister());
|
||||
return summary;
|
||||
} else if (op_kind() == Token::kSHR) {
|
||||
const intptr_t kNumTemps = 1;
|
||||
const intptr_t kNumTemps = 0;
|
||||
LocationSummary* summary =
|
||||
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
||||
summary->set_in(0, Location::RequiresRegister());
|
||||
summary->set_in(1, Location::RegisterLocation(ECX));
|
||||
summary->set_out(Location::SameAsFirstInput());
|
||||
summary->set_temp(0, Location::RequiresRegister());
|
||||
return summary;
|
||||
} else if (op_kind() == Token::kSHL) {
|
||||
// Two Smi operands can easily overflow into Mint.
|
||||
|
@ -1442,13 +1441,12 @@ LocationSummary* BinarySmiOpComp::MakeLocationSummary() const {
|
|||
summary->set_out(Location::RegisterLocation(EAX));
|
||||
return summary;
|
||||
} else {
|
||||
const intptr_t kNumTemps = 1;
|
||||
const intptr_t kNumTemps = 0;
|
||||
LocationSummary* summary =
|
||||
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
||||
summary->set_in(0, Location::RequiresRegister());
|
||||
summary->set_in(1, Location::RequiresRegister());
|
||||
summary->set_out(Location::SameAsFirstInput());
|
||||
summary->set_temp(0, Location::RequiresRegister());
|
||||
return summary;
|
||||
}
|
||||
}
|
||||
|
@ -1458,32 +1456,20 @@ void BinarySmiOpComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
Register left = locs()->in(0).reg();
|
||||
Register right = locs()->in(1).reg();
|
||||
Register result = locs()->out().reg();
|
||||
Register temp = locs()->temp(0).reg();
|
||||
ASSERT(left == result);
|
||||
const bool left_is_smi = this->left()->ResultCid() == kSmiCid;
|
||||
const bool right_is_smi = this->right()->ResultCid() == kSmiCid;
|
||||
bool can_deopt;
|
||||
Label* deopt = NULL;
|
||||
switch (op_kind()) {
|
||||
case Token::kBIT_AND:
|
||||
case Token::kBIT_OR:
|
||||
case Token::kBIT_XOR:
|
||||
can_deopt = !(right_is_smi && left_is_smi);
|
||||
// Can't deoptimize. Arguments are already checked for smi.
|
||||
break;
|
||||
default:
|
||||
can_deopt = true;
|
||||
}
|
||||
Label* deopt = NULL;
|
||||
if (can_deopt) {
|
||||
deopt = compiler->AddDeoptStub(instance_call()->deopt_id(),
|
||||
instance_call()->try_index(),
|
||||
kDeoptBinarySmiOp);
|
||||
}
|
||||
if (!left_is_smi || !right_is_smi) {
|
||||
__ movl(temp, left);
|
||||
__ orl(temp, right);
|
||||
__ testl(temp, Immediate(kSmiTagMask));
|
||||
__ j(NOT_ZERO, deopt);
|
||||
deopt = compiler->AddDeoptStub(instance_call()->deopt_id(),
|
||||
instance_call()->try_index(),
|
||||
kDeoptBinarySmiOp);
|
||||
}
|
||||
|
||||
switch (op_kind()) {
|
||||
case Token::kADD: {
|
||||
__ addl(left, right);
|
||||
|
@ -1517,6 +1503,7 @@ void BinarySmiOpComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
break;
|
||||
}
|
||||
case Token::kTRUNCDIV: {
|
||||
Register temp = locs()->temp(0).reg();
|
||||
// Handle divide by zero in runtime.
|
||||
// Deoptimization requires that temp and right are preserved.
|
||||
__ testl(right, right);
|
||||
|
@ -1557,6 +1544,7 @@ void BinarySmiOpComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
break;
|
||||
}
|
||||
case Token::kSHL: {
|
||||
Register temp = locs()->temp(0).reg();
|
||||
Label call_method, done;
|
||||
// Check if count too large for handling it inlined.
|
||||
__ movl(temp, left);
|
||||
|
@ -2186,6 +2174,27 @@ void CheckClassComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
__ Bind(&is_ok);
|
||||
}
|
||||
|
||||
|
||||
LocationSummary* CheckSmiComp::MakeLocationSummary() const {
|
||||
const intptr_t kNumInputs = 1;
|
||||
const intptr_t kNumTemps = 0;
|
||||
LocationSummary* summary =
|
||||
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
||||
summary->set_in(0, Location::RequiresRegister());
|
||||
return summary;
|
||||
}
|
||||
|
||||
|
||||
void CheckSmiComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
Register value = locs()->in(0).reg();
|
||||
Label* deopt = compiler->AddDeoptStub(deopt_id(),
|
||||
try_index(),
|
||||
kDeoptCheckSmi);
|
||||
__ testl(value, Immediate(kSmiTagMask));
|
||||
__ j(NOT_ZERO, deopt);
|
||||
}
|
||||
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#undef __
|
||||
|
|
|
@ -1438,13 +1438,12 @@ LocationSummary* BinarySmiOpComp::MakeLocationSummary() const {
|
|||
summary->set_temp(2, Location::RequiresRegister());
|
||||
return summary;
|
||||
} else if (op_kind() == Token::kSHR) {
|
||||
const intptr_t kNumTemps = 1;
|
||||
const intptr_t kNumTemps = 0;
|
||||
LocationSummary* summary =
|
||||
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
||||
summary->set_in(0, Location::RequiresRegister());
|
||||
summary->set_in(1, Location::RegisterLocation(RCX));
|
||||
summary->set_out(Location::SameAsFirstInput());
|
||||
summary->set_temp(0, Location::RequiresRegister());
|
||||
return summary;
|
||||
} else if (op_kind() == Token::kSHL) {
|
||||
// Two Smi operands can easily overflow into Mint.
|
||||
|
@ -1458,13 +1457,12 @@ LocationSummary* BinarySmiOpComp::MakeLocationSummary() const {
|
|||
summary->set_temp(1, Location::RegisterLocation(RCX));
|
||||
return summary;
|
||||
} else {
|
||||
const intptr_t kNumTemps = 1;
|
||||
const intptr_t kNumTemps = 0;
|
||||
LocationSummary* summary =
|
||||
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
||||
summary->set_in(0, Location::RequiresRegister());
|
||||
summary->set_in(1, Location::RequiresRegister());
|
||||
summary->set_out(Location::SameAsFirstInput());
|
||||
summary->set_temp(0, Location::RequiresRegister());
|
||||
return summary;
|
||||
}
|
||||
}
|
||||
|
@ -1474,31 +1472,18 @@ void BinarySmiOpComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
Register left = locs()->in(0).reg();
|
||||
Register right = locs()->in(1).reg();
|
||||
Register result = locs()->out().reg();
|
||||
Register temp = locs()->temp(0).reg();
|
||||
ASSERT(left == result);
|
||||
const bool left_is_smi = this->left()->ResultCid() == kSmiCid;
|
||||
const bool right_is_smi = this->right()->ResultCid() == kSmiCid;
|
||||
bool can_deopt;
|
||||
Label* deopt = NULL;
|
||||
switch (op_kind()) {
|
||||
case Token::kBIT_AND:
|
||||
case Token::kBIT_OR:
|
||||
case Token::kBIT_XOR:
|
||||
can_deopt = !(right_is_smi && left_is_smi);
|
||||
// Can't deoptimize. Arguments are already checked for smi.
|
||||
break;
|
||||
default:
|
||||
can_deopt = true;
|
||||
}
|
||||
Label* deopt = NULL;
|
||||
if (can_deopt) {
|
||||
deopt = compiler->AddDeoptStub(instance_call()->deopt_id(),
|
||||
instance_call()->try_index(),
|
||||
kDeoptBinarySmiOp);
|
||||
}
|
||||
if (!left_is_smi || !right_is_smi) {
|
||||
__ movq(temp, left);
|
||||
__ orq(temp, right);
|
||||
__ testq(temp, Immediate(kSmiTagMask));
|
||||
__ j(NOT_ZERO, deopt);
|
||||
deopt = compiler->AddDeoptStub(instance_call()->deopt_id(),
|
||||
instance_call()->try_index(),
|
||||
kDeoptBinarySmiOp);
|
||||
}
|
||||
switch (op_kind()) {
|
||||
case Token::kADD: {
|
||||
|
@ -1533,6 +1518,7 @@ void BinarySmiOpComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
break;
|
||||
}
|
||||
case Token::kTRUNCDIV: {
|
||||
Register temp = locs()->temp(0).reg();
|
||||
// Handle divide by zero in runtime.
|
||||
// Deoptimization requires that temp and right are preserved.
|
||||
__ testq(right, right);
|
||||
|
@ -1573,6 +1559,7 @@ void BinarySmiOpComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
break;
|
||||
}
|
||||
case Token::kSHL: {
|
||||
Register temp = locs()->temp(0).reg();
|
||||
Label call_method, done;
|
||||
// Check if count too large for handling it inlined.
|
||||
__ movq(temp, left);
|
||||
|
@ -2199,6 +2186,27 @@ void CheckClassComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
__ Bind(&is_ok);
|
||||
}
|
||||
|
||||
|
||||
LocationSummary* CheckSmiComp::MakeLocationSummary() const {
|
||||
const intptr_t kNumInputs = 1;
|
||||
const intptr_t kNumTemps = 0;
|
||||
LocationSummary* summary =
|
||||
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
||||
summary->set_in(0, Location::RequiresRegister());
|
||||
return summary;
|
||||
}
|
||||
|
||||
|
||||
void CheckSmiComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
Register value = locs()->in(0).reg();
|
||||
Label* deopt = compiler->AddDeoptStub(deopt_id(),
|
||||
try_index(),
|
||||
kDeoptCheckSmi);
|
||||
__ testq(value, Immediate(kSmiTagMask));
|
||||
__ j(NOT_ZERO, deopt);
|
||||
}
|
||||
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#undef __
|
||||
|
|
Loading…
Reference in a new issue