Commit e1bd9af1 authored by jarin's avatar jarin Committed by Commit bot

[turbofan] Add more sanity checks to representation inference.

The CL also add guard nodes to places where we assume that certain
values are numbers.

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

Cr-Commit-Position: refs/heads/master@{#34977}
parent 1d0df88b
...@@ -147,11 +147,19 @@ Reduction JSIntrinsicLowering::ReduceDeoptimizeNow(Node* node) { ...@@ -147,11 +147,19 @@ Reduction JSIntrinsicLowering::ReduceDeoptimizeNow(Node* node) {
Reduction JSIntrinsicLowering::ReduceDoubleHi(Node* node) { Reduction JSIntrinsicLowering::ReduceDoubleHi(Node* node) {
// Tell the compiler to assume number input.
Node* renamed = graph()->NewNode(common()->Guard(Type::Number()),
node->InputAt(0), graph()->start());
node->ReplaceInput(0, renamed);
return Change(node, machine()->Float64ExtractHighWord32()); return Change(node, machine()->Float64ExtractHighWord32());
} }
Reduction JSIntrinsicLowering::ReduceDoubleLo(Node* node) { Reduction JSIntrinsicLowering::ReduceDoubleLo(Node* node) {
// Tell the compiler to assume number input.
Node* renamed = graph()->NewNode(common()->Guard(Type::Number()),
node->InputAt(0), graph()->start());
node->ReplaceInput(0, renamed);
return Change(node, machine()->Float64ExtractLowWord32()); return Change(node, machine()->Float64ExtractLowWord32());
} }
...@@ -217,6 +225,10 @@ Reduction JSIntrinsicLowering::ReduceMathFloor(Node* node) { ...@@ -217,6 +225,10 @@ Reduction JSIntrinsicLowering::ReduceMathFloor(Node* node) {
Reduction JSIntrinsicLowering::ReduceMathSqrt(Node* node) { Reduction JSIntrinsicLowering::ReduceMathSqrt(Node* node) {
// Tell the compiler to assume number input.
Node* renamed = graph()->NewNode(common()->Guard(Type::Number()),
node->InputAt(0), graph()->start());
node->ReplaceInput(0, renamed);
return Change(node, machine()->Float64Sqrt()); return Change(node, machine()->Float64Sqrt());
} }
...@@ -377,7 +389,8 @@ Reduction JSIntrinsicLowering::ReduceToInteger(Node* node) { ...@@ -377,7 +389,8 @@ Reduction JSIntrinsicLowering::ReduceToInteger(Node* node) {
Node* if_true = graph()->NewNode(common()->IfTrue(), branch); Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
Node* etrue = effect; Node* etrue = effect;
Node* vtrue = value; Node* vtrue =
graph()->NewNode(common()->Guard(type_cache_.kSmi), value, if_true);
Node* if_false = graph()->NewNode(common()->IfFalse(), branch); Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
Node* efalse = effect; Node* efalse = effect;
...@@ -386,6 +399,9 @@ Reduction JSIntrinsicLowering::ReduceToInteger(Node* node) { ...@@ -386,6 +399,9 @@ Reduction JSIntrinsicLowering::ReduceToInteger(Node* node) {
vfalse = efalse = vfalse = efalse =
graph()->NewNode(javascript()->CallRuntime(Runtime::kToInteger), value, graph()->NewNode(javascript()->CallRuntime(Runtime::kToInteger), value,
context, frame_state, efalse, if_false); context, frame_state, efalse, if_false);
// TODO(jarin) Intersect the type with integers?
NodeProperties::SetType(vfalse, NodeProperties::GetType(node));
if_false = graph()->NewNode(common()->IfSuccess(), vfalse); if_false = graph()->NewNode(common()->IfSuccess(), vfalse);
} }
...@@ -393,6 +409,7 @@ Reduction JSIntrinsicLowering::ReduceToInteger(Node* node) { ...@@ -393,6 +409,7 @@ Reduction JSIntrinsicLowering::ReduceToInteger(Node* node) {
effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control); effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
value = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), value = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
vtrue, vfalse, control); vtrue, vfalse, control);
// TODO(bmeurer, mstarzinger): Rewire IfException inputs to {vfalse}. // TODO(bmeurer, mstarzinger): Rewire IfException inputs to {vfalse}.
ReplaceWithValue(node, value, effect, control); ReplaceWithValue(node, value, effect, control);
return Changed(value); return Changed(value);
......
...@@ -142,7 +142,8 @@ Node* RepresentationChanger::GetRepresentationFor( ...@@ -142,7 +142,8 @@ Node* RepresentationChanger::GetRepresentationFor(
case MachineRepresentation::kWord8: case MachineRepresentation::kWord8:
case MachineRepresentation::kWord16: case MachineRepresentation::kWord16:
case MachineRepresentation::kWord32: case MachineRepresentation::kWord32:
return GetWord32RepresentationFor(node, output_rep, output_type); return GetWord32RepresentationFor(node, output_rep, output_type,
truncation);
case MachineRepresentation::kWord64: case MachineRepresentation::kWord64:
return GetWord64RepresentationFor(node, output_rep, output_type); return GetWord64RepresentationFor(node, output_rep, output_type);
case MachineRepresentation::kSimd128: // Fall through. case MachineRepresentation::kSimd128: // Fall through.
...@@ -234,30 +235,34 @@ Node* RepresentationChanger::GetFloat32RepresentationFor( ...@@ -234,30 +235,34 @@ Node* RepresentationChanger::GetFloat32RepresentationFor(
break; break;
} }
// Select the correct X -> Float32 operator. // Select the correct X -> Float32 operator.
const Operator* op; const Operator* op = nullptr;
if (output_rep == MachineRepresentation::kBit) { if (IsWord(output_rep)) {
return TypeError(node, output_rep, output_type,
MachineRepresentation::kFloat32);
} else if (IsWord(output_rep)) {
if (output_type->Is(Type::Signed32())) { if (output_type->Is(Type::Signed32())) {
// int32 -> float64 -> float32
op = machine()->ChangeInt32ToFloat64(); op = machine()->ChangeInt32ToFloat64();
} else { node = jsgraph()->graph()->NewNode(op, node);
// Either the output is int32 or the uses only care about the op = machine()->TruncateFloat64ToFloat32();
// low 32 bits (so we can pick int32 safely). } else if (output_type->Is(Type::Unsigned32()) ||
DCHECK(output_type->Is(Type::Unsigned32()) || truncation.TruncatesToWord32()) {
truncation.TruncatesToWord32()); // Either the output is uint32 or the uses only care about the
// low 32 bits (so we can pick uint32 safely).
// uint32 -> float64 -> float32
op = machine()->ChangeUint32ToFloat64(); op = machine()->ChangeUint32ToFloat64();
node = jsgraph()->graph()->NewNode(op, node);
op = machine()->TruncateFloat64ToFloat32();
} }
// int32 -> float64 -> float32
node = jsgraph()->graph()->NewNode(op, node);
op = machine()->TruncateFloat64ToFloat32();
} else if (output_rep == MachineRepresentation::kTagged) { } else if (output_rep == MachineRepresentation::kTagged) {
op = simplified()->ChangeTaggedToFloat64(); // tagged -> float64 -> float32 if (output_type->Is(Type::Number())) {
node = jsgraph()->graph()->NewNode(op, node); op = simplified()
op = machine()->TruncateFloat64ToFloat32(); ->ChangeTaggedToFloat64(); // tagged -> float64 -> float32
node = jsgraph()->graph()->NewNode(op, node);
op = machine()->TruncateFloat64ToFloat32();
}
} else if (output_rep == MachineRepresentation::kFloat64) { } else if (output_rep == MachineRepresentation::kFloat64) {
op = machine()->TruncateFloat64ToFloat32(); op = machine()->TruncateFloat64ToFloat32();
} else { }
if (op == nullptr) {
return TypeError(node, output_rep, output_type, return TypeError(node, output_rep, output_type,
MachineRepresentation::kFloat32); MachineRepresentation::kFloat32);
} }
...@@ -289,25 +294,24 @@ Node* RepresentationChanger::GetFloat64RepresentationFor( ...@@ -289,25 +294,24 @@ Node* RepresentationChanger::GetFloat64RepresentationFor(
break; break;
} }
// Select the correct X -> Float64 operator. // Select the correct X -> Float64 operator.
const Operator* op; const Operator* op = nullptr;
if (output_rep == MachineRepresentation::kBit) { if (IsWord(output_rep)) {
return TypeError(node, output_rep, output_type,
MachineRepresentation::kFloat64);
} else if (IsWord(output_rep)) {
if (output_type->Is(Type::Signed32())) { if (output_type->Is(Type::Signed32())) {
op = machine()->ChangeInt32ToFloat64(); op = machine()->ChangeInt32ToFloat64();
} else { } else if (output_type->Is(Type::Unsigned32()) ||
// Either the output is int32 or the uses only care about the truncation.TruncatesToWord32()) {
// low 32 bits (so we can pick int32 safely). // Either the output is uint32 or the uses only care about the
DCHECK(output_type->Is(Type::Unsigned32()) || // low 32 bits (so we can pick uint32 safely).
truncation.TruncatesToWord32());
op = machine()->ChangeUint32ToFloat64(); op = machine()->ChangeUint32ToFloat64();
} }
} else if (output_rep == MachineRepresentation::kTagged) { } else if (output_rep == MachineRepresentation::kTagged) {
op = simplified()->ChangeTaggedToFloat64(); if (output_type->Is(Type::Number())) {
op = simplified()->ChangeTaggedToFloat64();
}
} else if (output_rep == MachineRepresentation::kFloat32) { } else if (output_rep == MachineRepresentation::kFloat32) {
op = machine()->ChangeFloat32ToFloat64(); op = machine()->ChangeFloat32ToFloat64();
} else { }
if (op == nullptr) {
return TypeError(node, output_rep, output_type, return TypeError(node, output_rep, output_type,
MachineRepresentation::kFloat64); MachineRepresentation::kFloat64);
} }
...@@ -319,9 +323,9 @@ Node* RepresentationChanger::MakeTruncatedInt32Constant(double value) { ...@@ -319,9 +323,9 @@ Node* RepresentationChanger::MakeTruncatedInt32Constant(double value) {
return jsgraph()->Int32Constant(DoubleToInt32(value)); return jsgraph()->Int32Constant(DoubleToInt32(value));
} }
Node* RepresentationChanger::GetWord32RepresentationFor( Node* RepresentationChanger::GetWord32RepresentationFor(
Node* node, MachineRepresentation output_rep, Type* output_type) { Node* node, MachineRepresentation output_rep, Type* output_type,
Truncation truncation) {
// Eagerly fold representation changes for constants. // Eagerly fold representation changes for constants.
switch (node->opcode()) { switch (node->opcode()) {
case IrOpcode::kInt32Constant: case IrOpcode::kInt32Constant:
...@@ -335,43 +339,37 @@ Node* RepresentationChanger::GetWord32RepresentationFor( ...@@ -335,43 +339,37 @@ Node* RepresentationChanger::GetWord32RepresentationFor(
break; break;
} }
// Select the correct X -> Word32 operator. // Select the correct X -> Word32 operator.
const Operator* op; const Operator* op = nullptr;
Type* type = NodeProperties::GetType(node);
if (output_rep == MachineRepresentation::kBit) { if (output_rep == MachineRepresentation::kBit) {
return node; // Sloppy comparison -> word32 return node; // Sloppy comparison -> word32
} else if (output_rep == MachineRepresentation::kFloat64) { } else if (output_rep == MachineRepresentation::kFloat64) {
// TODO(jarin) Use only output_type here, once we intersect it with the if (output_type->Is(Type::Unsigned32())) {
// type inferred by the typer.
if (output_type->Is(Type::Unsigned32()) || type->Is(Type::Unsigned32())) {
op = machine()->ChangeFloat64ToUint32(); op = machine()->ChangeFloat64ToUint32();
} else if (output_type->Is(Type::Signed32()) || } else if (output_type->Is(Type::Signed32())) {
type->Is(Type::Signed32())) {
op = machine()->ChangeFloat64ToInt32(); op = machine()->ChangeFloat64ToInt32();
} else { } else if (truncation.TruncatesToWord32()) {
op = machine()->TruncateFloat64ToInt32(TruncationMode::kJavaScript); op = machine()->TruncateFloat64ToInt32(TruncationMode::kJavaScript);
} }
} else if (output_rep == MachineRepresentation::kFloat32) { } else if (output_rep == MachineRepresentation::kFloat32) {
node = InsertChangeFloat32ToFloat64(node); // float32 -> float64 -> int32 node = InsertChangeFloat32ToFloat64(node); // float32 -> float64 -> int32
if (output_type->Is(Type::Unsigned32()) || type->Is(Type::Unsigned32())) { if (output_type->Is(Type::Unsigned32())) {
op = machine()->ChangeFloat64ToUint32(); op = machine()->ChangeFloat64ToUint32();
} else if (output_type->Is(Type::Signed32()) || } else if (output_type->Is(Type::Signed32())) {
type->Is(Type::Signed32())) {
op = machine()->ChangeFloat64ToInt32(); op = machine()->ChangeFloat64ToInt32();
} else { } else if (truncation.TruncatesToWord32()) {
op = machine()->TruncateFloat64ToInt32(TruncationMode::kJavaScript); op = machine()->TruncateFloat64ToInt32(TruncationMode::kJavaScript);
} }
} else if (output_rep == MachineRepresentation::kTagged) { } else if (output_rep == MachineRepresentation::kTagged) {
if (output_type->Is(Type::Unsigned32()) || type->Is(Type::Unsigned32())) { if (output_type->Is(Type::Unsigned32())) {
op = simplified()->ChangeTaggedToUint32(); op = simplified()->ChangeTaggedToUint32();
} else if (output_type->Is(Type::Signed32()) || } else if (output_type->Is(Type::Signed32())) {
type->Is(Type::Signed32())) {
op = simplified()->ChangeTaggedToInt32(); op = simplified()->ChangeTaggedToInt32();
} else { } else if (truncation.TruncatesToWord32()) {
node = InsertChangeTaggedToFloat64(node); node = InsertChangeTaggedToFloat64(node);
op = machine()->TruncateFloat64ToInt32(TruncationMode::kJavaScript); op = machine()->TruncateFloat64ToInt32(TruncationMode::kJavaScript);
} }
} else { }
if (op == nullptr) {
return TypeError(node, output_rep, output_type, return TypeError(node, output_rep, output_type,
MachineRepresentation::kWord32); MachineRepresentation::kWord32);
} }
......
...@@ -121,7 +121,7 @@ class RepresentationChanger final { ...@@ -121,7 +121,7 @@ class RepresentationChanger final {
MachineRepresentation output_rep, MachineRepresentation output_rep,
Type* output_type, Truncation truncation); Type* output_type, Truncation truncation);
Node* GetWord32RepresentationFor(Node* node, MachineRepresentation output_rep, Node* GetWord32RepresentationFor(Node* node, MachineRepresentation output_rep,
Type* output_type); Type* output_type, Truncation truncation);
Node* GetBitRepresentationFor(Node* node, MachineRepresentation output_rep, Node* GetBitRepresentationFor(Node* node, MachineRepresentation output_rep,
Type* output_type); Type* output_type);
Node* GetWord64RepresentationFor(Node* node, MachineRepresentation output_rep, Node* GetWord64RepresentationFor(Node* node, MachineRepresentation output_rep,
......
...@@ -928,10 +928,8 @@ TEST(LowerBooleanToNumber_tagged_tagged) { ...@@ -928,10 +928,8 @@ TEST(LowerBooleanToNumber_tagged_tagged) {
CHECK(c == cnv->InputAt(0) || c == cnv->InputAt(1)); CHECK(c == cnv->InputAt(0) || c == cnv->InputAt(1));
} }
static Type* test_types[] = {Type::Signed32(), Type::Unsigned32(), static Type* test_types[] = {Type::Signed32(), Type::Unsigned32(),
Type::Number(), Type::Any()}; Type::Number()};
TEST(LowerNumberCmp_to_int32) { TEST(LowerNumberCmp_to_int32) {
TestingGraph t(Type::Signed32(), Type::Signed32()); TestingGraph t(Type::Signed32(), Type::Signed32());
...@@ -956,18 +954,13 @@ TEST(LowerNumberCmp_to_uint32) { ...@@ -956,18 +954,13 @@ TEST(LowerNumberCmp_to_uint32) {
TEST(LowerNumberCmp_to_float64) { TEST(LowerNumberCmp_to_float64) {
static Type* types[] = {Type::Number(), Type::Any()}; TestingGraph t(Type::Number(), Type::Number());
for (size_t i = 0; i < arraysize(types); i++) {
TestingGraph t(types[i], types[i]);
t.CheckLoweringBinop(IrOpcode::kFloat64Equal, t.CheckLoweringBinop(IrOpcode::kFloat64Equal, t.simplified()->NumberEqual());
t.simplified()->NumberEqual()); t.CheckLoweringBinop(IrOpcode::kFloat64LessThan,
t.CheckLoweringBinop(IrOpcode::kFloat64LessThan, t.simplified()->NumberLessThan());
t.simplified()->NumberLessThan()); t.CheckLoweringBinop(IrOpcode::kFloat64LessThanOrEqual,
t.CheckLoweringBinop(IrOpcode::kFloat64LessThanOrEqual, t.simplified()->NumberLessThanOrEqual());
t.simplified()->NumberLessThanOrEqual());
}
} }
...@@ -1169,7 +1162,8 @@ TEST(InsertBasicChanges) { ...@@ -1169,7 +1162,8 @@ TEST(InsertBasicChanges) {
CheckChangeInsertion(IrOpcode::kChangeFloat64ToTagged, MachineType::Float64(), CheckChangeInsertion(IrOpcode::kChangeFloat64ToTagged, MachineType::Float64(),
MachineType::AnyTagged()); MachineType::AnyTagged());
CheckChangeInsertion(IrOpcode::kChangeTaggedToFloat64, CheckChangeInsertion(IrOpcode::kChangeTaggedToFloat64,
MachineType::AnyTagged(), MachineType::Float64()); MachineType::AnyTagged(), MachineType::Float64(),
Type::Number());
CheckChangeInsertion(IrOpcode::kChangeInt32ToFloat64, MachineType::Int32(), CheckChangeInsertion(IrOpcode::kChangeInt32ToFloat64, MachineType::Int32(),
MachineType::Float64(), Type::Signed32()); MachineType::Float64(), Type::Signed32());
......
...@@ -91,7 +91,8 @@ TEST_F(JSIntrinsicLoweringTest, InlineOptimizedDoubleLo) { ...@@ -91,7 +91,8 @@ TEST_F(JSIntrinsicLoweringTest, InlineOptimizedDoubleLo) {
graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineDoubleLo, 1), graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineDoubleLo, 1),
input, context, effect, control)); input, context, effect, control));
ASSERT_TRUE(r.Changed()); ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsFloat64ExtractLowWord32(input)); EXPECT_THAT(r.replacement(),
IsFloat64ExtractLowWord32(IsGuard(Type::Number(), input, _)));
} }
...@@ -108,7 +109,8 @@ TEST_F(JSIntrinsicLoweringTest, InlineOptimizedDoubleHi) { ...@@ -108,7 +109,8 @@ TEST_F(JSIntrinsicLoweringTest, InlineOptimizedDoubleHi) {
graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineDoubleHi, 1), graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineDoubleHi, 1),
input, context, effect, control)); input, context, effect, control));
ASSERT_TRUE(r.Changed()); ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsFloat64ExtractHighWord32(input)); EXPECT_THAT(r.replacement(),
IsFloat64ExtractHighWord32(IsGuard(Type::Number(), input, _)));
} }
...@@ -270,7 +272,8 @@ TEST_F(JSIntrinsicLoweringTest, InlineMathSqrt) { ...@@ -270,7 +272,8 @@ TEST_F(JSIntrinsicLoweringTest, InlineMathSqrt) {
graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineMathSqrt, 1), graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineMathSqrt, 1),
input, context, effect, control)); input, context, effect, control));
ASSERT_TRUE(r.Changed()); ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsFloat64Sqrt(input)); EXPECT_THAT(r.replacement(),
IsFloat64Sqrt(IsGuard(Type::Number(), input, _)));
} }
......
...@@ -1352,6 +1352,32 @@ class IsStackSlotMatcher final : public NodeMatcher { ...@@ -1352,6 +1352,32 @@ class IsStackSlotMatcher final : public NodeMatcher {
const Matcher<MachineRepresentation> rep_matcher_; const Matcher<MachineRepresentation> rep_matcher_;
}; };
class IsGuardMatcher final : public NodeMatcher {
public:
IsGuardMatcher(const Matcher<Type*>& type_matcher,
const Matcher<Node*>& value_matcher,
const Matcher<Node*>& control_matcher)
: NodeMatcher(IrOpcode::kGuard),
type_matcher_(type_matcher),
value_matcher_(value_matcher),
control_matcher_(control_matcher) {}
bool MatchAndExplain(Node* node, MatchResultListener* listener) const final {
return (NodeMatcher::MatchAndExplain(node, listener) &&
PrintMatchAndExplain(OpParameter<Type*>(node->op()), "type",
type_matcher_, listener) &&
PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0),
"value", value_matcher_, listener) &&
PrintMatchAndExplain(NodeProperties::GetControlInput(node, 0),
"control", control_matcher_, listener));
}
private:
const Matcher<Type*> type_matcher_;
const Matcher<Node*> value_matcher_;
const Matcher<Node*> control_matcher_;
};
class IsToNumberMatcher final : public NodeMatcher { class IsToNumberMatcher final : public NodeMatcher {
public: public:
IsToNumberMatcher(const Matcher<Node*>& base_matcher, IsToNumberMatcher(const Matcher<Node*>& base_matcher,
...@@ -2038,6 +2064,12 @@ Matcher<Node*> IsTailCall( ...@@ -2038,6 +2064,12 @@ Matcher<Node*> IsTailCall(
effect_matcher, control_matcher)); effect_matcher, control_matcher));
} }
Matcher<Node*> IsGuard(const Matcher<Type*>& type_matcher,
const Matcher<Node*>& value_matcher,
const Matcher<Node*>& control_matcher) {
return MakeMatcher(
new IsGuardMatcher(type_matcher, value_matcher, control_matcher));
}
Matcher<Node*> IsReferenceEqual(const Matcher<Type*>& type_matcher, Matcher<Node*> IsReferenceEqual(const Matcher<Type*>& type_matcher,
const Matcher<Node*>& lhs_matcher, const Matcher<Node*>& lhs_matcher,
......
...@@ -382,6 +382,9 @@ Matcher<Node*> IsWord32PairSar(const Matcher<Node*>& lhs_matcher, ...@@ -382,6 +382,9 @@ Matcher<Node*> IsWord32PairSar(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher); const Matcher<Node*>& rhs_matcher);
Matcher<Node*> IsStackSlot(); Matcher<Node*> IsStackSlot();
Matcher<Node*> IsGuard(const Matcher<Type*>& type_matcher,
const Matcher<Node*>& value_matcher,
const Matcher<Node*>& control_matcher);
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
......
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