[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:
parent
9e0801c306
commit
deaf463bf1
@ -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;
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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_; }
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user