Update V8 to version 4.1.0.21
This is a cherry-pick of all commits up to and including the
4.1.0.21 cherry-pick in Chromium.
Original commit message:
Version 4.1.0.21 (cherry-pick)
Merged 206e9136bde0f2b5ae8cb77afbb1e7833e5bd412
Unlink pages from the space page list after evacuation.
BUG=430201
LOG=N
R=jkummerow@chromium.org
Review URL: https://codereview.chromium.org/953813002
Cr-Commit-Position: refs/branch-heads/4.1@{#22}
Cr-Branched-From: 2e08d2a7aa9d65d269d8c57aba82eb38a8cb0a18-refs/heads/candidates@{#25353}
---
FPIIM-449
Change-Id: I8c23c7bbb70772b4858fe8a47b64fa97ee0d1f8c
diff --git a/src/compiler/simplified-lowering.cc b/src/compiler/simplified-lowering.cc
index f794525..1461709 100644
--- a/src/compiler/simplified-lowering.cc
+++ b/src/compiler/simplified-lowering.cc
@@ -4,10 +4,15 @@
#include "src/compiler/simplified-lowering.h"
+#include <limits>
+
#include "src/base/bits.h"
#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/representation-change.h"
#include "src/compiler/simplified-lowering.h"
@@ -66,11 +71,18 @@
info_(zone->NewArray<NodeInfo>(count_)),
nodes_(zone),
replacements_(zone),
- contains_js_nodes_(false),
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);
}
void Run(SimplifiedLowering* lowering) {
@@ -164,6 +176,30 @@
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 ProcessInput(Node* node, int index, MachineTypeUnion use) {
Node* input = node->InputAt(index);
if (phase_ == PROPAGATE) {
@@ -206,22 +242,19 @@
// context, effect, and control inputs, assuming that value inputs should have
// {kRepTagged} representation and can observe all output values {kTypeAny}.
void VisitInputs(Node* node) {
- InputIter i = node->inputs().begin();
- for (int j = OperatorProperties::GetValueInputCount(node->op()); j > 0;
- ++i, j--) {
- ProcessInput(node, i.index(), kMachAnyTagged); // Value inputs
+ auto i = node->input_edges().begin();
+ for (int j = node->op()->ValueInputCount(); j > 0; ++i, j--) {
+ ProcessInput(node, (*i).index(), kMachAnyTagged); // Value inputs
}
for (int j = OperatorProperties::GetContextInputCount(node->op()); j > 0;
++i, j--) {
- ProcessInput(node, i.index(), kMachAnyTagged); // Context inputs
+ ProcessInput(node, (*i).index(), kMachAnyTagged); // Context inputs
}
- for (int j = OperatorProperties::GetEffectInputCount(node->op()); j > 0;
- ++i, j--) {
- Enqueue(*i); // Effect inputs: just visit
+ for (int j = node->op()->EffectInputCount(); j > 0; ++i, j--) {
+ Enqueue((*i).to()); // Effect inputs: just visit
}
- for (int j = OperatorProperties::GetControlInputCount(node->op()); j > 0;
- ++i, j--) {
- Enqueue(*i); // Control inputs: just visit
+ for (int j = node->op()->ControlInputCount(); j > 0; ++i, j--) {
+ Enqueue((*i).to()); // Control inputs: just visit
}
SetOutput(node, kMachAnyTagged);
}
@@ -267,60 +300,83 @@
void VisitInt64Cmp(Node* node) { VisitBinop(node, kMachInt64, kRepBit); }
void VisitUint64Cmp(Node* node) { VisitBinop(node, kMachUint64, kRepBit); }
- // Helper for handling phis.
- void VisitPhi(Node* node, MachineTypeUnion use,
- SimplifiedLowering* lowering) {
- // First, propagate the usage information to inputs of the phi.
- if (!lower()) {
- int values = OperatorProperties::GetValueInputCount(node->op());
- // Propagate {use} of the phi to value inputs, and 0 to control.
- Node::Inputs inputs = node->inputs();
- for (Node::Inputs::iterator iter(inputs.begin()); iter != inputs.end();
- ++iter, --values) {
- // TODO(titzer): it'd be nice to have distinguished edge kinds here.
- ProcessInput(node, iter.index(), values > 0 ? use : 0);
- }
- }
- // Phis adapt to whatever output representation their uses demand,
- // pushing representation changes to their inputs.
- MachineTypeUnion use_rep = GetUseInfo(node) & kRepMask;
- MachineTypeUnion use_type = GetUseInfo(node) & kTypeMask;
- MachineTypeUnion rep = 0;
- if (use_rep & kRepTagged) {
- rep = kRepTagged; // Tagged overrides everything.
- } else if (use_rep & kRepFloat64) {
- rep = kRepFloat64;
- } else if (use_rep & kRepWord64) {
- rep = kRepWord64;
- } else if (use_rep & kRepWord32) {
- rep = kRepWord32;
- } else if (use_rep & kRepBit) {
- rep = kRepBit;
- } else {
- // There was no representation associated with any of the uses.
- // TODO(titzer): Select the best rep using phi's type, not the usage type?
- if (use_type & kTypeAny) {
- rep = kRepTagged;
- } else if (use_type & kTypeNumber) {
- rep = kRepFloat64;
- } else if (use_type & kTypeInt64 || use_type & kTypeUint64) {
- rep = kRepWord64;
- } else if (use_type & kTypeInt32 || use_type & kTypeUint32) {
- rep = kRepWord32;
- } else if (use_type & kTypeBool) {
- rep = kRepBit;
- } else {
- UNREACHABLE(); // should have at least a usage type!
- }
- }
- // Preserve the usage type, but set the representation.
+ // 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;
- MachineTypeUnion output_type = rep | changer_->TypeFromUpperBound(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;
+ }
+ return kRepTagged;
+ }
+
+ // Helper for handling selects.
+ void VisitSelect(Node* node, MachineTypeUnion use,
+ SimplifiedLowering* lowering) {
+ ProcessInput(node, 0, kRepBit);
+ 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);
if (lower()) {
- int values = OperatorProperties::GetValueInputCount(node->op());
+ // 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()));
+ }
+ // 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);
+ }
+ }
+
+ // Helper for handling phis.
+ void VisitPhi(Node* node, MachineTypeUnion use,
+ 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);
+
+ int values = node->op()->ValueInputCount();
+
+ if (lower()) {
// Update the phi operator.
MachineType type = static_cast<MachineType>(output_type);
if (type != OpParameter<MachineType>(node)) {
@@ -328,11 +384,19 @@
}
// Convert inputs to the output representation of this phi.
- Node::Inputs inputs = node->inputs();
- for (Node::Inputs::iterator iter(inputs.begin()); iter != inputs.end();
- ++iter, --values) {
+ for (Edge const edge : node->input_edges()) {
// TODO(titzer): it'd be nice to have distinguished edge kinds here.
- ProcessInput(node, iter.index(), values > 0 ? output_type : 0);
+ 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--;
}
}
}
@@ -349,13 +413,55 @@
return changer_->Float64OperatorFor(node->opcode());
}
- static MachineType AssumeImplicitFloat32Change(MachineType type) {
- // TODO(titzer): Assume loads of float32 change representation to float64.
- // Fix this with full support for float32 representations.
- if (type & kRepFloat32) {
- return static_cast<MachineType>((type & ~kRepFloat32) | kRepFloat64);
- }
- return type;
+ 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}.
@@ -401,6 +507,8 @@
ProcessInput(node, 0, kRepBit);
Enqueue(NodeProperties::GetControlInput(node, 0));
break;
+ case IrOpcode::kSelect:
+ return VisitSelect(node, use, lowering);
case IrOpcode::kPhi:
return VisitPhi(node, use, lowering);
@@ -415,19 +523,40 @@
#define DEFINE_JS_CASE(x) case IrOpcode::k##x:
JS_OP_LIST(DEFINE_JS_CASE)
#undef DEFINE_JS_CASE
- contains_js_nodes_ = true;
VisitInputs(node);
return SetOutput(node, kRepTagged);
//------------------------------------------------------------------
// 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) {
- // BooleanNot(x: kRepBit) => WordEqual(x, #0)
- node->set_op(lowering->machine()->WordEqual());
+ // BooleanNot(x: kRepBit) => Word32Equal(x, #0)
+ node->set_op(lowering->machine()->Word32Equal());
node->AppendInput(jsgraph_->zone(), jsgraph_->Int32Constant(0));
} else {
// BooleanNot(x: kRepTagged) => WordEqual(x, #false)
@@ -482,16 +611,26 @@
case IrOpcode::kNumberSubtract: {
// Add and subtract reduce to Int32Add/Sub if the inputs
// are already integers and all uses are truncating.
- if (BothInputsAre(node, Type::Signed32()) &&
- (use & (kTypeUint32 | kTypeNumber | kTypeAny)) == 0) {
+ if (CanLowerToInt32Binop(node, use)) {
// => signed Int32Add/Sub
VisitInt32Binop(node);
if (lower()) node->set_op(Int32Op(node));
- } else if (BothInputsAre(node, Type::Unsigned32()) &&
- (use & (kTypeInt32 | kTypeNumber | kTypeAny)) == 0) {
+ } 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));
} else {
// => Float64Add/Sub
VisitFloat64Binop(node);
@@ -499,54 +638,110 @@
}
break;
}
- case IrOpcode::kNumberMultiply:
- case IrOpcode::kNumberDivide:
+ case IrOpcode::kNumberMultiply: {
+ NumberMatcher right(node->InputAt(1));
+ if (right.IsInRange(-1048576, 1048576)) { // must fit double mantissa.
+ if (CanLowerToInt32Binop(node, use)) {
+ // => signed Int32Mul
+ VisitInt32Binop(node);
+ if (lower()) node->set_op(Int32Op(node));
+ break;
+ }
+ }
+ // => Float64Mul
+ VisitFloat64Binop(node);
+ if (lower()) node->set_op(Float64Op(node));
+ break;
+ }
+ case IrOpcode::kNumberDivide: {
+ if (CanLowerToInt32Binop(node, use)) {
+ // => signed Int32Div
+ VisitInt32Binop(node);
+ if (lower()) DeferReplacement(node, lowering->Int32Div(node));
+ break;
+ }
+ if (BothInputsAre(node, Type::Unsigned32()) && !CanObserveNaN(use)) {
+ // => unsigned Uint32Div
+ VisitUint32Binop(node);
+ if (lower()) DeferReplacement(node, lowering->Uint32Div(node));
+ break;
+ }
+ // => Float64Div
+ VisitFloat64Binop(node);
+ if (lower()) node->set_op(Float64Op(node));
+ break;
+ }
case IrOpcode::kNumberModulus: {
- // Float64Mul/Div/Mod
+ if (CanLowerToInt32Binop(node, use)) {
+ // => signed Int32Mod
+ VisitInt32Binop(node);
+ if (lower()) DeferReplacement(node, lowering->Int32Mod(node));
+ break;
+ }
+ if (BothInputsAre(node, Type::Unsigned32()) && !CanObserveNaN(use)) {
+ // => unsigned Uint32Mod
+ VisitUint32Binop(node);
+ if (lower()) DeferReplacement(node, lowering->Uint32Mod(node));
+ break;
+ }
+ // => Float64Mod
VisitFloat64Binop(node);
if (lower()) node->set_op(Float64Op(node));
break;
}
case IrOpcode::kNumberToInt32: {
MachineTypeUnion use_rep = use & kRepMask;
- if (lower()) {
- MachineTypeUnion in = GetInfo(node->InputAt(0))->output;
- if ((in & kTypeMask) == kTypeInt32 || (in & kRepMask) == kRepWord32) {
- // If the input has type int32, or is already a word32, just change
- // representation if necessary.
- VisitUnop(node, kTypeInt32 | use_rep, kTypeInt32 | use_rep);
- 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);
- node->set_op(lowering->machine()->TruncateFloat64ToInt32());
- }
+ 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 {
- // Propagate a type to the input, but pass through representation.
- VisitUnop(node, kTypeInt32, kTypeInt32 | use_rep);
+ // 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());
}
break;
}
case IrOpcode::kNumberToUint32: {
MachineTypeUnion use_rep = use & kRepMask;
- if (lower()) {
- MachineTypeUnion in = GetInfo(node->InputAt(0))->output;
- if ((in & kTypeMask) == kTypeUint32 ||
- (in & kRepMask) == kRepWord32) {
- // The input has type int32, just change representation.
- VisitUnop(node, kTypeUint32 | use_rep, kTypeUint32 | use_rep);
- DeferReplacement(node, node->InputAt(0));
- } else {
- // Require the input in float64 format to perform truncation.
- // TODO(turbofan): avoid the truncation with a smi check.
- VisitUnop(node, kTypeUint32 | kRepFloat64,
- kTypeUint32 | kRepWord32);
- node->set_op(lowering->machine()->TruncateFloat64ToInt32());
- }
+ 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 {
- // Propagate a type to the input, but pass through representation.
- VisitUnop(node, kTypeUint32, kTypeUint32 | use_rep);
+ // 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());
}
break;
}
@@ -579,47 +774,115 @@
FieldAccess access = FieldAccessOf(node->op());
ProcessInput(node, 0, changer_->TypeForBasePointer(access));
ProcessRemainingInputs(node, 1);
- SetOutput(node, AssumeImplicitFloat32Change(access.machine_type));
+ SetOutput(node, access.machine_type);
if (lower()) lowering->DoLoadField(node);
break;
}
case IrOpcode::kStoreField: {
FieldAccess access = FieldAccessOf(node->op());
ProcessInput(node, 0, changer_->TypeForBasePointer(access));
- ProcessInput(node, 1, AssumeImplicitFloat32Change(access.machine_type));
+ ProcessInput(node, 1, access.machine_type);
ProcessRemainingInputs(node, 2);
SetOutput(node, 0);
if (lower()) lowering->DoStoreField(node);
break;
}
- case IrOpcode::kLoadElement: {
- ElementAccess access = ElementAccessOf(node->op());
- ProcessInput(node, 0, changer_->TypeForBasePointer(access));
- ProcessInput(node, 1, kMachInt32); // element index
+ case IrOpcode::kLoadBuffer: {
+ BufferAccess access = BufferAccessOf(node->op());
+ ProcessInput(node, 0, kMachPtr); // buffer
+ ProcessInput(node, 1, kMachInt32); // offset
ProcessInput(node, 2, kMachInt32); // length
ProcessRemainingInputs(node, 3);
- SetOutput(node, AssumeImplicitFloat32Change(access.machine_type));
+ // 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();
+ } else {
+ output_type = kMachFloat64;
+ }
+ } else if (use & kRepFloat32) {
+ output_type = kMachFloat32;
+ } else {
+ output_type = access.machine_type();
+ }
+ SetOutput(node, output_type);
+ if (lower()) lowering->DoLoadBuffer(node, output_type, 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
+ ProcessRemainingInputs(node, 4);
+ SetOutput(node, 0);
+ 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
+ ProcessRemainingInputs(node, 2);
+ SetOutput(node, access.machine_type);
if (lower()) lowering->DoLoadElement(node);
break;
}
case IrOpcode::kStoreElement: {
ElementAccess access = ElementAccessOf(node->op());
- ProcessInput(node, 0, changer_->TypeForBasePointer(access));
- ProcessInput(node, 1, kMachInt32); // element index
- ProcessInput(node, 2, kMachInt32); // length
- ProcessInput(node, 3, AssumeImplicitFloat32Change(access.machine_type));
- ProcessRemainingInputs(node, 4);
+ ProcessInput(node, 0, changer_->TypeForBasePointer(access)); // base
+ ProcessInput(node, 1, kMachInt32); // index
+ ProcessInput(node, 2, access.machine_type); // value
+ ProcessRemainingInputs(node, 3);
SetOutput(node, 0);
if (lower()) lowering->DoStoreElement(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);
+ }
+ break;
+ }
//------------------------------------------------------------------
// Machine-level operators.
//------------------------------------------------------------------
case IrOpcode::kLoad: {
// TODO(titzer): machine loads/stores need to know BaseTaggedness!?
- MachineType tBase = kRepTagged;
+ MachineTypeUnion tBase = kRepTagged | kMachPtr;
LoadRepresentation rep = OpParameter<LoadRepresentation>(node);
ProcessInput(node, 0, tBase); // pointer or object
ProcessInput(node, 1, kMachInt32); // index
@@ -629,7 +892,7 @@
}
case IrOpcode::kStore: {
// TODO(titzer): machine loads/stores need to know BaseTaggedness!?
- MachineType tBase = kRepTagged;
+ MachineTypeUnion tBase = kRepTagged | kMachPtr;
StoreRepresentation rep = OpParameter<StoreRepresentation>(node);
ProcessInput(node, 0, tBase); // pointer or object
ProcessInput(node, 1, kMachInt32); // index
@@ -640,7 +903,7 @@
}
case IrOpcode::kWord32Shr:
// We output unsigned int32 for shift right because JavaScript.
- return VisitBinop(node, kRepWord32, kRepWord32 | kTypeUint32);
+ return VisitBinop(node, kMachUint32, kMachUint32);
case IrOpcode::kWord32And:
case IrOpcode::kWord32Or:
case IrOpcode::kWord32Xor:
@@ -656,11 +919,13 @@
case IrOpcode::kInt32Add:
case IrOpcode::kInt32Sub:
case IrOpcode::kInt32Mul:
+ case IrOpcode::kInt32MulHigh:
case IrOpcode::kInt32Div:
case IrOpcode::kInt32Mod:
return VisitInt32Binop(node);
- case IrOpcode::kInt32UDiv:
- case IrOpcode::kInt32UMod:
+ case IrOpcode::kUint32Div:
+ case IrOpcode::kUint32Mod:
+ case IrOpcode::kUint32MulHigh:
return VisitUint32Binop(node);
case IrOpcode::kInt32LessThan:
case IrOpcode::kInt32LessThanOrEqual:
@@ -680,8 +945,11 @@
case IrOpcode::kInt64LessThanOrEqual:
return VisitInt64Cmp(node);
- case IrOpcode::kInt64UDiv:
- case IrOpcode::kInt64UMod:
+ case IrOpcode::kUint64LessThan:
+ return VisitUint64Cmp(node);
+
+ case IrOpcode::kUint64Div:
+ case IrOpcode::kUint64Mod:
return VisitUint64Binop(node);
case IrOpcode::kWord64And:
@@ -700,11 +968,17 @@
case IrOpcode::kChangeUint32ToUint64:
return VisitUnop(node, kTypeUint32 | kRepWord32,
kTypeUint32 | kRepWord64);
+ case IrOpcode::kTruncateFloat64ToFloat32:
+ return VisitUnop(node, kTypeNumber | kRepFloat64,
+ kTypeNumber | kRepFloat32);
case IrOpcode::kTruncateInt64ToInt32:
// TODO(titzer): Is kTypeInt32 correct here?
return VisitUnop(node, kTypeInt32 | kRepWord64,
kTypeInt32 | kRepWord32);
+ case IrOpcode::kChangeFloat32ToFloat64:
+ return VisitUnop(node, kTypeNumber | kRepFloat32,
+ kTypeNumber | kRepFloat64);
case IrOpcode::kChangeInt32ToFloat64:
return VisitUnop(node, kTypeInt32 | kRepWord32,
kTypeInt32 | kRepFloat64);
@@ -725,11 +999,23 @@
case IrOpcode::kFloat64Mod:
return VisitFloat64Binop(node);
case IrOpcode::kFloat64Sqrt:
+ case IrOpcode::kFloat64Floor:
+ case IrOpcode::kFloat64Ceil:
+ case IrOpcode::kFloat64RoundTruncate:
+ case IrOpcode::kFloat64RoundTiesAway:
return VisitUnop(node, kMachFloat64, kMachFloat64);
case IrOpcode::kFloat64Equal:
case IrOpcode::kFloat64LessThan:
case IrOpcode::kFloat64LessThanOrEqual:
return VisitFloat64Cmp(node);
+ case IrOpcode::kLoadStackPointer:
+ return VisitLeaf(node, kMachPtr);
+ case IrOpcode::kStateValues:
+ for (int i = 0; i < node->InputCount(); i++) {
+ ProcessInput(node, i, kTypeAny);
+ }
+ SetOutput(node, kMachAnyTagged);
+ break;
default:
VisitInputs(node);
break;
@@ -737,6 +1023,11 @@
}
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.
node->ReplaceUses(replacement);
@@ -770,10 +1061,11 @@
NodeInfo* info_; // node id -> usage information
NodeVector nodes_; // collected nodes
NodeVector replacements_; // replacements to be done after lowering
- bool contains_js_nodes_; // {true} if a JS operator was seen
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_;
NodeInfo* GetInfo(Node* node) {
DCHECK(node->id() >= 0);
@@ -797,7 +1089,7 @@
SimplifiedOperatorBuilder simplified(graph()->zone());
RepresentationChanger changer(jsgraph(), &simplified,
graph()->zone()->isolate());
- RepresentationSelector selector(jsgraph(), zone(), &changer);
+ RepresentationSelector selector(jsgraph(), zone_, &changer);
selector.Run(this);
}
@@ -837,8 +1129,8 @@
void SimplifiedLowering::DoLoadField(Node* node) {
const FieldAccess& access = FieldAccessOf(node->op());
node->set_op(machine()->Load(access.machine_type));
- Node* offset = jsgraph()->Int32Constant(access.offset - access.tag());
- node->InsertInput(zone(), 1, offset);
+ Node* offset = jsgraph()->IntPtrConstant(access.offset - access.tag());
+ node->InsertInput(graph()->zone(), 1, offset);
}
@@ -848,22 +1140,96 @@
access.base_is_tagged, access.machine_type, access.type);
node->set_op(
machine()->Store(StoreRepresentation(access.machine_type, kind)));
- Node* offset = jsgraph()->Int32Constant(access.offset - access.tag());
- node->InsertInput(zone(), 1, offset);
+ Node* offset = jsgraph()->IntPtrConstant(access.offset - access.tag());
+ node->InsertInput(graph()->zone(), 1, offset);
}
Node* SimplifiedLowering::ComputeIndex(const ElementAccess& access,
- Node* index) {
- int element_size = ElementSizeOf(access.machine_type);
- if (element_size != 1) {
- index = graph()->NewNode(machine()->Int32Mul(),
- jsgraph()->Int32Constant(element_size), index);
+ 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));
}
- int fixed_offset = access.header_size - access.tag();
- if (fixed_offset == 0) return index;
- return graph()->NewNode(machine()->Int32Add(), index,
- jsgraph()->Int32Constant(fixed_offset));
+ 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,
+ 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) {
+ Node* const buffer = node->InputAt(0);
+ Node* const offset = node->InputAt(1);
+ Node* const length = node->InputAt(2);
+ Node* const effect = node->InputAt(3);
+ Node* const control = node->InputAt(4);
+ Node* const index =
+ machine()->Is64()
+ ? graph()->NewNode(machine()->ChangeUint32ToUint64(), offset)
+ : offset;
+
+ Node* check = graph()->NewNode(machine()->Uint32LessThan(), offset, length);
+ Node* branch =
+ 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* if_false = graph()->NewNode(common()->IfFalse(), branch);
+ Node* efalse = effect;
+ Node* vfalse;
+ if (output_type & kRepTagged) {
+ vfalse = jsgraph()->UndefinedConstant();
+ } else if (output_type & kRepFloat64) {
+ vfalse =
+ jsgraph()->Float64Constant(std::numeric_limits<double>::quiet_NaN());
+ } else if (output_type & kRepFloat32) {
+ vfalse =
+ jsgraph()->Float32Constant(std::numeric_limits<float>::quiet_NaN());
+ } else {
+ vfalse = jsgraph()->Int32Constant(0);
+ }
+
+ Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
+ Node* ephi = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, merge);
+
+ // Replace effect uses of {node} with the {ephi}.
+ NodeProperties::ReplaceWithValue(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);
+ } else {
+ node->set_op(machine()->CheckedLoad(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));
}
@@ -871,32 +1237,32 @@
const ElementAccess& access = ElementAccessOf(node->op());
node->set_op(machine()->Load(access.machine_type));
node->ReplaceInput(1, ComputeIndex(access, node->InputAt(1)));
- node->RemoveInput(2);
}
void SimplifiedLowering::DoStoreElement(Node* node) {
const ElementAccess& access = ElementAccessOf(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->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)));
- node->RemoveInput(2);
}
void SimplifiedLowering::DoStringAdd(Node* node) {
+ Operator::Properties properties = node->op()->properties();
Callable callable = CodeFactory::StringAdd(
zone()->isolate(), STRING_ADD_CHECK_NONE, NOT_TENURED);
CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
- CallDescriptor* desc =
- Linkage::GetStubCallDescriptor(callable.descriptor(), 0, flags, zone());
+ CallDescriptor* desc = Linkage::GetStubCallDescriptor(
+ callable.descriptor(), 0, flags, properties, zone());
node->set_op(common()->Call(desc));
- node->InsertInput(zone(), 0, jsgraph()->HeapConstant(callable.code()));
- node->AppendInput(zone(), jsgraph()->UndefinedConstant());
- node->AppendInput(zone(), graph()->start());
- node->AppendInput(zone(), graph()->start());
+ 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());
}
@@ -919,6 +1285,213 @@
}
+Node* SimplifiedLowering::Int32Div(Node* const node) {
+ Int32BinopMatcher m(node);
+ Node* const zero = jsgraph()->Int32Constant(0);
+ Node* const lhs = m.left().node();
+ Node* const rhs = m.right().node();
+
+ if (m.right().Is(-1)) {
+ return graph()->NewNode(machine()->Int32Sub(), zero, lhs);
+ } else if (m.right().Is(0)) {
+ return rhs;
+ } else if (machine()->Int32DivIsSafe() || m.right().HasValue()) {
+ return graph()->NewNode(machine()->Int32Div(), lhs, rhs, graph()->start());
+ }
+
+ Diamond if_zero(graph(), common(),
+ graph()->NewNode(machine()->Word32Equal(), rhs, zero),
+ BranchHint::kFalse);
+
+ 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);
+
+ return if_zero.Phi(kMachInt32, zero, if_minus_one.Phi(kMachInt32, sub, div));
+}
+
+
+Node* SimplifiedLowering::Int32Mod(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();
+
+ if (m.right().Is(-1) || m.right().Is(0)) {
+ return zero;
+ } else if (m.right().HasValue()) {
+ return graph()->NewNode(machine()->Int32Mod(), lhs, rhs, graph()->start());
+ }
+
+ // General case for signed integer modulus, with optimization for (unknown)
+ // power of 2 right hand side.
+ //
+ // if 0 < rhs then
+ // msk = rhs - 1
+ // if rhs & msk != 0 then
+ // lhs % rhs
+ // else
+ // if lhs < 0 then
+ // -(-lhs & msk)
+ // else
+ // lhs & msk
+ // else
+ // if rhs < -1 then
+ // lhs % rhs
+ // else
+ // zero
+ //
+ // 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);
+
+ Node* check0 = graph()->NewNode(machine()->Int32LessThan(), zero, rhs);
+ Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kTrue), check0,
+ graph()->start());
+
+ Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
+ Node* true0;
+ {
+ Node* msk = graph()->NewNode(machine()->Int32Add(), rhs, minus_one);
+
+ Node* check1 = graph()->NewNode(machine()->Word32And(), rhs, msk);
+ Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_true0);
+
+ Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
+ Node* true1 = graph()->NewNode(machine()->Int32Mod(), lhs, rhs, if_true1);
+
+ Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
+ Node* false1;
+ {
+ Node* check2 = graph()->NewNode(machine()->Int32LessThan(), lhs, zero);
+ Node* branch2 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
+ check2, if_false1);
+
+ Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
+ Node* true2 = graph()->NewNode(
+ machine()->Int32Sub(), zero,
+ graph()->NewNode(machine()->Word32And(),
+ graph()->NewNode(machine()->Int32Sub(), zero, lhs),
+ msk));
+
+ Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2);
+ Node* false2 = graph()->NewNode(machine()->Word32And(), lhs, msk);
+
+ if_false1 = graph()->NewNode(merge_op, if_true2, if_false2);
+ false1 = graph()->NewNode(phi_op, true2, false2, if_false1);
+ }
+
+ if_true0 = graph()->NewNode(merge_op, if_true1, if_false1);
+ true0 = graph()->NewNode(phi_op, true1, false1, 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(BranchHint::kTrue),
+ check1, if_false0);
+
+ Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
+ Node* true1 = graph()->NewNode(machine()->Int32Mod(), lhs, rhs, if_true1);
+
+ Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
+ Node* false1 = zero;
+
+ 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);
+}
+
+
+Node* SimplifiedLowering::Uint32Div(Node* const node) {
+ Uint32BinopMatcher m(node);
+ Node* const zero = jsgraph()->Uint32Constant(0);
+ Node* const lhs = m.left().node();
+ Node* const rhs = m.right().node();
+
+ if (m.right().Is(0)) {
+ return zero;
+ } else if (machine()->Uint32DivIsSafe() || m.right().HasValue()) {
+ return graph()->NewNode(machine()->Uint32Div(), lhs, rhs, graph()->start());
+ }
+
+ 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);
+}
+
+
+Node* SimplifiedLowering::Uint32Mod(Node* const node) {
+ Uint32BinopMatcher m(node);
+ Node* const minus_one = jsgraph()->Int32Constant(-1);
+ Node* const zero = jsgraph()->Uint32Constant(0);
+ Node* const lhs = m.left().node();
+ Node* const rhs = m.right().node();
+
+ if (m.right().Is(0)) {
+ return zero;
+ } else if (m.right().HasValue()) {
+ return graph()->NewNode(machine()->Uint32Mod(), lhs, rhs, graph()->start());
+ }
+
+ // General case for unsigned integer modulus, with optimization for (unknown)
+ // power of 2 right hand side.
+ //
+ // if rhs then
+ // msk = rhs - 1
+ // if rhs & msk != 0 then
+ // lhs % rhs
+ // else
+ // lhs & msk
+ // else
+ // zero
+ //
+ // 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);
+
+ Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kTrue), rhs,
+ graph()->start());
+
+ Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
+ Node* true0;
+ {
+ Node* msk = graph()->NewNode(machine()->Int32Add(), rhs, minus_one);
+
+ Node* check1 = graph()->NewNode(machine()->Word32And(), rhs, msk);
+ Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_true0);
+
+ Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
+ Node* true1 = graph()->NewNode(machine()->Uint32Mod(), lhs, rhs, if_true1);
+
+ Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
+ Node* false1 = graph()->NewNode(machine()->Word32And(), lhs, msk);
+
+ if_true0 = graph()->NewNode(merge_op, if_true1, if_false1);
+ true0 = graph()->NewNode(phi_op, true1, false1, if_true0);
+ }
+
+ Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
+ Node* false0 = zero;
+
+ Node* merge0 = graph()->NewNode(merge_op, if_true0, if_false0);
+ return graph()->NewNode(phi_op, true0, false0, merge0);
+}
+
+
void SimplifiedLowering::DoStringEqual(Node* node) {
node->set_op(machine()->WordEqual());
node->ReplaceInput(0, StringComparison(node, false));
@@ -939,7 +1512,6 @@
node->ReplaceInput(1, jsgraph()->SmiConstant(EQUAL));
}
-
} // namespace compiler
} // namespace internal
} // namespace v8