[vm/compiler] Cleanup CheckedSmi* instructions

This is a final cleanup of CheckedSmiOpInstr and
CheckedSmiComparisonInstr instructions.

Their uses were removed in the following changes:

  https://dart-review.googlesource.com/c/sdk/+/191761
  https://dart-review.googlesource.com/c/sdk/+/191760
  https://dart-review.googlesource.com/c/sdk/+/193447

TEST=ci
Issue: https://github.com/dart-lang/sdk/issues/44852
Change-Id: Ica52ab9e2fcabab1913228818642a27a8d842f92
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/193449
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Ryan Macnak <rmacnak@google.com>
This commit is contained in:
Alexander Markov
2021-03-31 22:10:42 +00:00
committed by commit-bot@chromium.org
parent db0fa84d59
commit 2a14259fd0
13 changed files with 3 additions and 1239 deletions
-7
View File
@@ -3249,13 +3249,6 @@ class MegamorphicCacheDeserializationCluster : public DeserializationCluster {
// In --use-bare-instruction we reduce the extra indirection via the
// [Function] object by storing the entry point directly into the hashmap.
//
// Currently our AOT compiler will emit megamorphic calls in certain
// situations (namely in slow-path code of CheckedSmi* instructions).
//
// TODO(compiler-team): Change the CheckedSmi* slow path code to use
// normal switchable calls instead of megamorphic calls. (This is also a
// memory balance beause [MegamorphicCache]s are per-selector while
// [ICData] are per-callsite.)
auto& cache = MegamorphicCache::Handle(d->zone());
for (intptr_t i = start_index_; i < stop_index_; ++i) {
cache ^= refs.At(i);
@@ -59,12 +59,12 @@ class AotCallSpecializer : public CallSpecializer {
const Function& InterfaceTargetForTableDispatch(InstanceCallBaseInstr* call);
// Try to replace a call with a more specialized instruction working on
// integers (e.g. BinaryInt64OpInstr, CheckedSmiComparisonInstr,
// integers (e.g. BinaryInt64OpInstr, EqualityCompareInstr,
// RelationalOpInstr)
bool TryOptimizeIntegerOperation(TemplateDartCall<0>* call, Token::Kind kind);
// Try to replace a call with a more specialized instruction working on
// doubles (e.g. BinaryDoubleOpInstr, CheckedSmiComparisonInstr,
// doubles (e.g. BinaryDoubleOpInstr, EqualityCompareInstr,
// RelationalOpInstr)
bool TryOptimizeDoubleOperation(TemplateDartCall<0>* call, Token::Kind kind);
@@ -1155,15 +1155,6 @@ void ConstantPropagator::VisitBinaryIntegerOp(BinaryIntegerOpInstr* binary_op) {
SetValue(binary_op, non_constant_);
}
void ConstantPropagator::VisitCheckedSmiOp(CheckedSmiOpInstr* instr) {
SetValue(instr, non_constant_);
}
void ConstantPropagator::VisitCheckedSmiComparison(
CheckedSmiComparisonInstr* instr) {
SetValue(instr, non_constant_);
}
void ConstantPropagator::VisitBinarySmiOp(BinarySmiOpInstr* instr) {
VisitBinaryIntegerOp(instr);
}
@@ -983,8 +983,6 @@ class FlowGraphCompiler : public ValueObject {
friend class StoreIndexedInstr; // For AddPcRelativeCallStubTarget().
friend class StoreInstanceFieldInstr; // For AddPcRelativeCallStubTarget().
friend class CheckStackOverflowSlowPath; // For pending_deoptimization_env_.
friend class CheckedSmiSlowPath; // Same.
friend class CheckedSmiComparisonSlowPath; // Same.
friend class GraphInstrinsicCodeGenScope; // For optimizing_.
// Architecture specific implementation of simple native moves.
-73
View File
@@ -2437,79 +2437,6 @@ BinaryIntegerOpInstr* BinaryIntegerOpInstr::Make(
return op;
}
Definition* CheckedSmiOpInstr::Canonicalize(FlowGraph* flow_graph) {
if ((left()->Type()->ToCid() == kSmiCid) &&
(right()->Type()->ToCid() == kSmiCid)) {
Definition* replacement = NULL;
// Operations that can't deoptimize are specialized here: These include
// bit-wise operators and comparisons. Other arithmetic operations can
// overflow or divide by 0 and can't be specialized unless we have extra
// range information.
switch (op_kind()) {
case Token::kBIT_AND:
FALL_THROUGH;
case Token::kBIT_OR:
FALL_THROUGH;
case Token::kBIT_XOR:
replacement = new BinarySmiOpInstr(
op_kind(), new Value(left()->definition()),
new Value(right()->definition()), DeoptId::kNone);
FALL_THROUGH;
default:
break;
}
if (replacement != NULL) {
flow_graph->InsertBefore(this, replacement, env(), FlowGraph::kValue);
return replacement;
}
}
return this;
}
ComparisonInstr* CheckedSmiComparisonInstr::CopyWithNewOperands(Value* left,
Value* right) {
UNREACHABLE();
return NULL;
}
Definition* CheckedSmiComparisonInstr::Canonicalize(FlowGraph* flow_graph) {
CompileType* left_type = left()->Type();
CompileType* right_type = right()->Type();
intptr_t op_cid = kIllegalCid;
SpeculativeMode speculative_mode = kGuardInputs;
if ((left_type->ToCid() == kSmiCid) && (right_type->ToCid() == kSmiCid)) {
op_cid = kSmiCid;
} else if ( // TODO(dartbug.com/30480): handle nullable types here
left_type->IsNullableInt() && !left_type->is_nullable() &&
right_type->IsNullableInt() && !right_type->is_nullable()) {
op_cid = kMintCid;
speculative_mode = kNotSpeculative;
}
if (op_cid != kIllegalCid) {
Definition* replacement = NULL;
if (Token::IsRelationalOperator(kind())) {
replacement = new RelationalOpInstr(
source(), kind(), left()->CopyWithType(), right()->CopyWithType(),
op_cid, DeoptId::kNone, speculative_mode);
} else if (Token::IsEqualityOperator(kind())) {
replacement = new EqualityCompareInstr(
source(), kind(), left()->CopyWithType(), right()->CopyWithType(),
op_cid, DeoptId::kNone, /*null_aware=*/false, speculative_mode);
}
if (replacement != NULL) {
if (FLAG_trace_strong_mode_types && (op_cid == kMintCid)) {
THR_Print("[Strong mode] Optimization: replacing %s with %s\n",
ToCString(), replacement->ToCString());
}
flow_graph->InsertBefore(this, replacement, env(), FlowGraph::kValue);
return replacement;
}
}
return this;
}
Definition* BinaryIntegerOpInstr::Canonicalize(FlowGraph* flow_graph) {
// If both operands are constants evaluate this expression. Might
// occur due to load forwarding after constant propagation pass
-96
View File
@@ -440,8 +440,6 @@ struct InstrAttrs {
M(AllocateUninitializedContext, _) \
M(CloneContext, _) \
M(BinarySmiOp, kNoGC) \
M(CheckedSmiComparison, _) \
M(CheckedSmiOp, _) \
M(BinaryInt32Op, kNoGC) \
M(UnarySmiOp, kNoGC) \
M(UnaryDoubleOp, kNoGC) \
@@ -7617,100 +7615,6 @@ class UnaryInt64OpInstr : public UnaryIntegerOpInstr {
DISALLOW_COPY_AND_ASSIGN(UnaryInt64OpInstr);
};
class CheckedSmiOpInstr : public TemplateDefinition<2, Throws> {
public:
CheckedSmiOpInstr(Token::Kind op_kind,
Value* left,
Value* right,
TemplateDartCall<0>* call)
: TemplateDefinition(call->deopt_id()), call_(call), op_kind_(op_kind) {
ASSERT(call->type_args_len() == 0);
ASSERT(!call->IsInstanceCallBase() ||
call->AsInstanceCallBase()->CanReceiverBeSmiBasedOnInterfaceTarget(
Thread::Current()->zone()));
SetInputAt(0, left);
SetInputAt(1, right);
}
TemplateDartCall<0>* call() const { return call_; }
Token::Kind op_kind() const { return op_kind_; }
Value* left() const { return inputs_[0]; }
Value* right() const { return inputs_[1]; }
virtual bool ComputeCanDeoptimize() const { return false; }
virtual CompileType ComputeType() const;
virtual bool RecomputeType();
virtual bool HasUnknownSideEffects() const { return true; }
virtual bool CanCallDart() const { return true; }
virtual Definition* Canonicalize(FlowGraph* flow_graph);
PRINT_OPERANDS_TO_SUPPORT
DECLARE_INSTRUCTION(CheckedSmiOp)
private:
TemplateDartCall<0>* call_;
const Token::Kind op_kind_;
DISALLOW_COPY_AND_ASSIGN(CheckedSmiOpInstr);
};
class CheckedSmiComparisonInstr : public TemplateComparison<2, Throws> {
public:
CheckedSmiComparisonInstr(Token::Kind op_kind,
Value* left,
Value* right,
TemplateDartCall<0>* call)
: TemplateComparison(call->source(), op_kind, call->deopt_id()),
call_(call),
is_negated_(false) {
ASSERT(call->type_args_len() == 0);
ASSERT(!call->IsInstanceCallBase() ||
call->AsInstanceCallBase()->CanReceiverBeSmiBasedOnInterfaceTarget(
Thread::Current()->zone()));
SetInputAt(0, left);
SetInputAt(1, right);
}
TemplateDartCall<0>* call() const { return call_; }
virtual bool ComputeCanDeoptimize() const { return false; }
virtual CompileType ComputeType() const;
virtual Definition* Canonicalize(FlowGraph* flow_graph);
virtual void NegateComparison() {
ComparisonInstr::NegateComparison();
is_negated_ = !is_negated_;
}
bool is_negated() const { return is_negated_; }
virtual bool HasUnknownSideEffects() const { return true; }
virtual bool CanCallDart() const { return true; }
PRINT_OPERANDS_TO_SUPPORT
DECLARE_INSTRUCTION(CheckedSmiComparison)
virtual void EmitBranchCode(FlowGraphCompiler* compiler, BranchInstr* branch);
virtual Condition EmitComparisonCode(FlowGraphCompiler* compiler,
BranchLabels labels);
virtual ComparisonInstr* CopyWithNewOperands(Value* left, Value* right);
private:
TemplateDartCall<0>* call_;
bool is_negated_;
DISALLOW_COPY_AND_ASSIGN(CheckedSmiComparisonInstr);
};
class BinaryIntegerOpInstr : public TemplateDefinition<2, NoThrow, Pure> {
public:
BinaryIntegerOpInstr(Token::Kind op_kind,
-328
View File
@@ -3897,334 +3897,6 @@ static void EmitSmiShiftLeft(FlowGraphCompiler* compiler,
}
}
class CheckedSmiSlowPath : public TemplateSlowPathCode<CheckedSmiOpInstr> {
public:
CheckedSmiSlowPath(CheckedSmiOpInstr* instruction, intptr_t try_index)
: TemplateSlowPathCode(instruction), try_index_(try_index) {}
static constexpr intptr_t kNumSlowPathArgs = 2;
virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
if (compiler::Assembler::EmittingComments()) {
__ Comment("slow path smi operation");
}
__ Bind(entry_label());
LocationSummary* locs = instruction()->locs();
Register result = locs->out(0).reg();
locs->live_registers()->Remove(Location::RegisterLocation(result));
compiler->SaveLiveRegisters(locs);
if (instruction()->env() != NULL) {
Environment* env =
compiler->SlowPathEnvironmentFor(instruction(), kNumSlowPathArgs);
compiler->pending_deoptimization_env_ = env;
}
__ Push(locs->in(0).reg());
__ Push(locs->in(1).reg());
const auto& selector = String::Handle(instruction()->call()->Selector());
const auto& arguments_descriptor =
Array::Handle(ArgumentsDescriptor::NewBoxed(
/*type_args_len=*/0, /*num_arguments=*/2));
compiler->EmitMegamorphicInstanceCall(
selector, arguments_descriptor, instruction()->call()->deopt_id(),
instruction()->source(), locs, try_index_, kNumSlowPathArgs);
__ mov(result, compiler::Operand(R0));
compiler->RestoreLiveRegisters(locs);
__ b(exit_label());
compiler->pending_deoptimization_env_ = NULL;
}
private:
intptr_t try_index_;
};
LocationSummary* CheckedSmiOpInstr::MakeLocationSummary(Zone* zone,
bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* summary = new (zone) LocationSummary(
zone, kNumInputs, kNumTemps, LocationSummary::kCallOnSlowPath);
summary->set_in(0, Location::RequiresRegister());
summary->set_in(1, Location::RequiresRegister());
summary->set_out(0, Location::RequiresRegister());
return summary;
}
void CheckedSmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
CheckedSmiSlowPath* slow_path =
new CheckedSmiSlowPath(this, compiler->CurrentTryIndex());
compiler->AddSlowPathCode(slow_path);
// Test operands if necessary.
Register left = locs()->in(0).reg();
Register right = locs()->in(1).reg();
Register result = locs()->out(0).reg();
intptr_t left_cid = this->left()->Type()->ToCid();
intptr_t right_cid = this->right()->Type()->ToCid();
bool combined_smi_check = false;
if (FLAG_use_slow_path) {
__ b(slow_path->entry_label());
} else if (this->left()->definition() == this->right()->definition()) {
__ BranchIfNotSmi(left, slow_path->entry_label());
} else if (left_cid == kSmiCid) {
__ BranchIfNotSmi(right, slow_path->entry_label());
} else if (right_cid == kSmiCid) {
__ BranchIfNotSmi(left, slow_path->entry_label());
} else {
combined_smi_check = true;
__ orr(result, left, compiler::Operand(right));
__ BranchIfNotSmi(result, slow_path->entry_label());
}
switch (op_kind()) {
case Token::kADD:
__ adds(result, left, compiler::Operand(right));
__ b(slow_path->entry_label(), VS);
break;
case Token::kSUB:
__ subs(result, left, compiler::Operand(right));
__ b(slow_path->entry_label(), VS);
break;
case Token::kMUL:
__ SmiUntag(IP, left);
__ smull(result, IP, IP, right);
// IP: result bits 32..63.
__ cmp(IP, compiler::Operand(result, ASR, 31));
__ b(slow_path->entry_label(), NE);
break;
case Token::kBIT_OR:
// Operation may be part of combined smi check.
if (!combined_smi_check) {
__ orr(result, left, compiler::Operand(right));
}
break;
case Token::kBIT_AND:
__ and_(result, left, compiler::Operand(right));
break;
case Token::kBIT_XOR:
__ eor(result, left, compiler::Operand(right));
break;
case Token::kSHL:
ASSERT(result != left);
ASSERT(result != right);
__ CompareImmediate(
right, compiler::target::ToRawSmi(compiler::target::kSmiBits));
__ b(slow_path->entry_label(), HI);
__ SmiUntag(TMP, right);
// Check for overflow by shifting left and shifting back arithmetically.
// If the result is different from the original, there was overflow.
__ Lsl(result, left, TMP);
__ cmp(left, compiler::Operand(result, ASR, TMP));
__ b(slow_path->entry_label(), NE);
break;
case Token::kSHR:
ASSERT(result != left);
ASSERT(result != right);
__ CompareImmediate(
right, compiler::target::ToRawSmi(compiler::target::kSmiBits));
__ b(slow_path->entry_label(), HI);
__ SmiUntag(result, right);
__ SmiUntag(TMP, left);
__ Asr(result, TMP, result);
__ SmiTag(result);
break;
case Token::kUSHR: {
ASSERT(result != left);
ASSERT(result != right);
__ CompareImmediate(right, compiler::target::ToRawSmi(kBitsPerInt64));
__ b(slow_path->entry_label(), UNSIGNED_GREATER_EQUAL);
compiler::Label done;
__ SmiUntag(result, right);
// 64-bit representation of left operand value:
//
// ss...sssss s s xxxxxxxxxxxxx
// | | | | | |
// 63 32 31 30 kSmiBits-1 0
//
// Where 's' is a sign bit.
//
// If left operand is negative (sign bit is set), then
// result will fit into Smi range if and only if
// the shift amount >= 64 - kSmiBits.
//
// If left operand is non-negative, the result always
// fits into Smi range.
//
__ CompareImmediate(result, 64 - compiler::target::kSmiBits);
// Shift amount >= 64 - kSmiBits > 32, but < 64.
// Result is guaranteed to fit into Smi range.
// Low (Smi) part of the left operand is shifted out.
// High part is filled with sign bits.
__ sub(result, result, compiler::Operand(32), GE);
__ Asr(TMP, left, compiler::Operand(31), GE);
__ Lsr(result, TMP, result, GE);
__ SmiTag(result, GE);
__ b(&done, GE);
// Shift amount < 64 - kSmiBits.
// If left is negative, then result will not fit into Smi range.
// Also deopt in case of negative shift amount.
__ tst(left, compiler::Operand(left));
__ b(slow_path->entry_label(), MI);
// At this point left operand is non-negative, so unsigned shift
// can't overflow.
__ CompareImmediate(result, compiler::target::kSmiBits);
// Left operand >= 0, shift amount >= kSmiBits. Result is 0.
__ LoadImmediate(result, 0, GE);
// Left operand >= 0, shift amount < kSmiBits < 32.
__ SmiUntag(TMP, left, LT);
__ Lsr(result, TMP, result, LT);
__ SmiTag(result, LT);
__ Bind(&done);
break;
}
default:
UNREACHABLE();
}
__ Bind(slow_path->exit_label());
}
class CheckedSmiComparisonSlowPath
: public TemplateSlowPathCode<CheckedSmiComparisonInstr> {
public:
static constexpr intptr_t kNumSlowPathArgs = 2;
CheckedSmiComparisonSlowPath(CheckedSmiComparisonInstr* instruction,
Environment* env,
intptr_t try_index,
BranchLabels labels,
bool merged)
: TemplateSlowPathCode(instruction),
try_index_(try_index),
labels_(labels),
merged_(merged),
env_(env) {
// The environment must either come from the comparison or the environment
// was cleared from the comparison (and moved to a branch).
ASSERT(env == instruction->env() ||
(merged && instruction->env() == nullptr));
}
virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
if (compiler::Assembler::EmittingComments()) {
__ Comment("slow path smi operation");
}
__ Bind(entry_label());
LocationSummary* locs = instruction()->locs();
Register result = merged_ ? locs->temp(0).reg() : locs->out(0).reg();
locs->live_registers()->Remove(Location::RegisterLocation(result));
compiler->SaveLiveRegisters(locs);
if (env_ != nullptr) {
compiler->pending_deoptimization_env_ =
compiler->SlowPathEnvironmentFor(env_, locs, kNumSlowPathArgs);
}
__ Push(locs->in(0).reg());
__ Push(locs->in(1).reg());
const auto& selector = String::Handle(instruction()->call()->Selector());
const auto& arguments_descriptor =
Array::Handle(ArgumentsDescriptor::NewBoxed(
/*type_args_len=*/0, /*num_arguments=*/2));
compiler->EmitMegamorphicInstanceCall(
selector, arguments_descriptor, instruction()->call()->deopt_id(),
instruction()->source(), locs, try_index_, kNumSlowPathArgs);
__ mov(result, compiler::Operand(R0));
compiler->RestoreLiveRegisters(locs);
compiler->pending_deoptimization_env_ = nullptr;
if (merged_) {
__ CompareObject(result, Bool::True());
__ b(instruction()->is_negated() ? labels_.false_label
: labels_.true_label,
EQ);
__ b(instruction()->is_negated() ? labels_.true_label
: labels_.false_label);
} else {
if (instruction()->is_negated()) {
// Need to negate the result of slow path call.
__ CompareObject(result, Bool::True());
__ LoadObject(result, Bool::True(), NE);
__ LoadObject(result, Bool::False(), EQ);
}
__ b(exit_label());
}
}
private:
intptr_t try_index_;
BranchLabels labels_;
bool merged_;
Environment* env_;
};
LocationSummary* CheckedSmiComparisonInstr::MakeLocationSummary(
Zone* zone,
bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 1;
LocationSummary* summary = new (zone) LocationSummary(
zone, kNumInputs, kNumTemps, LocationSummary::kCallOnSlowPath);
summary->set_in(0, Location::RequiresRegister());
summary->set_in(1, Location::RequiresRegister());
summary->set_temp(0, Location::RequiresRegister());
summary->set_out(0, Location::RequiresRegister());
return summary;
}
Condition CheckedSmiComparisonInstr::EmitComparisonCode(
FlowGraphCompiler* compiler,
BranchLabels labels) {
return EmitSmiComparisonOp(compiler, locs(), kind());
}
#define EMIT_SMI_CHECK \
Register left = locs()->in(0).reg(); \
Register right = locs()->in(1).reg(); \
Register temp = locs()->temp(0).reg(); \
intptr_t left_cid = this->left()->Type()->ToCid(); \
intptr_t right_cid = this->right()->Type()->ToCid(); \
if (FLAG_use_slow_path) { \
__ b(slow_path->entry_label()); \
} else if (this->left()->definition() == this->right()->definition()) { \
__ BranchIfNotSmi(left, slow_path->entry_label()); \
} else if (left_cid == kSmiCid) { \
__ BranchIfNotSmi(right, slow_path->entry_label()); \
} else if (right_cid == kSmiCid) { \
__ BranchIfNotSmi(left, slow_path->entry_label()); \
} else { \
__ orr(temp, left, compiler::Operand(right)); \
__ BranchIfNotSmi(temp, slow_path->entry_label()); \
}
void CheckedSmiComparisonInstr::EmitBranchCode(FlowGraphCompiler* compiler,
BranchInstr* branch) {
BranchLabels labels = compiler->CreateBranchLabels(branch);
CheckedSmiComparisonSlowPath* slow_path = new CheckedSmiComparisonSlowPath(
this, branch->env(), compiler->CurrentTryIndex(), labels,
/* merged = */ true);
compiler->AddSlowPathCode(slow_path);
EMIT_SMI_CHECK;
Condition true_condition = EmitComparisonCode(compiler, labels);
ASSERT(true_condition != kInvalidCondition);
EmitBranchOnCondition(compiler, true_condition, labels);
__ Bind(slow_path->exit_label());
}
void CheckedSmiComparisonInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
BranchLabels labels = {NULL, NULL, NULL};
CheckedSmiComparisonSlowPath* slow_path = new CheckedSmiComparisonSlowPath(
this, env(), compiler->CurrentTryIndex(), labels,
/* merged = */ false);
compiler->AddSlowPathCode(slow_path);
EMIT_SMI_CHECK;
Condition true_condition = EmitComparisonCode(compiler, labels);
ASSERT(true_condition != kInvalidCondition);
Register result = locs()->out(0).reg();
__ LoadObject(result, Bool::True(), true_condition);
__ LoadObject(result, Bool::False(), InvertCondition(true_condition));
__ Bind(slow_path->exit_label());
}
#undef EMIT_SMI_CHECK
LocationSummary* BinarySmiOpInstr::MakeLocationSummary(Zone* zone,
bool opt) const {
const intptr_t kNumInputs = 2;
-305
View File
@@ -3467,311 +3467,6 @@ static void EmitSmiShiftLeft(FlowGraphCompiler* compiler,
}
}
class CheckedSmiSlowPath : public TemplateSlowPathCode<CheckedSmiOpInstr> {
public:
static constexpr intptr_t kNumSlowPathArgs = 2;
CheckedSmiSlowPath(CheckedSmiOpInstr* instruction, intptr_t try_index)
: TemplateSlowPathCode(instruction), try_index_(try_index) {}
virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
if (compiler::Assembler::EmittingComments()) {
__ Comment("slow path smi operation");
}
__ Bind(entry_label());
LocationSummary* locs = instruction()->locs();
Register result = locs->out(0).reg();
locs->live_registers()->Remove(Location::RegisterLocation(result));
compiler->SaveLiveRegisters(locs);
if (instruction()->env() != NULL) {
Environment* env =
compiler->SlowPathEnvironmentFor(instruction(), kNumSlowPathArgs);
compiler->pending_deoptimization_env_ = env;
}
__ PushPair(locs->in(1).reg(), locs->in(0).reg());
const auto& selector = String::Handle(instruction()->call()->Selector());
const auto& arguments_descriptor =
Array::Handle(ArgumentsDescriptor::NewBoxed(
/*type_args_len=*/0, /*num_arguments=*/2));
compiler->EmitMegamorphicInstanceCall(
selector, arguments_descriptor, instruction()->call()->deopt_id(),
instruction()->source(), locs, try_index_, kNumSlowPathArgs);
__ mov(result, R0);
compiler->RestoreLiveRegisters(locs);
__ b(exit_label());
compiler->pending_deoptimization_env_ = NULL;
}
private:
intptr_t try_index_;
};
LocationSummary* CheckedSmiOpInstr::MakeLocationSummary(Zone* zone,
bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* summary = new (zone) LocationSummary(
zone, kNumInputs, kNumTemps, LocationSummary::kCallOnSlowPath);
summary->set_in(0, Location::RequiresRegister());
summary->set_in(1, Location::RequiresRegister());
summary->set_out(0, Location::RequiresRegister());
return summary;
}
void CheckedSmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
CheckedSmiSlowPath* slow_path =
new CheckedSmiSlowPath(this, compiler->CurrentTryIndex());
compiler->AddSlowPathCode(slow_path);
// Test operands if necessary.
Register left = locs()->in(0).reg();
Register right = locs()->in(1).reg();
Register result = locs()->out(0).reg();
intptr_t left_cid = this->left()->Type()->ToCid();
intptr_t right_cid = this->right()->Type()->ToCid();
bool combined_smi_check = false;
if (FLAG_use_slow_path) {
__ b(slow_path->entry_label());
} else if (this->left()->definition() == this->right()->definition()) {
__ BranchIfNotSmi(left, slow_path->entry_label());
} else if (left_cid == kSmiCid) {
__ BranchIfNotSmi(right, slow_path->entry_label());
} else if (right_cid == kSmiCid) {
__ BranchIfNotSmi(left, slow_path->entry_label());
} else {
combined_smi_check = true;
__ orr(result, left, compiler::Operand(right));
__ BranchIfNotSmi(result, slow_path->entry_label());
}
switch (op_kind()) {
case Token::kADD:
__ adds(result, left, compiler::Operand(right), compiler::kObjectBytes);
__ b(slow_path->entry_label(), VS);
break;
case Token::kSUB:
__ subs(result, left, compiler::Operand(right), compiler::kObjectBytes);
__ b(slow_path->entry_label(), VS);
break;
case Token::kMUL:
__ SmiUntag(TMP, left);
#if !defined(DART_COMPRESSED_POINTERS)
__ mul(result, TMP, right);
__ smulh(TMP, TMP, right);
// TMP: result bits 64..127.
#else
__ smull(result, TMP, right);
__ AsrImmediate(TMP, result, 31);
// TMP: result bits 32..63.
#endif
__ cmp(TMP, compiler::Operand(result, ASR, 63));
__ b(slow_path->entry_label(), NE);
break;
case Token::kBIT_OR:
// Operation may be part of combined smi check.
if (!combined_smi_check) {
__ orr(result, left, compiler::Operand(right));
}
break;
case Token::kBIT_AND:
__ and_(result, left, compiler::Operand(right));
break;
case Token::kBIT_XOR:
__ eor(result, left, compiler::Operand(right));
break;
case Token::kSHL:
ASSERT(result != left);
ASSERT(result != right);
__ CompareObject(right, Smi::ZoneHandle(Smi::New(Smi::kBits)));
__ b(slow_path->entry_label(), CS);
__ SmiUntag(TMP, right);
__ lslv(result, left, TMP, compiler::kObjectBytes);
__ asrv(TMP2, result, TMP, compiler::kObjectBytes);
__ cmp(left, compiler::Operand(TMP2), compiler::kObjectBytes);
__ b(slow_path->entry_label(), NE); // Overflow.
break;
case Token::kSHR:
ASSERT(result != left);
ASSERT(result != right);
__ CompareObject(right, Smi::ZoneHandle(Smi::New(Smi::kBits)));
__ b(slow_path->entry_label(), CS);
__ SmiUntag(result, right);
__ SmiUntag(TMP, left);
__ asrv(result, TMP, result, compiler::kObjectBytes);
__ SmiTag(result);
break;
case Token::kUSHR:
ASSERT(result != left);
ASSERT(result != right);
__ CompareObject(right, Smi::ZoneHandle(Smi::New(kBitsPerInt64)));
__ b(slow_path->entry_label(), UNSIGNED_GREATER_EQUAL);
__ SmiUntag(result, right);
__ SmiUntag(TMP, left);
__ lsrv(result, TMP, result);
__ SmiTagAndBranchIfOverflow(result, slow_path->entry_label());
break;
default:
UNIMPLEMENTED();
}
__ Bind(slow_path->exit_label());
}
class CheckedSmiComparisonSlowPath
: public TemplateSlowPathCode<CheckedSmiComparisonInstr> {
public:
static constexpr intptr_t kNumSlowPathArgs = 2;
CheckedSmiComparisonSlowPath(CheckedSmiComparisonInstr* instruction,
Environment* env,
intptr_t try_index,
BranchLabels labels,
bool merged)
: TemplateSlowPathCode(instruction),
try_index_(try_index),
labels_(labels),
merged_(merged),
env_(env) {
// The environment must either come from the comparison or the environment
// was cleared from the comparison (and moved to a branch).
ASSERT(env == instruction->env() ||
(merged && instruction->env() == nullptr));
}
virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
if (compiler::Assembler::EmittingComments()) {
__ Comment("slow path smi operation");
}
__ Bind(entry_label());
LocationSummary* locs = instruction()->locs();
Register result = merged_ ? locs->temp(0).reg() : locs->out(0).reg();
locs->live_registers()->Remove(Location::RegisterLocation(result));
compiler->SaveLiveRegisters(locs);
if (env_ != nullptr) {
compiler->pending_deoptimization_env_ =
compiler->SlowPathEnvironmentFor(env_, locs, kNumSlowPathArgs);
}
__ PushPair(locs->in(1).reg(), locs->in(0).reg());
const auto& selector = String::Handle(instruction()->call()->Selector());
const auto& arguments_descriptor =
Array::Handle(ArgumentsDescriptor::NewBoxed(
/*type_args_len=*/0, /*num_arguments=*/2));
compiler->EmitMegamorphicInstanceCall(
selector, arguments_descriptor, instruction()->call()->deopt_id(),
instruction()->source(), locs, try_index_, kNumSlowPathArgs);
__ mov(result, R0);
compiler->RestoreLiveRegisters(locs);
compiler->pending_deoptimization_env_ = nullptr;
if (merged_) {
__ CompareObject(result, Bool::True());
__ b(instruction()->is_negated() ? labels_.false_label
: labels_.true_label,
EQ);
__ b(instruction()->is_negated() ? labels_.true_label
: labels_.false_label);
ASSERT(exit_label()->IsUnused());
} else {
ASSERT(!instruction()->is_negated());
__ b(exit_label());
}
}
private:
intptr_t try_index_;
BranchLabels labels_;
bool merged_;
Environment* env_;
};
LocationSummary* CheckedSmiComparisonInstr::MakeLocationSummary(
Zone* zone,
bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 1;
LocationSummary* summary = new (zone) LocationSummary(
zone, kNumInputs, kNumTemps, LocationSummary::kCallOnSlowPath);
summary->set_in(0, Location::RequiresRegister());
summary->set_in(1, Location::RequiresRegister());
summary->set_temp(0, Location::RequiresRegister());
summary->set_out(0, Location::RequiresRegister());
return summary;
}
Condition CheckedSmiComparisonInstr::EmitComparisonCode(
FlowGraphCompiler* compiler,
BranchLabels labels) {
return EmitSmiComparisonOp(compiler, locs(), kind(), labels);
}
#define EMIT_SMI_CHECK \
Register left = locs()->in(0).reg(); \
Register right = locs()->in(1).reg(); \
Register temp = locs()->temp(0).reg(); \
intptr_t left_cid = this->left()->Type()->ToCid(); \
intptr_t right_cid = this->right()->Type()->ToCid(); \
if (FLAG_use_slow_path) { \
__ b(slow_path->entry_label()); \
} else if (this->left()->definition() == this->right()->definition()) { \
__ BranchIfNotSmi(left, slow_path->entry_label()); \
} else if (left_cid == kSmiCid) { \
__ BranchIfNotSmi(right, slow_path->entry_label()); \
} else if (right_cid == kSmiCid) { \
__ BranchIfNotSmi(left, slow_path->entry_label()); \
} else { \
__ orr(temp, left, compiler::Operand(right)); \
__ BranchIfNotSmi(temp, slow_path->entry_label()); \
}
void CheckedSmiComparisonInstr::EmitBranchCode(FlowGraphCompiler* compiler,
BranchInstr* branch) {
BranchLabels labels = compiler->CreateBranchLabels(branch);
CheckedSmiComparisonSlowPath* slow_path = new CheckedSmiComparisonSlowPath(
this, branch->env(), compiler->CurrentTryIndex(), labels,
/* merged = */ true);
compiler->AddSlowPathCode(slow_path);
EMIT_SMI_CHECK;
Condition true_condition = EmitComparisonCode(compiler, labels);
if (true_condition != kInvalidCondition) {
EmitBranchOnCondition(compiler, true_condition, labels);
}
// No need to bind slow_path->exit_label() as slow path exits through
// true/false branch labels.
}
void CheckedSmiComparisonInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
// Zone-allocate labels to pass them to slow-path which outlives local scope.
compiler::Label* true_label = new (Z) compiler::Label();
compiler::Label* false_label = new (Z) compiler::Label();
compiler::Label done;
BranchLabels labels = {true_label, false_label, false_label};
// In case of negated comparison result of a slow path call should be negated.
// For this purpose, 'merged' slow path is generated: it tests
// result of a call and jumps directly to true or false label.
CheckedSmiComparisonSlowPath* slow_path = new CheckedSmiComparisonSlowPath(
this, env(), compiler->CurrentTryIndex(), labels,
/* merged = */ is_negated());
compiler->AddSlowPathCode(slow_path);
EMIT_SMI_CHECK;
Condition true_condition = EmitComparisonCode(compiler, labels);
if (true_condition != kInvalidCondition) {
EmitBranchOnCondition(compiler, true_condition, labels);
}
Register result = locs()->out(0).reg();
__ Bind(false_label);
__ LoadObject(result, Bool::False());
__ b(&done);
__ Bind(true_label);
__ LoadObject(result, Bool::True());
__ Bind(&done);
// In case of negated comparison slow path exits through true/false labels.
if (!is_negated()) {
__ Bind(slow_path->exit_label());
}
}
LocationSummary* BinarySmiOpInstr::MakeLocationSummary(Zone* zone,
bool opt) const {
const intptr_t kNumInputs = 2;
-39
View File
@@ -3127,45 +3127,6 @@ static void EmitSmiShiftLeft(FlowGraphCompiler* compiler,
}
}
LocationSummary* CheckedSmiOpInstr::MakeLocationSummary(Zone* zone,
bool opt) const {
// Only for precompiled code, not on ia32 currently.
UNIMPLEMENTED();
return NULL;
}
void CheckedSmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
// Only for precompiled code, not on ia32 currently.
UNIMPLEMENTED();
}
LocationSummary* CheckedSmiComparisonInstr::MakeLocationSummary(
Zone* zone,
bool opt) const {
// Only for precompiled code, not on ia32 currently.
UNIMPLEMENTED();
return NULL;
}
Condition CheckedSmiComparisonInstr::EmitComparisonCode(
FlowGraphCompiler* compiler,
BranchLabels labels) {
// Only for precompiled code, not on ia32 currently.
UNIMPLEMENTED();
return ZERO;
}
void CheckedSmiComparisonInstr::EmitBranchCode(FlowGraphCompiler* compiler,
BranchInstr* instr) {
// Only for precompiled code, not on ia32 currently.
UNIMPLEMENTED();
}
void CheckedSmiComparisonInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
// Only for precompiled code, not on ia32 currently.
UNIMPLEMENTED();
}
static bool IsSmiValue(const Object& constant, intptr_t value) {
return constant.IsSmi() && (Smi::Cast(constant).Value() == value);
}
-16
View File
@@ -730,22 +730,6 @@ void UnaryIntegerOpInstr::PrintOperandsTo(BaseTextBuffer* f) const {
value()->PrintTo(f);
}
void CheckedSmiOpInstr::PrintOperandsTo(BaseTextBuffer* f) const {
f->Printf("%s", Token::Str(op_kind()));
f->AddString(", ");
left()->PrintTo(f);
f->AddString(", ");
right()->PrintTo(f);
}
void CheckedSmiComparisonInstr::PrintOperandsTo(BaseTextBuffer* f) const {
f->Printf("%s", Token::Str(kind()));
f->AddString(", ");
left()->PrintTo(f);
f->AddString(", ");
right()->PrintTo(f);
}
void BinaryIntegerOpInstr::PrintOperandsTo(BaseTextBuffer* f) const {
f->Printf("%s", Token::Str(op_kind()));
if (is_truncating()) {
@@ -202,8 +202,7 @@ void TestPipeline::CompileGraphAndAttachFunction() {
// We expect there to be no deoptimizations.
if (mode_ == CompilerPass::kAOT) {
// TODO(kustermann): Enable this once we get rid of [CheckedSmiSlowPath]s.
// EXPECT(deopt_info_array.IsNull() || deopt_info_array.Length() == 0);
EXPECT(deopt_info_array.IsNull() || deopt_info_array.Length() == 0);
}
}
-336
View File
@@ -3554,342 +3554,6 @@ static void EmitSmiShiftLeft(FlowGraphCompiler* compiler,
}
}
class CheckedSmiSlowPath : public TemplateSlowPathCode<CheckedSmiOpInstr> {
public:
CheckedSmiSlowPath(CheckedSmiOpInstr* instruction, intptr_t try_index)
: TemplateSlowPathCode(instruction), try_index_(try_index) {}
static constexpr intptr_t kNumSlowPathArgs = 2;
virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
if (compiler::Assembler::EmittingComments()) {
__ Comment("slow path smi operation");
}
__ Bind(entry_label());
LocationSummary* locs = instruction()->locs();
Register result = locs->out(0).reg();
locs->live_registers()->Remove(Location::RegisterLocation(result));
compiler->SaveLiveRegisters(locs);
if (instruction()->env() != NULL) {
Environment* env =
compiler->SlowPathEnvironmentFor(instruction(), kNumSlowPathArgs);
compiler->pending_deoptimization_env_ = env;
}
__ pushq(locs->in(0).reg());
__ pushq(locs->in(1).reg());
const auto& selector = String::Handle(instruction()->call()->Selector());
const auto& arguments_descriptor =
Array::Handle(ArgumentsDescriptor::NewBoxed(
/*type_args_len=*/0, /*num_arguments=*/2));
compiler->EmitMegamorphicInstanceCall(
selector, arguments_descriptor, instruction()->call()->deopt_id(),
instruction()->source(), locs, try_index_, kNumSlowPathArgs);
__ MoveRegister(result, RAX);
compiler->RestoreLiveRegisters(locs);
__ jmp(exit_label());
compiler->pending_deoptimization_env_ = NULL;
}
private:
intptr_t try_index_;
};
LocationSummary* CheckedSmiOpInstr::MakeLocationSummary(Zone* zone,
bool opt) const {
bool is_shift = (op_kind() == Token::kSHL) || (op_kind() == Token::kSHR) ||
(op_kind() == Token::kUSHR);
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = is_shift ? 1 : 0;
LocationSummary* summary = new (zone) LocationSummary(
zone, kNumInputs, kNumTemps, LocationSummary::kCallOnSlowPath);
summary->set_in(0, Location::RequiresRegister());
summary->set_in(1, Location::RequiresRegister());
switch (op_kind()) {
case Token::kADD:
case Token::kSUB:
case Token::kMUL:
case Token::kSHL:
case Token::kSHR:
case Token::kUSHR:
summary->set_out(0, Location::RequiresRegister());
break;
case Token::kBIT_OR:
case Token::kBIT_AND:
case Token::kBIT_XOR:
summary->set_out(0, Location::SameAsFirstInput());
break;
default:
UNIMPLEMENTED();
}
if (is_shift) {
summary->set_temp(0, Location::RegisterLocation(RCX));
}
return summary;
}
void CheckedSmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
CheckedSmiSlowPath* slow_path =
new CheckedSmiSlowPath(this, compiler->CurrentTryIndex());
compiler->AddSlowPathCode(slow_path);
// Test operands if necessary.
intptr_t left_cid = left()->Type()->ToCid();
intptr_t right_cid = right()->Type()->ToCid();
Register left = locs()->in(0).reg();
Register right = locs()->in(1).reg();
if (FLAG_use_slow_path) {
__ jmp(slow_path->entry_label());
} else if (this->left()->definition() == this->right()->definition()) {
__ BranchIfNotSmi(left, slow_path->entry_label());
} else if (left_cid == kSmiCid) {
__ BranchIfNotSmi(right, slow_path->entry_label());
} else if (right_cid == kSmiCid) {
__ BranchIfNotSmi(left, slow_path->entry_label());
} else {
__ movq(TMP, left);
__ orq(TMP, right);
__ BranchIfNotSmi(TMP, slow_path->entry_label());
}
Register result = locs()->out(0).reg();
switch (op_kind()) {
case Token::kADD:
__ movq(result, left);
__ OBJ(add)(result, right);
__ j(OVERFLOW, slow_path->entry_label());
break;
case Token::kSUB:
__ movq(result, left);
__ OBJ(sub)(result, right);
__ j(OVERFLOW, slow_path->entry_label());
break;
case Token::kMUL:
__ movq(result, left);
__ SmiUntag(result);
__ OBJ(imul)(result, right);
__ j(OVERFLOW, slow_path->entry_label());
break;
case Token::kBIT_OR:
ASSERT(left == result);
__ orq(result, right);
break;
case Token::kBIT_AND:
ASSERT(left == result);
__ andq(result, right);
break;
case Token::kBIT_XOR:
ASSERT(left == result);
__ xorq(result, right);
break;
case Token::kSHL:
ASSERT(result != right);
ASSERT(locs()->temp(0).reg() == RCX);
__ CompareObject(right, Smi::ZoneHandle(Smi::New(Smi::kBits)));
__ j(ABOVE_EQUAL, slow_path->entry_label());
__ movq(RCX, right);
__ SmiUntag(RCX);
__ movq(result, left);
__ shlq(result, RCX);
__ movq(TMP, result);
__ OBJ(sar)(TMP, RCX);
__ OBJ(cmp)(TMP, left);
__ j(NOT_EQUAL, slow_path->entry_label());
break;
case Token::kSHR:
ASSERT(result != right);
ASSERT(locs()->temp(0).reg() == RCX);
__ CompareObject(right, Smi::ZoneHandle(Smi::New(Smi::kBits)));
__ j(ABOVE_EQUAL, slow_path->entry_label());
__ movq(RCX, right);
__ SmiUntag(RCX);
__ movq(result, left);
__ SmiUntag(result);
__ OBJ(sar)(result, RCX);
__ SmiTag(result);
break;
case Token::kUSHR: {
ASSERT(result != right);
ASSERT(locs()->temp(0).reg() == RCX);
__ CompareObject(right, Smi::ZoneHandle(Smi::New(kBitsPerInt64)));
__ j(ABOVE_EQUAL, slow_path->entry_label());
__ movq(RCX, right);
__ SmiUntag(RCX);
__ movq(result, left);
__ SmiUntagAndSignExtend(result);
__ shrq(result, RCX);
__ shlq(result, compiler::Immediate(1)); // SmiTag, keep hi bits.
__ j(OVERFLOW, slow_path->entry_label());
#if defined(DART_COMPRESSED_POINTERS)
const Register temp = locs()->temp(0).reg();
__ movsxd(temp, result);
__ cmpq(temp, result);
__ j(NOT_EQUAL, slow_path->entry_label());
#endif // defined(DART_COMPRESSED_POINTERS)
break;
}
default:
UNIMPLEMENTED();
}
__ Bind(slow_path->exit_label());
}
class CheckedSmiComparisonSlowPath
: public TemplateSlowPathCode<CheckedSmiComparisonInstr> {
public:
static constexpr intptr_t kNumSlowPathArgs = 2;
CheckedSmiComparisonSlowPath(CheckedSmiComparisonInstr* instruction,
Environment* env,
intptr_t try_index,
BranchLabels labels,
bool merged)
: TemplateSlowPathCode(instruction),
try_index_(try_index),
labels_(labels),
merged_(merged),
env_(env) {
// The environment must either come from the comparison or the environment
// was cleared from the comparison (and moved to a branch).
ASSERT(env == instruction->env() ||
(merged && instruction->env() == nullptr));
}
virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
if (compiler::Assembler::EmittingComments()) {
__ Comment("slow path smi comparison");
}
__ Bind(entry_label());
LocationSummary* locs = instruction()->locs();
Register result = merged_ ? locs->temp(0).reg() : locs->out(0).reg();
locs->live_registers()->Remove(Location::RegisterLocation(result));
compiler->SaveLiveRegisters(locs);
if (env_ != nullptr) {
compiler->pending_deoptimization_env_ =
compiler->SlowPathEnvironmentFor(env_, locs, kNumSlowPathArgs);
}
__ pushq(locs->in(0).reg());
__ pushq(locs->in(1).reg());
const auto& selector = String::Handle(instruction()->call()->Selector());
const auto& arguments_descriptor =
Array::Handle(ArgumentsDescriptor::NewBoxed(
/*type_args_len=*/0, /*num_arguments=*/2));
compiler->EmitMegamorphicInstanceCall(
selector, arguments_descriptor, instruction()->call()->deopt_id(),
instruction()->source(), locs, try_index_, kNumSlowPathArgs);
__ MoveRegister(result, RAX);
compiler->RestoreLiveRegisters(locs);
compiler->pending_deoptimization_env_ = nullptr;
if (merged_) {
__ CompareObject(result, Bool::True());
__ j(EQUAL, instruction()->is_negated() ? labels_.false_label
: labels_.true_label);
__ jmp(instruction()->is_negated() ? labels_.true_label
: labels_.false_label);
ASSERT(exit_label()->IsUnused());
} else {
ASSERT(!instruction()->is_negated());
__ jmp(exit_label());
}
}
private:
intptr_t try_index_;
BranchLabels labels_;
bool merged_;
Environment* env_;
};
LocationSummary* CheckedSmiComparisonInstr::MakeLocationSummary(
Zone* zone,
bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 1;
LocationSummary* summary = new (zone) LocationSummary(
zone, kNumInputs, kNumTemps, LocationSummary::kCallOnSlowPath);
summary->set_in(0, Location::RequiresRegister());
summary->set_in(1, Location::RequiresRegister());
summary->set_temp(0, Location::RequiresRegister());
summary->set_out(0, Location::RequiresRegister());
return summary;
}
Condition CheckedSmiComparisonInstr::EmitComparisonCode(
FlowGraphCompiler* compiler,
BranchLabels labels) {
return EmitSmiComparisonOp(compiler, *locs(), kind());
}
#define EMIT_SMI_CHECK \
intptr_t left_cid = left()->Type()->ToCid(); \
intptr_t right_cid = right()->Type()->ToCid(); \
Register left = locs()->in(0).reg(); \
Register right = locs()->in(1).reg(); \
if (FLAG_use_slow_path) { \
__ jmp(slow_path->entry_label()); \
} else if (this->left()->definition() == this->right()->definition()) { \
__ BranchIfNotSmi(left, slow_path->entry_label()); \
} else if (left_cid == kSmiCid) { \
__ BranchIfNotSmi(right, slow_path->entry_label()); \
} else if (right_cid == kSmiCid) { \
__ BranchIfNotSmi(left, slow_path->entry_label()); \
} else { \
__ movq(TMP, left); \
__ orq(TMP, right); \
__ BranchIfNotSmi(TMP, slow_path->entry_label()); \
}
void CheckedSmiComparisonInstr::EmitBranchCode(FlowGraphCompiler* compiler,
BranchInstr* branch) {
BranchLabels labels = compiler->CreateBranchLabels(branch);
CheckedSmiComparisonSlowPath* slow_path = new CheckedSmiComparisonSlowPath(
this, branch->env(), compiler->CurrentTryIndex(), labels,
/* merged = */ true);
compiler->AddSlowPathCode(slow_path);
EMIT_SMI_CHECK;
Condition true_condition = EmitComparisonCode(compiler, labels);
ASSERT(true_condition != kInvalidCondition);
EmitBranchOnCondition(compiler, true_condition, labels);
// No need to bind slow_path->exit_label() as slow path exits through
// true/false branch labels.
}
void CheckedSmiComparisonInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
// Zone-allocate labels to pass them to slow-path which outlives local scope.
compiler::Label* true_label = new (Z) compiler::Label();
compiler::Label* false_label = new (Z) compiler::Label();
compiler::Label done;
BranchLabels labels = {true_label, false_label, false_label};
// In case of negated comparison result of a slow path call should be negated.
// For this purpose, 'merged' slow path is generated: it tests
// result of a call and jumps directly to true or false label.
CheckedSmiComparisonSlowPath* slow_path = new CheckedSmiComparisonSlowPath(
this, env(), compiler->CurrentTryIndex(), labels,
/* merged = */ is_negated());
compiler->AddSlowPathCode(slow_path);
EMIT_SMI_CHECK;
Condition true_condition = EmitComparisonCode(compiler, labels);
ASSERT(true_condition != kInvalidCondition);
EmitBranchOnCondition(compiler, true_condition, labels,
compiler::Assembler::kNearJump);
Register result = locs()->out(0).reg();
__ Bind(false_label);
__ LoadObject(result, Bool::False());
__ jmp(&done, compiler::Assembler::kNearJump);
__ Bind(true_label);
__ LoadObject(result, Bool::True());
__ Bind(&done);
// In case of negated comparison slow path exits through true/false labels.
if (!is_negated()) {
__ Bind(slow_path->exit_label());
}
}
static bool CanBeImmediate(const Object& constant) {
return constant.IsSmi() &&
compiler::Immediate(static_cast<int64_t>(constant.ptr())).is_int32();
@@ -1595,30 +1595,6 @@ CompileType UnaryInt64OpInstr::ComputeType() const {
return CompileType::Int();
}
CompileType CheckedSmiOpInstr::ComputeType() const {
if (left()->Type()->IsNullableInt() && right()->Type()->IsNullableInt()) {
const AbstractType& abstract_type =
AbstractType::ZoneHandle(Type::IntType());
TraceStrongModeType(this, abstract_type);
return CompileType::FromAbstractType(abstract_type,
CompileType::kNonNullable);
} else {
CompileType* type = call()->Type();
TraceStrongModeType(this, type);
return *type;
}
}
bool CheckedSmiOpInstr::RecomputeType() {
return UpdateType(ComputeType());
}
CompileType CheckedSmiComparisonInstr::ComputeType() const {
CompileType* type = call()->Type();
TraceStrongModeType(this, type);
return *type;
}
CompileType BoxIntegerInstr::ComputeType() const {
return ValueFitsSmi() ? CompileType::FromCid(kSmiCid) : CompileType::Int();
}