[turbofan] Avoid using the typer's types in representation inference for phis.

Once we use type feedback, we need to reflect the feedback in the types, propagate
the new narrower types forward and use them in the subsequent
representation inference. This CL propagates and uses the recomputed types
for Phi and Select nodes (rather than using the types from the typer).

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

Cr-Commit-Position: refs/heads/master@{#33268}
This commit is contained in:
jarin 2016-01-13 07:35:00 -08:00 committed by Commit bot
parent fc9a73e8a6
commit ed21aa2449
3 changed files with 76 additions and 74 deletions

View File

@ -64,7 +64,7 @@ Truncation::TruncationKind Truncation::Generalize(TruncationKind rep1,
return TruncationKind::kFloat64;
}
// All other combinations are illegal.
FATAL("Tried to combine incompatible representations");
FATAL("Tried to combine incompatible truncations");
return TruncationKind::kNone;
}

View File

@ -500,37 +500,39 @@ class RepresentationSelector {
// Every node should have at most one output representation. Note that
// phis can have 0, if they have not been used in a representation-inducing
// instruction.
Type* output_type = output_info.type();
if (NodeProperties::IsTyped(node)) {
output_type = Type::Intersect(NodeProperties::GetType(node),
output_info.type(), jsgraph_->zone());
}
NodeInfo* info = GetInfo(node);
DCHECK(info->output_type()->Is(output_type));
DCHECK(MachineRepresentationIsSubtype(info->representation(),
output_info.representation()));
DCHECK(info->output_type()->Is(output_info.type()));
if (!output_info.type()->Is(info->output_type()) ||
if (!output_type->Is(info->output_type()) ||
output_info.representation() != info->representation()) {
EnqueueUses(node);
}
info->set_output_type(output_info);
info->set_output_type(
NodeOutputInfo(output_info.representation(), output_type));
}
bool BothInputsAreSigned32(Node* node) {
DCHECK_EQ(2, node->InputCount());
return (NodeProperties::GetType(node->InputAt(0))->Is(Type::Signed32()) ||
GetInfo(node->InputAt(0))->output_type()->Is(Type::Signed32())) &&
(NodeProperties::GetType(node->InputAt(1))->Is(Type::Signed32()) ||
GetInfo(node->InputAt(1))->output_type()->Is(Type::Signed32()));
return GetInfo(node->InputAt(0))->output_type()->Is(Type::Signed32()) &&
GetInfo(node->InputAt(1))->output_type()->Is(Type::Signed32());
}
bool BothInputsAreUnsigned32(Node* node) {
DCHECK_EQ(2, node->InputCount());
return (NodeProperties::GetType(node->InputAt(0))->Is(Type::Unsigned32()) ||
GetInfo(node->InputAt(0))->output_type()->Is(Type::Unsigned32())) &&
(NodeProperties::GetType(node->InputAt(1))->Is(Type::Unsigned32()) ||
GetInfo(node->InputAt(1))->output_type()->Is(Type::Unsigned32()));
return GetInfo(node->InputAt(0))->output_type()->Is(Type::Unsigned32()) &&
GetInfo(node->InputAt(1))->output_type()->Is(Type::Unsigned32());
}
bool BothInputsAre(Node* node, Type* type) {
DCHECK_EQ(2, node->InputCount());
return NodeProperties::GetType(node->InputAt(0))->Is(type) &&
NodeProperties::GetType(node->InputAt(1))->Is(type);
return GetInfo(node->InputAt(0))->output_type()->Is(type) &&
GetInfo(node->InputAt(1))->output_type()->Is(type);
}
void ConvertInput(Node* node, int index, UseInfo use) {
@ -661,48 +663,66 @@ class RepresentationSelector {
}
// Infer representation for phi-like nodes.
static MachineRepresentation GetRepresentationForPhi(Node* node,
Truncation use) {
// Phis adapt to the output representation their uses demand.
Type* type = NodeProperties::GetType(node);
if (type->Is(Type::Signed32()) || type->Is(Type::Unsigned32())) {
// We are within 32 bits range => pick kRepWord32.
return MachineRepresentation::kWord32;
} else if (use.TruncatesToWord32()) {
// We only use 32 bits.
return MachineRepresentation::kWord32;
} else if (type->Is(Type::Boolean())) {
// multiple uses => pick kRepBit.
return MachineRepresentation::kBit;
} else if (type->Is(Type::Number())) {
// multiple uses => pick kRepFloat64.
return MachineRepresentation::kFloat64;
} else if (type->Is(Type::Internal())) {
return MachineType::PointerRepresentation();
NodeOutputInfo GetOutputInfoForPhi(Node* node, Truncation use) {
// Compute the type.
Type* type = GetInfo(node->InputAt(0))->output_type();
for (int i = 1; i < node->op()->ValueInputCount(); ++i) {
type = Type::Union(type, GetInfo(node->InputAt(i))->output_type(),
jsgraph_->zone());
}
return MachineRepresentation::kTagged;
// Compute the representation.
MachineRepresentation rep = MachineRepresentation::kTagged;
if (type->Is(Type::None())) {
rep = MachineRepresentation::kNone;
} else if (type->Is(Type::Signed32()) || type->Is(Type::Unsigned32())) {
rep = MachineRepresentation::kWord32;
} else if (use.TruncatesToWord32()) {
rep = MachineRepresentation::kWord32;
} else if (type->Is(Type::Boolean())) {
rep = MachineRepresentation::kBit;
} else if (type->Is(Type::Number())) {
rep = MachineRepresentation::kFloat64;
} else if (type->Is(Type::Internal())) {
// We mark (u)int64 as Type::Internal.
// TODO(jarin) This is a workaround for our lack of (u)int64
// types. This can be removed once we can represent (u)int64
// unambiguously. (At the moment internal objects, such as the hole,
// are also Type::Internal()).
bool is_word64 = GetInfo(node->InputAt(0))->representation() ==
MachineRepresentation::kWord64;
#ifdef DEBUG
// Check that all the inputs agree on being Word64.
for (int i = 1; i < node->op()->ValueInputCount(); i++) {
DCHECK_EQ(is_word64, GetInfo(node->InputAt(i))->representation() ==
MachineRepresentation::kWord64);
}
#endif
rep = is_word64 ? MachineRepresentation::kWord64
: MachineRepresentation::kTagged;
}
return NodeOutputInfo(rep, type);
}
// Helper for handling selects.
void VisitSelect(Node* node, Truncation truncation,
SimplifiedLowering* lowering) {
ProcessInput(node, 0, UseInfo::Bool());
MachineRepresentation output = GetRepresentationForPhi(node, truncation);
Type* type = NodeProperties::GetType(node);
SetOutput(node, NodeOutputInfo(output, type));
NodeOutputInfo output = GetOutputInfoForPhi(node, truncation);
SetOutput(node, output);
if (lower()) {
// Update the select operator.
SelectParameters p = SelectParametersOf(node->op());
if (output != p.representation()) {
NodeProperties::ChangeOp(node,
lowering->common()->Select(output, p.hint()));
if (output.representation() != p.representation()) {
NodeProperties::ChangeOp(node, lowering->common()->Select(
output.representation(), p.hint()));
}
}
// Convert inputs to the output representation of this phi, pass the
// truncation truncation along.
UseInfo input_use(output, truncation);
UseInfo input_use(output.representation(), truncation);
ProcessInput(node, 1, input_use);
ProcessInput(node, 2, input_use);
}
@ -710,23 +730,21 @@ class RepresentationSelector {
// Helper for handling phis.
void VisitPhi(Node* node, Truncation truncation,
SimplifiedLowering* lowering) {
MachineRepresentation output = GetRepresentationForPhi(node, truncation);
Type* type = NodeProperties::GetType(node);
SetOutput(node, NodeOutputInfo(output, type));
NodeOutputInfo output = GetOutputInfoForPhi(node, truncation);
SetOutput(node, output);
int values = node->op()->ValueInputCount();
if (lower()) {
// Update the phi operator.
if (output != PhiRepresentationOf(node->op())) {
NodeProperties::ChangeOp(node, lowering->common()->Phi(output, values));
if (output.representation() != PhiRepresentationOf(node->op())) {
NodeProperties::ChangeOp(
node, lowering->common()->Phi(output.representation(), values));
}
}
// Convert inputs to the output representation of this phi, pass the
// truncation truncation along.
UseInfo input_use(output, truncation);
UseInfo input_use(output.representation(), truncation);
for (int i = 0; i < node->InputCount(); i++) {
ProcessInput(node, i, i < values ? input_use : UseInfo::None());
}
@ -780,9 +798,14 @@ class RepresentationSelector {
ZoneVector<MachineType>(node->InputCount(), zone);
for (int i = 0; i < node->InputCount(); i++) {
NodeInfo* input_info = GetInfo(node->InputAt(i));
(*types)[i] =
MachineType(input_info->representation(),
DeoptValueSemanticOf(input_info->output_type()));
MachineType machine_type(
input_info->representation(),
DeoptValueSemanticOf(input_info->output_type()));
DCHECK(machine_type.representation() !=
MachineRepresentation::kWord32 ||
machine_type.semantic() == MachineSemantic::kInt32 ||
machine_type.semantic() == MachineSemantic::kUint32);
(*types)[i] = machine_type;
}
NodeProperties::ChangeOp(node,
jsgraph_->common()->TypedStateValues(types));
@ -802,27 +825,6 @@ class RepresentationSelector {
return changer_->Float64OperatorFor(node->opcode());
}
bool CanLowerToInt32Binop(Node* node, Truncation use) {
return BothInputsAreSigned32(node) &&
NodeProperties::GetType(node)->Is(Type::Signed32());
}
bool CanLowerToInt32AdditiveBinop(Node* node, Truncation use) {
// It is safe to lower to word32 operation if:
// - the inputs are safe integers (so the low bits are not discarded), and
// - the uses can only observe the lowest 32 bits.
// TODO(jarin): we could support the uint32 case here, but that would
// require setting kTypeUint32 as the output type. Eventually, we will want
// to use only the big types, then this should work automatically.
return BothInputsAre(node, type_cache_.kAdditiveSafeInteger) &&
use.TruncatesToWord32();
}
bool CanLowerToInt32MultiplicativeBinop(Node* node, Truncation use) {
return BothInputsAreSigned32(node) && use.TruncatesToWord32() &&
NodeProperties::GetType(node)->Is(type_cache_.kSafeInteger);
}
// Dispatching routine for visiting the node {node} with the usage {use}.
// Depending on the operator, propagate new usage info to the inputs.
void VisitNode(Node* node, Truncation truncation,

View File

@ -908,7 +908,7 @@ TEST(LowerBooleanToNumber_bit_tagged) {
t.Return(use);
t.Lower();
CHECK_EQ(b, use->InputAt(0)->InputAt(0));
CHECK_EQ(IrOpcode::kChangeInt32ToTagged, use->InputAt(0)->opcode());
CHECK_EQ(IrOpcode::kChangeUint32ToTagged, use->InputAt(0)->opcode());
}
@ -921,7 +921,7 @@ TEST(LowerBooleanToNumber_tagged_tagged) {
t.Return(use);
t.Lower();
CHECK_EQ(cnv, use->InputAt(0)->InputAt(0));
CHECK_EQ(IrOpcode::kChangeInt32ToTagged, use->InputAt(0)->opcode());
CHECK_EQ(IrOpcode::kChangeUint32ToTagged, use->InputAt(0)->opcode());
CHECK_EQ(t.machine()->WordEqual()->opcode(), cnv->opcode());
CHECK(b == cnv->InputAt(0) || b == cnv->InputAt(1));
Node* c = t.jsgraph.TrueConstant();