Upgrade V8 to version 4.9.385.28
https://chromium.googlesource.com/v8/v8/+/4.9.385.28
FPIIM-449
Change-Id: I4b2e74289d4bf3667f2f3dc8aa2e541f63e26eb4
diff --git a/src/compiler/simplified-lowering.cc b/src/compiler/simplified-lowering.cc
index 1461709..653fea8 100644
--- a/src/compiler/simplified-lowering.cc
+++ b/src/compiler/simplified-lowering.cc
@@ -10,22 +10,25 @@
#include "src/code-factory.h"
#include "src/compiler/common-operator.h"
#include "src/compiler/diamond.h"
-#include "src/compiler/graph-inl.h"
#include "src/compiler/linkage.h"
#include "src/compiler/node-matchers.h"
-#include "src/compiler/node-properties-inl.h"
+#include "src/compiler/node-properties.h"
+#include "src/compiler/operator-properties.h"
#include "src/compiler/representation-change.h"
-#include "src/compiler/simplified-lowering.h"
#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 {
namespace compiler {
// Macro for outputting trace information from representation inference.
-#define TRACE(x) \
- if (FLAG_trace_representation) PrintF x
+#define TRACE(...) \
+ do { \
+ if (FLAG_trace_representation) PrintF(__VA_ARGS__); \
+ } while (false)
// Representation selection and lowering of {Simplified} operators to machine
// operators are interwined. We use a fixpoint calculation to compute both the
@@ -54,64 +57,329 @@
};
+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,
- RepresentationChanger* changer)
+ RepresentationChanger* changer,
+ 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) {
- memset(info_, 0, sizeof(NodeInfo) * count_);
-
- Factory* f = zone->isolate()->factory();
- safe_bit_range_ =
- Type::Union(Type::Boolean(),
- Type::Range(f->NewNumber(0), f->NewNumber(1), zone), zone);
- safe_int_additive_range_ =
- Type::Range(f->NewNumber(-std::pow(2.0, 52.0)),
- f->NewNumber(std::pow(2.0, 52.0)), zone);
+ queue_(zone),
+ source_positions_(source_positions),
+ type_cache_(TypeCache::Get()) {
}
void Run(SimplifiedLowering* lowering) {
// Run propagation phase to a fixpoint.
- TRACE(("--{Propagation phase}--\n"));
+ 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;
- TRACE((" visit #%d: %s\n", node->id(), node->op()->mnemonic()));
- VisitNode(node, info->use, NULL);
- TRACE((" ==> output "));
- PrintInfo(info->output);
- TRACE(("\n"));
+ info->set_queued(false);
+ TRACE(" visit #%d: %s\n", node->id(), node->op()->mnemonic());
+ VisitNode(node, info->truncation(), nullptr);
+ TRACE(" ==> output ");
+ PrintOutputInfo(info);
+ TRACE("\n");
}
// Run lowering and change insertion phase.
- TRACE(("--{Simplified lowering phase}--\n"));
+ TRACE("--{Simplified lowering phase}--\n");
phase_ = LOWER;
// Process nodes from the collected {nodes_} vector.
for (NodeVector::iterator i = nodes_.begin(); i != nodes_.end(); ++i) {
Node* node = *i;
- TRACE((" visit #%d: %s\n", node->id(), node->op()->mnemonic()));
+ NodeInfo* info = GetInfo(node);
+ TRACE(" visit #%d: %s\n", node->id(), node->op()->mnemonic());
// Reuse {VisitNode()} so the representation rules are in one place.
- VisitNode(node, GetUseInfo(node), lowering);
+ SourcePositionTable::Scope scope(
+ source_positions_, source_positions_->GetSourcePosition(node));
+ VisitNode(node, info->truncation(), lowering);
}
// Perform the final replacements.
@@ -120,108 +388,181 @@
Node* node = *i;
Node* replacement = *(++i);
node->ReplaceUses(replacement);
+ // We also need to replace the node in the rest of the vector.
+ for (NodeVector::iterator j = i + 1; j != replacements_.end(); ++j) {
+ ++j;
+ if (*j == node) *j = replacement;
+ }
}
}
- // 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);
+ TRACE(" initial: ");
+ info->AddUse(use_info);
+ PrintTruncation(info->truncation());
return;
}
- TRACE((" queue?: "));
- PrintUseInfo(node);
- if ((info->use & use) != use) {
+ TRACE(" queue?: ");
+ 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;
- TRACE((" added: "));
+ info->set_queued(true);
+ TRACE(" added: ");
} else {
- TRACE((" inqueue: "));
+ 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 SetOutput(Node* node, MachineTypeUnion output) {
- // 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;
- }
-
- bool BothInputsAre(Node* node, Type* type) {
- DCHECK_EQ(2, node->InputCount());
- return NodeProperties::GetBounds(node->InputAt(0)).upper->Is(type) &&
- NodeProperties::GetBounds(node->InputAt(1)).upper->Is(type);
- }
-
- void ProcessTruncateWord32Input(Node* node, int index, MachineTypeUnion 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);
+ 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 ProcessInput(Node* node, int index, MachineTypeUnion use) {
+ 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, 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.
+ 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 GetInfo(node->InputAt(0))->output_type()->Is(type) &&
+ GetInfo(node->InputAt(1))->output_type()->Is(type);
+ }
+
+ 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.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, 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);
}
}
@@ -230,175 +571,246 @@
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
}
}
// The default, most general visitation case. For {node}, process all value,
- // context, effect, and control inputs, assuming that value inputs should have
- // {kRepTagged} representation and can observe all output values {kTypeAny}.
+ // context, frame state, effect, and control inputs, assuming that value
+ // inputs should have {kRepTagged} representation and can observe all output
+ // values {kTypeAny}.
void VisitInputs(Node* node) {
- auto i = node->input_edges().begin();
- for (int j = node->op()->ValueInputCount(); j > 0; ++i, j--) {
- ProcessInput(node, (*i).index(), kMachAnyTagged); // Value inputs
+ int tagged_count = node->op()->ValueInputCount() +
+ OperatorProperties::GetContextInputCount(node->op());
+ // Visit value and context inputs as tagged.
+ for (int i = 0; i < tagged_count; i++) {
+ ProcessInput(node, i, UseInfo::AnyTagged());
}
- for (int j = OperatorProperties::GetContextInputCount(node->op()); j > 0;
- ++i, j--) {
- ProcessInput(node, (*i).index(), kMachAnyTagged); // Context inputs
+ // Only enqueue other inputs (framestates, effects, control).
+ for (int i = tagged_count; i < node->InputCount(); i++) {
+ EnqueueInput(node, i);
}
- for (int j = node->op()->EffectInputCount(); j > 0; ++i, j--) {
- Enqueue((*i).to()); // Effect inputs: just visit
- }
- for (int j = node->op()->ControlInputCount(); j > 0; ++i, j--) {
- Enqueue((*i).to()); // Control inputs: just visit
- }
- SetOutput(node, kMachAnyTagged);
}
- // Helper for binops of the I x I -> O variety.
- void VisitBinop(Node* node, MachineTypeUnion input_use,
- MachineTypeUnion output) {
- DCHECK_EQ(2, node->InputCount());
- ProcessInput(node, 0, input_use);
- ProcessInput(node, 1, input_use);
+ // Helper for binops of the R x L -> O variety.
+ 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++) {
+ EnqueueInput(node, i);
+ }
SetOutput(node, output);
}
+ // Helper for binops of the I x I -> O variety.
+ 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, kMachInt32, kMachInt32); }
+ void VisitInt32Binop(Node* node) {
+ VisitBinop(node, UseInfo::TruncatingWord32(), NodeOutputInfo::Int32());
+ }
+ void VisitWord32TruncatingBinop(Node* node) {
+ VisitBinop(node, UseInfo::TruncatingWord32(),
+ NodeOutputInfo::NumberTruncatedToWord32());
+ }
void VisitUint32Binop(Node* node) {
- VisitBinop(node, kMachUint32, kMachUint32);
+ VisitBinop(node, UseInfo::TruncatingWord32(), NodeOutputInfo::Uint32());
}
- void VisitInt64Binop(Node* node) { VisitBinop(node, kMachInt64, kMachInt64); }
+ void VisitInt64Binop(Node* node) {
+ VisitBinop(node, UseInfo::TruncatingWord64(), NodeOutputInfo::Int64());
+ }
void VisitUint64Binop(Node* node) {
- VisitBinop(node, kMachUint64, kMachUint64);
+ VisitBinop(node, UseInfo::TruncatingWord64(), NodeOutputInfo::Uint64());
}
- 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); }
+ 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());
+ }
// Infer representation for phi-like nodes.
- MachineType GetRepresentationForPhi(Node* node, MachineTypeUnion use) {
- // Phis adapt to the output representation their uses demand.
- Type* upper = NodeProperties::GetBounds(node).upper;
- if ((use & kRepMask) == kRepTagged) {
- // only tagged uses.
- return kRepTagged;
- } else if (upper->Is(Type::Integral32())) {
- // Integer within [-2^31, 2^32[ range.
- if ((use & kRepMask) == kRepFloat64) {
- // only float64 uses.
- return kRepFloat64;
- } else 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 & kRepMask) == kRepWord32 ||
- (use & kTypeMask) == kTypeInt32 ||
- (use & kTypeMask) == kTypeUint32) {
- // We only use 32 bits or we use the result consistently.
- return kRepWord32;
- } else {
- return kRepFloat64;
- }
- } else if (IsSafeBitOperand(node)) {
- // multiple uses => pick kRepBit.
- return kRepBit;
- } else if (upper->Is(Type::Number())) {
- // multiple uses => pick kRepFloat64.
- 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());
}
- return kRepTagged;
+
+ // Compute the representation.
+ MachineRepresentation rep = MachineRepresentation::kTagged;
+ if (type->Is(Type::None())) {
+ rep = MachineRepresentation::kNone;
+ } else if (type->Is(Type::Signed32()) || type->Is(Type::Unsigned32())) {
+ rep = MachineRepresentation::kWord32;
+ } else if (use.TruncatesToWord32()) {
+ rep = MachineRepresentation::kWord32;
+ } else if (type->Is(Type::Boolean())) {
+ rep = MachineRepresentation::kBit;
+ } else if (type->Is(Type::Number())) {
+ rep = MachineRepresentation::kFloat64;
+ } else if (type->Is(Type::Internal())) {
+ // We mark (u)int64 as Type::Internal.
+ // TODO(jarin) This is a workaround for our lack of (u)int64
+ // types. This can be removed once we can represent (u)int64
+ // unambiguously. (At the moment internal objects, such as the hole,
+ // are also Type::Internal()).
+ bool is_word64 = GetInfo(node->InputAt(0))->representation() ==
+ MachineRepresentation::kWord64;
+#ifdef DEBUG
+ // Check that all the inputs agree on being Word64.
+ for (int i = 1; i < node->op()->ValueInputCount(); i++) {
+ DCHECK_EQ(is_word64, GetInfo(node->InputAt(i))->representation() ==
+ MachineRepresentation::kWord64);
+ }
+#endif
+ rep = is_word64 ? MachineRepresentation::kWord64
+ : MachineRepresentation::kTagged;
+ }
+ return NodeOutputInfo(rep, type);
}
// Helper for handling selects.
- void VisitSelect(Node* node, 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::GetBounds(node).upper;
- 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()) {
- node->set_op(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::GetBounds(node).upper;
- 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)) {
- node->set_op(lowering->common()->Phi(type, values));
- }
-
- // Convert inputs to the output representation of this phi.
- for (Edge const edge : node->input_edges()) {
- // TODO(titzer): it'd be nice to have distinguished edge kinds here.
- ProcessInput(node, edge.index(), values > 0 ? output_type : 0);
- values--;
- }
- } else {
- // Propagate {use} of the phi to value inputs, and 0 to control.
- MachineType use_type =
- static_cast<MachineType>((use & kTypeMask) | output);
- for (Edge const edge : node->input_edges()) {
- // TODO(titzer): it'd be nice to have distinguished edge kinds here.
- ProcessInput(node, edge.index(), values > 0 ? use_type : 0);
- values--;
+ if (output.representation() != PhiRepresentationOf(node->op())) {
+ NodeProperties::ChangeOp(
+ node, lowering->common()->Phi(output.representation(), values));
}
}
+
+ // Convert inputs to the output representation of this phi, pass the
+ // truncation truncation along.
+ UseInfo input_use(output.representation(), truncation);
+ for (int i = 0; i < node->InputCount(); i++) {
+ ProcessInput(node, i, i < values ? input_use : UseInfo::None());
+ }
+ }
+
+ void VisitCall(Node* node, SimplifiedLowering* lowering) {
+ const CallDescriptor* desc = OpParameter<const CallDescriptor*>(node->op());
+ const MachineSignature* sig = desc->GetMachineSignature();
+ int params = static_cast<int>(sig->parameter_count());
+ // Propagate representation information from call descriptor.
+ for (int i = 0; i < node->InputCount(); i++) {
+ if (i == 0) {
+ // The target of the call.
+ ProcessInput(node, i, UseInfo::None());
+ } else if ((i - 1) < params) {
+ ProcessInput(node, i, TruncatingUseInfoFromRepresentation(
+ sig->GetParam(i - 1).representation()));
+ } else {
+ ProcessInput(node, i, UseInfo::None());
+ }
+ }
+
+ if (sig->return_count() > 0) {
+ SetOutputFromMachineType(node, desc->GetMachineSignature()->GetReturn());
+ } else {
+ 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++) {
+ EnqueueInput(node, i, UseInfo::Any());
+ }
+ } else {
+ Zone* zone = jsgraph_->zone();
+ ZoneVector<MachineType>* types =
+ new (zone->New(sizeof(ZoneVector<MachineType>)))
+ ZoneVector<MachineType>(node->InputCount(), zone);
+ for (int i = 0; i < node->InputCount(); i++) {
+ 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, NodeOutputInfo::AnyTagged());
}
const Operator* Int32Op(Node* node) {
@@ -413,60 +825,9 @@
return changer_->Float64OperatorFor(node->opcode());
}
- bool CanLowerToInt32Binop(Node* node, MachineTypeUnion use) {
- return BothInputsAre(node, Type::Signed32()) && !CanObserveNonInt32(use);
- }
-
- bool IsSafeBitOperand(Node* node) {
- Type* type = NodeProperties::GetBounds(node).upper;
- return type->Is(safe_bit_range_);
- }
-
- bool IsSafeIntAdditiveOperand(Node* node) {
- Type* type = NodeProperties::GetBounds(node).upper;
- // TODO(jarin): Unfortunately, bitset types are not subtypes of larger
- // range types, so we have to explicitly check for Integral32 here
- // (in addition to the safe integer range). Once we fix subtyping for
- // ranges, we should simplify this.
- return type->Is(safe_int_additive_range_) || type->Is(Type::Integral32());
- }
-
- bool CanLowerToInt32AdditiveBinop(Node* node, MachineTypeUnion use) {
- return IsSafeIntAdditiveOperand(node->InputAt(0)) &&
- IsSafeIntAdditiveOperand(node->InputAt(1)) &&
- !CanObserveNonInt32(use);
- }
-
- bool CanLowerToUint32Binop(Node* node, MachineTypeUnion use) {
- return BothInputsAre(node, Type::Unsigned32()) && !CanObserveNonUint32(use);
- }
-
- bool CanLowerToUint32AdditiveBinop(Node* node, MachineTypeUnion use) {
- return IsSafeIntAdditiveOperand(node->InputAt(0)) &&
- IsSafeIntAdditiveOperand(node->InputAt(1)) &&
- !CanObserveNonUint32(use);
- }
-
- bool CanObserveNonInt32(MachineTypeUnion use) {
- return (use & (kTypeUint32 | kTypeNumber | kTypeAny)) != 0;
- }
-
- bool CanObserveMinusZero(MachineTypeUnion use) {
- // TODO(turbofan): technically Uint32 cannot observe minus zero either.
- return (use & (kTypeUint32 | kTypeNumber | kTypeAny)) != 0;
- }
-
- bool CanObserveNaN(MachineTypeUnion use) {
- return (use & (kTypeNumber | kTypeAny)) != 0;
- }
-
- bool CanObserveNonUint32(MachineTypeUnion use) {
- return (use & (kTypeInt32 | 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()) {
//------------------------------------------------------------------
@@ -474,43 +835,43 @@
//------------------------------------------------------------------
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::GetBounds(node).upper;
- 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, 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);
-
- case IrOpcode::kEnd:
- case IrOpcode::kIfTrue:
- case IrOpcode::kIfFalse:
- case IrOpcode::kReturn:
- case IrOpcode::kMerge:
- case IrOpcode::kThrow:
- return VisitInputs(node); // default visit for all node inputs.
+ 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, 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);
//------------------------------------------------------------------
// JavaScript operators.
@@ -524,67 +885,45 @@
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::kAnyToBoolean: {
- if (IsSafeBitOperand(node->InputAt(0))) {
- VisitUnop(node, kRepBit, kRepBit);
- if (lower()) DeferReplacement(node, node->InputAt(0));
- } else {
- VisitUnop(node, kMachAnyTagged, kTypeBool | kRepTagged);
- if (lower()) {
- // AnyToBoolean(x) => Call(ToBooleanStub, x, no-context)
- Operator::Properties properties = node->op()->properties();
- Callable callable = CodeFactory::ToBoolean(
- jsgraph_->isolate(), ToBooleanStub::RESULT_AS_ODDBALL);
- CallDescriptor::Flags flags = CallDescriptor::kPatchableCallSite;
- CallDescriptor* desc = Linkage::GetStubCallDescriptor(
- callable.descriptor(), 0, flags, properties, jsgraph_->zone());
- node->set_op(jsgraph_->common()->Call(desc));
- node->InsertInput(jsgraph_->zone(), 0,
- jsgraph_->HeapConstant(callable.code()));
- node->AppendInput(jsgraph_->zone(), jsgraph_->NoContextConstant());
- }
- }
- break;
- }
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->set_op(lowering->machine()->Word32Equal());
node->AppendInput(jsgraph_->zone(), jsgraph_->Int32Constant(0));
+ NodeProperties::ChangeOp(node, lowering->machine()->Word32Equal());
} else {
// BooleanNot(x: kRepTagged) => WordEqual(x, #false)
- node->set_op(lowering->machine()->WordEqual());
node->AppendInput(jsgraph_->zone(), jsgraph_->FalseConstant());
+ NodeProperties::ChangeOp(node, lowering->machine()->WordEqual());
}
} 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 {
// BooleanToNumber(x: kRepTagged) => WordEqual(x, #true)
- node->set_op(lowering->machine()->WordEqual());
node->AppendInput(jsgraph_->zone(), jsgraph_->TrueConstant());
+ NodeProperties::ChangeOp(node, lowering->machine()->WordEqual());
}
} 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;
}
@@ -592,288 +931,319 @@
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()) node->set_op(Int32Op(node));
- } else if (BothInputsAre(node, Type::Unsigned32())) {
+ if (lower()) NodeProperties::ChangeOp(node, Int32Op(node));
+ } else if (BothInputsAreUnsigned32(node)) {
// => unsigned Int32Cmp
VisitUint32Cmp(node);
- if (lower()) node->set_op(Uint32Op(node));
+ if (lower()) NodeProperties::ChangeOp(node, Uint32Op(node));
} else {
// => Float64Cmp
VisitFloat64Cmp(node);
- if (lower()) node->set_op(Float64Op(node));
+ if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
}
break;
}
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()) node->set_op(Int32Op(node));
- } else if (CanLowerToInt32AdditiveBinop(node, use)) {
- // => signed Int32Add/Sub, truncating inputs
- ProcessTruncateWord32Input(node, 0, kTypeInt32);
- ProcessTruncateWord32Input(node, 1, kTypeInt32);
- SetOutput(node, kMachInt32);
- if (lower()) node->set_op(Int32Op(node));
- } else if (CanLowerToUint32Binop(node, use)) {
- // => unsigned Int32Add/Sub
- VisitUint32Binop(node);
- if (lower()) node->set_op(Uint32Op(node));
- } else if (CanLowerToUint32AdditiveBinop(node, use)) {
- // => signed Int32Add/Sub, truncating inputs
- ProcessTruncateWord32Input(node, 0, kTypeUint32);
- ProcessTruncateWord32Input(node, 1, kTypeUint32);
- SetOutput(node, kMachUint32);
- if (lower()) node->set_op(Uint32Op(node));
+ if (lower()) NodeProperties::ChangeOp(node, Int32Op(node));
+ } 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
VisitFloat64Binop(node);
- if (lower()) node->set_op(Float64Op(node));
+ if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
}
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()) node->set_op(Int32Op(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);
- if (lower()) node->set_op(Float64Op(node));
+ if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
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;
}
// => Float64Div
VisitFloat64Binop(node);
- if (lower()) node->set_op(Float64Op(node));
+ if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
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;
}
// => Float64Mod
VisitFloat64Binop(node);
- if (lower()) node->set_op(Float64Op(node));
+ if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
break;
}
- case IrOpcode::kNumberToInt32: {
- MachineTypeUnion use_rep = use & kRepMask;
- Node* input = node->InputAt(0);
- Type* in_upper = NodeProperties::GetBounds(input).upper;
- 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())
- node->set_op(lowering->machine()->TruncateFloat64ToInt32());
+ case IrOpcode::kNumberBitwiseOr:
+ case IrOpcode::kNumberBitwiseXor:
+ case IrOpcode::kNumberBitwiseAnd: {
+ VisitInt32Binop(node);
+ if (lower()) NodeProperties::ChangeOp(node, Int32Op(node));
+ break;
+ }
+ case IrOpcode::kNumberShiftLeft: {
+ 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: {
+ 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: {
+ 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: {
+ // 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::GetBounds(input).upper;
- 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) == kTypeUint32 ||
- in_upper->Is(Type::Unsigned32())) {
- // Just change representation if necessary.
- VisitUnop(node, kTypeUint32 | kRepWord32, kTypeUint32 | 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, 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())
- node->set_op(lowering->machine()->TruncateFloat64ToInt32());
+ // 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, UseInfo::AnyTagged(), NodeOutputInfo::NumberTagged());
+ if (lower()) {
+ // PlainPrimitiveToNumber(x) => Call(ToNumberStub, x, no-context)
+ Operator::Properties properties = node->op()->properties();
+ Callable callable = CodeFactory::ToNumber(jsgraph_->isolate());
+ CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
+ CallDescriptor* desc = Linkage::GetStubCallDescriptor(
+ jsgraph_->isolate(), jsgraph_->zone(), callable.descriptor(), 0,
+ flags, properties);
+ node->InsertInput(jsgraph_->zone(), 0,
+ jsgraph_->HeapConstant(callable.code()));
+ node->AppendInput(jsgraph_->zone(), jsgraph_->NoContextConstant());
+ NodeProperties::ChangeOp(node, jsgraph_->common()->Call(desc));
}
break;
}
case IrOpcode::kReferenceEqual: {
- VisitBinop(node, kMachAnyTagged, kRepBit);
- if (lower()) node->set_op(lowering->machine()->WordEqual());
+ 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::kStringAdd: {
- VisitBinop(node, kMachAnyTagged, kMachAnyTagged);
- if (lower()) lowering->DoStringAdd(node);
+ case IrOpcode::kAllocate: {
+ ProcessInput(node, 0, UseInfo::AnyTagged());
+ ProcessRemainingInputs(node, 1);
+ 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, UseInfo::AnyTagged());
+ SetOutput(node, NodeOutputInfo::Bool());
+ if (lower()) lowering->DoObjectIsNumber(node);
break;
}
case IrOpcode::kObjectIsSmi: {
- ProcessInput(node, 0, kMachAnyTagged);
- SetOutput(node, kRepBit | kTypeBool);
- if (lower()) {
- Node* is_tagged = jsgraph_->graph()->NewNode(
- jsgraph_->machine()->WordAnd(), node->InputAt(0),
- jsgraph_->Int32Constant(static_cast<int>(kSmiTagMask)));
- Node* is_smi = jsgraph_->graph()->NewNode(
- jsgraph_->machine()->WordEqual(), is_tagged,
- jsgraph_->Int32Constant(kSmiTag));
- DeferReplacement(node, is_smi);
- }
- break;
- }
- case IrOpcode::kObjectIsNonNegativeSmi: {
- ProcessInput(node, 0, kMachAnyTagged);
- SetOutput(node, kRepBit | kTypeBool);
- if (lower()) {
- Node* is_tagged = jsgraph_->graph()->NewNode(
- jsgraph_->machine()->WordAnd(), node->InputAt(0),
- jsgraph_->Int32Constant(static_cast<int>(kSmiTagMask)));
- Node* is_smi = jsgraph_->graph()->NewNode(
- jsgraph_->machine()->WordEqual(), is_tagged,
- jsgraph_->Int32Constant(kSmiTag));
- Node* is_non_neg = jsgraph_->graph()->NewNode(
- jsgraph_->machine()->IntLessThanOrEqual(),
- jsgraph_->Int32Constant(0), node->InputAt(0));
- Node* is_non_neg_smi = jsgraph_->graph()->NewNode(
- jsgraph_->machine()->Word32And(), is_smi, is_non_neg);
- DeferReplacement(node, is_non_neg_smi);
- }
+ ProcessInput(node, 0, UseInfo::AnyTagged());
+ SetOutput(node, NodeOutputInfo::Bool());
+ if (lower()) lowering->DoObjectIsSmi(node);
break;
}
@@ -881,29 +1251,31 @@
// 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, kMachInt32); // 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, kMachInt32); // 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:
@@ -912,9 +1284,15 @@
// 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, UseInfo::TruncatingWord32(),
+ NodeOutputInfo::Uint32());
case IrOpcode::kInt32Add:
case IrOpcode::kInt32Sub:
@@ -958,222 +1336,187 @@
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, 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:
case IrOpcode::kFloat64Mul:
case IrOpcode::kFloat64Div:
case IrOpcode::kFloat64Mod:
+ case IrOpcode::kFloat64Min:
return VisitFloat64Binop(node);
+ case IrOpcode::kFloat64Abs:
case IrOpcode::kFloat64Sqrt:
- case IrOpcode::kFloat64Floor:
- case IrOpcode::kFloat64Ceil:
+ 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, UseInfo::Float64(), NodeOutputInfo::Int32());
+ case IrOpcode::kFloat64InsertLowWord32:
+ case IrOpcode::kFloat64InsertHighWord32:
+ return VisitBinop(node, UseInfo::Float64(), UseInfo::TruncatingWord32(),
+ NodeOutputInfo::Float64());
case IrOpcode::kLoadStackPointer:
- return VisitLeaf(node, kMachPtr);
+ case IrOpcode::kLoadFramePointer:
+ return VisitLeaf(node, NodeOutputInfo::Pointer());
case IrOpcode::kStateValues:
- for (int i = 0; i < node->InputCount(); i++) {
- ProcessInput(node, i, kTypeAny);
- }
- SetOutput(node, kMachAnyTagged);
+ VisitStateValues(node);
break;
default:
VisitInputs(node);
+ // Assume the output is tagged.
+ SetOutput(node, NodeOutputInfo::AnyTagged());
break;
}
}
void DeferReplacement(Node* node, Node* replacement) {
- if (FLAG_trace_representation) {
- TRACE(("defer replacement #%d:%s with #%d:%s\n", node->id(),
- node->op()->mnemonic(), replacement->id(),
- replacement->op()->mnemonic()));
- }
- if (replacement->id() < count_) {
- // Replace with a previously existing node eagerly.
+ TRACE("defer replacement #%d:%s with #%d:%s\n", node->id(),
+ node->op()->mnemonic(), replacement->id(),
+ replacement->op()->mnemonic());
+
+ if (replacement->id() < count_ &&
+ 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);
} else {
// Otherwise, we are replacing a node with a representation change.
// Such a substitution must be done after all lowering is done, because
- // new nodes do not have {NodeInfo} entries, and that would confuse
- // the representation change insertion for uses of it.
+ // changing the type could confuse the representation change
+ // insertion for uses of the node.
replacements_.push_back(node);
replacements_.push_back(replacement);
}
- // TODO(titzer) node->RemoveAllInputs(); // Node is now dead.
+ 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) {
+ void PrintOutputInfo(NodeInfo* info) {
if (FLAG_trace_representation) {
OFStream os(stdout);
- os << static_cast<MachineType>(info);
+ os << info->representation() << " (";
+ info->output_type()->PrintTo(os, Type::SEMANTIC_DIM);
+ os << ")";
+ }
+ }
+
+ void PrintRepresentation(MachineRepresentation rep) {
+ if (FLAG_trace_representation) {
+ OFStream os(stdout);
+ 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_;
- int count_; // number of nodes in the graph
- NodeInfo* info_; // node id -> usage information
+ size_t const count_; // number of nodes in the graph
+ 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
RepresentationChanger* changer_; // for inserting representation changes
ZoneQueue<Node*> queue_; // queue for traversing the graph
- Type* safe_bit_range_;
- Type* safe_int_additive_range_;
+ // TODO(danno): RepresentationSelector shouldn't know anything about the
+ // source positions table, but must for now since there currently is no other
+ // way to pass down source position information to nodes created during
+ // lowering. Once this phase becomes a vanilla reducer, it should get source
+ // position information via the SourcePositionWrapper like all other reducers.
+ SourcePositionTable* source_positions_;
+ 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; }
};
-Node* SimplifiedLowering::IsTagged(Node* node) {
- // TODO(titzer): factor this out to a TaggingScheme abstraction.
- STATIC_ASSERT(kSmiTagMask == 1); // Only works if tag is the low bit.
- return graph()->NewNode(machine()->WordAnd(), node,
- jsgraph()->Int32Constant(kSmiTagMask));
-}
+SimplifiedLowering::SimplifiedLowering(JSGraph* jsgraph, Zone* zone,
+ SourcePositionTable* source_positions)
+ : jsgraph_(jsgraph),
+ zone_(zone),
+ type_cache_(TypeCache::Get()),
+ source_positions_(source_positions) {}
void SimplifiedLowering::LowerAllNodes() {
- SimplifiedOperatorBuilder simplified(graph()->zone());
- RepresentationChanger changer(jsgraph(), &simplified,
- graph()->zone()->isolate());
- RepresentationSelector selector(jsgraph(), zone_, &changer);
+ RepresentationChanger changer(jsgraph(), jsgraph()->isolate());
+ RepresentationSelector selector(jsgraph(), zone_, &changer,
+ source_positions_);
selector.Run(this);
}
-Node* SimplifiedLowering::Untag(Node* node) {
- // TODO(titzer): factor this out to a TaggingScheme abstraction.
- Node* shift_amount = jsgraph()->Int32Constant(kSmiTagSize + kSmiShiftSize);
- return graph()->NewNode(machine()->WordSar(), node, shift_amount);
-}
-
-
-Node* SimplifiedLowering::SmiTag(Node* node) {
- // TODO(titzer): factor this out to a TaggingScheme abstraction.
- Node* shift_amount = jsgraph()->Int32Constant(kSmiTagSize + kSmiShiftSize);
- return graph()->NewNode(machine()->WordShl(), node, shift_amount);
-}
-
-
-Node* SimplifiedLowering::OffsetMinusTagConstant(int32_t offset) {
- return jsgraph()->Int32Constant(offset - kHeapObjectTag);
-}
-
-
-static WriteBarrierKind ComputeWriteBarrierKind(BaseTaggedness base_is_tagged,
- MachineType representation,
- Type* type) {
- // TODO(turbofan): skip write barriers for Smis, etc.
- if (base_is_tagged == kTaggedBase &&
- RepresentationOf(representation) == kRepTagged) {
- // Write barriers are only for writes into heap objects (i.e. tagged base).
- return kFullWriteBarrier;
- }
- return kNoWriteBarrier;
-}
-
-
-void SimplifiedLowering::DoLoadField(Node* node) {
- const FieldAccess& access = FieldAccessOf(node->op());
- node->set_op(machine()->Load(access.machine_type));
- Node* offset = jsgraph()->IntPtrConstant(access.offset - access.tag());
- node->InsertInput(graph()->zone(), 1, offset);
-}
-
-
-void SimplifiedLowering::DoStoreField(Node* node) {
- const FieldAccess& access = FieldAccessOf(node->op());
- WriteBarrierKind kind = ComputeWriteBarrierKind(
- access.base_is_tagged, access.machine_type, access.type);
- node->set_op(
- machine()->Store(StoreRepresentation(access.machine_type, kind)));
- Node* offset = jsgraph()->IntPtrConstant(access.offset - access.tag());
- node->InsertInput(graph()->zone(), 1, offset);
-}
-
-
-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);
@@ -1189,19 +1532,21 @@
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 {
@@ -1212,82 +1557,83 @@
Node* ephi = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, merge);
// Replace effect uses of {node} with the {ephi}.
- NodeProperties::ReplaceWithValue(node, node, ephi);
+ NodeProperties::ReplaceUses(node, node, ephi);
// Turn the {node} into a Phi.
- node->set_op(common()->Phi(output_type, 2));
node->ReplaceInput(0, vtrue);
node->ReplaceInput(1, vfalse);
node->ReplaceInput(2, merge);
node->TrimInputCount(3);
+ NodeProperties::ChangeOp(node, common()->Phi(output_rep, 2));
} else {
- node->set_op(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();
- node->set_op(machine()->CheckedStore(type));
+ MachineRepresentation const rep =
+ BufferAccessOf(node->op()).machine_type().representation();
+ NodeProperties::ChangeOp(node, machine()->CheckedStore(rep));
}
-void SimplifiedLowering::DoLoadElement(Node* node) {
- const ElementAccess& access = ElementAccessOf(node->op());
- node->set_op(machine()->Load(access.machine_type));
- node->ReplaceInput(1, ComputeIndex(access, node->InputAt(1)));
+void SimplifiedLowering::DoObjectIsNumber(Node* node) {
+ Node* input = NodeProperties::GetValueInput(node, 0);
+ // TODO(bmeurer): Optimize somewhat based on input type.
+ Node* check =
+ graph()->NewNode(machine()->WordEqual(),
+ graph()->NewNode(machine()->WordAnd(), input,
+ jsgraph()->IntPtrConstant(kSmiTagMask)),
+ jsgraph()->IntPtrConstant(kSmiTag));
+ Node* branch = graph()->NewNode(common()->Branch(), check, graph()->start());
+ Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
+ Node* vtrue = jsgraph()->Int32Constant(1);
+ Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
+ Node* vfalse = graph()->NewNode(
+ machine()->WordEqual(),
+ graph()->NewNode(
+ machine()->Load(MachineType::AnyTagged()), input,
+ jsgraph()->IntPtrConstant(HeapObject::kMapOffset - kHeapObjectTag),
+ graph()->start(), if_false),
+ jsgraph()->HeapConstant(isolate()->factory()->heap_number_map()));
+ Node* control = graph()->NewNode(common()->Merge(2), if_true, if_false);
+ node->ReplaceInput(0, vtrue);
+ node->AppendInput(graph()->zone(), vfalse);
+ node->AppendInput(graph()->zone(), control);
+ NodeProperties::ChangeOp(node, common()->Phi(MachineRepresentation::kBit, 2));
}
-void SimplifiedLowering::DoStoreElement(Node* node) {
- const ElementAccess& access = ElementAccessOf(node->op());
- node->set_op(machine()->Store(StoreRepresentation(
- access.machine_type,
- ComputeWriteBarrierKind(access.base_is_tagged, access.machine_type,
- access.type))));
- node->ReplaceInput(1, ComputeIndex(access, node->InputAt(1)));
+void SimplifiedLowering::DoObjectIsSmi(Node* node) {
+ node->ReplaceInput(0,
+ graph()->NewNode(machine()->WordAnd(), node->InputAt(0),
+ jsgraph()->IntPtrConstant(kSmiTagMask)));
+ node->AppendInput(graph()->zone(), jsgraph()->IntPtrConstant(kSmiTag));
+ NodeProperties::ChangeOp(node, machine()->WordEqual());
}
-void SimplifiedLowering::DoStringAdd(Node* node) {
+Node* SimplifiedLowering::StringComparison(Node* node) {
Operator::Properties properties = node->op()->properties();
- Callable callable = CodeFactory::StringAdd(
- zone()->isolate(), STRING_ADD_CHECK_NONE, NOT_TENURED);
+ Callable callable = CodeFactory::StringCompare(isolate());
CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
CallDescriptor* desc = Linkage::GetStubCallDescriptor(
- callable.descriptor(), 0, flags, properties, zone());
- node->set_op(common()->Call(desc));
- node->InsertInput(graph()->zone(), 0,
- jsgraph()->HeapConstant(callable.code()));
- node->AppendInput(graph()->zone(), jsgraph()->UndefinedConstant());
- node->AppendInput(graph()->zone(), graph()->start());
- node->AppendInput(graph()->zone(), graph()->start());
-}
-
-
-Node* SimplifiedLowering::StringComparison(Node* node, bool requires_ordering) {
- CEntryStub stub(zone()->isolate(), 1);
- Runtime::FunctionId f =
- requires_ordering ? Runtime::kStringCompare : Runtime::kStringEquals;
- ExternalReference ref(f, zone()->isolate());
- Operator::Properties props = node->op()->properties();
- // TODO(mstarzinger): We should call StringCompareStub here instead, once an
- // interface descriptor is available for it.
- CallDescriptor* desc = Linkage::GetRuntimeCallDescriptor(f, 2, props, zone());
- return graph()->NewNode(common()->Call(desc),
- jsgraph()->HeapConstant(stub.GetCode()),
- NodeProperties::GetValueInput(node, 0),
- NodeProperties::GetValueInput(node, 1),
- jsgraph()->ExternalConstant(ref),
- jsgraph()->Int32Constant(2),
- jsgraph()->UndefinedConstant());
+ isolate(), zone(), callable.descriptor(), 0, flags, properties);
+ return graph()->NewNode(
+ common()->Call(desc), jsgraph()->HeapConstant(callable.code()),
+ NodeProperties::GetValueInput(node, 0),
+ NodeProperties::GetValueInput(node, 1), jsgraph()->NoContextConstant(),
+ NodeProperties::GetEffectInput(node),
+ NodeProperties::GetControlInput(node));
}
Node* SimplifiedLowering::Int32Div(Node* const node) {
Int32BinopMatcher m(node);
Node* const zero = jsgraph()->Int32Constant(0);
+ Node* const minus_one = jsgraph()->Int32Constant(-1);
Node* const lhs = m.left().node();
Node* const rhs = m.right().node();
@@ -1299,20 +1645,62 @@
return graph()->NewNode(machine()->Int32Div(), lhs, rhs, graph()->start());
}
- Diamond if_zero(graph(), common(),
- graph()->NewNode(machine()->Word32Equal(), rhs, zero),
- BranchHint::kFalse);
+ // General case for signed integer division.
+ //
+ // if 0 < rhs then
+ // lhs / rhs
+ // else
+ // if rhs < -1 then
+ // lhs / rhs
+ // else if rhs == 0 then
+ // 0
+ // else
+ // 0 - lhs
+ //
+ // 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(MachineRepresentation::kWord32, 2);
- Diamond if_minus_one(graph(), common(),
- graph()->NewNode(machine()->Word32Equal(), rhs,
- jsgraph()->Int32Constant(-1)),
- BranchHint::kFalse);
- if_minus_one.Nest(if_zero, false);
- Node* sub = graph()->NewNode(machine()->Int32Sub(), zero, lhs);
- Node* div =
- graph()->NewNode(machine()->Int32Div(), lhs, rhs, if_minus_one.if_false);
+ Node* check0 = graph()->NewNode(machine()->Int32LessThan(), zero, rhs);
+ Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kTrue), check0,
+ graph()->start());
- return if_zero.Phi(kMachInt32, zero, if_minus_one.Phi(kMachInt32, sub, div));
+ Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
+ Node* true0 = graph()->NewNode(machine()->Int32Div(), lhs, rhs, if_true0);
+
+ Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
+ Node* false0;
+ {
+ Node* check1 = graph()->NewNode(machine()->Int32LessThan(), rhs, minus_one);
+ Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_false0);
+
+ Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
+ Node* true1 = graph()->NewNode(machine()->Int32Div(), lhs, rhs, if_true1);
+
+ Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
+ Node* false1;
+ {
+ Node* check2 = graph()->NewNode(machine()->Word32Equal(), rhs, zero);
+ Node* branch2 = graph()->NewNode(common()->Branch(), check2, if_false1);
+
+ Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
+ Node* true2 = zero;
+
+ Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2);
+ Node* false2 = graph()->NewNode(machine()->Int32Sub(), zero, lhs);
+
+ if_false1 = graph()->NewNode(merge_op, if_true2, if_false2);
+ false1 = graph()->NewNode(phi_op, true2, false2, if_false1);
+ }
+
+ if_false0 = graph()->NewNode(merge_op, if_true1, if_false1);
+ false0 = graph()->NewNode(phi_op, true1, false1, if_false0);
+ }
+
+ Node* merge0 = graph()->NewNode(merge_op, if_true0, if_false0);
+ return graph()->NewNode(phi_op, true0, false0, merge0);
}
@@ -1350,7 +1738,8 @@
// 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,
@@ -1429,7 +1818,7 @@
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);
}
@@ -1461,7 +1850,8 @@
// 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());
@@ -1492,24 +1882,61 @@
}
+void SimplifiedLowering::DoShift(Node* node, Operator const* op,
+ Type* rhs_type) {
+ Node* const rhs = NodeProperties::GetValueInput(node, 1);
+ if (!rhs_type->Is(type_cache_.kZeroToThirtyOne)) {
+ node->ReplaceInput(1, graph()->NewNode(machine()->Word32And(), rhs,
+ jsgraph()->Int32Constant(0x1f)));
+ }
+ NodeProperties::ChangeOp(node, op);
+}
+
+
+namespace {
+
+void ReplaceEffectUses(Node* node, Node* replacement) {
+ // Requires distinguishing between value and effect edges.
+ DCHECK(replacement->op()->EffectOutputCount() > 0);
+ for (Edge edge : node->use_edges()) {
+ if (NodeProperties::IsEffectEdge(edge)) {
+ edge.UpdateTo(replacement);
+ } else {
+ DCHECK(NodeProperties::IsValueEdge(edge));
+ }
+ }
+}
+
+} // namespace
+
+
void SimplifiedLowering::DoStringEqual(Node* node) {
- node->set_op(machine()->WordEqual());
- node->ReplaceInput(0, StringComparison(node, false));
+ Node* comparison = StringComparison(node);
+ ReplaceEffectUses(node, comparison);
+ node->ReplaceInput(0, comparison);
node->ReplaceInput(1, jsgraph()->SmiConstant(EQUAL));
+ node->TrimInputCount(2);
+ NodeProperties::ChangeOp(node, machine()->WordEqual());
}
void SimplifiedLowering::DoStringLessThan(Node* node) {
- node->set_op(machine()->IntLessThan());
- node->ReplaceInput(0, StringComparison(node, true));
+ Node* comparison = StringComparison(node);
+ ReplaceEffectUses(node, comparison);
+ node->ReplaceInput(0, comparison);
node->ReplaceInput(1, jsgraph()->SmiConstant(EQUAL));
+ node->TrimInputCount(2);
+ NodeProperties::ChangeOp(node, machine()->IntLessThan());
}
void SimplifiedLowering::DoStringLessThanOrEqual(Node* node) {
- node->set_op(machine()->IntLessThanOrEqual());
- node->ReplaceInput(0, StringComparison(node, true));
+ Node* comparison = StringComparison(node);
+ ReplaceEffectUses(node, comparison);
+ node->ReplaceInput(0, comparison);
node->ReplaceInput(1, jsgraph()->SmiConstant(EQUAL));
+ node->TrimInputCount(2);
+ NodeProperties::ChangeOp(node, machine()->IntLessThanOrEqual());
}
} // namespace compiler