[turbofan] Add length operand to LoadElement and StoreElement.

This is preliminary work, required to properly support bounds checking for typed array loads/stores.

TEST=compiler-unittests,cctest
R=mstarzinger@chromium.org

Review URL: https://codereview.chromium.org/602563002

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24172 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
bmeurer@chromium.org 2014-09-24 09:28:56 +00:00
parent 9e0801c306
commit deaf463bf1
11 changed files with 250 additions and 54 deletions

View File

@ -177,6 +177,16 @@ void GenericNode<B, S>::InsertInput(Zone* zone, int index,
ReplaceInput(index, to_insert);
}
template <class B, class S>
void GenericNode<B, S>::RemoveInput(int index) {
DCHECK(index >= 0 && index < InputCount());
// TODO(turbofan): Optimize this implementation!
for (; index < InputCount() - 1; ++index) {
ReplaceInput(index, InputAt(index + 1));
}
TrimInputCount(InputCount() - 1);
}
template <class B, class S>
void GenericNode<B, S>::AppendUse(Use* use) {
use->next = NULL;

View File

@ -41,6 +41,7 @@ class GenericNode : public B {
inline void ReplaceInput(int index, GenericNode* new_input);
inline void AppendInput(Zone* zone, GenericNode* new_input);
inline void InsertInput(Zone* zone, int index, GenericNode* new_input);
inline void RemoveInput(int index);
int UseCount() { return use_count_; }
S* UseAt(int index) {
@ -56,7 +57,7 @@ class GenericNode : public B {
inline void ReplaceUsesIf(UnaryPredicate pred, GenericNode* replace_to);
inline void RemoveAllInputs();
void TrimInputCount(int input_count);
inline void TrimInputCount(int input_count);
class Inputs {
public:

View File

@ -176,14 +176,7 @@ void JSGenericLowering::ReplaceWithCompareIC(Node* node, Token::Value token,
if (has_frame_state) {
// Remove the frame state from inputs.
// TODO(jarin) This should use Node::RemoveInput (which does not exist yet).
int dest = NodeProperties::FirstFrameStateIndex(node);
for (int i = NodeProperties::PastFrameStateIndex(node);
i < node->InputCount(); i++) {
node->ReplaceInput(dest, node->InputAt(i));
dest++;
}
node->TrimInputCount(dest);
node->RemoveInput(NodeProperties::FirstFrameStateIndex(node));
}
ReplaceWithRuntimeCall(node, Runtime::kBooleanize);

View File

@ -540,6 +540,8 @@ Reduction JSTypedLowering::ReduceJSLoadProperty(Node* node) {
JSTypedArray* array = JSTypedArray::cast(*base_type->AsConstant()->Value());
ElementsKind elements_kind = array->map()->elements_kind();
ExternalArrayType type = array->type();
uint32_t length;
CHECK(array->length()->ToUint32(&length));
ElementAccess element_access;
Node* elements = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForJSObjectElements()), base,
@ -555,7 +557,8 @@ Reduction JSTypedLowering::ReduceJSLoadProperty(Node* node) {
}
Node* value =
graph()->NewNode(simplified()->LoadElement(element_access), elements,
key, NodeProperties::GetEffectInput(node));
key, jsgraph()->Uint32Constant(length),
NodeProperties::GetEffectInput(node));
return ReplaceEagerly(node, value);
}
return NoChange();
@ -599,9 +602,10 @@ Reduction JSTypedLowering::ReduceJSStoreProperty(Node* node) {
NodeProperties::GetControlInput(node));
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
Node* store = graph()->NewNode(
simplified()->StoreElement(element_access), elements, key, value,
NodeProperties::GetEffectInput(node), if_true);
Node* store =
graph()->NewNode(simplified()->StoreElement(element_access), elements,
key, jsgraph()->Uint32Constant(length), value,
NodeProperties::GetEffectInput(node), if_true);
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);

View File

@ -596,7 +596,8 @@ class RepresentationSelector {
ElementAccess access = ElementAccessOf(node->op());
ProcessInput(node, 0, changer_->TypeForBasePointer(access));
ProcessInput(node, 1, kMachInt32); // element index
ProcessRemainingInputs(node, 2);
ProcessInput(node, 2, kMachInt32); // length
ProcessRemainingInputs(node, 3);
SetOutput(node, AssumeImplicitFloat32Change(access.machine_type));
if (lower()) lowering->DoLoadElement(node);
break;
@ -605,8 +606,9 @@ class RepresentationSelector {
ElementAccess access = ElementAccessOf(node->op());
ProcessInput(node, 0, changer_->TypeForBasePointer(access));
ProcessInput(node, 1, kMachInt32); // element index
ProcessInput(node, 2, AssumeImplicitFloat32Change(access.machine_type));
ProcessRemainingInputs(node, 3);
ProcessInput(node, 2, kMachInt32); // length
ProcessInput(node, 3, AssumeImplicitFloat32Change(access.machine_type));
ProcessRemainingInputs(node, 4);
SetOutput(node, 0);
if (lower()) lowering->DoStoreElement(node);
break;
@ -867,6 +869,7 @@ void SimplifiedLowering::DoLoadElement(Node* node) {
const ElementAccess& access = ElementAccessOf(node->op());
node->set_op(machine()->Load(access.machine_type));
node->ReplaceInput(1, ComputeIndex(access, node->InputAt(1)));
node->RemoveInput(2);
}
@ -877,6 +880,7 @@ void SimplifiedLowering::DoStoreElement(Node* node) {
node->set_op(
machine()->Store(StoreRepresentation(access.machine_type, kind)));
node->ReplaceInput(1, ComputeIndex(access, node->InputAt(1)));
node->RemoveInput(2);
}

View File

@ -11,6 +11,14 @@ namespace v8 {
namespace internal {
namespace compiler {
// TODO(bmeurer): Drop once we use std::ostream instead of our OStream.
inline std::ostream& operator<<(std::ostream& os, const ElementAccess& access) {
OStringStream ost;
ost << access;
return os << ost.c_str();
}
// -----------------------------------------------------------------------------
// Pure operators.
@ -112,6 +120,103 @@ TEST_P(SimplifiedPureOperatorTest, Properties) {
INSTANTIATE_TEST_CASE_P(SimplifiedOperatorTest, SimplifiedPureOperatorTest,
::testing::ValuesIn(kPureOperators));
// -----------------------------------------------------------------------------
// Element access operators.
namespace {
const ElementAccess kElementAccesses[] = {
{kTaggedBase, FixedArray::kHeaderSize, Type::Any(), kMachAnyTagged},
{kUntaggedBase, kNonHeapObjectHeaderSize - kHeapObjectTag, Type::Any(),
kMachInt8},
{kUntaggedBase, kNonHeapObjectHeaderSize - kHeapObjectTag, Type::Any(),
kMachInt16},
{kUntaggedBase, kNonHeapObjectHeaderSize - kHeapObjectTag, Type::Any(),
kMachInt32},
{kUntaggedBase, kNonHeapObjectHeaderSize - kHeapObjectTag, Type::Any(),
kMachUint8},
{kUntaggedBase, kNonHeapObjectHeaderSize - kHeapObjectTag, Type::Any(),
kMachUint16},
{kUntaggedBase, kNonHeapObjectHeaderSize - kHeapObjectTag, Type::Any(),
kMachUint32},
{kUntaggedBase, 0, Type::Signed32(), kMachInt8},
{kUntaggedBase, 0, Type::Unsigned32(), kMachUint8},
{kUntaggedBase, 0, Type::Signed32(), kMachInt16},
{kUntaggedBase, 0, Type::Unsigned32(), kMachUint16},
{kUntaggedBase, 0, Type::Signed32(), kMachInt32},
{kUntaggedBase, 0, Type::Unsigned32(), kMachUint32},
{kUntaggedBase, 0, Type::Number(), kRepFloat32},
{kUntaggedBase, 0, Type::Number(), kRepFloat64},
{kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Signed32(),
kMachInt8},
{kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Unsigned32(),
kMachUint8},
{kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Signed32(),
kMachInt16},
{kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Unsigned32(),
kMachUint16},
{kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Signed32(),
kMachInt32},
{kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Unsigned32(),
kMachUint32},
{kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Number(),
kRepFloat32},
{kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Number(),
kRepFloat64}};
} // namespace
class SimplifiedElementAccessOperatorTest
: public TestWithZone,
public ::testing::WithParamInterface<ElementAccess> {};
TEST_P(SimplifiedElementAccessOperatorTest, LoadElement) {
SimplifiedOperatorBuilder simplified(zone());
const ElementAccess& access = GetParam();
const Operator* op = simplified.LoadElement(access);
EXPECT_EQ(IrOpcode::kLoadElement, op->opcode());
EXPECT_EQ(Operator::kNoThrow | Operator::kNoWrite, op->properties());
EXPECT_EQ(access, ElementAccessOf(op));
EXPECT_EQ(3, OperatorProperties::GetValueInputCount(op));
EXPECT_EQ(1, OperatorProperties::GetEffectInputCount(op));
EXPECT_EQ(0, OperatorProperties::GetControlInputCount(op));
EXPECT_EQ(4, OperatorProperties::GetTotalInputCount(op));
EXPECT_EQ(1, OperatorProperties::GetValueOutputCount(op));
EXPECT_EQ(1, OperatorProperties::GetEffectOutputCount(op));
EXPECT_EQ(0, OperatorProperties::GetControlOutputCount(op));
}
TEST_P(SimplifiedElementAccessOperatorTest, StoreElement) {
SimplifiedOperatorBuilder simplified(zone());
const ElementAccess& access = GetParam();
const Operator* op = simplified.StoreElement(access);
EXPECT_EQ(IrOpcode::kStoreElement, op->opcode());
EXPECT_EQ(Operator::kNoRead | Operator::kNoThrow, op->properties());
EXPECT_EQ(access, ElementAccessOf(op));
EXPECT_EQ(4, OperatorProperties::GetValueInputCount(op));
EXPECT_EQ(1, OperatorProperties::GetEffectInputCount(op));
EXPECT_EQ(1, OperatorProperties::GetControlInputCount(op));
EXPECT_EQ(6, OperatorProperties::GetTotalInputCount(op));
EXPECT_EQ(0, OperatorProperties::GetValueOutputCount(op));
EXPECT_EQ(1, OperatorProperties::GetEffectOutputCount(op));
EXPECT_EQ(0, OperatorProperties::GetControlOutputCount(op));
}
INSTANTIATE_TEST_CASE_P(SimplifiedOperatorTest,
SimplifiedElementAccessOperatorTest,
::testing::ValuesIn(kElementAccesses));
} // namespace compiler
} // namespace internal
} // namespace v8

View File

@ -13,6 +13,38 @@ namespace v8 {
namespace internal {
namespace compiler {
OStream& operator<<(OStream& os, BaseTaggedness base_taggedness) {
switch (base_taggedness) {
case kUntaggedBase:
return os << "untagged base";
case kTaggedBase:
return os << "tagged base";
}
UNREACHABLE();
return os;
}
bool operator==(ElementAccess const& lhs, ElementAccess const& rhs) {
return lhs.base_is_tagged == rhs.base_is_tagged &&
lhs.header_size == rhs.header_size && lhs.type == rhs.type &&
lhs.machine_type == rhs.machine_type;
}
bool operator!=(ElementAccess const& lhs, ElementAccess const& rhs) {
return !(lhs == rhs);
}
OStream& operator<<(OStream& os, ElementAccess const& access) {
os << "[" << access.base_is_tagged << ", " << access.header_size << ", ";
access.type->PrintTo(os);
os << ", " << access.machine_type << "]";
return os;
}
const FieldAccess& FieldAccessOf(const Operator* op) {
DCHECK_NOT_NULL(op);
DCHECK(op->opcode() == IrOpcode::kLoadField ||
@ -49,11 +81,11 @@ struct StaticParameterTraits<FieldAccess> {
// Specialization for static parameters of type {ElementAccess}.
template <>
struct StaticParameterTraits<ElementAccess> {
static OStream& PrintTo(OStream& os, const ElementAccess& val) {
return os << val.header_size;
static OStream& PrintTo(OStream& os, const ElementAccess& access) {
return os << access;
}
static int HashCode(const ElementAccess& val) {
return (val.header_size < 16) | (val.machine_type & 0xffff);
static int HashCode(const ElementAccess& access) {
return (access.header_size < 16) | (access.machine_type & 0xffff);
}
static bool Equals(const ElementAccess& lhs, const ElementAccess& rhs) {
return lhs.base_is_tagged == rhs.base_is_tagged &&
@ -93,8 +125,8 @@ struct StaticParameterTraits<ElementAccess> {
#define ACCESS_OP_LIST(V) \
V(LoadField, FieldAccess, Operator::kNoWrite, 1, 1) \
V(StoreField, FieldAccess, Operator::kNoRead, 2, 0) \
V(LoadElement, ElementAccess, Operator::kNoWrite, 2, 1) \
V(StoreElement, ElementAccess, Operator::kNoRead, 3, 0)
V(LoadElement, ElementAccess, Operator::kNoWrite, 3, 1) \
V(StoreElement, ElementAccess, Operator::kNoRead, 4, 0)
struct SimplifiedOperatorBuilderImpl FINAL {

View File

@ -28,6 +28,8 @@ struct SimplifiedOperatorBuilderImpl;
enum BaseTaggedness { kUntaggedBase, kTaggedBase };
OStream& operator<<(OStream&, BaseTaggedness);
// An access descriptor for loads/stores of fixed structures like field
// accesses of heap objects. Accesses from either tagged or untagged base
// pointers are supported; untagging is done automatically during lowering.
@ -55,6 +57,11 @@ struct ElementAccess {
int tag() const { return base_is_tagged == kTaggedBase ? kHeapObjectTag : 0; }
};
bool operator==(ElementAccess const& lhs, ElementAccess const& rhs);
bool operator!=(ElementAccess const& lhs, ElementAccess const& rhs);
OStream& operator<<(OStream&, ElementAccess const&);
// If the accessed object is not a heap object, add this to the header_size.
static const int kNonHeapObjectHeaderSize = kHeapObjectTag;
@ -122,8 +129,12 @@ class SimplifiedOperatorBuilder FINAL {
const Operator* LoadField(const FieldAccess&);
const Operator* StoreField(const FieldAccess&);
const Operator* LoadElement(const ElementAccess&);
const Operator* StoreElement(const ElementAccess&);
// load-element [base + index], length
const Operator* LoadElement(ElementAccess const&);
// store-element [base + index], length, value
const Operator* StoreElement(ElementAccess const&);
private:
Zone* zone() const { return zone_; }

View File

@ -127,12 +127,14 @@ class SimplifiedGraphBuilder : public GraphBuilder {
Node* StoreField(const FieldAccess& access, Node* object, Node* value) {
return NewNode(simplified()->StoreField(access), object, value);
}
Node* LoadElement(const ElementAccess& access, Node* object, Node* index) {
return NewNode(simplified()->LoadElement(access), object, index);
Node* LoadElement(const ElementAccess& access, Node* object, Node* index,
Node* length) {
return NewNode(simplified()->LoadElement(access), object, index, length);
}
Node* StoreElement(const ElementAccess& access, Node* object, Node* index,
Node* value) {
return NewNode(simplified()->StoreElement(access), object, index, value);
Node* length, Node* value) {
return NewNode(simplified()->StoreElement(access), object, index, length,
value);
}
protected:

View File

@ -338,6 +338,27 @@ TEST(Inputs) {
}
TEST(RemoveInput) {
GraphTester graph;
Node* n0 = graph.NewNode(&dummy_operator);
Node* n1 = graph.NewNode(&dummy_operator, n0);
Node* n2 = graph.NewNode(&dummy_operator, n0, n1);
n1->RemoveInput(0);
CHECK_EQ(0, n1->InputCount());
CHECK_EQ(1, n0->UseCount());
n2->RemoveInput(0);
CHECK_EQ(1, n2->InputCount());
CHECK_EQ(0, n0->UseCount());
CHECK_EQ(1, n1->UseCount());
n2->RemoveInput(0);
CHECK_EQ(0, n2->InputCount());
}
TEST(AppendInputsAndIterator) {
GraphTester graph;

View File

@ -207,8 +207,10 @@ TEST(RunLoadStoreMap) {
TEST(RunLoadStoreFixedArrayIndex) {
SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
ElementAccess access = AccessBuilder::ForFixedArrayElement();
Node* load = t.LoadElement(access, t.Parameter(0), t.Int32Constant(0));
t.StoreElement(access, t.Parameter(0), t.Int32Constant(1), load);
Node* load = t.LoadElement(access, t.Parameter(0), t.Int32Constant(0),
t.Int32Constant(2));
t.StoreElement(access, t.Parameter(0), t.Int32Constant(1), t.Int32Constant(2),
load);
t.Return(load);
t.LowerAllNodes();
@ -231,14 +233,16 @@ TEST(RunLoadStoreFixedArrayIndex) {
TEST(RunLoadStoreArrayBuffer) {
SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
const int index = 12;
const int array_length = 2 * index;
ElementAccess buffer_access =
AccessBuilder::ForBackingStoreElement(kMachInt8);
Node* backing_store = t.LoadField(
AccessBuilder::ForJSArrayBufferBackingStore(), t.Parameter(0));
Node* load =
t.LoadElement(buffer_access, backing_store, t.Int32Constant(index));
t.LoadElement(buffer_access, backing_store, t.Int32Constant(index),
t.Int32Constant(array_length));
t.StoreElement(buffer_access, backing_store, t.Int32Constant(index + 1),
load);
t.Int32Constant(array_length), load);
t.Return(t.jsgraph.TrueConstant());
t.LowerAllNodes();
@ -246,7 +250,6 @@ TEST(RunLoadStoreArrayBuffer) {
if (Pipeline::SupportedTarget()) {
Handle<JSArrayBuffer> array = t.factory()->NewJSArrayBuffer();
const int array_length = 2 * index;
Runtime::SetupArrayBufferAllocatingData(t.isolate(), array, array_length);
uint8_t* data = reinterpret_cast<uint8_t*>(array->backing_store());
for (int i = 0; i < array_length; i++) {
@ -326,8 +329,9 @@ TEST(RunLoadElementFromUntaggedBase) {
kMachAnyTagged};
SimplifiedLoweringTester<Object*> t;
Node* load = t.LoadElement(access, t.PointerConstant(smis),
t.Int32Constant(static_cast<int>(j)));
Node* load = t.LoadElement(
access, t.PointerConstant(smis), t.Int32Constant(static_cast<int>(j)),
t.Int32Constant(static_cast<int>(arraysize(smis))));
t.Return(load);
t.LowerAllNodes();
@ -356,7 +360,8 @@ TEST(RunStoreElementFromUntaggedBase) {
SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
Node* p0 = t.Parameter(0);
t.StoreElement(access, t.PointerConstant(smis),
t.Int32Constant(static_cast<int>(j)), p0);
t.Int32Constant(static_cast<int>(j)),
t.Int32Constant(static_cast<int>(arraysize(smis))), p0);
t.Return(p0);
t.LowerAllNodes();
@ -422,8 +427,10 @@ class AccessTester : public HandleAndZoneScope {
SimplifiedLoweringTester<Object*> t;
Node* ptr = GetBaseNode(&t);
Node* load = t.LoadElement(access, ptr, t.Int32Constant(from_index));
t.StoreElement(access, ptr, t.Int32Constant(to_index), load);
Node* load = t.LoadElement(access, ptr, t.Int32Constant(from_index),
t.Int32Constant(num_elements));
t.StoreElement(access, ptr, t.Int32Constant(to_index),
t.Int32Constant(num_elements), load);
t.Return(t.jsgraph.TrueConstant());
t.LowerAllNodes();
t.GenerateCode();
@ -633,11 +640,13 @@ class TestingGraph : public HandleAndZoneScope, public GraphAndBuilders {
JSGraph jsgraph;
Node* p0;
Node* p1;
Node* p2;
Node* start;
Node* end;
Node* ret;
explicit TestingGraph(Type* p0_type, Type* p1_type = Type::None())
explicit TestingGraph(Type* p0_type, Type* p1_type = Type::None(),
Type* p2_type = Type::None())
: GraphAndBuilders(main_zone()),
typer(main_zone()),
javascript(main_zone()),
@ -650,8 +659,10 @@ class TestingGraph : public HandleAndZoneScope, public GraphAndBuilders {
graph()->SetEnd(end);
p0 = graph()->NewNode(common()->Parameter(0), start);
p1 = graph()->NewNode(common()->Parameter(1), start);
p2 = graph()->NewNode(common()->Parameter(2), start);
NodeProperties::SetBounds(p0, Bounds(p0_type));
NodeProperties::SetBounds(p1, Bounds(p1_type));
NodeProperties::SetBounds(p2, Bounds(p2_type));
}
void CheckLoweringBinop(IrOpcode::Value expected, const Operator* op) {
@ -1341,8 +1352,9 @@ TEST(LowerLoadElement_to_load) {
ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
Type::Any(), machine_reps[i]};
Node* load = t.graph()->NewNode(t.simplified()->LoadElement(access), t.p0,
t.p1, t.start);
Node* load =
t.graph()->NewNode(t.simplified()->LoadElement(access), t.p0, t.p1,
t.jsgraph.Int32Constant(1024), t.start);
Node* use = t.Use(load, machine_reps[i]);
t.Return(use);
t.Lower();
@ -1365,7 +1377,8 @@ TEST(LowerStoreElement_to_store) {
Node* val = t.ExampleWithOutput(machine_reps[i]);
Node* store = t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0,
t.p1, val, t.start, t.start);
t.p1, t.jsgraph.Int32Constant(1024), val,
t.start, t.start);
t.Effect(store);
t.Lower();
CHECK_EQ(IrOpcode::kStore, store->opcode());
@ -1382,14 +1395,14 @@ TEST(LowerStoreElement_to_store) {
TEST(InsertChangeForLoadElementIndex) {
// LoadElement(obj: Tagged, index: kTypeInt32 | kRepTagged) =>
// LoadElement(obj: Tagged, index: kTypeInt32 | kRepTagged, length) =>
// Load(obj, Int32Add(Int32Mul(ChangeTaggedToInt32(index), #k), #k))
TestingGraph t(Type::Any(), Type::Signed32());
TestingGraph t(Type::Any(), Type::Signed32(), Type::Any());
ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(),
kMachAnyTagged};
Node* load = t.graph()->NewNode(t.simplified()->LoadElement(access), t.p0,
t.p1, t.start);
t.p1, t.p2, t.start);
t.Return(load);
t.Lower();
CHECK_EQ(IrOpcode::kLoad, load->opcode());
@ -1401,14 +1414,14 @@ TEST(InsertChangeForLoadElementIndex) {
TEST(InsertChangeForStoreElementIndex) {
// StoreElement(obj: Tagged, index: kTypeInt32 | kRepTagged, val) =>
// StoreElement(obj: Tagged, index: kTypeInt32 | kRepTagged, length, val) =>
// Store(obj, Int32Add(Int32Mul(ChangeTaggedToInt32(index), #k), #k), val)
TestingGraph t(Type::Any(), Type::Signed32());
TestingGraph t(Type::Any(), Type::Signed32(), Type::Any());
ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(),
kMachAnyTagged};
Node* store =
t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0, t.p1,
t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0, t.p1, t.p2,
t.jsgraph.TrueConstant(), t.start, t.start);
t.Effect(store);
t.Lower();
@ -1422,12 +1435,12 @@ TEST(InsertChangeForStoreElementIndex) {
TEST(InsertChangeForLoadElement) {
// TODO(titzer): test all load/store representation change insertions.
TestingGraph t(Type::Any(), Type::Signed32());
TestingGraph t(Type::Any(), Type::Signed32(), Type::Any());
ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(),
kMachFloat64};
Node* load = t.graph()->NewNode(t.simplified()->LoadElement(access), t.p0,
t.p1, t.start);
t.p1, t.p1, t.start);
t.Return(load);
t.Lower();
CHECK_EQ(IrOpcode::kLoad, load->opcode());
@ -1454,13 +1467,13 @@ TEST(InsertChangeForLoadField) {
TEST(InsertChangeForStoreElement) {
// TODO(titzer): test all load/store representation change insertions.
TestingGraph t(Type::Any(), Type::Signed32());
TestingGraph t(Type::Any(), Type::Signed32(), Type::Any());
ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(),
kMachFloat64};
Node* store =
t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0,
t.jsgraph.Int32Constant(0), t.p1, t.start, t.start);
Node* store = t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0,
t.jsgraph.Int32Constant(0), t.p2, t.p1,
t.start, t.start);
t.Effect(store);
t.Lower();