mirror of
https://github.com/dart-lang/sdk
synced 2024-09-19 20:51:50 +00:00
[vm/test] Add IL matching of abstract instructions.
Also marks CheckBoundBase as an abstract instruction, instead of it being treated specially. Now when matching IL graphs that use bounds check instructions, which differ in JIT vs. AOT, the matcher can match the abstract base instruction (CheckBoundBase) instead of having to separately match the concrete subclasses on JIT (CheckArrayBound) and AOT (GenericCheckBound). TEST=ci Change-Id: I73dd6bf6711a99cc2c52a69cf31f22ba4850f2b3 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/327001 Reviewed-by: Alexander Markov <alexmarkov@google.com> Commit-Queue: Tess Strickland <sstrickl@google.com>
This commit is contained in:
parent
f5208f5d59
commit
c562719814
|
@ -3180,8 +3180,8 @@ void NullErrorSlowPath::EmitSharedStubCall(FlowGraphCompiler* compiler,
|
|||
void RangeErrorSlowPath::PushArgumentsForRuntimeCall(
|
||||
FlowGraphCompiler* compiler) {
|
||||
LocationSummary* locs = instruction()->locs();
|
||||
__ PushRegisterPair(locs->in(CheckBoundBase::kIndexPos).reg(),
|
||||
locs->in(CheckBoundBase::kLengthPos).reg());
|
||||
__ PushRegisterPair(locs->in(CheckBoundBaseInstr::kIndexPos).reg(),
|
||||
locs->in(CheckBoundBaseInstr::kLengthPos).reg());
|
||||
}
|
||||
|
||||
void RangeErrorSlowPath::EmitSharedStubCall(FlowGraphCompiler* compiler,
|
||||
|
|
|
@ -548,7 +548,7 @@ Value* AssertBooleanInstr::RedefinedValue() const {
|
|||
return value();
|
||||
}
|
||||
|
||||
Value* CheckBoundBase::RedefinedValue() const {
|
||||
Value* CheckBoundBaseInstr::RedefinedValue() const {
|
||||
return index();
|
||||
}
|
||||
|
||||
|
@ -6483,7 +6483,7 @@ bool CheckArrayBoundInstr::IsFixedLengthArrayType(intptr_t cid) {
|
|||
return LoadFieldInstr::IsFixedLengthArrayCid(cid);
|
||||
}
|
||||
|
||||
Definition* CheckBoundBase::Canonicalize(FlowGraph* flow_graph) {
|
||||
Definition* CheckBoundBaseInstr::Canonicalize(FlowGraph* flow_graph) {
|
||||
return IsRedundant() ? index()->definition() : this;
|
||||
}
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ class BlockEntryWithInitialDefs;
|
|||
class BoxIntegerInstr;
|
||||
class CallTargets;
|
||||
class CatchBlockEntryInstr;
|
||||
class CheckBoundBase;
|
||||
class CheckBoundBaseInstr;
|
||||
class ComparisonInstr;
|
||||
class Definition;
|
||||
class Environment;
|
||||
|
@ -553,6 +553,7 @@ struct InstrAttrs {
|
|||
M(BinaryIntegerOp, _) \
|
||||
M(BlockEntry, _) \
|
||||
M(BoxInteger, _) \
|
||||
M(CheckBoundBase, _) \
|
||||
M(Comparison, _) \
|
||||
M(InstanceCallBase, _) \
|
||||
M(ShiftIntegerOp, _) \
|
||||
|
@ -1143,7 +1144,6 @@ class Instruction : public ZoneAllocated {
|
|||
DECLARE_INSTRUCTION_TYPE_CHECK(Definition, Definition)
|
||||
DECLARE_INSTRUCTION_TYPE_CHECK(BlockEntryWithInitialDefs,
|
||||
BlockEntryWithInitialDefs)
|
||||
DECLARE_INSTRUCTION_TYPE_CHECK(CheckBoundBase, CheckBoundBase)
|
||||
FOR_EACH_INSTRUCTION(INSTRUCTION_TYPE_CHECK)
|
||||
FOR_EACH_ABSTRACT_INSTRUCTION(INSTRUCTION_TYPE_CHECK)
|
||||
|
||||
|
@ -10112,9 +10112,9 @@ class CheckClassIdInstr : public TemplateInstruction<1, NoThrow> {
|
|||
|
||||
// Base class for speculative [CheckArrayBoundInstr] and
|
||||
// non-speculative [GenericCheckBoundInstr] bounds checking.
|
||||
class CheckBoundBase : public TemplateDefinition<2, NoThrow, Pure> {
|
||||
class CheckBoundBaseInstr : public TemplateDefinition<2, NoThrow, Pure> {
|
||||
public:
|
||||
CheckBoundBase(Value* length, Value* index, intptr_t deopt_id)
|
||||
CheckBoundBaseInstr(Value* length, Value* index, intptr_t deopt_id)
|
||||
: TemplateDefinition(deopt_id) {
|
||||
SetInputAt(kLengthPos, length);
|
||||
SetInputAt(kIndexPos, index);
|
||||
|
@ -10125,8 +10125,8 @@ class CheckBoundBase : public TemplateDefinition<2, NoThrow, Pure> {
|
|||
|
||||
virtual Definition* Canonicalize(FlowGraph* flow_graph);
|
||||
|
||||
virtual CheckBoundBase* AsCheckBoundBase() { return this; }
|
||||
virtual const CheckBoundBase* AsCheckBoundBase() const { return this; }
|
||||
DECLARE_ABSTRACT_INSTRUCTION(CheckBoundBase);
|
||||
|
||||
virtual Value* RedefinedValue() const;
|
||||
|
||||
// Returns true if the bounds check can be eliminated without
|
||||
|
@ -10136,10 +10136,10 @@ class CheckBoundBase : public TemplateDefinition<2, NoThrow, Pure> {
|
|||
// Give a name to the location/input indices.
|
||||
enum { kLengthPos = 0, kIndexPos = 1 };
|
||||
|
||||
DECLARE_EMPTY_SERIALIZATION(CheckBoundBase, TemplateDefinition)
|
||||
DECLARE_EMPTY_SERIALIZATION(CheckBoundBaseInstr, TemplateDefinition)
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(CheckBoundBase);
|
||||
DISALLOW_COPY_AND_ASSIGN(CheckBoundBaseInstr);
|
||||
};
|
||||
|
||||
// Performs an array bounds check, where
|
||||
|
@ -10147,10 +10147,10 @@ class CheckBoundBase : public TemplateDefinition<2, NoThrow, Pure> {
|
|||
// returns the "safe" index when
|
||||
// 0 <= index < length
|
||||
// or otherwise deoptimizes (viz. speculative).
|
||||
class CheckArrayBoundInstr : public CheckBoundBase {
|
||||
class CheckArrayBoundInstr : public CheckBoundBaseInstr {
|
||||
public:
|
||||
CheckArrayBoundInstr(Value* length, Value* index, intptr_t deopt_id)
|
||||
: CheckBoundBase(length, index, deopt_id), generalized_(false) {}
|
||||
: CheckBoundBaseInstr(length, index, deopt_id), generalized_(false) {}
|
||||
|
||||
DECLARE_INSTRUCTION(CheckArrayBound)
|
||||
|
||||
|
@ -10171,7 +10171,7 @@ class CheckArrayBoundInstr : public CheckBoundBase {
|
|||
#define FIELD_LIST(F) F(bool, generalized_)
|
||||
|
||||
DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(CheckArrayBoundInstr,
|
||||
CheckBoundBase,
|
||||
CheckBoundBaseInstr,
|
||||
FIELD_LIST)
|
||||
#undef FIELD_LIST
|
||||
|
||||
|
@ -10184,7 +10184,7 @@ class CheckArrayBoundInstr : public CheckBoundBase {
|
|||
// returns the "safe" index when
|
||||
// 0 <= index < length
|
||||
// or otherwise throws an out-of-bounds exception (viz. non-speculative).
|
||||
class GenericCheckBoundInstr : public CheckBoundBase {
|
||||
class GenericCheckBoundInstr : public CheckBoundBaseInstr {
|
||||
public:
|
||||
// We prefer to have unboxed inputs on 64-bit where values can fit into a
|
||||
// register.
|
||||
|
@ -10193,7 +10193,7 @@ class GenericCheckBoundInstr : public CheckBoundBase {
|
|||
}
|
||||
|
||||
GenericCheckBoundInstr(Value* length, Value* index, intptr_t deopt_id)
|
||||
: CheckBoundBase(length, index, deopt_id) {}
|
||||
: CheckBoundBaseInstr(length, index, deopt_id) {}
|
||||
|
||||
virtual bool AttributesEqual(const Instruction& other) const { return true; }
|
||||
|
||||
|
@ -10230,7 +10230,7 @@ class GenericCheckBoundInstr : public CheckBoundBase {
|
|||
return SlowPathSharingSupported(is_optimizing);
|
||||
}
|
||||
|
||||
DECLARE_EMPTY_SERIALIZATION(GenericCheckBoundInstr, CheckBoundBase)
|
||||
DECLARE_EMPTY_SERIALIZATION(GenericCheckBoundInstr, CheckBoundBaseInstr)
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(GenericCheckBoundInstr);
|
||||
|
|
|
@ -410,6 +410,7 @@ Instruction* ILMatcher::MatchInternal(std::vector<MatchCode> match_codes,
|
|||
return cursor; \
|
||||
}
|
||||
FOR_EACH_INSTRUCTION(EMIT_CASE)
|
||||
FOR_EACH_ABSTRACT_INSTRUCTION(EMIT_CASE)
|
||||
#undef EMIT_CASE
|
||||
default:
|
||||
UNREACHABLE();
|
||||
|
@ -451,6 +452,7 @@ const char* ILMatcher::MatchOpCodeToCString(MatchOpCode opcode) {
|
|||
case kMatchAndMoveOptional##Instruction: \
|
||||
return "kMatchAndMoveOptional" #Instruction;
|
||||
FOR_EACH_INSTRUCTION(EMIT_CASE)
|
||||
FOR_EACH_ABSTRACT_INSTRUCTION(EMIT_CASE)
|
||||
#undef EMIT_CASE
|
||||
default:
|
||||
UNREACHABLE();
|
||||
|
|
|
@ -118,6 +118,7 @@ enum MatchOpCode {
|
|||
kMatch##Instruction, kMatchAndMove##Instruction, \
|
||||
kMatchAndMoveOptional##Instruction,
|
||||
FOR_EACH_INSTRUCTION(DEFINE_MATCH_OPCODES)
|
||||
FOR_EACH_ABSTRACT_INSTRUCTION(DEFINE_MATCH_OPCODES)
|
||||
#undef DEFINE_MATCH_OPCODES
|
||||
|
||||
// Matches a branch and moves left.
|
||||
|
@ -161,6 +162,7 @@ class MatchCode {
|
|||
RELEASE_ASSERT(opcode == kMatch##Type || opcode == kMatchAndMove##Type); \
|
||||
}
|
||||
FOR_EACH_INSTRUCTION(DEFINE_TYPED_CONSTRUCTOR)
|
||||
FOR_EACH_ABSTRACT_INSTRUCTION(DEFINE_TYPED_CONSTRUCTOR)
|
||||
#undef DEFINE_TYPED_CONSTRUCTOR
|
||||
|
||||
MatchOpCode opcode() { return opcode_; }
|
||||
|
|
|
@ -222,17 +222,17 @@ void RangeAnalysis::InsertConstraintsFor(Definition* defn) {
|
|||
}
|
||||
|
||||
void RangeAnalysis::ConstrainValueAfterCheckBound(Value* use,
|
||||
CheckBoundBase* check,
|
||||
CheckBoundBaseInstr* check,
|
||||
Definition* defn) {
|
||||
const intptr_t use_index = use->use_index();
|
||||
|
||||
Range* constraint_range = nullptr;
|
||||
if (use_index == CheckBoundBase::kIndexPos) {
|
||||
if (use_index == CheckBoundBaseInstr::kIndexPos) {
|
||||
Definition* length = check->length()->definition();
|
||||
constraint_range = new (Z) Range(RangeBoundary::FromConstant(0),
|
||||
RangeBoundary::FromDefinition(length, -1));
|
||||
} else {
|
||||
ASSERT(use_index == CheckBoundBase::kLengthPos);
|
||||
ASSERT(use_index == CheckBoundBaseInstr::kLengthPos);
|
||||
Definition* index = check->index()->definition();
|
||||
constraint_range = new (Z)
|
||||
Range(RangeBoundary::FromDefinition(index, 1), RangeBoundary::MaxSmi());
|
||||
|
@ -1349,7 +1349,7 @@ void RangeAnalysis::EliminateRedundantBoundsChecks() {
|
|||
!CompilerState::Current().is_aot() &&
|
||||
!function.ProhibitsBoundsCheckGeneralization();
|
||||
BoundsCheckGeneralizer generalizer(this, flow_graph_);
|
||||
for (CheckBoundBase* check : bounds_checks_) {
|
||||
for (CheckBoundBaseInstr* check : bounds_checks_) {
|
||||
if (check->IsRedundant(/*use_loops=*/true)) {
|
||||
check->ReplaceUsesWith(check->index()->definition());
|
||||
check->RemoveFromGraph();
|
||||
|
@ -3181,7 +3181,7 @@ static bool IsRedundantBasedOnRangeInformation(Value* index, Value* length) {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool CheckBoundBase::IsRedundant(bool use_loops) {
|
||||
bool CheckBoundBaseInstr::IsRedundant(bool use_loops) {
|
||||
// First, try to prove redundancy with the results of range analysis.
|
||||
if (IsRedundantBasedOnRangeInformation(index(), length())) {
|
||||
return true;
|
||||
|
|
|
@ -632,7 +632,7 @@ class RangeAnalysis : public ValueObject {
|
|||
|
||||
bool ConstrainValueAfterBranch(Value* use, Definition* defn);
|
||||
void ConstrainValueAfterCheckBound(Value* use,
|
||||
CheckBoundBase* check,
|
||||
CheckBoundBaseInstr* check,
|
||||
Definition* defn);
|
||||
|
||||
// Infer ranges for integer (smi or mint) definitions.
|
||||
|
@ -679,7 +679,7 @@ class RangeAnalysis : public ValueObject {
|
|||
GrowableArray<ShiftIntegerOpInstr*> shift_int64_ops_;
|
||||
|
||||
// All CheckArrayBound/GenericCheckBound instructions.
|
||||
GrowableArray<CheckBoundBase*> bounds_checks_;
|
||||
GrowableArray<CheckBoundBaseInstr*> bounds_checks_;
|
||||
|
||||
// All Constraints inserted during InsertConstraints phase. They are treated
|
||||
// as smi values.
|
||||
|
|
Loading…
Reference in a new issue