[turbofan] Eliminate unused effectful nodes during representation selection.

We can actually eliminate certain effectful operations like loads and
speculative number operations during representation selection if we
discover that their value outputs are unused (we also propagate this
information through pure operations as well, so that we remove the
maximum number of effectful nodes possible).

R=jarin@chromium.org

Review-Url: https://codereview.chromium.org/2168023002
Cr-Commit-Position: refs/heads/master@{#37928}
This commit is contained in:
bmeurer 2016-07-21 02:09:28 -07:00 committed by Commit bot
parent c4ef8a8d6e
commit 2744fcbb6c
3 changed files with 75 additions and 19 deletions

View File

@ -390,10 +390,10 @@ struct CommonOperatorGlobalCache final {
template <int kEffectInputCount> template <int kEffectInputCount>
struct EffectPhiOperator final : public Operator { struct EffectPhiOperator final : public Operator {
EffectPhiOperator() EffectPhiOperator()
: Operator( // -- : Operator( // --
IrOpcode::kEffectPhi, Operator::kPure, // opcode IrOpcode::kEffectPhi, Operator::kKontrol, // opcode
"EffectPhi", // name "EffectPhi", // name
0, kEffectInputCount, 1, 0, 1, 0) {} // counts 0, kEffectInputCount, 1, 0, 1, 0) {} // counts
}; };
#define CACHED_EFFECT_PHI(input_count) \ #define CACHED_EFFECT_PHI(input_count) \
EffectPhiOperator<input_count> kEffectPhi##input_count##Operator; EffectPhiOperator<input_count> kEffectPhi##input_count##Operator;
@ -827,10 +827,10 @@ const Operator* CommonOperatorBuilder::EffectPhi(int effect_input_count) {
break; break;
} }
// Uncached. // Uncached.
return new (zone()) Operator( // -- return new (zone()) Operator( // --
IrOpcode::kEffectPhi, Operator::kPure, // opcode IrOpcode::kEffectPhi, Operator::kKontrol, // opcode
"EffectPhi", // name "EffectPhi", // name
0, effect_input_count, 1, 0, 1, 0); // counts 0, effect_input_count, 1, 0, 1, 0); // counts
} }
const Operator* CommonOperatorBuilder::BeginRegion( const Operator* CommonOperatorBuilder::BeginRegion(

View File

@ -28,6 +28,7 @@ class Truncation final {
} }
// Queries. // Queries.
bool IsUnused() const { return kind_ == TruncationKind::kNone; }
bool TruncatesToWord32() const { bool TruncatesToWord32() const {
return LessGeneral(kind_, TruncationKind::kWord32); return LessGeneral(kind_, TruncationKind::kWord32);
} }

View File

@ -761,17 +761,30 @@ class RepresentationSelector {
// values {kTypeAny}. // values {kTypeAny}.
void VisitInputs(Node* node) { void VisitInputs(Node* node) {
int tagged_count = node->op()->ValueInputCount() + int tagged_count = node->op()->ValueInputCount() +
OperatorProperties::GetContextInputCount(node->op()); OperatorProperties::GetContextInputCount(node->op()) +
// Visit value and context inputs as tagged. OperatorProperties::GetFrameStateInputCount(node->op());
// Visit value, context and frame state inputs as tagged.
for (int i = 0; i < tagged_count; i++) { for (int i = 0; i < tagged_count; i++) {
ProcessInput(node, i, UseInfo::AnyTagged()); ProcessInput(node, i, UseInfo::AnyTagged());
} }
// Only enqueue other inputs (framestates, effects, control). // Only enqueue other inputs (effects, control).
for (int i = tagged_count; i < node->InputCount(); i++) { for (int i = tagged_count; i < node->InputCount(); i++) {
EnqueueInput(node, i); EnqueueInput(node, i);
} }
} }
// Helper for an unused node.
void VisitUnused(Node* node) {
int value_count = node->op()->ValueInputCount() +
OperatorProperties::GetContextInputCount(node->op()) +
OperatorProperties::GetFrameStateInputCount(node->op());
for (int i = 0; i < value_count; i++) {
ProcessInput(node, i, UseInfo::None());
}
ProcessRemainingInputs(node, value_count);
if (lower()) Kill(node);
}
// Helper for binops of the R x L -> O variety. // Helper for binops of the R x L -> O variety.
void VisitBinop(Node* node, UseInfo left_use, UseInfo right_use, void VisitBinop(Node* node, UseInfo left_use, UseInfo right_use,
MachineRepresentation output, MachineRepresentation output,
@ -934,18 +947,20 @@ class RepresentationSelector {
void VisitCall(Node* node, SimplifiedLowering* lowering) { void VisitCall(Node* node, SimplifiedLowering* lowering) {
const CallDescriptor* desc = CallDescriptorOf(node->op()); const CallDescriptor* desc = CallDescriptorOf(node->op());
int params = static_cast<int>(desc->ParameterCount()); int params = static_cast<int>(desc->ParameterCount());
int value_input_count = node->op()->ValueInputCount();
// Propagate representation information from call descriptor. // Propagate representation information from call descriptor.
for (int i = 0; i < node->InputCount(); i++) { for (int i = 0; i < value_input_count; i++) {
if (i == 0) { if (i == 0) {
// The target of the call. // The target of the call.
ProcessInput(node, i, UseInfo::None()); ProcessInput(node, i, UseInfo::Any());
} else if ((i - 1) < params) { } else if ((i - 1) < params) {
ProcessInput(node, i, TruncatingUseInfoFromRepresentation( ProcessInput(node, i, TruncatingUseInfoFromRepresentation(
desc->GetInputType(i).representation())); desc->GetInputType(i).representation()));
} else { } else {
ProcessInput(node, i, UseInfo::None()); ProcessInput(node, i, UseInfo::AnyTagged());
} }
} }
ProcessRemainingInputs(node, value_input_count);
if (desc->ReturnCount() > 0) { if (desc->ReturnCount() > 0) {
SetOutput(node, desc->GetReturnType(0).representation()); SetOutput(node, desc->GetReturnType(0).representation());
@ -1109,6 +1124,7 @@ class RepresentationSelector {
void VisitSpeculativeAdditiveOp(Node* node, Truncation truncation, void VisitSpeculativeAdditiveOp(Node* node, Truncation truncation,
SimplifiedLowering* lowering) { SimplifiedLowering* lowering) {
if (truncation.IsUnused()) return VisitUnused(node);
if (BothInputsAre(node, type_cache_.kSigned32OrMinusZero) && if (BothInputsAre(node, type_cache_.kSigned32OrMinusZero) &&
NodeProperties::GetType(node)->Is(Type::Signed32())) { NodeProperties::GetType(node)->Is(Type::Signed32())) {
// int32 + int32 = int32 ==> signed Int32Add/Sub // int32 + int32 = int32 ==> signed Int32Add/Sub
@ -1166,11 +1182,21 @@ class RepresentationSelector {
// Depending on the operator, propagate new usage info to the inputs. // Depending on the operator, propagate new usage info to the inputs.
void VisitNode(Node* node, Truncation truncation, void VisitNode(Node* node, Truncation truncation,
SimplifiedLowering* lowering) { SimplifiedLowering* lowering) {
// Unconditionally eliminate unused pure nodes (only relevant if there's
// a pure operation in between two effectful ones, where the last one
// is unused).
if (node->op()->HasProperty(Operator::kPure) && truncation.IsUnused()) {
return VisitUnused(node);
}
switch (node->opcode()) { switch (node->opcode()) {
//------------------------------------------------------------------ //------------------------------------------------------------------
// Common operators. // Common operators.
//------------------------------------------------------------------ //------------------------------------------------------------------
case IrOpcode::kStart: case IrOpcode::kStart:
// We use Start as a terminator for the frame state chain, so even
// tho Start doesn't really produce a value, we have to say Tagged
// here, otherwise the input conversion will fail.
return VisitLeaf(node, MachineRepresentation::kTagged);
case IrOpcode::kDead: case IrOpcode::kDead:
return VisitLeaf(node, MachineRepresentation::kNone); return VisitLeaf(node, MachineRepresentation::kNone);
case IrOpcode::kParameter: { case IrOpcode::kParameter: {
@ -1284,6 +1310,7 @@ class RepresentationSelector {
case IrOpcode::kSpeculativeNumberLessThan: case IrOpcode::kSpeculativeNumberLessThan:
case IrOpcode::kSpeculativeNumberLessThanOrEqual: case IrOpcode::kSpeculativeNumberLessThanOrEqual:
case IrOpcode::kSpeculativeNumberEqual: { case IrOpcode::kSpeculativeNumberEqual: {
if (truncation.IsUnused()) return VisitUnused(node);
// Number comparisons reduce to integer comparisons for integer inputs. // Number comparisons reduce to integer comparisons for integer inputs.
if (TypeOf(node->InputAt(0))->Is(Type::Unsigned32()) && if (TypeOf(node->InputAt(0))->Is(Type::Unsigned32()) &&
TypeOf(node->InputAt(1))->Is(Type::Unsigned32())) { TypeOf(node->InputAt(1))->Is(Type::Unsigned32())) {
@ -1338,6 +1365,7 @@ class RepresentationSelector {
return; return;
} }
case IrOpcode::kSpeculativeNumberMultiply: { case IrOpcode::kSpeculativeNumberMultiply: {
if (truncation.IsUnused()) return VisitUnused(node);
if (BothInputsAre(node, Type::Integral32()) && if (BothInputsAre(node, Type::Integral32()) &&
(NodeProperties::GetType(node)->Is(Type::Signed32()) || (NodeProperties::GetType(node)->Is(Type::Signed32()) ||
NodeProperties::GetType(node)->Is(Type::Unsigned32()) || NodeProperties::GetType(node)->Is(Type::Unsigned32()) ||
@ -1412,6 +1440,7 @@ class RepresentationSelector {
return; return;
} }
case IrOpcode::kSpeculativeNumberDivide: { case IrOpcode::kSpeculativeNumberDivide: {
if (truncation.IsUnused()) return VisitUnused(node);
if (BothInputsAreUnsigned32(node) && truncation.TruncatesToWord32()) { if (BothInputsAreUnsigned32(node) && truncation.TruncatesToWord32()) {
// => unsigned Uint32Div // => unsigned Uint32Div
VisitWord32TruncatingBinop(node); VisitWord32TruncatingBinop(node);
@ -1517,6 +1546,7 @@ class RepresentationSelector {
return; return;
} }
case IrOpcode::kSpeculativeNumberModulus: { case IrOpcode::kSpeculativeNumberModulus: {
if (truncation.IsUnused()) return VisitUnused(node);
if (BothInputsAreUnsigned32(node) && truncation.TruncatesToWord32()) { if (BothInputsAreUnsigned32(node) && truncation.TruncatesToWord32()) {
// => unsigned Uint32Mod // => unsigned Uint32Mod
VisitWord32TruncatingBinop(node); VisitWord32TruncatingBinop(node);
@ -1630,6 +1660,7 @@ class RepresentationSelector {
return; return;
} }
case IrOpcode::kSpeculativeNumberShiftLeft: { case IrOpcode::kSpeculativeNumberShiftLeft: {
if (truncation.IsUnused()) return VisitUnused(node);
if (BothInputsAre(node, Type::NumberOrOddball())) { if (BothInputsAre(node, Type::NumberOrOddball())) {
Type* rhs_type = GetUpperBound(node->InputAt(1)); Type* rhs_type = GetUpperBound(node->InputAt(1));
VisitBinop(node, UseInfo::TruncatingWord32(), VisitBinop(node, UseInfo::TruncatingWord32(),
@ -1941,8 +1972,9 @@ class RepresentationSelector {
return; return;
} }
case IrOpcode::kLoadField: { case IrOpcode::kLoadField: {
if (truncation.IsUnused()) return VisitUnused(node);
FieldAccess access = FieldAccessOf(node->op()); FieldAccess access = FieldAccessOf(node->op());
MachineRepresentation representation = MachineRepresentation const representation =
access.machine_type.representation(); access.machine_type.representation();
// If we are loading from a Smi field and truncate the result to Word32, // If we are loading from a Smi field and truncate the result to Word32,
// we can instead just load the high word on 64-bit architectures, which // we can instead just load the high word on 64-bit architectures, which
@ -1989,6 +2021,7 @@ class RepresentationSelector {
return; return;
} }
case IrOpcode::kLoadBuffer: { case IrOpcode::kLoadBuffer: {
if (truncation.IsUnused()) return VisitUnused(node);
BufferAccess access = BufferAccessOf(node->op()); BufferAccess access = BufferAccessOf(node->op());
ProcessInput(node, 0, UseInfo::PointerInt()); // buffer ProcessInput(node, 0, UseInfo::PointerInt()); // buffer
ProcessInput(node, 1, UseInfo::TruncatingWord32()); // offset ProcessInput(node, 1, UseInfo::TruncatingWord32()); // offset
@ -2035,11 +2068,11 @@ class RepresentationSelector {
return; return;
} }
case IrOpcode::kLoadElement: { case IrOpcode::kLoadElement: {
if (truncation.IsUnused()) return VisitUnused(node);
ElementAccess access = ElementAccessOf(node->op()); ElementAccess access = ElementAccessOf(node->op());
ProcessInput(node, 0, UseInfoForBasePointer(access)); // base VisitBinop(node, UseInfoForBasePointer(access),
ProcessInput(node, 1, UseInfo::TruncatingWord32()); // index UseInfo::TruncatingWord32(),
ProcessRemainingInputs(node, 2); access.machine_type.representation());
SetOutput(node, access.machine_type.representation());
return; return;
} }
case IrOpcode::kStoreElement: { case IrOpcode::kStoreElement: {
@ -2112,6 +2145,7 @@ class RepresentationSelector {
return; return;
} }
case IrOpcode::kCheckFloat64Hole: { case IrOpcode::kCheckFloat64Hole: {
if (truncation.IsUnused()) return VisitUnused(node);
CheckFloat64HoleMode mode = CheckFloat64HoleModeOf(node->op()); CheckFloat64HoleMode mode = CheckFloat64HoleModeOf(node->op());
ProcessInput(node, 0, UseInfo::TruncatingFloat64()); ProcessInput(node, 0, UseInfo::TruncatingFloat64());
ProcessRemainingInputs(node, 1); ProcessRemainingInputs(node, 1);
@ -2348,6 +2382,27 @@ class RepresentationSelector {
node->NullAllInputs(); // Node is now dead. node->NullAllInputs(); // Node is now dead.
} }
void Kill(Node* node) {
TRACE("killing #%d:%s\n", node->id(), node->op()->mnemonic());
if (node->op()->EffectInputCount() == 1) {
DCHECK_LT(0, node->op()->ControlInputCount());
// Disconnect the node from effect and control chains.
Node* control = NodeProperties::GetControlInput(node);
Node* effect = NodeProperties::GetEffectInput(node);
ReplaceEffectControlUses(node, effect, control);
} else {
DCHECK_EQ(0, node->op()->ControlInputCount());
DCHECK_EQ(0, node->op()->EffectInputCount());
DCHECK_EQ(0, node->op()->ControlOutputCount());
DCHECK_EQ(0, node->op()->EffectOutputCount());
}
node->ReplaceUses(jsgraph_->Dead());
node->NullAllInputs(); // The {node} is now dead.
}
void PrintOutputInfo(NodeInfo* info) { void PrintOutputInfo(NodeInfo* info) {
if (FLAG_trace_representation) { if (FLAG_trace_representation) {
OFStream os(stdout); OFStream os(stdout);