[vm, compiler] Make UnboxedConstant more like Constant.

TEST=ci
Bug: https://github.com/dart-lang/sdk/issues/45555
Change-Id: Ib396b0281d4e138cc252baacaac18e42057d7bb6
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/194502
Commit-Queue: Ryan Macnak <rmacnak@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
Ryan Macnak
2021-04-21 22:45:31 +00:00
committed by commit-bot@chromium.org
parent 1c86b2f5f6
commit 571908fbec
14 changed files with 172 additions and 141 deletions
+22 -21
View File
@@ -183,16 +183,24 @@ GrowableArray<BlockEntryInstr*>* FlowGraph::CodegenBlockOrder(
: &reverse_postorder_;
}
ConstantInstr* FlowGraph::GetExistingConstant(const Object& object) const {
return constant_instr_pool_.LookupValue(object);
ConstantInstr* FlowGraph::GetExistingConstant(
const Object& object,
Representation representation) const {
return constant_instr_pool_.LookupValue(
ConstantAndRepresentation{object, representation});
}
ConstantInstr* FlowGraph::GetConstant(const Object& object) {
ConstantInstr* constant = GetExistingConstant(object);
ConstantInstr* FlowGraph::GetConstant(const Object& object,
Representation representation) {
ConstantInstr* constant = GetExistingConstant(object, representation);
if (constant == nullptr) {
// Otherwise, allocate and add it to the pool.
constant =
new (zone()) ConstantInstr(Object::ZoneHandle(zone(), object.ptr()));
const Object& zone_object = Object::ZoneHandle(zone(), object.ptr());
if (representation == kTagged) {
constant = new (zone()) ConstantInstr(zone_object);
} else {
constant = new (zone()) UnboxedConstantInstr(zone_object, representation);
}
constant->set_ssa_temp_index(alloc_ssa_temp_index());
if (NeedsPairLocation(constant->representation())) {
alloc_ssa_temp_index();
@@ -236,28 +244,21 @@ bool FlowGraph::IsConstantRepresentable(const Object& value,
Definition* FlowGraph::TryCreateConstantReplacementFor(Definition* op,
const Object& value) {
// Check that representation of the constant matches expected representation.
const auto representation = op->representation();
if (!IsConstantRepresentable(
value, op->representation(),
value, representation,
/*tagged_value_must_be_smi=*/op->Type()->IsNullableSmi())) {
return op;
}
Definition* result = GetConstant(value);
if (op->representation() != kTagged) {
// We checked above that constant can be safely unboxed.
result = UnboxInstr::Create(op->representation(), new Value(result),
DeoptId::kNone, Instruction::kNotSpeculative);
// If the current instruction is a phi we need to insert the replacement
// into the block which contains this phi - because phis exist separately
// from all other instructions.
if (auto phi = op->AsPhi()) {
InsertAfter(phi->GetBlock(), result, nullptr, FlowGraph::kValue);
} else {
InsertBefore(op, result, nullptr, FlowGraph::kValue);
}
if (representation == kUnboxedDouble && value.IsInteger()) {
// Convert the boxed constant from int to double.
return GetConstant(Double::Handle(Double::NewCanonical(
Integer::Cast(value).AsDoubleValue())),
kUnboxedDouble);
}
return result;
return GetConstant(value, representation);
}
void FlowGraph::AddToGraphInitialDefinitions(Definition* defn) {
+25 -14
View File
@@ -49,34 +49,42 @@ class BlockIterator : public ValueObject {
intptr_t current_;
};
struct ConstantAndRepresentation {
const Object& constant;
Representation representation;
};
struct ConstantPoolTrait {
typedef ConstantInstr* Value;
typedef const Object& Key;
typedef ConstantAndRepresentation Key;
typedef ConstantInstr* Pair;
static Key KeyOf(Pair kv) { return kv->value(); }
static Key KeyOf(Pair kv) {
return ConstantAndRepresentation{kv->value(), kv->representation()};
}
static Value ValueOf(Pair kv) { return kv; }
static inline uword Hash(Key key) {
if (key.IsSmi()) {
return Smi::Cast(key).Value();
if (key.constant.IsSmi()) {
return Smi::Cast(key.constant).Value();
}
if (key.IsDouble()) {
if (key.constant.IsDouble()) {
return static_cast<intptr_t>(bit_cast<int32_t, float>(
static_cast<float>(Double::Cast(key).value())));
static_cast<float>(Double::Cast(key.constant).value())));
}
if (key.IsMint()) {
return static_cast<intptr_t>(Mint::Cast(key).value());
if (key.constant.IsMint()) {
return static_cast<intptr_t>(Mint::Cast(key.constant).value());
}
if (key.IsString()) {
return String::Cast(key).Hash();
if (key.constant.IsString()) {
return String::Cast(key.constant).Hash();
}
return key.GetClassId();
return key.constant.GetClassId();
}
static inline bool IsKeyEqual(Pair kv, Key key) {
return kv->value().ptr() == key.ptr();
return (kv->value().ptr() == key.constant.ptr()) &&
(kv->representation() == key.representation);
}
};
@@ -264,11 +272,14 @@ class FlowGraph : public ZoneAllocated {
// Returns the definition for the object from the constant pool if
// one exists, otherwise returns nullptr.
ConstantInstr* GetExistingConstant(const Object& object) const;
ConstantInstr* GetExistingConstant(
const Object& object,
Representation representation = kTagged) const;
// Always returns a definition for the object from the constant pool,
// allocating one if it doesn't already exist.
ConstantInstr* GetConstant(const Object& object);
ConstantInstr* GetConstant(const Object& object,
Representation representation = kTagged);
void AddToGraphInitialDefinitions(Definition* defn);
void AddToInitialDefinitions(BlockEntryWithInitialDefs* entry,
@@ -966,10 +966,12 @@ void FlowGraphCompiler::EmitMove(Location destination,
if (destination.IsFpuRegister() || destination.IsDoubleStackSlot() ||
destination.IsStackSlot()) {
Register tmp = allocator->AllocateTemporary();
source.constant_instruction()->EmitMoveToLocation(this, destination, tmp);
source.constant_instruction()->EmitMoveToLocation(this, destination, tmp,
source.pair_index());
allocator->ReleaseTemporary();
} else {
source.constant_instruction()->EmitMoveToLocation(this, destination);
source.constant_instruction()->EmitMoveToLocation(
this, destination, kNoRegister, source.pair_index());
}
}
}
@@ -918,7 +918,8 @@ void FlowGraphCompiler::EmitMove(Location destination,
}
} else {
ASSERT(source.IsConstant());
source.constant_instruction()->EmitMoveToLocation(this, destination);
source.constant_instruction()->EmitMoveToLocation(
this, destination, kNoRegister, source.pair_index());
}
}
+5 -24
View File
@@ -3207,21 +3207,14 @@ Definition* UnboxInstr::Canonicalize(FlowGraph* flow_graph) {
}
if (representation() == kUnboxedDouble && value()->BindsToConstant()) {
UnboxedConstantInstr* uc = NULL;
const Object& val = value()->BoundConstant();
if (val.IsInteger()) {
const Double& double_val = Double::ZoneHandle(
flow_graph->zone(),
Double::NewCanonical(Integer::Cast(val).AsDoubleValue()));
uc = new UnboxedConstantInstr(double_val, kUnboxedDouble);
return flow_graph->GetConstant(double_val, kUnboxedDouble);
} else if (val.IsDouble()) {
uc = new UnboxedConstantInstr(val, kUnboxedDouble);
}
if (uc != NULL) {
flow_graph->InsertBefore(this, uc, NULL, FlowGraph::kValue);
return uc;
return flow_graph->GetConstant(val, kUnboxedDouble);
}
}
@@ -3283,13 +3276,7 @@ Definition* UnboxInt32Instr::Canonicalize(FlowGraph* flow_graph) {
}
}
UnboxedConstantInstr* uc =
new UnboxedConstantInstr(c->value(), kUnboxedInt32);
if (c->range() != NULL) {
uc->set_range(*c->range());
}
flow_graph->InsertBefore(this, uc, NULL, FlowGraph::kValue);
return uc;
return flow_graph->GetConstant(c->value(), kUnboxedInt32);
}
return this;
@@ -3304,14 +3291,8 @@ Definition* UnboxInt64Instr::Canonicalize(FlowGraph* flow_graph) {
// Currently we perform this only on 64-bit architectures.
if (compiler::target::kBitsPerWord == 64) {
ConstantInstr* c = value()->definition()->AsConstant();
if (c != NULL && (c->value().IsSmi() || c->value().IsMint())) {
UnboxedConstantInstr* uc =
new UnboxedConstantInstr(c->value(), kUnboxedInt64);
if (c->range() != NULL) {
uc->set_range(*c->range());
}
flow_graph->InsertBefore(this, uc, NULL, FlowGraph::kValue);
return uc;
if (c != NULL && c->value().IsInteger()) {
return flow_graph->GetConstant(c->value(), kUnboxedInt64);
}
}
+4 -1
View File
@@ -3561,7 +3561,8 @@ class ConstantInstr : public TemplateDefinition<0, NoThrow, Pure> {
void EmitMoveToLocation(FlowGraphCompiler* compiler,
const Location& destination,
Register tmp = kNoRegister);
Register tmp = kNoRegister,
intptr_t pair_index = 0);
PRINT_OPERANDS_TO_SUPPORT
@@ -5657,6 +5658,7 @@ class LoadIndexedInstr : public TemplateDefinition<2, NoThrow> {
intptr_t class_id() const { return class_id_; }
bool aligned() const { return alignment_ == kAlignedAccess; }
virtual intptr_t DeoptimizationTarget() const { return GetDeoptId(); }
virtual bool ComputeCanDeoptimize() const {
return GetDeoptId() != DeoptId::kNone;
}
@@ -6586,6 +6588,7 @@ class LoadFieldInstr : public TemplateDefinition<1, Throws> {
DECLARE_INSTRUCTION(LoadField)
virtual CompileType ComputeType() const;
virtual intptr_t DeoptimizationTarget() const { return GetDeoptId(); }
virtual bool ComputeCanDeoptimize() const { return false; }
virtual bool ComputeCanDeoptimizeAfterCall() const {
return calls_initializer() && !CompilerState::Current().is_aot();
+7 -3
View File
@@ -664,7 +664,8 @@ void ConstantInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
void ConstantInstr::EmitMoveToLocation(FlowGraphCompiler* compiler,
const Location& destination,
Register tmp) {
Register tmp,
intptr_t pair_index) {
if (destination.IsRegister()) {
if (RepresentationUtils::IsUnboxedInteger(representation())) {
int64_t v;
@@ -675,7 +676,9 @@ void ConstantInstr::EmitMoveToLocation(FlowGraphCompiler* compiler,
// Smi untagging, which means the resulting value may be unexpected.
ASSERT(v >= 0);
}
__ LoadImmediate(destination.reg(), v);
__ LoadImmediate(destination.reg(), pair_index == 0
? Utils::Low32Bits(v)
: Utils::High32Bits(v));
} else {
ASSERT(representation() == kTagged);
__ LoadObject(destination.reg(), value_);
@@ -708,7 +711,8 @@ void ConstantInstr::EmitMoveToLocation(FlowGraphCompiler* compiler,
int64_t v;
const bool ok = compiler::HasIntegerValue(value_, &v);
RELEASE_ASSERT(ok);
__ LoadImmediate(tmp, v);
__ LoadImmediate(
tmp, pair_index == 0 ? Utils::Low32Bits(v) : Utils::High32Bits(v));
} else {
__ LoadObject(tmp, value_);
}
+3 -1
View File
@@ -580,7 +580,9 @@ void ConstantInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
void ConstantInstr::EmitMoveToLocation(FlowGraphCompiler* compiler,
const Location& destination,
Register tmp) {
Register tmp,
intptr_t pair_index) {
ASSERT(pair_index == 0); // No pair representation needed on 64-bit.
if (destination.IsRegister()) {
if (representation() == kUnboxedInt32 ||
representation() == kUnboxedUint32 ||
+11 -5
View File
@@ -398,7 +398,8 @@ void ConstantInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
void ConstantInstr::EmitMoveToLocation(FlowGraphCompiler* compiler,
const Location& destination,
Register tmp) {
Register tmp,
intptr_t pair_index) {
if (destination.IsRegister()) {
if (RepresentationUtils::IsUnboxedInteger(representation())) {
int64_t v;
@@ -409,7 +410,9 @@ void ConstantInstr::EmitMoveToLocation(FlowGraphCompiler* compiler,
// Smi untagging, which means the resulting value may be unexpected.
ASSERT(v >= 0);
}
__ movl(destination.reg(), compiler::Immediate(v));
__ movl(destination.reg(),
compiler::Immediate(pair_index == 0 ? Utils::Low32Bits(v)
: Utils::High32Bits(v)));
} else {
ASSERT(representation() == kTagged);
__ LoadObjectSafely(destination.reg(), value_);
@@ -444,10 +447,13 @@ void ConstantInstr::EmitMoveToLocation(FlowGraphCompiler* compiler,
__ movsd(LocationToStackSlotAddress(destination), FpuTMP);
} else {
ASSERT(destination.IsStackSlot());
if (value_.IsSmi() &&
RepresentationUtils::IsUnboxedInteger(representation())) {
if (RepresentationUtils::IsUnboxedInteger(representation())) {
int64_t v;
const bool ok = compiler::HasIntegerValue(value_, &v);
RELEASE_ASSERT(ok);
__ movl(LocationToStackSlotAddress(destination),
compiler::Immediate(Smi::Cast(value_).Value()));
compiler::Immediate(pair_index == 0 ? Utils::Low32Bits(v)
: Utils::High32Bits(v)));
} else {
if (compiler::Assembler::IsSafeSmi(value_) || value_.IsNull()) {
__ movl(LocationToStackSlotAddress(destination),
+3 -1
View File
@@ -529,7 +529,9 @@ void ConstantInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
void ConstantInstr::EmitMoveToLocation(FlowGraphCompiler* compiler,
const Location& destination,
Register tmp) {
Register tmp,
intptr_t pair_index) {
ASSERT(pair_index == 0); // No pair representation needed on 64-bit.
if (destination.IsRegister()) {
if (RepresentationUtils::IsUnboxedInteger(representation())) {
const int64_t value = Integer::Cast(value_).AsInt64Value();
+5 -8
View File
@@ -216,15 +216,15 @@ ISOLATE_UNIT_TEST_CASE(Inliner_List_generate) {
ILMatcher cursor(flow_graph, entry, /*trace=*/true,
ParallelMovesHandling::kSkip);
Instruction* unbox1 = nullptr;
Instruction* unbox2 = nullptr;
RELEASE_ASSERT(cursor.TryMatch({
kMoveGlob,
kMatchAndMoveCreateArray,
{kMoveAny, &unbox1},
kMatchAndMoveUnboxInt64,
{kMoveAny, &unbox2},
#if defined(TARGET_ARCH_IS_32_BIT)
// TODO(rmacnak): Implement missing ops to allow 32-bit architectures in
// UnboxInt64Instr::Canonicalize.
kMatchAndMoveUnboxInt64,
#endif
kMatchAndMoveGoto,
// Loop header
@@ -249,9 +249,6 @@ ISOLATE_UNIT_TEST_CASE(Inliner_List_generate) {
kMatchAndMoveTargetEntry,
kMatchReturn,
}));
EXPECT(unbox1->IsUnboxedConstant() || unbox1->IsUnboxInt64());
EXPECT(unbox2->IsUnboxedConstant() || unbox2->IsUnboxInt64());
}
#endif // defined(DART_PRECOMPILER)
+20 -5
View File
@@ -642,7 +642,14 @@ void FlowGraphAllocator::BuildLiveRanges() {
GraphEntryInstr* graph_entry = flow_graph_.graph_entry();
for (intptr_t i = 0; i < graph_entry->initial_definitions()->length(); i++) {
Definition* defn = (*graph_entry->initial_definitions())[i];
ASSERT(!defn->HasPairRepresentation());
if (defn->HasPairRepresentation()) {
// The lower bits are pushed after the higher bits
LiveRange* range = GetLiveRange(ToSecondPairVreg(defn->ssa_temp_index()));
range->AddUseInterval(graph_entry->start_pos(), graph_entry->end_pos());
range->DefineAt(graph_entry->start_pos());
ProcessInitialDefinition(defn, range, graph_entry,
/*second_location_for_definition=*/true);
}
LiveRange* range = GetLiveRange(defn->ssa_temp_index());
range->AddUseInterval(graph_entry->start_pos(), graph_entry->end_pos());
range->DefineAt(graph_entry->start_pos());
@@ -724,8 +731,9 @@ void FlowGraphAllocator::ProcessInitialDefinition(
} else {
ConstantInstr* constant = defn->AsConstant();
ASSERT(constant != NULL);
range->set_assigned_location(Location::Constant(constant));
range->set_spill_slot(Location::Constant(constant));
const intptr_t pair_index = second_location_for_definition ? 1 : 0;
range->set_assigned_location(Location::Constant(constant, pair_index));
range->set_spill_slot(Location::Constant(constant, pair_index));
}
AssignSafepoints(defn, range);
range->finger()->Initialize(range);
@@ -823,7 +831,11 @@ Instruction* FlowGraphAllocator::ConnectOutgoingPhiMoves(
ConstantInstr* constant = val->definition()->AsConstant();
if (constant != NULL) {
move->set_src(Location::Constant(constant));
move->set_src(Location::Constant(constant, /*pair_index*/ 0));
if (val->definition()->HasPairRepresentation()) {
move = parallel_move->MoveOperandsAt(move_index++);
move->set_src(Location::Constant(constant, /*pair_index*/ 1));
}
continue;
}
@@ -2926,7 +2938,10 @@ void FlowGraphAllocator::CollectRepresentations() {
Definition* def = (*initial_definitions)[i];
value_representations_[def->ssa_temp_index()] =
RepresentationForRange(def->representation());
ASSERT(!def->HasPairRepresentation());
if (def->HasPairRepresentation()) {
value_representations_[ToSecondPairVreg(def->ssa_temp_index())] =
RepresentationForRange(def->representation());
}
}
for (BlockIterator it = flow_graph_.reverse_postorder_iterator(); !it.Done();
+19 -12
View File
@@ -145,21 +145,21 @@ class Location : public ValueObject {
// allocated by a register allocator. Each unallocated location has
// a policy that specifies what kind of location is suitable. Payload
// contains register allocation policy.
kUnallocated = 3,
kUnallocated = 1 << 2,
// Spill slots allocated by the register allocator. Payload contains
// a spill index.
kStackSlot = 4, // Word size slot.
kDoubleStackSlot = 7, // 64bit stack slot.
kQuadStackSlot = 11, // 128bit stack slot.
kStackSlot = 2 << 2, // Word size slot.
kDoubleStackSlot = 3 << 2, // 64bit stack slot.
kQuadStackSlot = 4 << 2, // 128bit stack slot.
// Register location represents a fixed register. Payload contains
// register code.
kRegister = 8,
kRegister = 5 << 2,
// FpuRegister location represents a fixed fpu register. Payload contains
// its code.
kFpuRegister = 12,
kFpuRegister = 6 << 2,
};
Location() : value_(kInvalidLocation) {
@@ -204,14 +204,21 @@ class Location : public ValueObject {
bool IsInvalid() const { return value_ == kInvalidLocation; }
// Constants.
bool IsConstant() const {
return (value_ & kLocationTagMask) == kConstantTag;
bool IsConstant() const { return (value_ & kConstantTag) == kConstantTag; }
static Location Constant(const ConstantInstr* obj, int pair_index = 0) {
ASSERT((pair_index == 0) || (pair_index == 1));
Location loc(reinterpret_cast<uword>(obj) |
(pair_index != 0 ? kPairLocationTag : 0) |
kConstantTag);
ASSERT(obj == loc.constant_instruction());
ASSERT(loc.pair_index() == pair_index);
return loc;
}
static Location Constant(const ConstantInstr* obj) {
Location loc(reinterpret_cast<uword>(obj) | kConstantTag);
ASSERT(obj == loc.constant_instruction());
return loc;
intptr_t pair_index() const {
ASSERT(IsConstant());
return (value_ & kPairLocationTag) != 0 ? 1 : 0;
}
ConstantInstr* constant_instruction() const {
@@ -1150,47 +1150,48 @@ main() {
/* Flow graph to match:
4: CheckStackOverflow:8(stack=0, loop=0)
6: v590 <- UnboxedConstant(#1.0 double) T{_Double}
8: v592 <- UnboxedConstant(#2.0 double) T{_Double}
9: ParallelMove r0 <- S+2
10: CheckClass:14(v2 Cids[1: _Double@0150898 etc. cid 52])
12: v526 <- Unbox:14(v2 T{_Double}) T{_Double}
14: v352 <- BinaryDoubleOp:22(+, v590, v526) T{_Double}
15: ParallelMove DS-9 <- q3
16: v363 <- BinaryDoubleOp:34(+, v592, v526) T{_Double}
17: ParallelMove DS-7 <- q0
18: v21 <- BinaryDoubleOp:28(+, v352, v363) T{_Double}
19: ParallelMove r1 <- C, r2 <- C, DS-5 <- q1
20: v24 <- CreateArray:30(v0, v23) T{_List}
21: ParallelMove r2 <- r0
22: ParallelMove S-3 <- r2
22: StoreIndexed(v24, v6, v26, NoStoreBarrier)
24: StoreIndexed(v24, v7, v7, NoStoreBarrier)
26: StoreIndexed(v24, v3, v29, NoStoreBarrier)
28: StoreIndexed(v24, v30, v8, NoStoreBarrier)
30: StoreIndexed(v24, v33, v34, NoStoreBarrier)
32: StoreIndexed(v24, v35, v9, NoStoreBarrier)
34: StoreIndexed(v24, v38, v29, NoStoreBarrier)
36: StoreIndexed(v24, v39, v10, NoStoreBarrier)
38: StoreIndexed(v24, v42, v43, NoStoreBarrier)
39: ParallelMove q0 <- DS-9
40: v586 <- Box(v352) T{_Double}
41: ParallelMove r1 <- r2, r0 <- r0
42: StoreIndexed(v24, v44, v586)
44: StoreIndexed(v24, v47, v29, NoStoreBarrier)
45: ParallelMove q0 <- DS-7
46: v588 <- Box(v363) T{_Double}
47: ParallelMove r1 <- r2, r0 <- r0
48: StoreIndexed(v24, v48, v588)
50: StoreIndexed(v24, v51, v52, NoStoreBarrier)
51: ParallelMove q0 <- DS-5
52: v580 <- Box(v21) T{_Double}
53: ParallelMove r1 <- r2, r0 <- r0
54: StoreIndexed(v24, v53, v580)
55: ParallelMove r0 <- r2
56: v54 <- StringInterpolate:44(v24) T{String}
57: ParallelMove r0 <- r0
58: Return:48(v54)
5: ParallelMove rax <- S+2
6: CheckClass:14(v2 Cids[1: _Double@0150898 etc. cid 52])
8: v526 <- Unbox:14(v2 T{_Double}) T{_Double}
10: ParallelMove xmm1 <- C
10: v352 <- BinaryDoubleOp:22(+, v590, v526) T{_Double}
11: ParallelMove DS-6 <- xmm1
12: ParallelMove xmm2 <- C
12: v363 <- BinaryDoubleOp:34(+, v591, v526) T{_Double}
13: ParallelMove DS-5 <- xmm2
14: ParallelMove xmm0 <- xmm1
14: v21 <- BinaryDoubleOp:28(+, v352, v363) T{_Double}
15: ParallelMove rbx <- C, r10 <- C, DS-4 <- xmm0
16: v24 <- CreateArray:30(v0, v23) T{_List}
17: ParallelMove rcx <- rax
18: ParallelMove S-3 <- rcx
18: StoreIndexed(v24, v6, v26, NoStoreBarrier)
20: StoreIndexed(v24, v7, v7, NoStoreBarrier)
22: StoreIndexed(v24, v3, v29, NoStoreBarrier)
24: StoreIndexed(v24, v30, v8, NoStoreBarrier)
26: StoreIndexed(v24, v33, v34, NoStoreBarrier)
28: StoreIndexed(v24, v35, v9, NoStoreBarrier)
30: StoreIndexed(v24, v38, v29, NoStoreBarrier)
32: StoreIndexed(v24, v39, v10, NoStoreBarrier)
34: StoreIndexed(v24, v42, v43, NoStoreBarrier)
35: ParallelMove xmm0 <- DS-6
36: v586 <- Box(v352) T{_Double}
37: ParallelMove rdx <- rcx, rax <- rax
38: StoreIndexed(v24, v44, v586)
40: StoreIndexed(v24, v47, v29, NoStoreBarrier)
41: ParallelMove xmm0 <- DS-5
42: v588 <- Box(v363) T{_Double}
43: ParallelMove rdx <- rcx, rax <- rax
44: StoreIndexed(v24, v48, v588)
46: StoreIndexed(v24, v51, v52, NoStoreBarrier)
47: ParallelMove xmm0 <- DS-4
48: v580 <- Box(v21) T{_Double}
49: ParallelMove rdx <- rcx, rax <- rax
50: StoreIndexed(v24, v53, v580)
51: ParallelMove rax <- rcx
52: v54 <- StringInterpolate:44(v24) T{String}
53: ParallelMove rax <- rax
54: Return:48(v54)
*/
CreateArrayInstr* create_array = nullptr;
@@ -1201,8 +1202,6 @@ main() {
RELEASE_ASSERT(cursor.TryMatch({
kMatchAndMoveFunctionEntry,
kMatchAndMoveCheckStackOverflow,
kMatchAndMoveUnboxedConstant,
kMatchAndMoveUnboxedConstant,
kMatchAndMoveCheckClass,
kMatchAndMoveUnbox,
kMatchAndMoveBinaryDoubleOp,