Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(77)

Unified Diff: src/compiler/simplified-lowering.cc

Issue 1464763003: [turbofan] Replace information about uses by UseInfo in representation selection. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: final goodness Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/compiler/representation-change.h ('k') | test/cctest/compiler/test-representation-change.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/compiler/simplified-lowering.cc
diff --git a/src/compiler/simplified-lowering.cc b/src/compiler/simplified-lowering.cc
index cf76002872e8d3e20f676f499ec5ab2e2c04f64e..a541161f88706a81fc862468f638b8d1101672eb 100644
--- a/src/compiler/simplified-lowering.cc
+++ b/src/compiler/simplified-lowering.cc
@@ -72,67 +72,57 @@ namespace {
// need the signedness information to produce the correct value.
class UseInfo {
public:
- // Constructors
- // ================================================================
-
- // Uses truncating to the preferred representation.
+ UseInfo(MachineType preferred, Truncation truncation)
+ : preferred_(preferred), truncation_(truncation) {
+ DCHECK(preferred == (preferred & kRepMask));
+ }
static UseInfo TruncatingWord32() {
- return UseInfo(kTypeInt32 | kTypeUint32 | kRepWord32);
+ return UseInfo(kRepWord32, Truncation::Word32());
}
static UseInfo TruncatingWord64() {
- return UseInfo(kTypeInt64 | kTypeUint64 | kRepWord64);
+ return UseInfo(kRepWord64, Truncation::Word64());
+ }
+ static UseInfo Bool() { return UseInfo(kRepBit, Truncation::Bool()); }
+ static UseInfo Float32() {
+ return UseInfo(kRepFloat32, Truncation::Float32());
+ }
+ static UseInfo Float64() {
+ return UseInfo(kRepFloat64, Truncation::Float64());
}
- static UseInfo Bool() { return UseInfo(kMachBool); }
- static UseInfo Float32() { return UseInfo(kMachFloat32); }
- static UseInfo Float64() { return UseInfo(kMachFloat64); }
static UseInfo PointerInt() {
return kPointerSize == 4 ? TruncatingWord32() : TruncatingWord64();
}
+ static UseInfo AnyTagged() { return UseInfo(kRepTagged, Truncation::Any()); }
- // Non-truncating uses.
- static UseInfo AnyTagged() { return UseInfo(kMachAnyTagged); }
- static UseInfo Any() { return UseInfo(kTypeAny); }
+ // Undetermined representation.
+ static UseInfo Any() { return UseInfo(kMachNone, Truncation::Any()); }
+ static UseInfo None() { return UseInfo(kMachNone, Truncation::None()); }
- // Ignored-value 'use'.
- static UseInfo None() { return UseInfo(kMachNone); }
-
- // Truncating to a representation that is smaller than the preferred
+ // Truncation to a representation that is smaller than the preferred
// one.
static UseInfo Float64TruncatingToWord32() {
- return UseInfo(kRepFloat64 | kTypeInt32 | kTypeUint32);
+ return UseInfo(kRepFloat64, Truncation::Word32());
}
static UseInfo Word64TruncatingToWord32() {
- return UseInfo(kRepWord64 | kTypeInt32 | kTypeUint32);
- }
- static UseInfo AnyTruncatingToBool() { return UseInfo(kTypeBool); }
-
- UseInfo(MachineTypeUnion representation, MachineTypeUnion truncation)
- : type_(representation | truncation) {
- DCHECK(base::bits::CountPopulation32(representation & kRepMask) == 1);
- DCHECK((representation & kTypeMask) == 0);
- DCHECK((truncation & kRepMask) == 0);
- // TODO(jarin) Check/normalize truncation?
+ return UseInfo(kRepWord64, Truncation::Word32());
}
-
- // Queries
- // ================================================================
- MachineType GetRepresentation() const {
- return static_cast<MachineType>(type_ & kRepMask);
+ static UseInfo AnyTruncatingToBool() {
+ return UseInfo(kMachNone, Truncation::Bool());
}
- // This should only be used by the Enqueue method.
- MachineTypeUnion machine_type() const { return type_; }
+ MachineType preferred() const { return preferred_; }
+ Truncation truncation() const { return truncation_; }
private:
- explicit UseInfo(MachineTypeUnion type) : type_(type) {}
-
- MachineTypeUnion type_;
+ MachineType preferred_;
+ Truncation truncation_;
};
UseInfo UseInfoFromMachineType(MachineType type) {
MachineTypeUnion rep = RepresentationOf(type);
DCHECK((rep & kTypeMask) == 0);
+
if (rep & kRepTagged) return UseInfo::AnyTagged();
if (rep & kRepFloat64) {
DCHECK((rep & kRepWord64) == 0);
@@ -169,11 +159,29 @@ UseInfo UseInfoForBasePointer(const ElementAccess& access) {
class RepresentationSelector {
public:
// Information for each node tracked during the fixpoint.
- struct NodeInfo {
- MachineTypeUnion use : 15; // Union of all usages for the node.
- bool queued : 1; // Bookkeeping for the traversal.
- bool visited : 1; // Bookkeeping for the traversal.
- MachineTypeUnion output : 15; // Output type of the node.
+ class NodeInfo {
+ public:
+ // Adds new use to the node. Returns true if something has changed
+ // and the node has to be requeued.
+ bool AddUse(UseInfo info) {
+ Truncation old_truncation = truncation_;
+ truncation_ = Truncation::Generalize(truncation_, info.truncation());
+ return truncation_ != old_truncation;
+ }
+
+ void set_queued(bool value) { queued_ = value; }
+ bool queued() const { return queued_; }
+ void set_visited() { visited_ = true; }
+ bool visited() const { return visited_; }
+ Truncation truncation() const { return truncation_; }
+ void set_output_type(MachineTypeUnion type) { output_ = type; }
+ MachineTypeUnion output_type() const { return output_; }
+
+ private:
+ bool queued_ = false; // Bookkeeping for the traversal.
+ bool visited_ = false; // Bookkeeping for the traversal.
+ MachineTypeUnion output_ = kMachNone; // Output type of the node.
+ Truncation truncation_ = Truncation::None(); // Information about uses.
};
RepresentationSelector(JSGraph* jsgraph, Zone* zone,
@@ -181,15 +189,13 @@ class RepresentationSelector {
SourcePositionTable* source_positions)
: jsgraph_(jsgraph),
count_(jsgraph->graph()->NodeCount()),
- info_(zone->NewArray<NodeInfo>(count_)),
+ info_(count_, zone),
nodes_(zone),
replacements_(zone),
phase_(PROPAGATE),
changer_(changer),
queue_(zone),
source_positions_(source_positions) {
- memset(info_, 0, sizeof(NodeInfo) * count_);
-
safe_int_additive_range_ =
Type::Range(-std::pow(2.0, 52.0), std::pow(2.0, 52.0), zone);
}
@@ -204,11 +210,11 @@ class RepresentationSelector {
Node* node = queue_.front();
NodeInfo* info = GetInfo(node);
queue_.pop();
- info->queued = false;
+ info->set_queued(false);
TRACE(" visit #%d: %s\n", node->id(), node->op()->mnemonic());
- VisitNode(node, info->use, NULL);
+ VisitNode(node, info->truncation(), NULL);
TRACE(" ==> output ");
- PrintInfo(info->output);
+ PrintInfo(info->output_type());
TRACE("\n");
}
@@ -218,11 +224,12 @@ class RepresentationSelector {
// Process nodes from the collected {nodes_} vector.
for (NodeVector::iterator i = nodes_.begin(); i != nodes_.end(); ++i) {
Node* node = *i;
+ NodeInfo* info = GetInfo(node);
TRACE(" visit #%d: %s\n", node->id(), node->op()->mnemonic());
// Reuse {VisitNode()} so the representation rules are in one place.
SourcePositionTable::Scope scope(
source_positions_, source_positions_->GetSourcePosition(node));
- VisitNode(node, GetUseInfo(node), lowering);
+ VisitNode(node, info->truncation(), lowering);
}
// Perform the final replacements.
@@ -242,34 +249,31 @@ class RepresentationSelector {
// Enqueue {node} if the {use} contains new information for that node.
// Add {node} to {nodes_} if this is the first time it's been visited.
void Enqueue(Node* node, UseInfo use_info = UseInfo::None()) {
- MachineTypeUnion use = use_info.machine_type();
-
if (phase_ != PROPAGATE) return;
NodeInfo* info = GetInfo(node);
- if (!info->visited) {
+ if (!info->visited()) {
// First visit of this node.
- info->visited = true;
- info->queued = true;
+ info->set_visited();
+ info->set_queued(true);
nodes_.push_back(node);
queue_.push(node);
TRACE(" initial: ");
- info->use |= use;
- PrintUseInfo(node);
+ info->AddUse(use_info);
+ PrintTruncation(info->truncation());
return;
}
TRACE(" queue?: ");
- PrintUseInfo(node);
- if ((info->use & use) != use) {
+ PrintTruncation(info->truncation());
+ if (info->AddUse(use_info)) {
// New usage information for the node is available.
- if (!info->queued) {
+ if (!info->queued()) {
queue_.push(node);
- info->queued = true;
+ info->set_queued(true);
TRACE(" added: ");
} else {
TRACE(" inqueue: ");
}
- info->use |= use;
- PrintUseInfo(node);
+ PrintTruncation(info->truncation());
}
}
@@ -281,7 +285,7 @@ class RepresentationSelector {
// instruction.
DCHECK((output & kRepMask) == 0 ||
base::bits::IsPowerOfTwo32(output & kRepMask));
- GetInfo(node)->output = output;
+ GetInfo(node)->set_output_type(output);
}
bool BothInputsAre(Node* node, Type* type) {
@@ -297,7 +301,7 @@ class RepresentationSelector {
Enqueue(input, UseInfo::TruncatingWord32());
} else {
// In the change phase, insert a change before the use if necessary.
- MachineTypeUnion output = GetInfo(input)->output;
+ MachineTypeUnion output = GetInfo(input)->output_type();
if ((output & (kRepBit | kRepWord8 | kRepWord16 | kRepWord32)) == 0) {
// Output representation doesn't match usage.
TRACE(" truncate-to-int32: #%d:%s(@%d #%d:%s) ", node->id(),
@@ -319,10 +323,10 @@ class RepresentationSelector {
void ConvertInput(Node* node, int index, UseInfo use) {
Node* input = node->InputAt(index);
// In the change phase, insert a change before the use if necessary.
- if (use.GetRepresentation() == kMachNone)
+ if (use.preferred() == kMachNone)
return; // No input requirement on the use.
- MachineTypeUnion output = GetInfo(input)->output;
- if ((output & kRepMask) != use.GetRepresentation()) {
+ MachineTypeUnion output = GetInfo(input)->output_type();
+ if ((output & kRepMask) != use.preferred()) {
// Output representation doesn't match usage.
TRACE(" change: #%d:%s(@%d #%d:%s) ", node->id(), node->op()->mnemonic(),
index, input->id(), input->op()->mnemonic());
@@ -331,8 +335,8 @@ class RepresentationSelector {
TRACE(" to ");
PrintUseInfo(use);
TRACE("\n");
- Node* n =
- changer_->GetRepresentationFor(input, output, use.machine_type());
+ Node* n = changer_->GetRepresentationFor(input, output, use.preferred(),
+ use.truncation());
node->ReplaceInput(index, n);
}
}
@@ -440,13 +444,13 @@ class RepresentationSelector {
}
// Infer representation for phi-like nodes.
- static MachineType GetRepresentationForPhi(Node* node, MachineTypeUnion use) {
+ static MachineType GetRepresentationForPhi(Node* node, Truncation use) {
// Phis adapt to the output representation their uses demand.
Type* upper = NodeProperties::GetType(node);
if (upper->Is(Type::Signed32()) || upper->Is(Type::Unsigned32())) {
// We are within 32 bits range => pick kRepWord32.
return kRepWord32;
- } else if (!CanObserveNonWord32(use)) {
+ } else if (use.TruncatesToWord32()) {
// We only use 32 bits.
return kRepWord32;
} else if (upper->Is(Type::Boolean())) {
@@ -462,10 +466,10 @@ class RepresentationSelector {
}
// Helper for handling selects.
- void VisitSelect(Node* node, MachineTypeUnion use,
+ void VisitSelect(Node* node, Truncation truncation,
SimplifiedLowering* lowering) {
ProcessInput(node, 0, UseInfo::Bool());
- MachineType output = GetRepresentationForPhi(node, use);
+ MachineType output = GetRepresentationForPhi(node, truncation);
Type* upper = NodeProperties::GetType(node);
MachineType output_type =
@@ -482,16 +486,16 @@ class RepresentationSelector {
}
}
// Convert inputs to the output representation of this phi, pass the
- // use truncation along.
- UseInfo input_use(output, use & kTypeMask);
+ // truncation truncation along.
+ UseInfo input_use(output, truncation);
ProcessInput(node, 1, input_use);
ProcessInput(node, 2, input_use);
}
// Helper for handling phis.
- void VisitPhi(Node* node, MachineTypeUnion use,
+ void VisitPhi(Node* node, Truncation truncation,
SimplifiedLowering* lowering) {
- MachineType output = GetRepresentationForPhi(node, use);
+ MachineType output = GetRepresentationForPhi(node, truncation);
Type* upper = NodeProperties::GetType(node);
MachineType output_type =
@@ -509,8 +513,8 @@ class RepresentationSelector {
}
// Convert inputs to the output representation of this phi, pass the
- // use truncation along.
- UseInfo input_use(output, use & kTypeMask);
+ // truncation truncation along.
+ UseInfo input_use(output, truncation);
for (int i = 0; i < node->InputCount(); i++) {
ProcessInput(node, i, i < values ? input_use : UseInfo::None());
}
@@ -550,7 +554,7 @@ class RepresentationSelector {
new (zone->New(sizeof(ZoneVector<MachineType>)))
ZoneVector<MachineType>(node->InputCount(), zone);
for (int i = 0; i < node->InputCount(); i++) {
- MachineTypeUnion input_type = GetInfo(node->InputAt(i))->output;
+ MachineTypeUnion input_type = GetInfo(node->InputAt(i))->output_type();
(*types)[i] = static_cast<MachineType>(input_type);
}
NodeProperties::ChangeOp(node,
@@ -571,34 +575,20 @@ class RepresentationSelector {
return changer_->Float64OperatorFor(node->opcode());
}
- bool CanLowerToInt32Binop(Node* node, MachineTypeUnion use) {
+ bool CanLowerToInt32Binop(Node* node, Truncation use) {
return BothInputsAre(node, Type::Signed32()) &&
- (!CanObserveNonWord32(use) ||
+ (use.TruncatesToWord32() ||
NodeProperties::GetType(node)->Is(Type::Signed32()));
}
- bool CanLowerToWord32AdditiveBinop(Node* node, MachineTypeUnion use) {
+ bool CanLowerToWord32AdditiveBinop(Node* node, Truncation use) {
return BothInputsAre(node, safe_int_additive_range_) &&
- !CanObserveNonWord32(use);
- }
-
- bool CanLowerToUint32Binop(Node* node, MachineTypeUnion use) {
- return BothInputsAre(node, Type::Unsigned32()) &&
- (!CanObserveNonWord32(use) ||
- NodeProperties::GetType(node)->Is(Type::Unsigned32()));
- }
-
- static bool CanObserveNonWord32(MachineTypeUnion use) {
- return (use & kTypeMask & ~(kTypeInt32 | kTypeUint32)) != 0;
- }
-
- static bool CanObserveNaN(MachineTypeUnion use) {
- return (use & (kTypeNumber | kTypeAny)) != 0;
+ use.TruncatesToWord32();
}
// 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, MachineTypeUnion use,
+ void VisitNode(Node* node, Truncation truncation,
SimplifiedLowering* lowering) {
switch (node->opcode()) {
//------------------------------------------------------------------
@@ -638,9 +628,9 @@ class RepresentationSelector {
Enqueue(NodeProperties::GetControlInput(node, 0));
break;
case IrOpcode::kSelect:
- return VisitSelect(node, use, lowering);
+ return VisitSelect(node, truncation, lowering);
case IrOpcode::kPhi:
- return VisitPhi(node, use, lowering);
+ return VisitPhi(node, truncation, lowering);
case IrOpcode::kCall:
return VisitCall(node, lowering);
@@ -663,7 +653,7 @@ class RepresentationSelector {
//------------------------------------------------------------------
case IrOpcode::kBooleanNot: {
if (lower()) {
- MachineTypeUnion input = GetInfo(node->InputAt(0))->output;
+ MachineTypeUnion input = GetInfo(node->InputAt(0))->output_type();
if (input & kRepBit) {
// BooleanNot(x: kRepBit) => Word32Equal(x, #0)
node->AppendInput(jsgraph_->zone(), jsgraph_->Int32Constant(0));
@@ -682,7 +672,7 @@ class RepresentationSelector {
}
case IrOpcode::kBooleanToNumber: {
if (lower()) {
- MachineTypeUnion input = GetInfo(node->InputAt(0))->output;
+ MachineTypeUnion input = GetInfo(node->InputAt(0))->output_type();
if (input & kRepBit) {
// BooleanToNumber(x: kRepBit) => x
DeferReplacement(node, node->InputAt(0));
@@ -721,7 +711,7 @@ class RepresentationSelector {
case IrOpcode::kNumberSubtract: {
// Add and subtract reduce to Int32Add/Sub if the inputs
// are already integers and all uses are truncating.
- if (CanLowerToWord32AdditiveBinop(node, use)) {
+ if (CanLowerToWord32AdditiveBinop(node, truncation)) {
// => signed Int32Add/Sub
VisitInt32Binop(node);
if (lower()) NodeProperties::ChangeOp(node, Int32Op(node));
@@ -735,7 +725,7 @@ class RepresentationSelector {
case IrOpcode::kNumberMultiply: {
NumberMatcher right(node->InputAt(1));
if (right.IsInRange(-1048576, 1048576)) { // must fit double mantissa.
- if (CanLowerToInt32Binop(node, use)) {
+ if (CanLowerToInt32Binop(node, truncation)) {
// => signed Int32Mul
VisitInt32Binop(node);
if (lower()) NodeProperties::ChangeOp(node, Int32Op(node));
@@ -748,13 +738,14 @@ class RepresentationSelector {
break;
}
case IrOpcode::kNumberDivide: {
- if (CanLowerToInt32Binop(node, use)) {
+ if (CanLowerToInt32Binop(node, truncation)) {
// => signed Int32Div
VisitInt32Binop(node);
if (lower()) DeferReplacement(node, lowering->Int32Div(node));
break;
}
- if (BothInputsAre(node, Type::Unsigned32()) && !CanObserveNaN(use)) {
+ if (BothInputsAre(node, Type::Unsigned32()) &&
+ truncation.TruncatesNaNToZero()) {
// => unsigned Uint32Div
VisitUint32Binop(node);
if (lower()) DeferReplacement(node, lowering->Uint32Div(node));
@@ -766,13 +757,14 @@ class RepresentationSelector {
break;
}
case IrOpcode::kNumberModulus: {
- if (CanLowerToInt32Binop(node, use)) {
+ if (CanLowerToInt32Binop(node, truncation)) {
// => signed Int32Mod
VisitInt32Binop(node);
if (lower()) DeferReplacement(node, lowering->Int32Mod(node));
break;
}
- if (BothInputsAre(node, Type::Unsigned32()) && !CanObserveNaN(use)) {
+ if (BothInputsAre(node, Type::Unsigned32()) &&
+ truncation.TruncatesNaNToZero()) {
// => unsigned Uint32Mod
VisitUint32Binop(node);
if (lower()) DeferReplacement(node, lowering->Uint32Mod(node));
@@ -901,21 +893,27 @@ class RepresentationSelector {
ProcessInput(node, 1, UseInfo::TruncatingWord32()); // offset
ProcessInput(node, 2, UseInfo::TruncatingWord32()); // length
ProcessRemainingInputs(node, 3);
- // Tagged overrides everything if we have to do a typed array bounds
- // check, because we may need to return undefined then.
+
MachineType output_type;
- if (use & kRepTagged) {
- output_type = kMachAnyTagged;
- } else if (use & kRepFloat64) {
- if (access.machine_type() & kRepFloat32) {
+ if (truncation.TruncatesUndefinedToZeroOrNaN()) {
+ if (truncation.TruncatesNaNToZero()) {
+ // If undefined is truncated to a non-NaN number, we can use
+ // the load's representation.
output_type = access.machine_type();
} else {
- output_type = kMachFloat64;
+ // If undefined is truncated to a number, but the use can
+ // observe NaN, we need to output at least the float32
+ // representation.
+ if (access.machine_type() & kRepFloat32) {
+ output_type = access.machine_type();
+ } else {
+ output_type = kMachFloat64;
+ }
}
- } else if (use & kRepFloat32) {
- output_type = kMachFloat32;
} else {
- output_type = access.machine_type();
+ // If undefined is not truncated away, we need to have the tagged
+ // representation.
+ output_type = kMachAnyTagged;
}
SetOutput(node, output_type);
if (lower()) lowering->DoLoadBuffer(node, output_type, changer_);
@@ -1125,7 +1123,7 @@ class RepresentationSelector {
replacement->op()->mnemonic());
if (replacement->id() < count_ &&
- GetInfo(replacement)->output == GetInfo(node)->output) {
+ GetInfo(replacement)->output_type() == GetInfo(node)->output_type()) {
// Replace with a previously existing node eagerly only if the type is the
// same.
node->ReplaceUses(replacement);
@@ -1140,12 +1138,6 @@ class RepresentationSelector {
node->NullAllInputs(); // Node is now dead.
}
- void PrintUseInfo(Node* node) {
- TRACE("#%d:%-20s ", node->id(), node->op()->mnemonic());
- PrintInfo(GetUseInfo(node));
- TRACE("\n");
- }
-
void PrintInfo(MachineTypeUnion info) {
if (FLAG_trace_representation) {
OFStream os(stdout);
@@ -1153,17 +1145,24 @@ class RepresentationSelector {
}
}
+ void PrintTruncation(Truncation truncation) {
+ if (FLAG_trace_representation) {
+ OFStream os(stdout);
+ os << truncation.description();
+ }
+ }
+
void PrintUseInfo(UseInfo info) {
if (FLAG_trace_representation) {
OFStream os(stdout);
- os << static_cast<MachineType>(info.machine_type());
+ os << info.preferred() << ":" << info.truncation().description();
}
}
private:
JSGraph* jsgraph_;
size_t const count_; // number of nodes in the graph
- NodeInfo* info_; // node id -> usage information
+ ZoneVector<NodeInfo> info_; // node id -> usage information
NodeVector nodes_; // collected nodes
NodeVector replacements_; // replacements to be done after lowering
Phase phase_; // current phase of algorithm
@@ -1182,8 +1181,6 @@ class RepresentationSelector {
DCHECK(node->id() < count_);
return &info_[node->id()];
}
-
- MachineTypeUnion GetUseInfo(Node* node) { return GetInfo(node)->use; }
};
@@ -1226,7 +1223,8 @@ void SimplifiedLowering::DoLoadBuffer(Node* node, MachineType output_type,
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
Node* etrue =
graph()->NewNode(machine()->Load(type), buffer, index, effect, if_true);
- Node* vtrue = changer->GetRepresentationFor(etrue, type, output_type);
+ Node* vtrue = changer->GetRepresentationFor(
+ etrue, type, RepresentationOf(output_type), Truncation::None());
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
Node* efalse = effect;
« no previous file with comments | « src/compiler/representation-change.h ('k') | test/cctest/compiler/test-representation-change.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698