Skip to content

Commit a22daf8

Browse files
alexmarkovCommit Queue
authored andcommitted
[vm/compiler] Remove speculative shift instructions
SpeculattiveShiftInt64Op and SpeculativeShiftUint32Op instructions are only used in JIT. The only advantage of these instructions over non-speculative shifts is that they can be hoisted out of the loops in more cases. However, speculative instructions can suffer from deopt storm, introduce unnecessary differences in IL and generated code between JIT and AOT and add sufficient amount of extra code to maintain. TEST=ci Change-Id: I689e44b54832e2af76cbc99b9fc4bc937b9f2c87 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/394566 Commit-Queue: Alexander Markov <[email protected]> Reviewed-by: Slava Egorov <[email protected]>
1 parent 843c47b commit a22daf8

File tree

10 files changed

+26
-626
lines changed

10 files changed

+26
-626
lines changed

runtime/vm/compiler/backend/constant_propagator.cc

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1197,20 +1197,10 @@ void ConstantPropagator::VisitShiftInt64Op(ShiftInt64OpInstr* instr) {
11971197
VisitBinaryIntegerOp(instr);
11981198
}
11991199

1200-
void ConstantPropagator::VisitSpeculativeShiftInt64Op(
1201-
SpeculativeShiftInt64OpInstr* instr) {
1202-
VisitBinaryIntegerOp(instr);
1203-
}
1204-
12051200
void ConstantPropagator::VisitShiftUint32Op(ShiftUint32OpInstr* instr) {
12061201
VisitBinaryIntegerOp(instr);
12071202
}
12081203

1209-
void ConstantPropagator::VisitSpeculativeShiftUint32Op(
1210-
SpeculativeShiftUint32OpInstr* instr) {
1211-
VisitBinaryIntegerOp(instr);
1212-
}
1213-
12141204
void ConstantPropagator::VisitBoxInt64(BoxInt64Instr* instr) {
12151205
VisitBox(instr);
12161206
}

runtime/vm/compiler/backend/il.cc

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2285,27 +2285,16 @@ BinaryIntegerOpInstr* BinaryIntegerOpInstr::Make(Representation representation,
22852285
case kUnboxedUint32:
22862286
if ((op_kind == Token::kSHL) || (op_kind == Token::kSHR) ||
22872287
(op_kind == Token::kUSHR)) {
2288-
if (CompilerState::Current().is_aot()) {
2289-
op = new ShiftUint32OpInstr(op_kind, left, right, deopt_id,
2290-
right_range);
2291-
} else {
2292-
op = new SpeculativeShiftUint32OpInstr(op_kind, left, right, deopt_id,
2293-
right_range);
2294-
}
2288+
op =
2289+
new ShiftUint32OpInstr(op_kind, left, right, deopt_id, right_range);
22952290
} else {
22962291
op = new BinaryUint32OpInstr(op_kind, left, right, deopt_id);
22972292
}
22982293
break;
22992294
case kUnboxedInt64:
23002295
if ((op_kind == Token::kSHL) || (op_kind == Token::kSHR) ||
23012296
(op_kind == Token::kUSHR)) {
2302-
if (CompilerState::Current().is_aot()) {
2303-
op = new ShiftInt64OpInstr(op_kind, left, right, deopt_id,
2304-
right_range);
2305-
} else {
2306-
op = new SpeculativeShiftInt64OpInstr(op_kind, left, right, deopt_id,
2307-
right_range);
2308-
}
2297+
op = new ShiftInt64OpInstr(op_kind, left, right, deopt_id, right_range);
23092298
} else {
23102299
op = new BinaryInt64OpInstr(op_kind, left, right, deopt_id);
23112300
}
@@ -2430,10 +2419,8 @@ Definition* BinaryIntegerOpInstr::Canonicalize(FlowGraph* flow_graph) {
24302419
return right()->definition();
24312420
} else if ((rhs > 0) && Utils::IsPowerOfTwo(rhs)) {
24322421
const int64_t shift_amount = Utils::ShiftForPowerOfTwo(rhs);
2433-
const Representation shift_amount_rep =
2434-
CompilerState::Current().is_aot() ? kUnboxedInt64 : kTagged;
24352422
ConstantInstr* constant_shift_amount = flow_graph->GetConstant(
2436-
Smi::Handle(Smi::New(shift_amount)), shift_amount_rep);
2423+
Smi::Handle(Smi::New(shift_amount)), kUnboxedInt64);
24372424
BinaryIntegerOpInstr* shift = BinaryIntegerOpInstr::Make(
24382425
representation(), Token::kSHL, left()->CopyWithType(),
24392426
new Value(constant_shift_amount), GetDeoptId(), can_overflow(),

runtime/vm/compiler/backend/il.h

Lines changed: 7 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -503,7 +503,6 @@ struct InstrAttrs {
503503
M(CaseInsensitiveCompare, kNoGC) \
504504
M(BinaryInt64Op, kNoGC) \
505505
M(ShiftInt64Op, kNoGC) \
506-
M(SpeculativeShiftInt64Op, kNoGC) \
507506
M(UnaryInt64Op, kNoGC) \
508507
M(CheckArrayBound, kNoGC) \
509508
M(GenericCheckBound, kNoGC) \
@@ -529,7 +528,6 @@ struct InstrAttrs {
529528
M(BoxLanes, _) \
530529
M(BinaryUint32Op, kNoGC) \
531530
M(ShiftUint32Op, kNoGC) \
532-
M(SpeculativeShiftUint32Op, kNoGC) \
533531
M(UnaryUint32Op, kNoGC) \
534532
M(BoxUint32, _) \
535533
M(UnboxUint32, kNoGC) \
@@ -8739,8 +8737,7 @@ class UnboxInt64Instr : public UnboxIntegerInstr {
87398737

87408738
bool Definition::IsInt64Definition() {
87418739
return (Type()->ToCid() == kMintCid) || IsBinaryInt64Op() ||
8742-
IsUnaryInt64Op() || IsShiftInt64Op() || IsSpeculativeShiftInt64Op() ||
8743-
IsBoxInt64() || IsUnboxInt64();
8740+
IsUnaryInt64Op() || IsShiftInt64Op() || IsBoxInt64() || IsUnboxInt64();
87448741
}
87458742

87468743
// Calls into the runtime and performs a case-insensitive comparison of the
@@ -9495,6 +9492,9 @@ class ShiftInt64OpInstr : public ShiftIntegerOpInstr {
94959492
: ShiftIntegerOpInstr(op_kind, left, right, deopt_id, right_range) {}
94969493

94979494
virtual bool ComputeCanDeoptimize() const { return false; }
9495+
virtual bool ComputeCanDeoptimizeAfterCall() const {
9496+
return !CompilerState::Current().is_aot();
9497+
}
94989498
virtual bool MayThrow() const { return !IsShiftCountInRange(); }
94999499

95009500
virtual Representation representation() const { return kUnboxedInt64; }
@@ -9512,37 +9512,6 @@ class ShiftInt64OpInstr : public ShiftIntegerOpInstr {
95129512
DISALLOW_COPY_AND_ASSIGN(ShiftInt64OpInstr);
95139513
};
95149514

9515-
// Speculative int64 shift. Takes unboxed int64 and smi.
9516-
// Deoptimizes if right operand is negative or greater than kShiftCountLimit.
9517-
class SpeculativeShiftInt64OpInstr : public ShiftIntegerOpInstr {
9518-
public:
9519-
SpeculativeShiftInt64OpInstr(Token::Kind op_kind,
9520-
Value* left,
9521-
Value* right,
9522-
intptr_t deopt_id,
9523-
Range* right_range = nullptr)
9524-
: ShiftIntegerOpInstr(op_kind, left, right, deopt_id, right_range) {}
9525-
9526-
virtual bool ComputeCanDeoptimize() const {
9527-
ASSERT(!can_overflow());
9528-
return !IsShiftCountInRange();
9529-
}
9530-
9531-
virtual Representation representation() const { return kUnboxedInt64; }
9532-
9533-
virtual Representation RequiredInputRepresentation(intptr_t idx) const {
9534-
ASSERT((idx == 0) || (idx == 1));
9535-
return (idx == 0) ? kUnboxedInt64 : kTagged;
9536-
}
9537-
9538-
DECLARE_INSTRUCTION(SpeculativeShiftInt64Op)
9539-
9540-
DECLARE_EMPTY_SERIALIZATION(SpeculativeShiftInt64OpInstr, ShiftIntegerOpInstr)
9541-
9542-
private:
9543-
DISALLOW_COPY_AND_ASSIGN(SpeculativeShiftInt64OpInstr);
9544-
};
9545-
95469515
// Non-speculative uint32 shift. Takes unboxed uint32 and unboxed int64.
95479516
// Throws if right operand is negative.
95489517
class ShiftUint32OpInstr : public ShiftIntegerOpInstr {
@@ -9555,6 +9524,9 @@ class ShiftUint32OpInstr : public ShiftIntegerOpInstr {
95559524
: ShiftIntegerOpInstr(op_kind, left, right, deopt_id, right_range) {}
95569525

95579526
virtual bool ComputeCanDeoptimize() const { return false; }
9527+
virtual bool ComputeCanDeoptimizeAfterCall() const {
9528+
return !CompilerState::Current().is_aot();
9529+
}
95589530
virtual bool MayThrow() const {
95599531
return !IsShiftCountInRange(kUint32ShiftCountLimit);
95609532
}
@@ -9576,37 +9548,6 @@ class ShiftUint32OpInstr : public ShiftIntegerOpInstr {
95769548
DISALLOW_COPY_AND_ASSIGN(ShiftUint32OpInstr);
95779549
};
95789550

9579-
// Speculative uint32 shift. Takes unboxed uint32 and smi.
9580-
// Deoptimizes if right operand is negative.
9581-
class SpeculativeShiftUint32OpInstr : public ShiftIntegerOpInstr {
9582-
public:
9583-
SpeculativeShiftUint32OpInstr(Token::Kind op_kind,
9584-
Value* left,
9585-
Value* right,
9586-
intptr_t deopt_id,
9587-
Range* right_range = nullptr)
9588-
: ShiftIntegerOpInstr(op_kind, left, right, deopt_id, right_range) {}
9589-
9590-
virtual bool ComputeCanDeoptimize() const { return !IsShiftCountInRange(); }
9591-
9592-
virtual Representation representation() const { return kUnboxedUint32; }
9593-
9594-
virtual Representation RequiredInputRepresentation(intptr_t idx) const {
9595-
ASSERT((idx == 0) || (idx == 1));
9596-
return (idx == 0) ? kUnboxedUint32 : kTagged;
9597-
}
9598-
9599-
DECLARE_INSTRUCTION(SpeculativeShiftUint32Op)
9600-
9601-
DECLARE_EMPTY_SERIALIZATION(SpeculativeShiftUint32OpInstr,
9602-
ShiftIntegerOpInstr)
9603-
9604-
private:
9605-
static constexpr intptr_t kUint32ShiftCountLimit = 31;
9606-
9607-
DISALLOW_COPY_AND_ASSIGN(SpeculativeShiftUint32OpInstr);
9608-
};
9609-
96109551
class UnaryDoubleOpInstr : public TemplateDefinition<1, NoThrow, Pure> {
96119552
public:
96129553
UnaryDoubleOpInstr(Token::Kind op_kind,

runtime/vm/compiler/backend/il_arm.cc

Lines changed: 0 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -6667,53 +6667,6 @@ void ShiftInt64OpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
66676667
}
66686668
}
66696669

6670-
LocationSummary* SpeculativeShiftInt64OpInstr::MakeLocationSummary(
6671-
Zone* zone,
6672-
bool opt) const {
6673-
const intptr_t kNumInputs = 2;
6674-
const intptr_t kNumTemps = 0;
6675-
LocationSummary* summary = new (zone)
6676-
LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
6677-
summary->set_in(0, Location::Pair(Location::RequiresRegister(),
6678-
Location::RequiresRegister()));
6679-
summary->set_in(1, LocationWritableRegisterOrSmiConstant(right()));
6680-
summary->set_out(0, Location::Pair(Location::RequiresRegister(),
6681-
Location::RequiresRegister()));
6682-
return summary;
6683-
}
6684-
6685-
void SpeculativeShiftInt64OpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
6686-
PairLocation* left_pair = locs()->in(0).AsPairLocation();
6687-
Register left_lo = left_pair->At(0).reg();
6688-
Register left_hi = left_pair->At(1).reg();
6689-
PairLocation* out_pair = locs()->out(0).AsPairLocation();
6690-
Register out_lo = out_pair->At(0).reg();
6691-
Register out_hi = out_pair->At(1).reg();
6692-
ASSERT(!can_overflow());
6693-
6694-
if (locs()->in(1).IsConstant()) {
6695-
EmitShiftInt64ByConstant(compiler, op_kind(), out_lo, out_hi, left_lo,
6696-
left_hi, locs()->in(1).constant());
6697-
} else {
6698-
// Code for a variable shift amount.
6699-
Register shift = locs()->in(1).reg();
6700-
__ SmiUntag(shift);
6701-
6702-
// Deopt if shift is larger than 63 or less than 0 (or not a smi).
6703-
if (!IsShiftCountInRange()) {
6704-
ASSERT(CanDeoptimize());
6705-
compiler::Label* deopt =
6706-
compiler->AddDeoptStub(deopt_id(), ICData::kDeoptBinaryInt64Op);
6707-
6708-
__ CompareImmediate(shift, kShiftCountLimit);
6709-
__ b(deopt, HI);
6710-
}
6711-
6712-
EmitShiftInt64ByRegister(compiler, op_kind(), out_lo, out_hi, left_lo,
6713-
left_hi, shift);
6714-
}
6715-
}
6716-
67176670
class ShiftUint32OpSlowPath : public ThrowErrorSlowPathCode {
67186671
public:
67196672
explicit ShiftUint32OpSlowPath(ShiftUint32OpInstr* instruction)
@@ -6799,57 +6752,6 @@ void ShiftUint32OpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
67996752
}
68006753
}
68016754

6802-
LocationSummary* SpeculativeShiftUint32OpInstr::MakeLocationSummary(
6803-
Zone* zone,
6804-
bool opt) const {
6805-
const intptr_t kNumInputs = 2;
6806-
const intptr_t kNumTemps = 1;
6807-
LocationSummary* summary = new (zone)
6808-
LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
6809-
summary->set_in(0, Location::RequiresRegister());
6810-
summary->set_in(1, LocationRegisterOrSmiConstant(right()));
6811-
summary->set_temp(0, Location::RequiresRegister());
6812-
summary->set_out(0, Location::RequiresRegister());
6813-
return summary;
6814-
}
6815-
6816-
void SpeculativeShiftUint32OpInstr::EmitNativeCode(
6817-
FlowGraphCompiler* compiler) {
6818-
Register left = locs()->in(0).reg();
6819-
Register out = locs()->out(0).reg();
6820-
Register temp = locs()->temp(0).reg();
6821-
ASSERT(left != out);
6822-
6823-
if (locs()->in(1).IsConstant()) {
6824-
EmitShiftUint32ByConstant(compiler, op_kind(), out, left,
6825-
locs()->in(1).constant());
6826-
} else {
6827-
Register right = locs()->in(1).reg();
6828-
const bool shift_count_in_range =
6829-
IsShiftCountInRange(kUint32ShiftCountLimit);
6830-
6831-
__ SmiUntag(temp, right);
6832-
right = temp;
6833-
6834-
// Deopt if shift count is negative.
6835-
if (!shift_count_in_range) {
6836-
ASSERT(CanDeoptimize());
6837-
compiler::Label* deopt =
6838-
compiler->AddDeoptStub(deopt_id(), ICData::kDeoptBinaryInt64Op);
6839-
6840-
__ CompareImmediate(right, 0);
6841-
__ b(deopt, LT);
6842-
}
6843-
6844-
EmitShiftUint32ByRegister(compiler, op_kind(), out, left, right);
6845-
6846-
if (!shift_count_in_range) {
6847-
__ CompareImmediate(right, kUint32ShiftCountLimit);
6848-
__ LoadImmediate(out, 0, HI);
6849-
}
6850-
}
6851-
}
6852-
68536755
LocationSummary* UnaryInt64OpInstr::MakeLocationSummary(Zone* zone,
68546756
bool opt) const {
68556757
const intptr_t kNumInputs = 1;

0 commit comments

Comments
 (0)