Commit de088f20 authored by bmeurer@chromium.org's avatar bmeurer@chromium.org

[turbofan] Introduce new Select operator to improve bounds checking.

TEST=mjsunit,unittests
R=dcarney@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#24980}
git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24980 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent db3eab1d
......@@ -50,6 +50,32 @@ BranchHint BranchHintOf(const Operator* const op) {
}
bool operator==(SelectParameters const& lhs, SelectParameters const& rhs) {
return lhs.type() == rhs.type() && lhs.hint() == rhs.hint();
}
bool operator!=(SelectParameters const& lhs, SelectParameters const& rhs) {
return !(lhs == rhs);
}
size_t hash_value(SelectParameters const& p) {
return base::hash_combine(p.type(), p.hint());
}
std::ostream& operator<<(std::ostream& os, SelectParameters const& p) {
return os << p.type() << "|" << p.hint();
}
SelectParameters const& SelectParametersOf(const Operator* const op) {
DCHECK_EQ(IrOpcode::kSelect, op->opcode());
return OpParameter<SelectParameters>(op);
}
size_t hash_value(OutputFrameStateCombine const& sc) {
return base::hash_combine(sc.kind_, sc.parameter_);
}
......@@ -219,6 +245,14 @@ const Operator* CommonOperatorBuilder::HeapConstant(
}
const Operator* CommonOperatorBuilder::Select(MachineType type,
BranchHint hint) {
return new (zone())
Operator1<SelectParameters>(IrOpcode::kSelect, Operator::kPure, 3, 1,
"Select", SelectParameters(type, hint));
}
const Operator* CommonOperatorBuilder::Phi(MachineType type, int arguments) {
DCHECK(arguments > 0); // Disallow empty phis.
return new (zone()) Operator1<MachineType>(IrOpcode::kPhi, Operator::kPure,
......
......@@ -33,6 +33,30 @@ std::ostream& operator<<(std::ostream&, BranchHint);
BranchHint BranchHintOf(const Operator* const);
class SelectParameters FINAL {
public:
explicit SelectParameters(MachineType type,
BranchHint hint = BranchHint::kNone)
: type_(type), hint_(hint) {}
MachineType type() const { return type_; }
BranchHint hint() const { return hint_; }
private:
const MachineType type_;
const BranchHint hint_;
};
bool operator==(SelectParameters const&, SelectParameters const&);
bool operator!=(SelectParameters const&, SelectParameters const&);
size_t hash_value(SelectParameters const& p);
std::ostream& operator<<(std::ostream&, SelectParameters const& p);
SelectParameters const& SelectParametersOf(const Operator* const);
// Flag that describes how to combine the current environment with
// the output of a node to obtain a framestate for lazy bailout.
class OutputFrameStateCombine {
......@@ -157,6 +181,7 @@ class CommonOperatorBuilder FINAL : public ZoneObject {
const Operator* NumberConstant(volatile double);
const Operator* HeapConstant(const Unique<HeapObject>&);
const Operator* Select(MachineType, BranchHint = BranchHint::kNone);
const Operator* Phi(MachineType type, int arguments);
const Operator* EffectPhi(int arguments);
const Operator* ValueEffect(int arguments);
......
......@@ -322,6 +322,8 @@ class ControlReducerImpl {
case IrOpcode::kLoop:
case IrOpcode::kMerge:
return ReduceMerge(node);
case IrOpcode::kSelect:
return ReduceSelect(node);
case IrOpcode::kPhi:
case IrOpcode::kEffectPhi:
return ReducePhi(node);
......@@ -330,6 +332,32 @@ class ControlReducerImpl {
}
}
// Reduce redundant selects.
Node* ReduceSelect(Node* const node) {
Node* const cond = node->InputAt(0);
Node* const tvalue = node->InputAt(1);
Node* const fvalue = node->InputAt(2);
if (tvalue == fvalue) return tvalue;
switch (cond->opcode()) {
case IrOpcode::kInt32Constant:
return Int32Matcher(cond).Is(0) ? fvalue : tvalue;
case IrOpcode::kInt64Constant:
return Int64Matcher(cond).Is(0) ? fvalue : tvalue;
case IrOpcode::kNumberConstant:
return NumberMatcher(cond).Is(0) ? fvalue : tvalue;
case IrOpcode::kHeapConstant: {
Handle<Object> object =
HeapObjectMatcher<Object>(cond).Value().handle();
if (object->IsTrue()) return tvalue;
if (object->IsFalse()) return fvalue;
break;
}
default:
break;
}
return node;
}
// Reduce redundant phis.
Node* ReducePhi(Node* node) {
int n = node->InputCount();
......@@ -406,6 +434,9 @@ class ControlReducerImpl {
case IrOpcode::kInt32Constant:
is_true = !Int32Matcher(cond).Is(0);
break;
case IrOpcode::kInt64Constant:
is_true = !Int64Matcher(cond).Is(0);
break;
case IrOpcode::kNumberConstant:
is_true = !NumberMatcher(cond).Is(0);
break;
......
......@@ -64,6 +64,7 @@ Reduction JSGenericLowering::Reduce(Node* node) {
Lower##x(node); \
break;
DECLARE_CASE(Branch)
DECLARE_CASE(Select)
JS_OP_LIST(DECLARE_CASE)
#undef DECLARE_CASE
default:
......@@ -241,6 +242,23 @@ void JSGenericLowering::LowerBranch(Node* node) {
}
void JSGenericLowering::LowerSelect(Node* node) {
// TODO(bmeurer): This should probably be moved into a separate file.
SelectParameters const& p = SelectParametersOf(node->op());
Node* branch = graph()->NewNode(common()->Branch(p.hint()), node->InputAt(0),
graph()->start());
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
Node* vtrue = node->InputAt(1);
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
Node* vfalse = node->InputAt(2);
Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
node->set_op(common()->Phi(p.type(), 2));
node->ReplaceInput(0, vtrue);
node->ReplaceInput(1, vfalse);
node->ReplaceInput(2, merge);
}
void JSGenericLowering::LowerJSUnaryNot(Node* node) {
Callable callable = CodeFactory::ToBoolean(
isolate(), ToBooleanStub::RESULT_AS_INVERSE_ODDBALL);
......
......@@ -612,7 +612,7 @@ Reduction JSTypedLowering::ReduceJSLoadProperty(Node* node) {
Handle<ExternalArray>::cast(handle(array->elements()));
Node* pointer = jsgraph()->IntPtrConstant(
bit_cast<intptr_t>(elements->external_pointer()));
Node* length = jsgraph()->Constant(byte_length / array->element_size());
Node* length = jsgraph()->Constant(array->length()->Number());
Node* effect = NodeProperties::GetEffectInput(node);
Node* load = graph()->NewNode(
simplified()->LoadElement(
......@@ -647,7 +647,7 @@ Reduction JSTypedLowering::ReduceJSStoreProperty(Node* node) {
Handle<ExternalArray>::cast(handle(array->elements()));
Node* pointer = jsgraph()->IntPtrConstant(
bit_cast<intptr_t>(elements->external_pointer()));
Node* length = jsgraph()->Constant(byte_length / array->element_size());
Node* length = jsgraph()->Constant(array->length()->Number());
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
Node* store = graph()->NewNode(
......
......@@ -50,6 +50,8 @@ enum MachineType {
kMachUint32 = kRepWord32 | kTypeUint32,
kMachInt64 = kRepWord64 | kTypeInt64,
kMachUint64 = kRepWord64 | kTypeUint64,
kMachIntPtr = (kPointerSize == 4) ? kMachInt32 : kMachInt64,
kMachUintPtr = (kPointerSize == 4) ? kMachUint32 : kMachUint64,
kMachPtr = (kPointerSize == 4) ? kRepWord32 : kRepWord64,
kMachAnyTagged = kRepTagged | kTypeAny
};
......
......@@ -81,6 +81,13 @@ typedef IntMatcher<int32_t, IrOpcode::kInt32Constant> Int32Matcher;
typedef IntMatcher<uint32_t, IrOpcode::kInt32Constant> Uint32Matcher;
typedef IntMatcher<int64_t, IrOpcode::kInt64Constant> Int64Matcher;
typedef IntMatcher<uint64_t, IrOpcode::kInt64Constant> Uint64Matcher;
#if V8_HOST_ARCH_32_BIT
typedef Int32Matcher IntPtrMatcher;
typedef Uint32Matcher UintPtrMatcher;
#else
typedef Int64Matcher IntPtrMatcher;
typedef Uint64Matcher UintPtrMatcher;
#endif
// A pattern matcher for floating point constants.
......@@ -138,6 +145,8 @@ typedef BinopMatcher<Int32Matcher, Int32Matcher> Int32BinopMatcher;
typedef BinopMatcher<Uint32Matcher, Uint32Matcher> Uint32BinopMatcher;
typedef BinopMatcher<Int64Matcher, Int64Matcher> Int64BinopMatcher;
typedef BinopMatcher<Uint64Matcher, Uint64Matcher> Uint64BinopMatcher;
typedef BinopMatcher<IntPtrMatcher, IntPtrMatcher> IntPtrBinopMatcher;
typedef BinopMatcher<UintPtrMatcher, UintPtrMatcher> UintPtrBinopMatcher;
typedef BinopMatcher<Float64Matcher, Float64Matcher> Float64BinopMatcher;
typedef BinopMatcher<NumberMatcher, NumberMatcher> NumberBinopMatcher;
......
......@@ -33,6 +33,7 @@
V(HeapConstant)
#define INNER_OP_LIST(V) \
V(Select) \
V(Phi) \
V(EffectPhi) \
V(ValueEffect) \
......
......@@ -299,6 +299,85 @@ class RepresentationSelector {
void VisitInt64Cmp(Node* node) { VisitBinop(node, kMachInt64, kRepBit); }
void VisitUint64Cmp(Node* node) { VisitBinop(node, kMachUint64, kRepBit); }
// Helper for handling selects.
// TODO(turbofan): Share some code with VisitPhi() below?
void VisitSelect(Node* node, MachineTypeUnion use,
SimplifiedLowering* lowering) {
ProcessInput(node, 0, kRepBit);
// Selects adapt to the output representation their uses demand, pushing
// representation changes to their inputs.
Type* upper = NodeProperties::GetBounds(node).upper;
MachineType output = kMachNone;
MachineType propagate = kMachNone;
if (upper->Is(Type::Signed32()) || upper->Is(Type::Unsigned32())) {
// legal = kRepTagged | kRepFloat64 | kRepWord32;
if ((use & kRepMask) == kRepTagged) {
// only tagged uses.
output = kRepTagged;
propagate = kRepTagged;
} else if ((use & kRepMask) == kRepFloat64) {
// only float64 uses.
output = kRepFloat64;
propagate = kRepFloat64;
} else {
// multiple uses.
output = kRepWord32;
propagate = kRepWord32;
}
} else if (upper->Is(Type::Boolean())) {
// legal = kRepTagged | kRepBit;
if ((use & kRepMask) == kRepTagged) {
// only tagged uses.
output = kRepTagged;
propagate = kRepTagged;
} else {
// multiple uses.
output = kRepBit;
propagate = kRepBit;
}
} else if (upper->Is(Type::Number())) {
// legal = kRepTagged | kRepFloat64;
if ((use & kRepMask) == kRepTagged) {
// only tagged uses.
output = kRepTagged;
propagate = kRepTagged;
} else {
// multiple uses.
output = kRepFloat64;
propagate = kRepFloat64;
}
} else {
// legal = kRepTagged;
output = kRepTagged;
propagate = kRepTagged;
}
MachineType output_type =
static_cast<MachineType>(changer_->TypeFromUpperBound(upper) | output);
SetOutput(node, output_type);
if (lower()) {
// Update the select operator.
SelectParameters p = SelectParametersOf(node->op());
MachineType type = static_cast<MachineType>(output_type);
if (type != p.type()) {
node->set_op(lowering->common()->Select(type, p.hint()));
}
// Convert inputs to the output representation of this select.
ProcessInput(node, 1, output_type);
ProcessInput(node, 2, output_type);
} else {
// Propagate {use} of the select to value inputs.
MachineType use_type =
static_cast<MachineType>((use & kTypeMask) | propagate);
ProcessInput(node, 1, use_type);
ProcessInput(node, 2, use_type);
}
}
// Helper for handling phis.
void VisitPhi(Node* node, MachineTypeUnion use,
SimplifiedLowering* lowering) {
......@@ -481,6 +560,8 @@ class RepresentationSelector {
ProcessInput(node, 0, kRepBit);
Enqueue(NodeProperties::GetControlInput(node, 0));
break;
case IrOpcode::kSelect:
return VisitSelect(node, use, lowering);
case IrOpcode::kPhi:
return VisitPhi(node, use, lowering);
......@@ -1057,25 +1138,67 @@ void SimplifiedLowering::DoStoreField(Node* node) {
Node* SimplifiedLowering::ComputeIndex(const ElementAccess& access,
Node* index) {
int element_size = ElementSizeOf(access.machine_type);
Node* const key) {
Node* index = key;
const int element_size = ElementSizeOf(access.machine_type);
if (element_size != 1) {
index = graph()->NewNode(machine()->Int32Mul(),
jsgraph()->Int32Constant(element_size), index);
index = graph()->NewNode(machine()->Int32Mul(), index,
jsgraph()->Int32Constant(element_size));
}
int fixed_offset = access.header_size - access.tag();
if (fixed_offset == 0) return index;
return graph()->NewNode(machine()->Int32Add(), index,
const int fixed_offset = access.header_size - access.tag();
if (fixed_offset != 0) {
index = graph()->NewNode(machine()->Int32Add(), index,
jsgraph()->Int32Constant(fixed_offset));
}
// TODO(bmeurer): 64-Bit
// if (machine()->Is64()) {
// index = graph()->NewNode(machine()->ChangeInt32ToInt64(), index);
// }
return index;
}
namespace {
intptr_t AddressForOutOfBoundsLoad(MachineType type) {
switch (RepresentationOf(type)) {
case kRepFloat32: {
static const float dummy = std::numeric_limits<float>::quiet_NaN();
return bit_cast<intptr_t>(&dummy);
}
case kRepFloat64: {
static const double dummy = std::numeric_limits<double>::quiet_NaN();
return bit_cast<intptr_t>(&dummy);
}
case kRepBit:
case kRepWord8:
case kRepWord16:
case kRepWord32: {
static const int32_t dummy = 0;
return bit_cast<intptr_t>(&dummy);
}
default:
break;
}
UNREACHABLE();
return 0;
}
intptr_t AddressForOutOfBoundsStore() {
static volatile double dummy = 0;
return bit_cast<intptr_t>(&dummy);
}
} // namespace
void SimplifiedLowering::DoLoadElement(Node* node, MachineType output_type) {
const ElementAccess& access = ElementAccessOf(node->op());
const Operator* op = machine()->Load(access.machine_type);
Node* key = node->InputAt(1);
Node* effect = node->InputAt(3);
Node* index = ComputeIndex(access, key);
Node* effect = node->InputAt(3);
if (access.bounds_check == kNoBoundsCheck) {
DCHECK_EQ(access.machine_type, output_type);
node->set_op(op);
......@@ -1087,10 +1210,22 @@ void SimplifiedLowering::DoLoadElement(Node* node, MachineType output_type) {
Node* base = node->InputAt(0);
Node* length = node->InputAt(2);
Node* check = graph()->NewNode(machine()->Uint32LessThan(), key, length);
Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), check,
graph()->start());
IntPtrMatcher mbase(base);
if (mbase.HasValue() && (output_type & kRepTagged) == 0) {
Node* select = graph()->NewNode(
common()->Select(kMachIntPtr, BranchHint::kTrue), check, index,
jsgraph()->IntPtrConstant(AddressForOutOfBoundsLoad(output_type) -
mbase.Value()));
node->set_op(op);
node->ReplaceInput(1, select);
node->ReplaceInput(2, effect);
node->ReplaceInput(3, graph()->start());
} else {
Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
check, graph()->start());
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
Node* load = graph()->NewNode(op, base, index, effect, if_true);
......@@ -1100,20 +1235,21 @@ void SimplifiedLowering::DoLoadElement(Node* node, MachineType output_type) {
SimplifiedOperatorBuilder simplified(graph()->zone());
RepresentationChanger changer(jsgraph(), &simplified,
graph()->zone()->isolate());
result = changer.GetTaggedRepresentationFor(result, access.machine_type);
result =
changer.GetTaggedRepresentationFor(result, access.machine_type);
}
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
Node* undefined;
if (output_type & kRepTagged) {
DCHECK(!(access.machine_type & kRepTagged));
DCHECK_EQ(0, access.machine_type & kRepTagged);
undefined = jsgraph()->UndefinedConstant();
} else if (output_type & kRepFloat32) {
undefined =
jsgraph()->Float32Constant(std::numeric_limits<float>::quiet_NaN());
} else if (output_type & kRepFloat64) {
undefined =
jsgraph()->Float64Constant(std::numeric_limits<double>::quiet_NaN());
undefined = jsgraph()->Float64Constant(
std::numeric_limits<double>::quiet_NaN());
} else {
undefined = jsgraph()->Int32Constant(0);
}
......@@ -1136,6 +1272,7 @@ void SimplifiedLowering::DoLoadElement(Node* node, MachineType output_type) {
node->ReplaceInput(2, merge);
node->TrimInputCount(3);
}
}
}
......@@ -1159,8 +1296,19 @@ void SimplifiedLowering::DoStoreElement(Node* node) {
Node* value = node->InputAt(3);
Node* effect = node->InputAt(4);
Node* control = node->InputAt(5);
Node* check = graph()->NewNode(machine()->Uint32LessThan(), key, length);
IntPtrMatcher mbase(base);
if (mbase.HasValue()) {
Node* select = graph()->NewNode(
common()->Select(kMachIntPtr, BranchHint::kTrue), check, index,
jsgraph()->IntPtrConstant(AddressForOutOfBoundsStore() -
mbase.Value()));
node->set_op(op);
node->ReplaceInput(1, select);
node->RemoveInput(2);
} else {
Node* branch =
graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
......@@ -1177,6 +1325,7 @@ void SimplifiedLowering::DoStoreElement(Node* node) {
node->ReplaceInput(2, merge);
node->TrimInputCount(3);
}
}
}
......@@ -1375,7 +1524,6 @@ void SimplifiedLowering::DoStringLessThanOrEqual(Node* node) {
node->ReplaceInput(1, jsgraph()->SmiConstant(EQUAL));
}
} // namespace compiler
} // namespace internal
} // namespace v8
......@@ -40,7 +40,7 @@ class SimplifiedLowering FINAL {
Node* IsTagged(Node* node);
Node* Untag(Node* node);
Node* OffsetMinusTagConstant(int32_t offset);
Node* ComputeIndex(const ElementAccess& access, Node* index);
Node* ComputeIndex(const ElementAccess& access, Node* const key);
Node* StringComparison(Node* node, bool requires_ordering);
Node* Int32Div(Node* const node);
Node* Int32Mod(Node* const node);
......
......@@ -535,6 +535,11 @@ Bounds Typer::Visitor::TypeExternalConstant(Node* node) {
}
Bounds Typer::Visitor::TypeSelect(Node* node) {
return Bounds::Either(Operand(node, 1), Operand(node, 2), zone());
}
Bounds Typer::Visitor::TypePhi(Node* node) {
int arity = OperatorProperties::GetValueInputCount(node->op());
Bounds bounds = Operand(node, 0);
......
......@@ -310,6 +310,12 @@ GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) {
CheckUpperIs(node, Type::Any());
break;
}
case IrOpcode::kSelect: {
CHECK_EQ(0, effect_count);
CHECK_EQ(0, control_count);
CHECK_EQ(3, value_count);
break;
}
case IrOpcode::kPhi: {
// Phi input count matches parent control node.
CHECK_EQ(0, effect_count);
......
......@@ -10,16 +10,28 @@ function Module(stdlib, foreign, heap) {
i = MEM16[i >> 1] | 0;
return i;
}
function loadm1() {
return MEM16[-1] | 0;
}
function store(i, v) {
i = i|0;
v = v|0;
MEM16[i >> 1] = v;
}
return { load: load, store: store };
function storem1(v) {
v = v|0;
MEM16[-1] = v;
}
return {load: load, loadm1: loadm1, store: store, storem1: storem1};
}
var m = Module(this, {}, new ArrayBuffer(2));
m.store(-1000, 4);
assertEquals(0, m.load(-1000));
assertEquals(0, m.loadm1());
m.storem1(1);
assertEquals(0, m.loadm1());
m.store(0, 32767);
for (var i = 1; i < 64; ++i) {
m.store(i * 2 * 32 * 1024, i);
......
......@@ -156,16 +156,19 @@ const double kDoubleValues[] = {-std::numeric_limits<double>::infinity(),
std::numeric_limits<double>::quiet_NaN(),
std::numeric_limits<double>::signaling_NaN()};
const BranchHint kHints[] = {BranchHint::kNone, BranchHint::kTrue,
BranchHint::kFalse};
} // namespace
TEST_F(CommonOperatorTest, Branch) {
static const BranchHint kHints[] = {BranchHint::kNone, BranchHint::kTrue,
BranchHint::kFalse};
TRACED_FOREACH(BranchHint, hint, kHints) {
const Operator* const op = common()->Branch(hint);
EXPECT_EQ(IrOpcode::kBranch, op->opcode());
EXPECT_EQ(Operator::kFoldable, op->properties());
EXPECT_EQ(hint, BranchHintOf(op));
EXPECT_EQ(1, OperatorProperties::GetValueInputCount(op));
EXPECT_EQ(0, OperatorProperties::GetEffectInputCount(op));
EXPECT_EQ(1, OperatorProperties::GetControlInputCount(op));
......@@ -177,6 +180,30 @@ TEST_F(CommonOperatorTest, Branch) {
}
TEST_F(CommonOperatorTest, Select) {
static const MachineType kTypes[] = {
kMachInt8, kMachUint8, kMachInt16, kMachUint16,
kMachInt32, kMachUint32, kMachInt64, kMachUint64,
kMachFloat32, kMachFloat64, kMachAnyTagged};
TRACED_FOREACH(MachineType, type, kTypes) {
TRACED_FOREACH(BranchHint, hint, kHints) {
const Operator* const op = common()->Select(type, hint);
EXPECT_EQ(IrOpcode::kSelect, op->opcode());
EXPECT_EQ(Operator::kPure, op->properties());
EXPECT_EQ(type, SelectParametersOf(op).type());
EXPECT_EQ(hint, SelectParametersOf(op).hint());
EXPECT_EQ(3, OperatorProperties::GetValueInputCount(op));
EXPECT_EQ(0, OperatorProperties::GetEffectInputCount(op));
EXPECT_EQ(0, OperatorProperties::GetControlInputCount(op));
EXPECT_EQ(3, OperatorProperties::GetTotalInputCount(op));
EXPECT_EQ(1, OperatorProperties::GetValueOutputCount(op));
EXPECT_EQ(0, OperatorProperties::GetEffectOutputCount(op));
EXPECT_EQ(0, OperatorProperties::GetControlOutputCount(op));
}
}
}
TEST_F(CommonOperatorTest, Float32Constant) {
TRACED_FOREACH(float, value, kFloatValues) {
const Operator* op = common()->Float32Constant(value);
......
......@@ -114,9 +114,9 @@ TEST_F(JSTypedLoweringTest, JSToBooleanWithOrderedNumberAndBoolean) {
TEST_F(JSTypedLoweringTest, JSLoadPropertyFromExternalTypedArray) {
const size_t kLength = 17;
uint8_t backing_store[kLength * 8];
double backing_store[kLength];
Handle<JSArrayBuffer> buffer =
NewArrayBuffer(backing_store, arraysize(backing_store));
NewArrayBuffer(backing_store, sizeof(backing_store));
VectorSlotPair feedback(Handle<TypeFeedbackVector>::null(),
FeedbackVectorICSlot::Invalid());
TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) {
......@@ -138,12 +138,11 @@ TEST_F(JSTypedLoweringTest, JSLoadPropertyFromExternalTypedArray) {
Reduction r = Reduce(node);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(
r.replacement(),
IsLoadElement(AccessBuilder::ForTypedArrayElement(type, true),
EXPECT_THAT(r.replacement(),
IsLoadElement(
AccessBuilder::ForTypedArrayElement(type, true),
IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])),
key, IsNumberConstant(static_cast<double>(kLength)),
effect));
key, IsNumberConstant(array->length()->Number()), effect));
}
}
......@@ -154,9 +153,9 @@ TEST_F(JSTypedLoweringTest, JSLoadPropertyFromExternalTypedArray) {
TEST_F(JSTypedLoweringTest, JSStorePropertyToExternalTypedArray) {
const size_t kLength = 17;
uint8_t backing_store[kLength * 8];
double backing_store[kLength];
Handle<JSArrayBuffer> buffer =
NewArrayBuffer(backing_store, arraysize(backing_store));
NewArrayBuffer(backing_store, sizeof(backing_store));
TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) {
TRACED_FOREACH(StrictMode, strict_mode, kStrictModes) {
Handle<JSTypedArray> array =
......@@ -182,8 +181,8 @@ TEST_F(JSTypedLoweringTest, JSStorePropertyToExternalTypedArray) {
IsStoreElement(
AccessBuilder::ForTypedArrayElement(type, true),
IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])),
key, IsNumberConstant(static_cast<double>(kLength)),
value, effect, control));
key, IsNumberConstant(array->length()->Number()), value,
effect, control));
}
}
}
......
......@@ -208,6 +208,52 @@ class IsConstantMatcher FINAL : public NodeMatcher {
};
class IsSelectMatcher FINAL : public NodeMatcher {
public:
IsSelectMatcher(const Matcher<MachineType>& type_matcher,
const Matcher<Node*>& value0_matcher,
const Matcher<Node*>& value1_matcher,
const Matcher<Node*>& value2_matcher)
: NodeMatcher(IrOpcode::kSelect),
type_matcher_(type_matcher),
value0_matcher_(value0_matcher),
value1_matcher_(value1_matcher),
value2_matcher_(value2_matcher) {}
virtual void DescribeTo(std::ostream* os) const OVERRIDE {
NodeMatcher::DescribeTo(os);
*os << " whose type (";
type_matcher_.DescribeTo(os);
*os << "), value0 (";
value0_matcher_.DescribeTo(os);
*os << "), value1 (";
value1_matcher_.DescribeTo(os);
*os << ") and value2 (";
value2_matcher_.DescribeTo(os);
*os << ")";
}
virtual bool MatchAndExplain(Node* node,
MatchResultListener* listener) const OVERRIDE {
return (NodeMatcher::MatchAndExplain(node, listener) &&
PrintMatchAndExplain(OpParameter<MachineType>(node), "type",
type_matcher_, listener) &&
PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0),
"value0", value0_matcher_, listener) &&
PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1),
"value1", value1_matcher_, listener) &&
PrintMatchAndExplain(NodeProperties::GetValueInput(node, 2),
"value2", value2_matcher_, listener));
}
private:
const Matcher<MachineType> type_matcher_;
const Matcher<Node*> value0_matcher_;
const Matcher<Node*> value1_matcher_;
const Matcher<Node*> value2_matcher_;
};
class IsPhiMatcher FINAL : public NodeMatcher {
public:
IsPhiMatcher(const Matcher<MachineType>& type_matcher,
......@@ -765,6 +811,15 @@ Matcher<Node*> IsNumberConstant(const Matcher<double>& value_matcher) {
}
Matcher<Node*> IsSelect(const Matcher<MachineType>& type_matcher,
const Matcher<Node*>& value0_matcher,
const Matcher<Node*>& value1_matcher,
const Matcher<Node*>& value2_matcher) {
return MakeMatcher(new IsSelectMatcher(type_matcher, value0_matcher,
value1_matcher, value2_matcher));
}
Matcher<Node*> IsPhi(const Matcher<MachineType>& type_matcher,
const Matcher<Node*>& value0_matcher,
const Matcher<Node*>& value1_matcher,
......@@ -857,6 +912,7 @@ Matcher<Node*> IsStore(const Matcher<StoreRepresentation>& rep_matcher,
IS_BINOP_MATCHER(NumberEqual)
IS_BINOP_MATCHER(NumberLessThan)
IS_BINOP_MATCHER(NumberSubtract)
IS_BINOP_MATCHER(NumberMultiply)
IS_BINOP_MATCHER(Word32And)
IS_BINOP_MATCHER(Word32Sar)
IS_BINOP_MATCHER(Word32Shl)
......
......@@ -48,6 +48,10 @@ Matcher<Node*> IsFloat64Constant(const Matcher<double>& value_matcher);
Matcher<Node*> IsInt32Constant(const Matcher<int32_t>& value_matcher);
Matcher<Node*> IsInt64Constant(const Matcher<int64_t>& value_matcher);
Matcher<Node*> IsNumberConstant(const Matcher<double>& value_matcher);
Matcher<Node*> IsSelect(const Matcher<MachineType>& type_matcher,
const Matcher<Node*>& value0_matcher,
const Matcher<Node*>& value1_matcher,
const Matcher<Node*>& value2_matcher);
Matcher<Node*> IsPhi(const Matcher<MachineType>& type_matcher,
const Matcher<Node*>& value0_matcher,
const Matcher<Node*>& value1_matcher,
......@@ -69,6 +73,8 @@ Matcher<Node*> IsNumberLessThan(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher);
Matcher<Node*> IsNumberSubtract(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher);
Matcher<Node*> IsNumberMultiply(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher);
Matcher<Node*> IsLoadField(const Matcher<FieldAccess>& access_matcher,
const Matcher<Node*>& base_matcher,
const Matcher<Node*>& effect_matcher,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment