summaryrefslogtreecommitdiff
path: root/deps/v8/src/compiler/simplified-lowering.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/compiler/simplified-lowering.cc')
-rw-r--r--deps/v8/src/compiler/simplified-lowering.cc1429
1 files changed, 831 insertions, 598 deletions
diff --git a/deps/v8/src/compiler/simplified-lowering.cc b/deps/v8/src/compiler/simplified-lowering.cc
index 80c7ff5a94..653fea80ea 100644
--- a/deps/v8/src/compiler/simplified-lowering.cc
+++ b/deps/v8/src/compiler/simplified-lowering.cc
@@ -6,7 +6,6 @@
#include <limits>
-#include "src/address-map.h"
#include "src/base/bits.h"
#include "src/code-factory.h"
#include "src/compiler/common-operator.h"
@@ -19,6 +18,7 @@
#include "src/compiler/simplified-operator.h"
#include "src/compiler/source-position.h"
#include "src/objects.h"
+#include "src/type-cache.h"
namespace v8 {
namespace internal {
@@ -57,14 +57,279 @@ enum Phase {
};
+namespace {
+
+// The {UseInfo} class is used to describe a use of an input of a node.
+//
+// This information is used in two different ways, based on the phase:
+//
+// 1. During propagation, the use info is used to inform the input node
+// about what part of the input is used (we call this truncation) and what
+// is the preferred representation.
+//
+// 2. During lowering, the use info is used to properly convert the input
+// to the preferred representation. The preferred representation might be
+// insufficient to do the conversion (e.g. word32->float64 conv), so we also
+// need the signedness information to produce the correct value.
+class UseInfo {
+ public:
+ UseInfo(MachineRepresentation preferred, Truncation truncation)
+ : preferred_(preferred), truncation_(truncation) {}
+ static UseInfo TruncatingWord32() {
+ return UseInfo(MachineRepresentation::kWord32, Truncation::Word32());
+ }
+ static UseInfo TruncatingWord64() {
+ return UseInfo(MachineRepresentation::kWord64, Truncation::Word64());
+ }
+ static UseInfo Bool() {
+ return UseInfo(MachineRepresentation::kBit, Truncation::Bool());
+ }
+ static UseInfo Float32() {
+ return UseInfo(MachineRepresentation::kFloat32, Truncation::Float32());
+ }
+ static UseInfo Float64() {
+ return UseInfo(MachineRepresentation::kFloat64, Truncation::Float64());
+ }
+ static UseInfo PointerInt() {
+ return kPointerSize == 4 ? TruncatingWord32() : TruncatingWord64();
+ }
+ static UseInfo AnyTagged() {
+ return UseInfo(MachineRepresentation::kTagged, Truncation::Any());
+ }
+
+ // Undetermined representation.
+ static UseInfo Any() {
+ return UseInfo(MachineRepresentation::kNone, Truncation::Any());
+ }
+ static UseInfo None() {
+ return UseInfo(MachineRepresentation::kNone, Truncation::None());
+ }
+
+ // Truncation to a representation that is smaller than the preferred
+ // one.
+ static UseInfo Float64TruncatingToWord32() {
+ return UseInfo(MachineRepresentation::kFloat64, Truncation::Word32());
+ }
+ static UseInfo Word64TruncatingToWord32() {
+ return UseInfo(MachineRepresentation::kWord64, Truncation::Word32());
+ }
+ static UseInfo AnyTruncatingToBool() {
+ return UseInfo(MachineRepresentation::kNone, Truncation::Bool());
+ }
+
+ MachineRepresentation preferred() const { return preferred_; }
+ Truncation truncation() const { return truncation_; }
+
+ private:
+ MachineRepresentation preferred_;
+ Truncation truncation_;
+};
+
+
+UseInfo TruncatingUseInfoFromRepresentation(MachineRepresentation rep) {
+ switch (rep) {
+ case MachineRepresentation::kTagged:
+ return UseInfo::AnyTagged();
+ case MachineRepresentation::kFloat64:
+ return UseInfo::Float64();
+ case MachineRepresentation::kFloat32:
+ return UseInfo::Float32();
+ case MachineRepresentation::kWord64:
+ return UseInfo::TruncatingWord64();
+ case MachineRepresentation::kWord8:
+ case MachineRepresentation::kWord16:
+ case MachineRepresentation::kWord32:
+ return UseInfo::TruncatingWord32();
+ case MachineRepresentation::kBit:
+ return UseInfo::Bool();
+ case MachineRepresentation::kNone:
+ break;
+ }
+ UNREACHABLE();
+ return UseInfo::None();
+}
+
+
+UseInfo UseInfoForBasePointer(const FieldAccess& access) {
+ return access.tag() != 0 ? UseInfo::AnyTagged() : UseInfo::PointerInt();
+}
+
+
+UseInfo UseInfoForBasePointer(const ElementAccess& access) {
+ return access.tag() != 0 ? UseInfo::AnyTagged() : UseInfo::PointerInt();
+}
+
+
+#ifdef DEBUG
+// Helpers for monotonicity checking.
+bool MachineRepresentationIsSubtype(MachineRepresentation r1,
+ MachineRepresentation r2) {
+ switch (r1) {
+ case MachineRepresentation::kNone:
+ return true;
+ case MachineRepresentation::kBit:
+ return r2 == MachineRepresentation::kBit ||
+ r2 == MachineRepresentation::kTagged;
+ case MachineRepresentation::kWord8:
+ return r2 == MachineRepresentation::kWord8 ||
+ r2 == MachineRepresentation::kWord16 ||
+ r2 == MachineRepresentation::kWord32 ||
+ r2 == MachineRepresentation::kWord64 ||
+ r2 == MachineRepresentation::kFloat32 ||
+ r2 == MachineRepresentation::kFloat64 ||
+ r2 == MachineRepresentation::kTagged;
+ case MachineRepresentation::kWord16:
+ return r2 == MachineRepresentation::kWord16 ||
+ r2 == MachineRepresentation::kWord32 ||
+ r2 == MachineRepresentation::kWord64 ||
+ r2 == MachineRepresentation::kFloat32 ||
+ r2 == MachineRepresentation::kFloat64 ||
+ r2 == MachineRepresentation::kTagged;
+ case MachineRepresentation::kWord32:
+ return r2 == MachineRepresentation::kWord32 ||
+ r2 == MachineRepresentation::kWord64 ||
+ r2 == MachineRepresentation::kFloat64 ||
+ r2 == MachineRepresentation::kTagged;
+ case MachineRepresentation::kWord64:
+ return r2 == MachineRepresentation::kWord64;
+ case MachineRepresentation::kFloat32:
+ return r2 == MachineRepresentation::kFloat32 ||
+ r2 == MachineRepresentation::kFloat64 ||
+ r2 == MachineRepresentation::kTagged;
+ case MachineRepresentation::kFloat64:
+ return r2 == MachineRepresentation::kFloat64 ||
+ r2 == MachineRepresentation::kTagged;
+ case MachineRepresentation::kTagged:
+ return r2 == MachineRepresentation::kTagged;
+ }
+ UNREACHABLE();
+ return false;
+}
+
+
+class InputUseInfos {
+ public:
+ explicit InputUseInfos(Zone* zone) : input_use_infos_(zone) {}
+
+ void SetAndCheckInput(Node* node, int index, UseInfo use_info) {
+ if (input_use_infos_.empty()) {
+ input_use_infos_.resize(node->InputCount(), UseInfo::None());
+ }
+ // Check that the new use informatin is a super-type of the old
+ // one.
+ CHECK(IsUseLessGeneral(input_use_infos_[index], use_info));
+ input_use_infos_[index] = use_info;
+ }
+
+ private:
+ ZoneVector<UseInfo> input_use_infos_;
+
+ static bool IsUseLessGeneral(UseInfo use1, UseInfo use2) {
+ return MachineRepresentationIsSubtype(use1.preferred(), use2.preferred()) &&
+ use1.truncation().IsLessGeneralThan(use2.truncation());
+ }
+};
+
+#endif // DEBUG
+
+} // namespace
+
+
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 NodeOutputInfo {
+ public:
+ NodeOutputInfo(MachineRepresentation representation, Type* type)
+ : type_(type), representation_(representation) {}
+ NodeOutputInfo()
+ : type_(Type::None()), representation_(MachineRepresentation::kNone) {}
+
+ MachineRepresentation representation() const { return representation_; }
+ Type* type() const { return type_; }
+
+ static NodeOutputInfo None() {
+ return NodeOutputInfo(MachineRepresentation::kNone, Type::None());
+ }
+
+ static NodeOutputInfo Float32() {
+ return NodeOutputInfo(MachineRepresentation::kFloat32, Type::Number());
+ }
+
+ static NodeOutputInfo Float64() {
+ return NodeOutputInfo(MachineRepresentation::kFloat64, Type::Number());
+ }
+
+ static NodeOutputInfo NumberTruncatedToWord32() {
+ return NodeOutputInfo(MachineRepresentation::kWord32, Type::Number());
+ }
+
+ static NodeOutputInfo Int32() {
+ return NodeOutputInfo(MachineRepresentation::kWord32, Type::Signed32());
+ }
+
+ static NodeOutputInfo Uint32() {
+ return NodeOutputInfo(MachineRepresentation::kWord32, Type::Unsigned32());
+ }
+
+ static NodeOutputInfo Bool() {
+ return NodeOutputInfo(MachineRepresentation::kBit, Type::Boolean());
+ }
+
+ static NodeOutputInfo Int64() {
+ // TODO(jarin) Fix once we have a real int64 type.
+ return NodeOutputInfo(MachineRepresentation::kWord64, Type::Internal());
+ }
+
+ static NodeOutputInfo Uint64() {
+ // TODO(jarin) Fix once we have a real uint64 type.
+ return NodeOutputInfo(MachineRepresentation::kWord64, Type::Internal());
+ }
+
+ static NodeOutputInfo AnyTagged() {
+ return NodeOutputInfo(MachineRepresentation::kTagged, Type::Any());
+ }
+
+ static NodeOutputInfo NumberTagged() {
+ return NodeOutputInfo(MachineRepresentation::kTagged, Type::Number());
+ }
+
+ static NodeOutputInfo Pointer() {
+ return NodeOutputInfo(MachineType::PointerRepresentation(), Type::Any());
+ }
+
+ private:
+ Type* type_;
+ MachineRepresentation representation_;
+ };
+
+ 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(NodeOutputInfo output) { output_ = output; }
+
+ Type* output_type() const { return output_.type(); }
+ MachineRepresentation representation() const {
+ return output_.representation();
+ }
+
+ private:
+ bool queued_ = false; // Bookkeeping for the traversal.
+ bool visited_ = false; // Bookkeeping for the traversal.
+ NodeOutputInfo output_; // Output type and representation.
+ Truncation truncation_ = Truncation::None(); // Information about uses.
};
RepresentationSelector(JSGraph* jsgraph, Zone* zone,
@@ -72,34 +337,34 @@ class RepresentationSelector {
SourcePositionTable* source_positions)
: jsgraph_(jsgraph),
count_(jsgraph->graph()->NodeCount()),
- info_(zone->NewArray<NodeInfo>(count_)),
+ info_(count_, zone),
+#ifdef DEBUG
+ node_input_use_infos_(count_, InputUseInfos(zone), zone),
+#endif
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);
+ source_positions_(source_positions),
+ type_cache_(TypeCache::Get()) {
}
void Run(SimplifiedLowering* lowering) {
// Run propagation phase to a fixpoint.
TRACE("--{Propagation phase}--\n");
phase_ = PROPAGATE;
- Enqueue(jsgraph_->graph()->end());
+ EnqueueInitial(jsgraph_->graph()->end());
// Process nodes from the queue until it is empty.
while (!queue_.empty()) {
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(), nullptr);
TRACE(" ==> output ");
- PrintInfo(info->output);
+ PrintOutputInfo(info);
TRACE("\n");
}
@@ -109,11 +374,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.
@@ -130,105 +396,173 @@ 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, MachineTypeUnion use = 0) {
+ void EnqueueInitial(Node* node) {
+ NodeInfo* info = GetInfo(node);
+ info->set_visited();
+ info->set_queued(true);
+ nodes_.push_back(node);
+ queue_.push(node);
+ }
+
+ // Enqueue {use_node}'s {index} input if the {use} contains new information
+ // for that input node. Add the input to {nodes_} if this is the first time
+ // it's been visited.
+ void EnqueueInput(Node* use_node, int index,
+ UseInfo use_info = UseInfo::None()) {
+ Node* node = use_node->InputAt(index);
if (phase_ != PROPAGATE) return;
NodeInfo* info = GetInfo(node);
- if (!info->visited) {
+#ifdef DEBUG
+ // Check monotonicity of input requirements.
+ node_input_use_infos_[use_node->id()].SetAndCheckInput(use_node, index,
+ use_info);
+#endif // DEBUG
+ 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());
}
}
bool lower() { return phase_ == LOWER; }
- void Enqueue(Node* node, MachineType use) {
- Enqueue(node, static_cast<MachineTypeUnion>(use));
+ void EnqueueUses(Node* node) {
+ for (Edge edge : node->use_edges()) {
+ if (NodeProperties::IsValueEdge(edge)) {
+ Node* const user = edge.from();
+ if (user->id() < count_) {
+ // New type information for the node is available.
+ NodeInfo* info = GetInfo(user);
+ // Enqueue the node only if we are sure it is reachable from
+ // the end and it has not been queued yet.
+ if (info->visited() && !info->queued()) {
+ queue_.push(user);
+ info->set_queued(true);
+ }
+ }
+ }
+ }
+ }
+
+ void SetOutputFromMachineType(Node* node, MachineType machine_type) {
+ Type* type = Type::None();
+ switch (machine_type.semantic()) {
+ case MachineSemantic::kNone:
+ type = Type::None();
+ break;
+ case MachineSemantic::kBool:
+ type = Type::Boolean();
+ break;
+ case MachineSemantic::kInt32:
+ type = Type::Signed32();
+ break;
+ case MachineSemantic::kUint32:
+ type = Type::Unsigned32();
+ break;
+ case MachineSemantic::kInt64:
+ // TODO(jarin) Fix once we have proper int64.
+ type = Type::Internal();
+ break;
+ case MachineSemantic::kUint64:
+ // TODO(jarin) Fix once we have proper uint64.
+ type = Type::Internal();
+ break;
+ case MachineSemantic::kNumber:
+ type = Type::Number();
+ break;
+ case MachineSemantic::kAny:
+ type = Type::Any();
+ break;
+ }
+ return SetOutput(node, NodeOutputInfo(machine_type.representation(), type));
}
- void SetOutput(Node* node, MachineTypeUnion output) {
+ void SetOutput(Node* node, NodeOutputInfo output_info) {
// 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.
- DCHECK((output & kRepMask) == 0 ||
- base::bits::IsPowerOfTwo32(output & kRepMask));
- GetInfo(node)->output = output;
+ 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()));
+ if (!output_type->Is(info->output_type()) ||
+ output_info.representation() != info->representation()) {
+ EnqueueUses(node);
+ }
+ info->set_output_type(
+ NodeOutputInfo(output_info.representation(), output_type));
+ }
+
+ bool BothInputsAreSigned32(Node* node) {
+ DCHECK_EQ(2, node->InputCount());
+ 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 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 ProcessTruncateWord32Input(Node* node, int index, MachineTypeUnion use) {
+ void ConvertInput(Node* node, int index, UseInfo use) {
Node* input = node->InputAt(index);
- if (phase_ == PROPAGATE) {
- // In the propagate phase, propagate the usage information backward.
- Enqueue(input, use);
- } else {
- // In the change phase, insert a change before the use if necessary.
- MachineTypeUnion output = GetInfo(input)->output;
- if ((output & (kRepBit | kRepWord8 | kRepWord16 | kRepWord32)) == 0) {
- // Output representation doesn't match usage.
- TRACE(" truncate-to-int32: #%d:%s(@%d #%d:%s) ", node->id(),
- node->op()->mnemonic(), index, input->id(),
- input->op()->mnemonic());
- TRACE(" from ");
- PrintInfo(output);
- TRACE(" to ");
- PrintInfo(use);
- TRACE("\n");
- Node* n = changer_->GetTruncatedWord32For(input, output);
- node->ReplaceInput(index, n);
- }
+ // In the change phase, insert a change before the use if necessary.
+ if (use.preferred() == MachineRepresentation::kNone)
+ return; // No input requirement on the use.
+ NodeInfo* input_info = GetInfo(input);
+ MachineRepresentation input_rep = input_info->representation();
+ if (input_rep != 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());
+ TRACE(" from ");
+ PrintOutputInfo(input_info);
+ TRACE(" to ");
+ PrintUseInfo(use);
+ TRACE("\n");
+ Node* n = changer_->GetRepresentationFor(
+ input, input_info->representation(), input_info->output_type(),
+ use.preferred(), use.truncation());
+ node->ReplaceInput(index, n);
}
}
- void ProcessInput(Node* node, int index, MachineTypeUnion use) {
- Node* input = node->InputAt(index);
+ void ProcessInput(Node* node, int index, UseInfo use) {
if (phase_ == PROPAGATE) {
- // In the propagate phase, propagate the usage information backward.
- Enqueue(input, use);
+ EnqueueInput(node, index, use);
} else {
- // In the change phase, insert a change before the use if necessary.
- if ((use & kRepMask) == 0) return; // No input requirement on the use.
- MachineTypeUnion output = GetInfo(input)->output;
- if ((output & kRepMask & use) == 0) {
- // Output representation doesn't match usage.
- TRACE(" change: #%d:%s(@%d #%d:%s) ", node->id(),
- node->op()->mnemonic(), index, input->id(),
- input->op()->mnemonic());
- TRACE(" from ");
- PrintInfo(output);
- TRACE(" to ");
- PrintInfo(use);
- TRACE("\n");
- Node* n = changer_->GetRepresentationFor(input, output, use);
- node->ReplaceInput(index, n);
- }
+ ConvertInput(node, index, use);
}
}
@@ -237,11 +571,11 @@ class RepresentationSelector {
DCHECK_GE(index, NodeProperties::PastContextIndex(node));
for (int i = std::max(index, NodeProperties::FirstEffectIndex(node));
i < NodeProperties::PastEffectIndex(node); ++i) {
- Enqueue(node->InputAt(i)); // Effect inputs: just visit
+ EnqueueInput(node, i); // Effect inputs: just visit
}
for (int i = std::max(index, NodeProperties::FirstControlIndex(node));
i < NodeProperties::PastControlIndex(node); ++i) {
- Enqueue(node->InputAt(i)); // Control inputs: just visit
+ EnqueueInput(node, i); // Control inputs: just visit
}
}
@@ -254,165 +588,165 @@ class RepresentationSelector {
OperatorProperties::GetContextInputCount(node->op());
// Visit value and context inputs as tagged.
for (int i = 0; i < tagged_count; i++) {
- ProcessInput(node, i, kMachAnyTagged);
+ ProcessInput(node, i, UseInfo::AnyTagged());
}
// Only enqueue other inputs (framestates, effects, control).
for (int i = tagged_count; i < node->InputCount(); i++) {
- Enqueue(node->InputAt(i));
+ EnqueueInput(node, i);
}
- // Assume the output is tagged.
- SetOutput(node, kMachAnyTagged);
}
// Helper for binops of the R x L -> O variety.
- void VisitBinop(Node* node, MachineTypeUnion left_use,
- MachineTypeUnion right_use, MachineTypeUnion output) {
+ void VisitBinop(Node* node, UseInfo left_use, UseInfo right_use,
+ NodeOutputInfo output) {
DCHECK_EQ(2, node->op()->ValueInputCount());
ProcessInput(node, 0, left_use);
ProcessInput(node, 1, right_use);
for (int i = 2; i < node->InputCount(); i++) {
- Enqueue(node->InputAt(i));
+ EnqueueInput(node, i);
}
SetOutput(node, output);
}
// Helper for binops of the I x I -> O variety.
- void VisitBinop(Node* node, MachineTypeUnion input_use,
- MachineTypeUnion output) {
+ void VisitBinop(Node* node, UseInfo input_use, NodeOutputInfo output) {
VisitBinop(node, input_use, input_use, output);
}
// Helper for unops of the I -> O variety.
- void VisitUnop(Node* node, MachineTypeUnion input_use,
- MachineTypeUnion output) {
+ void VisitUnop(Node* node, UseInfo input_use, NodeOutputInfo output) {
DCHECK_EQ(1, node->InputCount());
ProcessInput(node, 0, input_use);
SetOutput(node, output);
}
// Helper for leaf nodes.
- void VisitLeaf(Node* node, MachineTypeUnion output) {
+ void VisitLeaf(Node* node, NodeOutputInfo output) {
DCHECK_EQ(0, node->InputCount());
SetOutput(node, output);
}
// Helpers for specific types of binops.
void VisitFloat64Binop(Node* node) {
- VisitBinop(node, kMachFloat64, kMachFloat64);
+ VisitBinop(node, UseInfo::Float64(), NodeOutputInfo::Float64());
+ }
+ void VisitInt32Binop(Node* node) {
+ VisitBinop(node, UseInfo::TruncatingWord32(), NodeOutputInfo::Int32());
+ }
+ void VisitWord32TruncatingBinop(Node* node) {
+ VisitBinop(node, UseInfo::TruncatingWord32(),
+ NodeOutputInfo::NumberTruncatedToWord32());
}
- void VisitInt32Binop(Node* node) { VisitBinop(node, kMachInt32, kMachInt32); }
void VisitUint32Binop(Node* node) {
- VisitBinop(node, kMachUint32, kMachUint32);
+ VisitBinop(node, UseInfo::TruncatingWord32(), NodeOutputInfo::Uint32());
+ }
+ void VisitInt64Binop(Node* node) {
+ VisitBinop(node, UseInfo::TruncatingWord64(), NodeOutputInfo::Int64());
}
- void VisitInt64Binop(Node* node) { VisitBinop(node, kMachInt64, kMachInt64); }
void VisitUint64Binop(Node* node) {
- VisitBinop(node, kMachUint64, kMachUint64);
+ VisitBinop(node, UseInfo::TruncatingWord64(), NodeOutputInfo::Uint64());
+ }
+ void VisitFloat64Cmp(Node* node) {
+ VisitBinop(node, UseInfo::Float64(), NodeOutputInfo::Bool());
+ }
+ void VisitInt32Cmp(Node* node) {
+ VisitBinop(node, UseInfo::TruncatingWord32(), NodeOutputInfo::Bool());
+ }
+ void VisitUint32Cmp(Node* node) {
+ VisitBinop(node, UseInfo::TruncatingWord32(), NodeOutputInfo::Bool());
+ }
+ void VisitInt64Cmp(Node* node) {
+ VisitBinop(node, UseInfo::TruncatingWord64(), NodeOutputInfo::Bool());
+ }
+ void VisitUint64Cmp(Node* node) {
+ VisitBinop(node, UseInfo::TruncatingWord64(), NodeOutputInfo::Bool());
}
- void VisitFloat64Cmp(Node* node) { VisitBinop(node, kMachFloat64, kRepBit); }
- void VisitInt32Cmp(Node* node) { VisitBinop(node, kMachInt32, kRepBit); }
- void VisitUint32Cmp(Node* node) { VisitBinop(node, kMachUint32, kRepBit); }
- void VisitInt64Cmp(Node* node) { VisitBinop(node, kMachInt64, kRepBit); }
- void VisitUint64Cmp(Node* node) { VisitBinop(node, kMachUint64, kRepBit); }
// Infer representation for phi-like nodes.
- MachineType GetRepresentationForPhi(Node* node, MachineTypeUnion use) {
- // Phis adapt to the output representation their uses demand.
- Type* upper = NodeProperties::GetType(node);
- if ((use & kRepMask) == kRepFloat32) {
- // only float32 uses.
- return kRepFloat32;
- } else if ((use & kRepMask) == kRepFloat64) {
- // only float64 uses.
- return kRepFloat64;
- } else if ((use & kRepMask) == kRepTagged) {
- // only tagged uses.
- return kRepTagged;
- } else if (upper->Is(Type::Integral32())) {
- // Integer within [-2^31, 2^32[ range.
- if (upper->Is(Type::Signed32()) || upper->Is(Type::Unsigned32())) {
- // multiple uses, but we are within 32 bits range => pick kRepWord32.
- return kRepWord32;
- } else if ((use & kTypeMask) == kTypeInt32 ||
- (use & kTypeMask) == kTypeUint32) {
- // We only use 32 bits or we use the result consistently.
- return kRepWord32;
- } else {
- return kRepFloat64;
+ 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());
+ }
+
+ // 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);
}
- } else if (upper->Is(Type::Boolean())) {
- // multiple uses => pick kRepBit.
- return kRepBit;
- } else if (upper->Is(Type::Number())) {
- // multiple uses => pick kRepFloat64.
- return kRepFloat64;
- } else if (upper->Is(Type::Internal())) {
- return kMachPtr;
+#endif
+ rep = is_word64 ? MachineRepresentation::kWord64
+ : MachineRepresentation::kTagged;
}
- return kRepTagged;
+ return NodeOutputInfo(rep, type);
}
// Helper for handling selects.
- void VisitSelect(Node* node, MachineTypeUnion use,
+ void VisitSelect(Node* node, Truncation truncation,
SimplifiedLowering* lowering) {
- ProcessInput(node, 0, kRepBit);
- MachineType output = GetRepresentationForPhi(node, use);
+ ProcessInput(node, 0, UseInfo::Bool());
- Type* upper = NodeProperties::GetType(node);
- MachineType output_type =
- static_cast<MachineType>(changer_->TypeFromUpperBound(upper) | output);
- SetOutput(node, output_type);
+ NodeOutputInfo output = GetOutputInfoForPhi(node, truncation);
+ SetOutput(node, output);
if (lower()) {
// Update the select operator.
SelectParameters p = SelectParametersOf(node->op());
- MachineType type = static_cast<MachineType>(output_type);
- if (type != p.type()) {
- NodeProperties::ChangeOp(node,
- lowering->common()->Select(type, 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 select.
- ProcessInput(node, 1, output_type);
- ProcessInput(node, 2, output_type);
- } else {
- // Propagate {use} of the select to value inputs.
- MachineType use_type =
- static_cast<MachineType>((use & kTypeMask) | output);
- ProcessInput(node, 1, use_type);
- ProcessInput(node, 2, use_type);
}
+ // Convert inputs to the output representation of this phi, pass the
+ // truncation truncation along.
+ UseInfo input_use(output.representation(), 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);
-
- Type* upper = NodeProperties::GetType(node);
- MachineType output_type =
- static_cast<MachineType>(changer_->TypeFromUpperBound(upper) | output);
- SetOutput(node, output_type);
+ NodeOutputInfo output = GetOutputInfoForPhi(node, truncation);
+ SetOutput(node, output);
int values = node->op()->ValueInputCount();
-
if (lower()) {
// Update the phi operator.
- MachineType type = static_cast<MachineType>(output_type);
- if (type != OpParameter<MachineType>(node)) {
- NodeProperties::ChangeOp(node, lowering->common()->Phi(type, 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.
- for (int i = 0; i < node->InputCount(); i++) {
- ProcessInput(node, i, i < values ? output_type : 0);
- }
- } else {
- // Propagate {use} of the phi to value inputs, and 0 to control.
- MachineType use_type =
- static_cast<MachineType>((use & kTypeMask) | output);
- for (int i = 0; i < node->InputCount(); i++) {
- ProcessInput(node, i, i < values ? use_type : 0);
- }
+ // Convert inputs to the output representation of this phi, pass the
+ // truncation truncation along.
+ UseInfo input_use(output.representation(), truncation);
+ for (int i = 0; i < node->InputCount(); i++) {
+ ProcessInput(node, i, i < values ? input_use : UseInfo::None());
}
}
@@ -424,25 +758,38 @@ class RepresentationSelector {
for (int i = 0; i < node->InputCount(); i++) {
if (i == 0) {
// The target of the call.
- ProcessInput(node, i, 0);
+ ProcessInput(node, i, UseInfo::None());
} else if ((i - 1) < params) {
- ProcessInput(node, i, sig->GetParam(i - 1));
+ ProcessInput(node, i, TruncatingUseInfoFromRepresentation(
+ sig->GetParam(i - 1).representation()));
} else {
- ProcessInput(node, i, 0);
+ ProcessInput(node, i, UseInfo::None());
}
}
if (sig->return_count() > 0) {
- SetOutput(node, desc->GetMachineSignature()->GetReturn());
+ SetOutputFromMachineType(node, desc->GetMachineSignature()->GetReturn());
} else {
- SetOutput(node, kMachAnyTagged);
+ SetOutput(node, NodeOutputInfo::AnyTagged());
+ }
+ }
+
+ MachineSemantic DeoptValueSemanticOf(Type* type) {
+ CHECK(!type->Is(Type::None()));
+ // We only need signedness to do deopt correctly.
+ if (type->Is(Type::Signed32())) {
+ return MachineSemantic::kInt32;
+ } else if (type->Is(Type::Unsigned32())) {
+ return MachineSemantic::kUint32;
+ } else {
+ return MachineSemantic::kAny;
}
}
void VisitStateValues(Node* node) {
if (phase_ == PROPAGATE) {
for (int i = 0; i < node->InputCount(); i++) {
- Enqueue(node->InputAt(i), kTypeAny);
+ EnqueueInput(node, i, UseInfo::Any());
}
} else {
Zone* zone = jsgraph_->zone();
@@ -450,13 +797,20 @@ 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;
- (*types)[i] = static_cast<MachineType>(input_type);
+ NodeInfo* input_info = GetInfo(node->InputAt(i));
+ 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));
}
- SetOutput(node, kMachAnyTagged);
+ SetOutput(node, NodeOutputInfo::AnyTagged());
}
const Operator* Int32Op(Node* node) {
@@ -471,34 +825,9 @@ class RepresentationSelector {
return changer_->Float64OperatorFor(node->opcode());
}
- bool CanLowerToInt32Binop(Node* node, MachineTypeUnion use) {
- return BothInputsAre(node, Type::Signed32()) &&
- (!CanObserveNonWord32(use) ||
- NodeProperties::GetType(node)->Is(Type::Signed32()));
- }
-
- bool CanLowerToWord32AdditiveBinop(Node* node, MachineTypeUnion 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()));
- }
-
- bool CanObserveNonWord32(MachineTypeUnion use) {
- return (use & kTypeMask & ~(kTypeInt32 | kTypeUint32)) != 0;
- }
-
- bool CanObserveNaN(MachineTypeUnion use) {
- return (use & (kTypeNumber | kTypeAny)) != 0;
- }
-
// 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()) {
//------------------------------------------------------------------
@@ -506,41 +835,41 @@ class RepresentationSelector {
//------------------------------------------------------------------
case IrOpcode::kStart:
case IrOpcode::kDead:
- return VisitLeaf(node, 0);
+ return VisitLeaf(node, NodeOutputInfo::None());
case IrOpcode::kParameter: {
// TODO(titzer): use representation from linkage.
- Type* upper = NodeProperties::GetType(node);
- ProcessInput(node, 0, 0);
- SetOutput(node, kRepTagged | changer_->TypeFromUpperBound(upper));
+ Type* type = NodeProperties::GetType(node);
+ ProcessInput(node, 0, UseInfo::None());
+ SetOutput(node, NodeOutputInfo(MachineRepresentation::kTagged, type));
return;
}
case IrOpcode::kInt32Constant:
- return VisitLeaf(node, kRepWord32);
+ return VisitLeaf(node, NodeOutputInfo::Int32());
case IrOpcode::kInt64Constant:
- return VisitLeaf(node, kRepWord64);
+ return VisitLeaf(node, NodeOutputInfo::Int64());
case IrOpcode::kFloat32Constant:
- return VisitLeaf(node, kRepFloat32);
+ return VisitLeaf(node, NodeOutputInfo::Float32());
case IrOpcode::kFloat64Constant:
- return VisitLeaf(node, kRepFloat64);
+ return VisitLeaf(node, NodeOutputInfo::Float64());
case IrOpcode::kExternalConstant:
- return VisitLeaf(node, kMachPtr);
+ return VisitLeaf(node, NodeOutputInfo::Pointer());
case IrOpcode::kNumberConstant:
- return VisitLeaf(node, kRepTagged);
+ return VisitLeaf(node, NodeOutputInfo::NumberTagged());
case IrOpcode::kHeapConstant:
- return VisitLeaf(node, kRepTagged);
+ return VisitLeaf(node, NodeOutputInfo::AnyTagged());
case IrOpcode::kBranch:
- ProcessInput(node, 0, kRepBit);
- Enqueue(NodeProperties::GetControlInput(node, 0));
+ ProcessInput(node, 0, UseInfo::Bool());
+ EnqueueInput(node, NodeProperties::FirstControlIndex(node));
break;
case IrOpcode::kSwitch:
- ProcessInput(node, 0, kRepWord32);
- Enqueue(NodeProperties::GetControlInput(node, 0));
+ ProcessInput(node, 0, UseInfo::TruncatingWord32());
+ EnqueueInput(node, NodeProperties::FirstControlIndex(node));
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);
@@ -556,15 +885,15 @@ class RepresentationSelector {
JS_OP_LIST(DEFINE_JS_CASE)
#undef DEFINE_JS_CASE
VisitInputs(node);
- return SetOutput(node, kRepTagged);
+ return SetOutput(node, NodeOutputInfo::AnyTagged());
//------------------------------------------------------------------
// Simplified operators.
//------------------------------------------------------------------
case IrOpcode::kBooleanNot: {
if (lower()) {
- MachineTypeUnion input = GetInfo(node->InputAt(0))->output;
- if (input & kRepBit) {
+ NodeInfo* input_info = GetInfo(node->InputAt(0));
+ if (input_info->representation() == MachineRepresentation::kBit) {
// BooleanNot(x: kRepBit) => Word32Equal(x, #0)
node->AppendInput(jsgraph_->zone(), jsgraph_->Int32Constant(0));
NodeProperties::ChangeOp(node, lowering->machine()->Word32Equal());
@@ -575,15 +904,15 @@ class RepresentationSelector {
}
} else {
// No input representation requirement; adapt during lowering.
- ProcessInput(node, 0, kTypeBool);
- SetOutput(node, kRepBit);
+ ProcessInput(node, 0, UseInfo::AnyTruncatingToBool());
+ SetOutput(node, NodeOutputInfo::Bool());
}
break;
}
case IrOpcode::kBooleanToNumber: {
if (lower()) {
- MachineTypeUnion input = GetInfo(node->InputAt(0))->output;
- if (input & kRepBit) {
+ NodeInfo* input_info = GetInfo(node->InputAt(0));
+ if (input_info->representation() == MachineRepresentation::kBit) {
// BooleanToNumber(x: kRepBit) => x
DeferReplacement(node, node->InputAt(0));
} else {
@@ -593,8 +922,8 @@ class RepresentationSelector {
}
} else {
// No input representation requirement; adapt during lowering.
- ProcessInput(node, 0, kTypeBool);
- SetOutput(node, kMachInt32);
+ ProcessInput(node, 0, UseInfo::AnyTruncatingToBool());
+ SetOutput(node, NodeOutputInfo::Int32());
}
break;
}
@@ -602,11 +931,11 @@ class RepresentationSelector {
case IrOpcode::kNumberLessThan:
case IrOpcode::kNumberLessThanOrEqual: {
// Number comparisons reduce to integer comparisons for integer inputs.
- if (BothInputsAre(node, Type::Signed32())) {
+ if (BothInputsAreSigned32(node)) {
// => signed Int32Cmp
VisitInt32Cmp(node);
if (lower()) NodeProperties::ChangeOp(node, Int32Op(node));
- } else if (BothInputsAre(node, Type::Unsigned32())) {
+ } else if (BothInputsAreUnsigned32(node)) {
// => unsigned Int32Cmp
VisitUint32Cmp(node);
if (lower()) NodeProperties::ChangeOp(node, Uint32Op(node));
@@ -619,21 +948,17 @@ class RepresentationSelector {
}
case IrOpcode::kNumberAdd:
case IrOpcode::kNumberSubtract: {
- // Add and subtract reduce to Int32Add/Sub if the inputs
- // are already integers and all uses are truncating.
- if (CanLowerToInt32Binop(node, use)) {
+ if (BothInputsAre(node, Type::Signed32()) &&
+ NodeProperties::GetType(node)->Is(Type::Signed32())) {
+ // int32 + int32 = int32
// => signed Int32Add/Sub
VisitInt32Binop(node);
if (lower()) NodeProperties::ChangeOp(node, Int32Op(node));
- } else if (CanLowerToUint32Binop(node, use)) {
- // => unsigned Int32Add/Sub
- VisitUint32Binop(node);
- if (lower()) NodeProperties::ChangeOp(node, Uint32Op(node));
- } else if (CanLowerToWord32AdditiveBinop(node, use)) {
- // => signed Int32Add/Sub, truncating inputs
- ProcessTruncateWord32Input(node, 0, kTypeInt32);
- ProcessTruncateWord32Input(node, 1, kTypeInt32);
- SetOutput(node, kMachInt32);
+ } else if (BothInputsAre(node, type_cache_.kAdditiveSafeInteger) &&
+ truncation.TruncatesToWord32()) {
+ // safe-int + safe-int = x (truncated to int32)
+ // => signed Int32Add/Sub (truncated)
+ VisitWord32TruncatingBinop(node);
if (lower()) NodeProperties::ChangeOp(node, Int32Op(node));
} else {
// => Float64Add/Sub
@@ -643,14 +968,23 @@ class RepresentationSelector {
break;
}
case IrOpcode::kNumberMultiply: {
- NumberMatcher right(node->InputAt(1));
- if (right.IsInRange(-1048576, 1048576)) { // must fit double mantissa.
- if (CanLowerToInt32Binop(node, use)) {
- // => signed Int32Mul
+ if (BothInputsAreSigned32(node)) {
+ if (NodeProperties::GetType(node)->Is(Type::Signed32())) {
+ // Multiply reduces to Int32Mul if the inputs and the output
+ // are integers.
VisitInt32Binop(node);
if (lower()) NodeProperties::ChangeOp(node, Int32Op(node));
break;
}
+ if (truncation.TruncatesToWord32() &&
+ NodeProperties::GetType(node)->Is(type_cache_.kSafeInteger)) {
+ // Multiply reduces to Int32Mul if the inputs are integers,
+ // the uses are truncating and the result is in the safe
+ // integer range.
+ VisitWord32TruncatingBinop(node);
+ if (lower()) NodeProperties::ChangeOp(node, Int32Op(node));
+ break;
+ }
}
// => Float64Mul
VisitFloat64Binop(node);
@@ -658,15 +992,23 @@ class RepresentationSelector {
break;
}
case IrOpcode::kNumberDivide: {
- if (CanLowerToInt32Binop(node, use)) {
+ if (BothInputsAreSigned32(node)) {
+ if (NodeProperties::GetType(node)->Is(Type::Signed32())) {
// => signed Int32Div
VisitInt32Binop(node);
if (lower()) DeferReplacement(node, lowering->Int32Div(node));
break;
+ }
+ if (truncation.TruncatesToWord32()) {
+ // => signed Int32Div
+ VisitWord32TruncatingBinop(node);
+ if (lower()) DeferReplacement(node, lowering->Int32Div(node));
+ break;
+ }
}
- if (BothInputsAre(node, Type::Unsigned32()) && !CanObserveNaN(use)) {
+ if (BothInputsAreUnsigned32(node) && truncation.TruncatesToWord32()) {
// => unsigned Uint32Div
- VisitUint32Binop(node);
+ VisitWord32TruncatingBinop(node);
if (lower()) DeferReplacement(node, lowering->Uint32Div(node));
break;
}
@@ -676,15 +1018,23 @@ class RepresentationSelector {
break;
}
case IrOpcode::kNumberModulus: {
- if (CanLowerToInt32Binop(node, use)) {
- // => signed Int32Mod
- VisitInt32Binop(node);
- if (lower()) DeferReplacement(node, lowering->Int32Mod(node));
- break;
+ if (BothInputsAreSigned32(node)) {
+ if (NodeProperties::GetType(node)->Is(Type::Signed32())) {
+ // => signed Int32Mod
+ VisitInt32Binop(node);
+ if (lower()) DeferReplacement(node, lowering->Int32Mod(node));
+ break;
+ }
+ if (truncation.TruncatesToWord32()) {
+ // => signed Int32Mod
+ VisitWord32TruncatingBinop(node);
+ if (lower()) DeferReplacement(node, lowering->Int32Mod(node));
+ break;
+ }
}
- if (BothInputsAre(node, Type::Unsigned32()) && !CanObserveNaN(use)) {
+ if (BothInputsAreUnsigned32(node) && truncation.TruncatesToWord32()) {
// => unsigned Uint32Mod
- VisitUint32Binop(node);
+ VisitWord32TruncatingBinop(node);
if (lower()) DeferReplacement(node, lowering->Uint32Mod(node));
break;
}
@@ -701,84 +1051,61 @@ class RepresentationSelector {
break;
}
case IrOpcode::kNumberShiftLeft: {
- VisitBinop(node, kMachInt32, kMachUint32, kMachInt32);
- if (lower()) lowering->DoShift(node, lowering->machine()->Word32Shl());
+ Type* rhs_type = GetInfo(node->InputAt(1))->output_type();
+ VisitBinop(node, UseInfo::TruncatingWord32(),
+ UseInfo::TruncatingWord32(), NodeOutputInfo::Int32());
+ if (lower()) {
+ lowering->DoShift(node, lowering->machine()->Word32Shl(), rhs_type);
+ }
break;
}
case IrOpcode::kNumberShiftRight: {
- VisitBinop(node, kMachInt32, kMachUint32, kMachInt32);
- if (lower()) lowering->DoShift(node, lowering->machine()->Word32Sar());
+ Type* rhs_type = GetInfo(node->InputAt(1))->output_type();
+ VisitBinop(node, UseInfo::TruncatingWord32(),
+ UseInfo::TruncatingWord32(), NodeOutputInfo::Int32());
+ if (lower()) {
+ lowering->DoShift(node, lowering->machine()->Word32Sar(), rhs_type);
+ }
break;
}
case IrOpcode::kNumberShiftRightLogical: {
- VisitBinop(node, kMachUint32, kMachUint32, kMachUint32);
- if (lower()) lowering->DoShift(node, lowering->machine()->Word32Shr());
+ Type* rhs_type = GetInfo(node->InputAt(1))->output_type();
+ VisitBinop(node, UseInfo::TruncatingWord32(),
+ UseInfo::TruncatingWord32(), NodeOutputInfo::Uint32());
+ if (lower()) {
+ lowering->DoShift(node, lowering->machine()->Word32Shr(), rhs_type);
+ }
break;
}
case IrOpcode::kNumberToInt32: {
- MachineTypeUnion use_rep = use & kRepMask;
- Node* input = node->InputAt(0);
- Type* in_upper = NodeProperties::GetType(input);
- MachineTypeUnion in = GetInfo(input)->output;
- if (in_upper->Is(Type::Signed32())) {
- // If the input has type int32, pass through representation.
- VisitUnop(node, kTypeInt32 | use_rep, kTypeInt32 | use_rep);
- if (lower()) DeferReplacement(node, node->InputAt(0));
- } else if ((in & kTypeMask) == kTypeUint32 ||
- in_upper->Is(Type::Unsigned32())) {
- // Just change representation if necessary.
- VisitUnop(node, kTypeUint32 | kRepWord32, kTypeInt32 | kRepWord32);
- if (lower()) DeferReplacement(node, node->InputAt(0));
- } else if ((in & kTypeMask) == kTypeInt32 ||
- (in & kRepMask) == kRepWord32) {
- // Just change representation if necessary.
- VisitUnop(node, kTypeInt32 | kRepWord32, kTypeInt32 | kRepWord32);
- if (lower()) DeferReplacement(node, node->InputAt(0));
- } else {
- // Require the input in float64 format and perform truncation.
- // TODO(turbofan): avoid a truncation with a smi check.
- VisitUnop(node, kTypeInt32 | kRepFloat64, kTypeInt32 | kRepWord32);
- if (lower()) {
- NodeProperties::ChangeOp(
- node, lowering->machine()->TruncateFloat64ToInt32(
- TruncationMode::kJavaScript));
- }
- }
+ // Just change representation if necessary.
+ VisitUnop(node, UseInfo::TruncatingWord32(), NodeOutputInfo::Int32());
+ if (lower()) DeferReplacement(node, node->InputAt(0));
break;
}
case IrOpcode::kNumberToUint32: {
- MachineTypeUnion use_rep = use & kRepMask;
- Node* input = node->InputAt(0);
- Type* in_upper = NodeProperties::GetType(input);
- MachineTypeUnion in = GetInfo(input)->output;
- if (in_upper->Is(Type::Unsigned32())) {
- // If the input has type uint32, pass through representation.
- VisitUnop(node, kTypeUint32 | use_rep, kTypeUint32 | use_rep);
- if (lower()) DeferReplacement(node, node->InputAt(0));
- } else if ((in & kTypeMask) == kTypeInt32 ||
- in_upper->Is(Type::Signed32())) {
- // Just change representation if necessary.
- VisitUnop(node, kTypeInt32 | kRepWord32, kTypeUint32 | kRepWord32);
- if (lower()) DeferReplacement(node, node->InputAt(0));
- } else if ((in & kTypeMask) == kTypeUint32 ||
- (in & kRepMask) == kRepWord32) {
- // Just change representation if necessary.
- VisitUnop(node, kTypeUint32 | kRepWord32, kTypeUint32 | kRepWord32);
- if (lower()) DeferReplacement(node, node->InputAt(0));
- } else {
- // Require the input in float64 format and perform truncation.
- // TODO(turbofan): avoid a truncation with a smi check.
- VisitUnop(node, kTypeUint32 | kRepFloat64, kTypeUint32 | kRepWord32);
- if (lower()) {
- NodeProperties::ChangeOp(
- node, lowering->machine()->TruncateFloat64ToInt32(
- TruncationMode::kJavaScript));
- }
+ // Just change representation if necessary.
+ VisitUnop(node, UseInfo::TruncatingWord32(), NodeOutputInfo::Uint32());
+ if (lower()) DeferReplacement(node, node->InputAt(0));
+ break;
+ }
+ case IrOpcode::kNumberIsHoleNaN: {
+ VisitUnop(node, UseInfo::Float64(), NodeOutputInfo::Bool());
+ if (lower()) {
+ // NumberIsHoleNaN(x) => Word32Equal(Float64ExtractLowWord32(x),
+ // #HoleNaNLower32)
+ node->ReplaceInput(0,
+ jsgraph_->graph()->NewNode(
+ lowering->machine()->Float64ExtractLowWord32(),
+ node->InputAt(0)));
+ node->AppendInput(jsgraph_->zone(),
+ jsgraph_->Int32Constant(kHoleNanLower32));
+ NodeProperties::ChangeOp(node, jsgraph_->machine()->Word32Equal());
}
break;
}
case IrOpcode::kPlainPrimitiveToNumber: {
- VisitUnop(node, kMachAnyTagged, kTypeNumber | kRepTagged);
+ VisitUnop(node, UseInfo::AnyTagged(), NodeOutputInfo::NumberTagged());
if (lower()) {
// PlainPrimitiveToNumber(x) => Call(ToNumberStub, x, no-context)
Operator::Properties properties = node->op()->properties();
@@ -795,116 +1122,127 @@ class RepresentationSelector {
break;
}
case IrOpcode::kReferenceEqual: {
- VisitBinop(node, kMachAnyTagged, kRepBit);
+ VisitBinop(node, UseInfo::AnyTagged(), NodeOutputInfo::Bool());
if (lower()) {
NodeProperties::ChangeOp(node, lowering->machine()->WordEqual());
}
break;
}
case IrOpcode::kStringEqual: {
- VisitBinop(node, kMachAnyTagged, kRepBit);
+ VisitBinop(node, UseInfo::AnyTagged(), NodeOutputInfo::Bool());
if (lower()) lowering->DoStringEqual(node);
break;
}
case IrOpcode::kStringLessThan: {
- VisitBinop(node, kMachAnyTagged, kRepBit);
+ VisitBinop(node, UseInfo::AnyTagged(), NodeOutputInfo::Bool());
if (lower()) lowering->DoStringLessThan(node);
break;
}
case IrOpcode::kStringLessThanOrEqual: {
- VisitBinop(node, kMachAnyTagged, kRepBit);
+ VisitBinop(node, UseInfo::AnyTagged(), NodeOutputInfo::Bool());
if (lower()) lowering->DoStringLessThanOrEqual(node);
break;
}
case IrOpcode::kAllocate: {
- ProcessInput(node, 0, kMachAnyTagged);
+ ProcessInput(node, 0, UseInfo::AnyTagged());
ProcessRemainingInputs(node, 1);
- SetOutput(node, kMachAnyTagged);
- if (lower()) lowering->DoAllocate(node);
+ SetOutput(node, NodeOutputInfo::AnyTagged());
break;
}
case IrOpcode::kLoadField: {
FieldAccess access = FieldAccessOf(node->op());
- ProcessInput(node, 0, changer_->TypeForBasePointer(access));
+ ProcessInput(node, 0, UseInfoForBasePointer(access));
ProcessRemainingInputs(node, 1);
- SetOutput(node, access.machine_type);
- if (lower()) lowering->DoLoadField(node);
+ SetOutputFromMachineType(node, access.machine_type);
break;
}
case IrOpcode::kStoreField: {
FieldAccess access = FieldAccessOf(node->op());
- ProcessInput(node, 0, changer_->TypeForBasePointer(access));
- ProcessInput(node, 1, access.machine_type);
+ ProcessInput(node, 0, UseInfoForBasePointer(access));
+ ProcessInput(node, 1, TruncatingUseInfoFromRepresentation(
+ access.machine_type.representation()));
ProcessRemainingInputs(node, 2);
- SetOutput(node, 0);
- if (lower()) lowering->DoStoreField(node);
+ SetOutput(node, NodeOutputInfo::None());
break;
}
case IrOpcode::kLoadBuffer: {
BufferAccess access = BufferAccessOf(node->op());
- ProcessInput(node, 0, kMachPtr); // buffer
- ProcessInput(node, 1, kMachInt32); // offset
- ProcessInput(node, 2, kMachInt32); // length
+ ProcessInput(node, 0, UseInfo::PointerInt()); // buffer
+ 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) {
- output_type = access.machine_type();
+
+ NodeOutputInfo output_info;
+ if (truncation.TruncatesUndefinedToZeroOrNaN()) {
+ if (truncation.TruncatesNaNToZero()) {
+ // If undefined is truncated to a non-NaN number, we can use
+ // the load's representation.
+ output_info = NodeOutputInfo(access.machine_type().representation(),
+ NodeProperties::GetType(node));
} 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().representation() ==
+ MachineRepresentation::kFloat32) {
+ output_info =
+ NodeOutputInfo(access.machine_type().representation(),
+ NodeProperties::GetType(node));
+ } else {
+ output_info = NodeOutputInfo::Float64();
+ }
}
- } 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_info = NodeOutputInfo::AnyTagged();
}
- SetOutput(node, output_type);
- if (lower()) lowering->DoLoadBuffer(node, output_type, changer_);
+ SetOutput(node, output_info);
+ if (lower())
+ lowering->DoLoadBuffer(node, output_info.representation(), changer_);
break;
}
case IrOpcode::kStoreBuffer: {
BufferAccess access = BufferAccessOf(node->op());
- ProcessInput(node, 0, kMachPtr); // buffer
- ProcessInput(node, 1, kMachInt32); // offset
- ProcessInput(node, 2, kMachInt32); // length
- ProcessInput(node, 3, access.machine_type()); // value
+ ProcessInput(node, 0, UseInfo::PointerInt()); // buffer
+ ProcessInput(node, 1, UseInfo::TruncatingWord32()); // offset
+ ProcessInput(node, 2, UseInfo::TruncatingWord32()); // length
+ ProcessInput(node, 3,
+ TruncatingUseInfoFromRepresentation(
+ access.machine_type().representation())); // value
ProcessRemainingInputs(node, 4);
- SetOutput(node, 0);
+ SetOutput(node, NodeOutputInfo::None());
if (lower()) lowering->DoStoreBuffer(node);
break;
}
case IrOpcode::kLoadElement: {
ElementAccess access = ElementAccessOf(node->op());
- ProcessInput(node, 0, changer_->TypeForBasePointer(access)); // base
- ProcessInput(node, 1, kMachInt32); // index
+ ProcessInput(node, 0, UseInfoForBasePointer(access)); // base
+ ProcessInput(node, 1, UseInfo::TruncatingWord32()); // index
ProcessRemainingInputs(node, 2);
- SetOutput(node, access.machine_type);
- if (lower()) lowering->DoLoadElement(node);
+ SetOutputFromMachineType(node, access.machine_type);
break;
}
case IrOpcode::kStoreElement: {
ElementAccess access = ElementAccessOf(node->op());
- ProcessInput(node, 0, changer_->TypeForBasePointer(access)); // base
- ProcessInput(node, 1, kMachInt32); // index
- ProcessInput(node, 2, access.machine_type); // value
+ ProcessInput(node, 0, UseInfoForBasePointer(access)); // base
+ ProcessInput(node, 1, UseInfo::TruncatingWord32()); // index
+ ProcessInput(node, 2,
+ TruncatingUseInfoFromRepresentation(
+ access.machine_type.representation())); // value
ProcessRemainingInputs(node, 3);
- SetOutput(node, 0);
- if (lower()) lowering->DoStoreElement(node);
+ SetOutput(node, NodeOutputInfo::None());
break;
}
case IrOpcode::kObjectIsNumber: {
- ProcessInput(node, 0, kMachAnyTagged);
- SetOutput(node, kRepBit | kTypeBool);
+ ProcessInput(node, 0, UseInfo::AnyTagged());
+ SetOutput(node, NodeOutputInfo::Bool());
if (lower()) lowering->DoObjectIsNumber(node);
break;
}
case IrOpcode::kObjectIsSmi: {
- ProcessInput(node, 0, kMachAnyTagged);
- SetOutput(node, kRepBit | kTypeBool);
+ ProcessInput(node, 0, UseInfo::AnyTagged());
+ SetOutput(node, NodeOutputInfo::Bool());
if (lower()) lowering->DoObjectIsSmi(node);
break;
}
@@ -913,29 +1251,31 @@ class RepresentationSelector {
// Machine-level operators.
//------------------------------------------------------------------
case IrOpcode::kLoad: {
- // TODO(titzer): machine loads/stores need to know BaseTaggedness!?
- MachineTypeUnion tBase = kRepTagged | kMachPtr;
- LoadRepresentation rep = OpParameter<LoadRepresentation>(node);
- ProcessInput(node, 0, tBase); // pointer or object
- ProcessInput(node, 1, kMachIntPtr); // index
+ // TODO(jarin) Eventually, we should get rid of all machine stores
+ // from the high-level phases, then this becomes UNREACHABLE.
+ LoadRepresentation rep = LoadRepresentationOf(node->op());
+ ProcessInput(node, 0, UseInfo::AnyTagged()); // tagged pointer
+ ProcessInput(node, 1, UseInfo::PointerInt()); // index
ProcessRemainingInputs(node, 2);
- SetOutput(node, rep);
+ SetOutputFromMachineType(node, rep);
break;
}
case IrOpcode::kStore: {
- // TODO(titzer): machine loads/stores need to know BaseTaggedness!?
- MachineTypeUnion tBase = kRepTagged | kMachPtr;
- StoreRepresentation rep = OpParameter<StoreRepresentation>(node);
- ProcessInput(node, 0, tBase); // pointer or object
- ProcessInput(node, 1, kMachIntPtr); // index
- ProcessInput(node, 2, rep.machine_type());
+ // TODO(jarin) Eventually, we should get rid of all machine stores
+ // from the high-level phases, then this becomes UNREACHABLE.
+ StoreRepresentation rep = StoreRepresentationOf(node->op());
+ ProcessInput(node, 0, UseInfo::AnyTagged()); // tagged pointer
+ ProcessInput(node, 1, UseInfo::PointerInt()); // index
+ ProcessInput(node, 2,
+ TruncatingUseInfoFromRepresentation(rep.representation()));
ProcessRemainingInputs(node, 3);
- SetOutput(node, 0);
+ SetOutput(node, NodeOutputInfo::None());
break;
}
case IrOpcode::kWord32Shr:
// We output unsigned int32 for shift right because JavaScript.
- return VisitBinop(node, kMachUint32, kMachUint32);
+ return VisitBinop(node, UseInfo::TruncatingWord32(),
+ NodeOutputInfo::Uint32());
case IrOpcode::kWord32And:
case IrOpcode::kWord32Or:
case IrOpcode::kWord32Xor:
@@ -944,12 +1284,15 @@ class RepresentationSelector {
// We use signed int32 as the output type for these word32 operations,
// though the machine bits are the same for either signed or unsigned,
// because JavaScript considers the result from these operations signed.
- return VisitBinop(node, kRepWord32, kRepWord32 | kTypeInt32);
+ return VisitBinop(node, UseInfo::TruncatingWord32(),
+ NodeOutputInfo::Int32());
case IrOpcode::kWord32Equal:
- return VisitBinop(node, kRepWord32, kRepBit);
+ return VisitBinop(node, UseInfo::TruncatingWord32(),
+ NodeOutputInfo::Bool());
case IrOpcode::kWord32Clz:
- return VisitUnop(node, kMachUint32, kMachUint32);
+ return VisitUnop(node, UseInfo::TruncatingWord32(),
+ NodeOutputInfo::Uint32());
case IrOpcode::kInt32Add:
case IrOpcode::kInt32Sub:
@@ -993,42 +1336,45 @@ class RepresentationSelector {
case IrOpcode::kWord64Shl:
case IrOpcode::kWord64Shr:
case IrOpcode::kWord64Sar:
- return VisitBinop(node, kRepWord64, kRepWord64);
+ return VisitBinop(node, UseInfo::TruncatingWord64(),
+ NodeOutputInfo::Int64());
case IrOpcode::kWord64Equal:
- return VisitBinop(node, kRepWord64, kRepBit);
+ return VisitBinop(node, UseInfo::TruncatingWord64(),
+ NodeOutputInfo::Bool());
case IrOpcode::kChangeInt32ToInt64:
- return VisitUnop(node, kTypeInt32 | kRepWord32,
- kTypeInt32 | kRepWord64);
+ return VisitUnop(
+ node, UseInfo::TruncatingWord32(),
+ NodeOutputInfo(MachineRepresentation::kWord64, Type::Signed32()));
case IrOpcode::kChangeUint32ToUint64:
- return VisitUnop(node, kTypeUint32 | kRepWord32,
- kTypeUint32 | kRepWord64);
+ return VisitUnop(
+ node, UseInfo::TruncatingWord32(),
+ NodeOutputInfo(MachineRepresentation::kWord64, Type::Unsigned32()));
case IrOpcode::kTruncateFloat64ToFloat32:
- return VisitUnop(node, kTypeNumber | kRepFloat64,
- kTypeNumber | kRepFloat32);
+ return VisitUnop(node, UseInfo::Float64(), NodeOutputInfo::Float32());
case IrOpcode::kTruncateFloat64ToInt32:
- return VisitUnop(node, kTypeNumber | kRepFloat64,
- kTypeInt32 | kRepWord32);
+ return VisitUnop(node, UseInfo::Float64(), NodeOutputInfo::Int32());
case IrOpcode::kTruncateInt64ToInt32:
// TODO(titzer): Is kTypeInt32 correct here?
- return VisitUnop(node, kTypeInt32 | kRepWord64,
- kTypeInt32 | kRepWord32);
+ return VisitUnop(node, UseInfo::Word64TruncatingToWord32(),
+ NodeOutputInfo::Int32());
case IrOpcode::kChangeFloat32ToFloat64:
- return VisitUnop(node, kTypeNumber | kRepFloat32,
- kTypeNumber | kRepFloat64);
+ return VisitUnop(node, UseInfo::Float32(), NodeOutputInfo::Float64());
case IrOpcode::kChangeInt32ToFloat64:
- return VisitUnop(node, kTypeInt32 | kRepWord32,
- kTypeInt32 | kRepFloat64);
+ return VisitUnop(
+ node, UseInfo::TruncatingWord32(),
+ NodeOutputInfo(MachineRepresentation::kFloat64, Type::Signed32()));
case IrOpcode::kChangeUint32ToFloat64:
- return VisitUnop(node, kTypeUint32 | kRepWord32,
- kTypeUint32 | kRepFloat64);
+ return VisitUnop(node, UseInfo::TruncatingWord32(),
+ NodeOutputInfo(MachineRepresentation::kFloat64,
+ Type::Unsigned32()));
case IrOpcode::kChangeFloat64ToInt32:
- return VisitUnop(node, kTypeInt32 | kRepFloat64,
- kTypeInt32 | kRepWord32);
+ return VisitUnop(node, UseInfo::Float64TruncatingToWord32(),
+ NodeOutputInfo::Int32());
case IrOpcode::kChangeFloat64ToUint32:
- return VisitUnop(node, kTypeUint32 | kRepFloat64,
- kTypeUint32 | kRepWord32);
+ return VisitUnop(node, UseInfo::Float64TruncatingToWord32(),
+ NodeOutputInfo::Uint32());
case IrOpcode::kFloat64Add:
case IrOpcode::kFloat64Sub:
@@ -1042,25 +1388,28 @@ class RepresentationSelector {
case IrOpcode::kFloat64RoundDown:
case IrOpcode::kFloat64RoundTruncate:
case IrOpcode::kFloat64RoundTiesAway:
- return VisitUnop(node, kMachFloat64, kMachFloat64);
+ return VisitUnop(node, UseInfo::Float64(), NodeOutputInfo::Float64());
case IrOpcode::kFloat64Equal:
case IrOpcode::kFloat64LessThan:
case IrOpcode::kFloat64LessThanOrEqual:
return VisitFloat64Cmp(node);
case IrOpcode::kFloat64ExtractLowWord32:
case IrOpcode::kFloat64ExtractHighWord32:
- return VisitUnop(node, kMachFloat64, kMachInt32);
+ return VisitUnop(node, UseInfo::Float64(), NodeOutputInfo::Int32());
case IrOpcode::kFloat64InsertLowWord32:
case IrOpcode::kFloat64InsertHighWord32:
- return VisitBinop(node, kMachFloat64, kMachInt32, kMachFloat64);
+ return VisitBinop(node, UseInfo::Float64(), UseInfo::TruncatingWord32(),
+ NodeOutputInfo::Float64());
case IrOpcode::kLoadStackPointer:
case IrOpcode::kLoadFramePointer:
- return VisitLeaf(node, kMachPtr);
+ return VisitLeaf(node, NodeOutputInfo::Pointer());
case IrOpcode::kStateValues:
VisitStateValues(node);
break;
default:
VisitInputs(node);
+ // Assume the output is tagged.
+ SetOutput(node, NodeOutputInfo::AnyTagged());
break;
}
}
@@ -1071,7 +1420,7 @@ class RepresentationSelector {
replacement->op()->mnemonic());
if (replacement->id() < count_ &&
- GetInfo(replacement)->output == GetInfo(node)->output) {
+ GetInfo(node)->output_type()->Is(GetInfo(replacement)->output_type())) {
// Replace with a previously existing node eagerly only if the type is the
// same.
node->ReplaceUses(replacement);
@@ -1086,23 +1435,44 @@ 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 PrintOutputInfo(NodeInfo* info) {
+ if (FLAG_trace_representation) {
+ OFStream os(stdout);
+ os << info->representation() << " (";
+ info->output_type()->PrintTo(os, Type::SEMANTIC_DIM);
+ os << ")";
+ }
}
- void PrintInfo(MachineTypeUnion info) {
+ void PrintRepresentation(MachineRepresentation rep) {
if (FLAG_trace_representation) {
OFStream os(stdout);
- os << static_cast<MachineType>(info);
+ os << rep;
+ }
+ }
+
+ 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 << 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
+#ifdef DEBUG
+ ZoneVector<InputUseInfos> node_input_use_infos_; // Debug information about
+ // requirements on inputs.
+#endif // DEBUG
NodeVector nodes_; // collected nodes
NodeVector replacements_; // replacements to be done after lowering
Phase phase_; // current phase of algorithm
@@ -1114,15 +1484,13 @@ class RepresentationSelector {
// lowering. Once this phase becomes a vanilla reducer, it should get source
// position information via the SourcePositionWrapper like all other reducers.
SourcePositionTable* source_positions_;
- Type* safe_int_additive_range_;
+ TypeCache const& type_cache_;
NodeInfo* GetInfo(Node* node) {
DCHECK(node->id() >= 0);
DCHECK(node->id() < count_);
return &info_[node->id()];
}
-
- MachineTypeUnion GetUseInfo(Node* node) { return GetInfo(node)->use; }
};
@@ -1130,7 +1498,7 @@ SimplifiedLowering::SimplifiedLowering(JSGraph* jsgraph, Zone* zone,
SourcePositionTable* source_positions)
: jsgraph_(jsgraph),
zone_(zone),
- zero_thirtyone_range_(Type::Range(0, 31, zone)),
+ type_cache_(TypeCache::Get()),
source_positions_(source_positions) {}
@@ -1142,134 +1510,13 @@ void SimplifiedLowering::LowerAllNodes() {
}
-namespace {
-
-WriteBarrierKind ComputeWriteBarrierKind(BaseTaggedness base_is_tagged,
- MachineType representation,
- Type* field_type, Type* input_type) {
- if (field_type->Is(Type::TaggedSigned()) ||
- input_type->Is(Type::TaggedSigned())) {
- // Write barriers are only for writes of heap objects.
- return kNoWriteBarrier;
- }
- if (input_type->Is(Type::BooleanOrNullOrUndefined())) {
- // Write barriers are not necessary when storing true, false, null or
- // undefined, because these special oddballs are always in the root set.
- return kNoWriteBarrier;
- }
- if (base_is_tagged == kTaggedBase &&
- RepresentationOf(representation) == kRepTagged) {
- if (input_type->IsConstant() &&
- input_type->AsConstant()->Value()->IsHeapObject()) {
- Handle<HeapObject> input =
- Handle<HeapObject>::cast(input_type->AsConstant()->Value());
- if (input->IsMap()) {
- // Write barriers for storing maps are cheaper.
- return kMapWriteBarrier;
- }
- Isolate* const isolate = input->GetIsolate();
- RootIndexMap root_index_map(isolate);
- int root_index = root_index_map.Lookup(*input);
- if (root_index != RootIndexMap::kInvalidRootIndex &&
- isolate->heap()->RootIsImmortalImmovable(root_index)) {
- // Write barriers are unnecessary for immortal immovable roots.
- return kNoWriteBarrier;
- }
- }
- if (field_type->Is(Type::TaggedPointer()) ||
- input_type->Is(Type::TaggedPointer())) {
- // Write barriers for heap objects don't need a Smi check.
- return kPointerWriteBarrier;
- }
- // Write barriers are only for writes into heap objects (i.e. tagged base).
- return kFullWriteBarrier;
- }
- return kNoWriteBarrier;
-}
-
-} // namespace
-
-
-void SimplifiedLowering::DoAllocate(Node* node) {
- PretenureFlag pretenure = OpParameter<PretenureFlag>(node->op());
- if (pretenure == NOT_TENURED) {
- Callable callable = CodeFactory::AllocateInNewSpace(isolate());
- Node* target = jsgraph()->HeapConstant(callable.code());
- CallDescriptor* descriptor = Linkage::GetStubCallDescriptor(
- isolate(), jsgraph()->zone(), callable.descriptor(), 0,
- CallDescriptor::kNoFlags, Operator::kNoThrow);
- const Operator* op = common()->Call(descriptor);
- node->InsertInput(graph()->zone(), 0, target);
- node->InsertInput(graph()->zone(), 2, jsgraph()->NoContextConstant());
- NodeProperties::ChangeOp(node, op);
- } else {
- DCHECK_EQ(TENURED, pretenure);
- AllocationSpace space = OLD_SPACE;
- Runtime::FunctionId f = Runtime::kAllocateInTargetSpace;
- Operator::Properties props = node->op()->properties();
- CallDescriptor* desc =
- Linkage::GetRuntimeCallDescriptor(zone(), f, 2, props);
- ExternalReference ref(f, jsgraph()->isolate());
- int32_t flags = AllocateTargetSpace::encode(space);
- node->InsertInput(graph()->zone(), 0, jsgraph()->CEntryStubConstant(1));
- node->InsertInput(graph()->zone(), 2, jsgraph()->SmiConstant(flags));
- node->InsertInput(graph()->zone(), 3, jsgraph()->ExternalConstant(ref));
- node->InsertInput(graph()->zone(), 4, jsgraph()->Int32Constant(2));
- node->InsertInput(graph()->zone(), 5, jsgraph()->NoContextConstant());
- NodeProperties::ChangeOp(node, common()->Call(desc));
- }
-}
-
-
-void SimplifiedLowering::DoLoadField(Node* node) {
- const FieldAccess& access = FieldAccessOf(node->op());
- Node* offset = jsgraph()->IntPtrConstant(access.offset - access.tag());
- node->InsertInput(graph()->zone(), 1, offset);
- NodeProperties::ChangeOp(node, machine()->Load(access.machine_type));
-}
-
-
-void SimplifiedLowering::DoStoreField(Node* node) {
- const FieldAccess& access = FieldAccessOf(node->op());
- Type* type = NodeProperties::GetType(node->InputAt(1));
- WriteBarrierKind kind = ComputeWriteBarrierKind(
- access.base_is_tagged, access.machine_type, access.type, type);
- Node* offset = jsgraph()->IntPtrConstant(access.offset - access.tag());
- node->InsertInput(graph()->zone(), 1, offset);
- NodeProperties::ChangeOp(
- node, machine()->Store(StoreRepresentation(access.machine_type, kind)));
-}
-
-
-Node* SimplifiedLowering::ComputeIndex(const ElementAccess& access,
- Node* const key) {
- Node* index = key;
- const int element_size_shift = ElementSizeLog2Of(access.machine_type);
- if (element_size_shift) {
- index = graph()->NewNode(machine()->Word32Shl(), index,
- jsgraph()->Int32Constant(element_size_shift));
- }
- const int fixed_offset = access.header_size - access.tag();
- if (fixed_offset) {
- index = graph()->NewNode(machine()->Int32Add(), index,
- jsgraph()->Int32Constant(fixed_offset));
- }
- if (machine()->Is64()) {
- // TODO(turbofan): This is probably only correct for typed arrays, and only
- // if the typed arrays are at most 2GiB in size, which happens to match
- // exactly our current situation.
- index = graph()->NewNode(machine()->ChangeUint32ToUint64(), index);
- }
- return index;
-}
-
-
-void SimplifiedLowering::DoLoadBuffer(Node* node, MachineType output_type,
+void SimplifiedLowering::DoLoadBuffer(Node* node,
+ MachineRepresentation output_rep,
RepresentationChanger* changer) {
DCHECK_EQ(IrOpcode::kLoadBuffer, node->opcode());
- DCHECK_NE(kMachNone, RepresentationOf(output_type));
- MachineType const type = BufferAccessOf(node->op()).machine_type();
- if (output_type != type) {
+ DCHECK_NE(MachineRepresentation::kNone, output_rep);
+ MachineType const access_type = BufferAccessOf(node->op()).machine_type();
+ if (output_rep != access_type.representation()) {
Node* const buffer = node->InputAt(0);
Node* const offset = node->InputAt(1);
Node* const length = node->InputAt(2);
@@ -1285,19 +1532,21 @@ void SimplifiedLowering::DoLoadBuffer(Node* node, MachineType output_type,
graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
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* etrue = graph()->NewNode(machine()->Load(access_type), buffer, index,
+ effect, if_true);
+ Node* vtrue = changer->GetRepresentationFor(
+ etrue, access_type.representation(), NodeProperties::GetType(node),
+ output_rep, Truncation::None());
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
Node* efalse = effect;
Node* vfalse;
- if (output_type & kRepTagged) {
+ if (output_rep == MachineRepresentation::kTagged) {
vfalse = jsgraph()->UndefinedConstant();
- } else if (output_type & kRepFloat64) {
+ } else if (output_rep == MachineRepresentation::kFloat64) {
vfalse =
jsgraph()->Float64Constant(std::numeric_limits<double>::quiet_NaN());
- } else if (output_type & kRepFloat32) {
+ } else if (output_rep == MachineRepresentation::kFloat32) {
vfalse =
jsgraph()->Float32Constant(std::numeric_limits<float>::quiet_NaN());
} else {
@@ -1315,37 +1564,18 @@ void SimplifiedLowering::DoLoadBuffer(Node* node, MachineType output_type,
node->ReplaceInput(1, vfalse);
node->ReplaceInput(2, merge);
node->TrimInputCount(3);
- NodeProperties::ChangeOp(node, common()->Phi(output_type, 2));
+ NodeProperties::ChangeOp(node, common()->Phi(output_rep, 2));
} else {
- NodeProperties::ChangeOp(node, machine()->CheckedLoad(type));
+ NodeProperties::ChangeOp(node, machine()->CheckedLoad(access_type));
}
}
void SimplifiedLowering::DoStoreBuffer(Node* node) {
DCHECK_EQ(IrOpcode::kStoreBuffer, node->opcode());
- MachineType const type = BufferAccessOf(node->op()).machine_type();
- NodeProperties::ChangeOp(node, machine()->CheckedStore(type));
-}
-
-
-void SimplifiedLowering::DoLoadElement(Node* node) {
- const ElementAccess& access = ElementAccessOf(node->op());
- node->ReplaceInput(1, ComputeIndex(access, node->InputAt(1)));
- NodeProperties::ChangeOp(node, machine()->Load(access.machine_type));
-}
-
-
-void SimplifiedLowering::DoStoreElement(Node* node) {
- const ElementAccess& access = ElementAccessOf(node->op());
- Type* type = NodeProperties::GetType(node->InputAt(2));
- node->ReplaceInput(1, ComputeIndex(access, node->InputAt(1)));
- NodeProperties::ChangeOp(
- node,
- machine()->Store(StoreRepresentation(
- access.machine_type,
- ComputeWriteBarrierKind(access.base_is_tagged, access.machine_type,
- access.type, type))));
+ MachineRepresentation const rep =
+ BufferAccessOf(node->op()).machine_type().representation();
+ NodeProperties::ChangeOp(node, machine()->CheckedStore(rep));
}
@@ -1364,7 +1594,7 @@ void SimplifiedLowering::DoObjectIsNumber(Node* node) {
Node* vfalse = graph()->NewNode(
machine()->WordEqual(),
graph()->NewNode(
- machine()->Load(kMachAnyTagged), input,
+ machine()->Load(MachineType::AnyTagged()), input,
jsgraph()->IntPtrConstant(HeapObject::kMapOffset - kHeapObjectTag),
graph()->start(), if_false),
jsgraph()->HeapConstant(isolate()->factory()->heap_number_map()));
@@ -1372,7 +1602,7 @@ void SimplifiedLowering::DoObjectIsNumber(Node* node) {
node->ReplaceInput(0, vtrue);
node->AppendInput(graph()->zone(), vfalse);
node->AppendInput(graph()->zone(), control);
- NodeProperties::ChangeOp(node, common()->Phi(kMachBool, 2));
+ NodeProperties::ChangeOp(node, common()->Phi(MachineRepresentation::kBit, 2));
}
@@ -1430,7 +1660,8 @@ Node* SimplifiedLowering::Int32Div(Node* const node) {
// Note: We do not use the Diamond helper class here, because it really hurts
// readability with nested diamonds.
const Operator* const merge_op = common()->Merge(2);
- const Operator* const phi_op = common()->Phi(kMachInt32, 2);
+ const Operator* const phi_op =
+ common()->Phi(MachineRepresentation::kWord32, 2);
Node* check0 = graph()->NewNode(machine()->Int32LessThan(), zero, rhs);
Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kTrue), check0,
@@ -1507,7 +1738,8 @@ Node* SimplifiedLowering::Int32Mod(Node* const node) {
// Note: We do not use the Diamond helper class here, because it really hurts
// readability with nested diamonds.
const Operator* const merge_op = common()->Merge(2);
- const Operator* const phi_op = common()->Phi(kMachInt32, 2);
+ const Operator* const phi_op =
+ common()->Phi(MachineRepresentation::kWord32, 2);
Node* check0 = graph()->NewNode(machine()->Int32LessThan(), zero, rhs);
Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kTrue), check0,
@@ -1586,7 +1818,7 @@ Node* SimplifiedLowering::Uint32Div(Node* const node) {
Node* check = graph()->NewNode(machine()->Word32Equal(), rhs, zero);
Diamond d(graph(), common(), check, BranchHint::kFalse);
Node* div = graph()->NewNode(machine()->Uint32Div(), lhs, rhs, d.if_false);
- return d.Phi(kMachUint32, zero, div);
+ return d.Phi(MachineRepresentation::kWord32, zero, div);
}
@@ -1618,7 +1850,8 @@ Node* SimplifiedLowering::Uint32Mod(Node* const node) {
// Note: We do not use the Diamond helper class here, because it really hurts
// readability with nested diamonds.
const Operator* const merge_op = common()->Merge(2);
- const Operator* const phi_op = common()->Phi(kMachInt32, 2);
+ const Operator* const phi_op =
+ common()->Phi(MachineRepresentation::kWord32, 2);
Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kTrue), rhs,
graph()->start());
@@ -1649,10 +1882,10 @@ Node* SimplifiedLowering::Uint32Mod(Node* const node) {
}
-void SimplifiedLowering::DoShift(Node* node, Operator const* op) {
+void SimplifiedLowering::DoShift(Node* node, Operator const* op,
+ Type* rhs_type) {
Node* const rhs = NodeProperties::GetValueInput(node, 1);
- Type* const rhs_type = NodeProperties::GetType(rhs);
- if (!rhs_type->Is(zero_thirtyone_range_)) {
+ if (!rhs_type->Is(type_cache_.kZeroToThirtyOne)) {
node->ReplaceInput(1, graph()->NewNode(machine()->Word32And(), rhs,
jsgraph()->Int32Constant(0x1f)));
}