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) {
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());
}
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());
}
......@@ -217,6 +225,10 @@ Reduction JSIntrinsicLowering::ReduceMathFloor(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());
}
......@@ -377,7 +389,8 @@ Reduction JSIntrinsicLowering::ReduceToInteger(Node* node) {
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
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* efalse = effect;
......@@ -386,6 +399,9 @@ Reduction JSIntrinsicLowering::ReduceToInteger(Node* node) {
vfalse = efalse =
graph()->NewNode(javascript()->CallRuntime(Runtime::kToInteger), value,
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);
}
......@@ -393,6 +409,7 @@ Reduction JSIntrinsicLowering::ReduceToInteger(Node* node) {
effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
value = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
vtrue, vfalse, control);
// TODO(bmeurer, mstarzinger): Rewire IfException inputs to {vfalse}.
ReplaceWithValue(node, value, effect, control);
return Changed(value);
......
......@@ -142,7 +142,8 @@ Node* RepresentationChanger::GetRepresentationFor(
case MachineRepresentation::kWord8:
case MachineRepresentation::kWord16:
case MachineRepresentation::kWord32:
return GetWord32RepresentationFor(node, output_rep, output_type);
return GetWord32RepresentationFor(node, output_rep, output_type,
truncation);
case MachineRepresentation::kWord64:
return GetWord64RepresentationFor(node, output_rep, output_type);
case MachineRepresentation::kSimd128: // Fall through.
......@@ -234,30 +235,34 @@ Node* RepresentationChanger::GetFloat32RepresentationFor(
break;
}
// Select the correct X -> Float32 operator.
const Operator* op;
if (output_rep == MachineRepresentation::kBit) {
return TypeError(node, output_rep, output_type,
MachineRepresentation::kFloat32);
} else if (IsWord(output_rep)) {
const Operator* op = nullptr;
if (IsWord(output_rep)) {
if (output_type->Is(Type::Signed32())) {
// int32 -> float64 -> float32
op = machine()->ChangeInt32ToFloat64();
} else {
// Either the output is int32 or the uses only care about the
// low 32 bits (so we can pick int32 safely).
DCHECK(output_type->Is(Type::Unsigned32()) ||
truncation.TruncatesToWord32());
node = jsgraph()->graph()->NewNode(op, node);
op = machine()->TruncateFloat64ToFloat32();
} else if (output_type->Is(Type::Unsigned32()) ||
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();
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) {
op = simplified()->ChangeTaggedToFloat64(); // tagged -> float64 -> float32
node = jsgraph()->graph()->NewNode(op, node);
op = machine()->TruncateFloat64ToFloat32();
if (output_type->Is(Type::Number())) {
op = simplified()
->ChangeTaggedToFloat64(); // tagged -> float64 -> float32
node = jsgraph()->graph()->NewNode(op, node);
op = machine()->TruncateFloat64ToFloat32();
}
} else if (output_rep == MachineRepresentation::kFloat64) {
op = machine()->TruncateFloat64ToFloat32();
} else {
}
if (op == nullptr) {
return TypeError(node, output_rep, output_type,
MachineRepresentation::kFloat32);
}
......@@ -289,25 +294,24 @@ Node* RepresentationChanger::GetFloat64RepresentationFor(
break;
}
// Select the correct X -> Float64 operator.
const Operator* op;
if (output_rep == MachineRepresentation::kBit) {
return TypeError(node, output_rep, output_type,
MachineRepresentation::kFloat64);
} else if (IsWord(output_rep)) {
const Operator* op = nullptr;
if (IsWord(output_rep)) {
if (output_type->Is(Type::Signed32())) {
op = machine()->ChangeInt32ToFloat64();
} else {
// Either the output is int32 or the uses only care about the
// low 32 bits (so we can pick int32 safely).
DCHECK(output_type->Is(Type::Unsigned32()) ||
truncation.TruncatesToWord32());
} else if (output_type->Is(Type::Unsigned32()) ||
truncation.TruncatesToWord32()) {
// Either the output is uint32 or the uses only care about the
// low 32 bits (so we can pick uint32 safely).
op = machine()->ChangeUint32ToFloat64();
}
} else if (output_rep == MachineRepresentation::kTagged) {
op = simplified()->ChangeTaggedToFloat64();
if (output_type->Is(Type::Number())) {
op = simplified()->ChangeTaggedToFloat64();
}
} else if (output_rep == MachineRepresentation::kFloat32) {
op = machine()->ChangeFloat32ToFloat64();
} else {
}
if (op == nullptr) {
return TypeError(node, output_rep, output_type,
MachineRepresentation::kFloat64);
}
......@@ -319,9 +323,9 @@ Node* RepresentationChanger::MakeTruncatedInt32Constant(double value) {
return jsgraph()->Int32Constant(DoubleToInt32(value));
}
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.
switch (node->opcode()) {
case IrOpcode::kInt32Constant:
......@@ -335,43 +339,37 @@ Node* RepresentationChanger::GetWord32RepresentationFor(
break;
}
// Select the correct X -> Word32 operator.
const Operator* op;
Type* type = NodeProperties::GetType(node);
const Operator* op = nullptr;
if (output_rep == MachineRepresentation::kBit) {
return node; // Sloppy comparison -> word32
} else if (output_rep == MachineRepresentation::kFloat64) {
// TODO(jarin) Use only output_type here, once we intersect it with the
// type inferred by the typer.
if (output_type->Is(Type::Unsigned32()) || type->Is(Type::Unsigned32())) {
if (output_type->Is(Type::Unsigned32())) {
op = machine()->ChangeFloat64ToUint32();
} else if (output_type->Is(Type::Signed32()) ||
type->Is(Type::Signed32())) {
} else if (output_type->Is(Type::Signed32())) {
op = machine()->ChangeFloat64ToInt32();
} else {
} else if (truncation.TruncatesToWord32()) {
op = machine()->TruncateFloat64ToInt32(TruncationMode::kJavaScript);
}
} else if (output_rep == MachineRepresentation::kFloat32) {
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();
} else if (output_type->Is(Type::Signed32()) ||
type->Is(Type::Signed32())) {
} else if (output_type->Is(Type::Signed32())) {
op = machine()->ChangeFloat64ToInt32();
} else {
} else if (truncation.TruncatesToWord32()) {
op = machine()->TruncateFloat64ToInt32(TruncationMode::kJavaScript);
}
} 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();
} else if (output_type->Is(Type::Signed32()) ||
type->Is(Type::Signed32())) {
} else if (output_type->Is(Type::Signed32())) {
op = simplified()->ChangeTaggedToInt32();
} else {
} else if (truncation.TruncatesToWord32()) {
node = InsertChangeTaggedToFloat64(node);
op = machine()->TruncateFloat64ToInt32(TruncationMode::kJavaScript);
}
} else {
}
if (op == nullptr) {
return TypeError(node, output_rep, output_type,
MachineRepresentation::kWord32);
}
......
......@@ -121,7 +121,7 @@ class RepresentationChanger final {
MachineRepresentation output_rep,
Type* output_type, Truncation truncation);
Node* GetWord32RepresentationFor(Node* node, MachineRepresentation output_rep,
Type* output_type);
Type* output_type, Truncation truncation);
Node* GetBitRepresentationFor(Node* node, MachineRepresentation output_rep,
Type* output_type);
Node* GetWord64RepresentationFor(Node* node, MachineRepresentation output_rep,
......
......@@ -928,10 +928,8 @@ TEST(LowerBooleanToNumber_tagged_tagged) {
CHECK(c == cnv->InputAt(0) || c == cnv->InputAt(1));
}
static Type* test_types[] = {Type::Signed32(), Type::Unsigned32(),
Type::Number(), Type::Any()};
Type::Number()};
TEST(LowerNumberCmp_to_int32) {
TestingGraph t(Type::Signed32(), Type::Signed32());
......@@ -956,18 +954,13 @@ TEST(LowerNumberCmp_to_uint32) {
TEST(LowerNumberCmp_to_float64) {
static Type* types[] = {Type::Number(), Type::Any()};
for (size_t i = 0; i < arraysize(types); i++) {
TestingGraph t(types[i], types[i]);
TestingGraph t(Type::Number(), Type::Number());
t.CheckLoweringBinop(IrOpcode::kFloat64Equal,
t.simplified()->NumberEqual());
t.CheckLoweringBinop(IrOpcode::kFloat64LessThan,
t.simplified()->NumberLessThan());
t.CheckLoweringBinop(IrOpcode::kFloat64LessThanOrEqual,
t.simplified()->NumberLessThanOrEqual());
}
t.CheckLoweringBinop(IrOpcode::kFloat64Equal, t.simplified()->NumberEqual());
t.CheckLoweringBinop(IrOpcode::kFloat64LessThan,
t.simplified()->NumberLessThan());
t.CheckLoweringBinop(IrOpcode::kFloat64LessThanOrEqual,
t.simplified()->NumberLessThanOrEqual());
}
......@@ -1169,7 +1162,8 @@ TEST(InsertBasicChanges) {
CheckChangeInsertion(IrOpcode::kChangeFloat64ToTagged, MachineType::Float64(),
MachineType::AnyTagged());
CheckChangeInsertion(IrOpcode::kChangeTaggedToFloat64,
MachineType::AnyTagged(), MachineType::Float64());
MachineType::AnyTagged(), MachineType::Float64(),
Type::Number());
CheckChangeInsertion(IrOpcode::kChangeInt32ToFloat64, MachineType::Int32(),
MachineType::Float64(), Type::Signed32());
......
......@@ -91,7 +91,8 @@ TEST_F(JSIntrinsicLoweringTest, InlineOptimizedDoubleLo) {
graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineDoubleLo, 1),
input, context, effect, control));
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) {
graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineDoubleHi, 1),
input, context, effect, control));
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) {
graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineMathSqrt, 1),
input, context, effect, control));
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 {
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 {
public:
IsToNumberMatcher(const Matcher<Node*>& base_matcher,
......@@ -2038,6 +2064,12 @@ Matcher<Node*> IsTailCall(
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,
const Matcher<Node*>& lhs_matcher,
......
......@@ -382,6 +382,9 @@ Matcher<Node*> IsWord32PairSar(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher);
Matcher<Node*> IsStackSlot();
Matcher<Node*> IsGuard(const Matcher<Type*>& type_matcher,
const Matcher<Node*>& value_matcher,
const Matcher<Node*>& control_matcher);
} // namespace compiler
} // 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