return lowering_->Changed(node_);
}
+ Reduction ChangeToStringComparisonOperator(const Operator* op,
+ bool invert = false) {
+ if (node_->op()->ControlInputCount() > 0) {
+ lowering_->RelaxControls(node_);
+ }
+ // String comparison operators need effect and control inputs, so copy them
+ // over.
+ Node* effect = NodeProperties::GetEffectInput(node_);
+ Node* control = NodeProperties::GetControlInput(node_);
+ node_->ReplaceInput(2, effect);
+ node_->ReplaceInput(3, control);
+
+ node_->TrimInputCount(4);
+ NodeProperties::ChangeOp(node_, op);
+
+ if (invert) {
+ // Insert a boolean-not to invert the value.
+ Node* value = graph()->NewNode(simplified()->BooleanNot(), node_);
+ node_->ReplaceUses(value);
+ // Note: ReplaceUses() smashes all uses, so smash it back here.
+ value->ReplaceInput(0, node_);
+ return lowering_->Replace(value);
+ }
+ return lowering_->Changed(node_);
+ }
+
Reduction ChangeToPureOperator(const Operator* op, Type* type) {
return ChangeToPureOperator(op, false, type);
}
default:
return NoChange();
}
- return r.ChangeToPureOperator(stringOp);
+ r.ChangeToStringComparisonOperator(stringOp);
+ return Changed(node);
}
if (r.OneInputCannotBe(Type::StringOrReceiver())) {
const Operator* less_than;
return r.ChangeToPureOperator(simplified()->NumberEqual(), invert);
}
if (r.BothInputsAre(Type::String())) {
- return r.ChangeToPureOperator(simplified()->StringEqual(), invert);
+ return r.ChangeToStringComparisonOperator(simplified()->StringEqual(),
+ invert);
}
if (r.BothInputsAre(Type::Receiver())) {
return r.ChangeToPureOperator(
invert);
}
if (r.BothInputsAre(Type::String())) {
- return r.ChangeToPureOperator(simplified()->StringEqual(), invert);
+ return r.ChangeToStringComparisonOperator(simplified()->StringEqual(),
+ invert);
}
if (r.BothInputsAre(Type::Number())) {
return r.ChangeToPureOperator(simplified()->NumberEqual(), invert);
return graph()->NewNode(
common()->Call(desc), jsgraph()->HeapConstant(callable.code()),
NodeProperties::GetValueInput(node, 0),
- NodeProperties::GetValueInput(node, 1), jsgraph()->NoContextConstant());
+ NodeProperties::GetValueInput(node, 1), jsgraph()->NoContextConstant(),
+ NodeProperties::GetEffectInput(node),
+ NodeProperties::GetControlInput(node));
}
}
+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->ReplaceInput(0, StringComparison(node));
+ 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->ReplaceInput(0, StringComparison(node));
+ 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->ReplaceInput(0, StringComparison(node));
+ 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());
}
V(NumberToInt32, Operator::kNoProperties, 1) \
V(NumberToUint32, Operator::kNoProperties, 1) \
V(PlainPrimitiveToNumber, Operator::kNoProperties, 1) \
- V(StringEqual, Operator::kCommutative, 2) \
- V(StringLessThan, Operator::kNoProperties, 2) \
- V(StringLessThanOrEqual, Operator::kNoProperties, 2) \
V(ChangeTaggedToInt32, Operator::kNoProperties, 1) \
V(ChangeTaggedToUint32, Operator::kNoProperties, 1) \
V(ChangeTaggedToFloat64, Operator::kNoProperties, 1) \
V(ChangeBitToBool, Operator::kNoProperties, 1) \
V(ObjectIsSmi, Operator::kNoProperties, 1)
+#define NO_THROW_OP_LIST(V) \
+ V(StringEqual, Operator::kCommutative, 2) \
+ V(StringLessThan, Operator::kNoThrow, 2) \
+ V(StringLessThanOrEqual, Operator::kNoThrow, 2)
struct SimplifiedOperatorGlobalCache final {
#define PURE(Name, properties, input_count) \
PURE_OP_LIST(PURE)
#undef PURE
+#define NO_THROW(Name, properties, input_count) \
+ struct Name##Operator final : public Operator { \
+ Name##Operator() \
+ : Operator(IrOpcode::k##Name, Operator::kNoThrow | properties, #Name, \
+ input_count, 1, 1, 1, 1, 0) {} \
+ }; \
+ Name##Operator k##Name;
+ NO_THROW_OP_LIST(NO_THROW)
+#undef NO_THROW
+
#define BUFFER_ACCESS(Type, type, TYPE, ctype, size) \
struct LoadBuffer##Type##Operator final : public Operator1<BufferAccess> { \
LoadBuffer##Type##Operator() \
: cache_(kCache.Get()), zone_(zone) {}
-#define PURE(Name, properties, input_count) \
+#define GET_FROM_CACHE(Name, properties, input_count) \
const Operator* SimplifiedOperatorBuilder::Name() { return &cache_.k##Name; }
-PURE_OP_LIST(PURE)
-#undef PURE
+PURE_OP_LIST(GET_FROM_CACHE)
+NO_THROW_OP_LIST(GET_FROM_CACHE)
+#undef GET_FROM_CACHE
const Operator* SimplifiedOperatorBuilder::ReferenceEqual(Type* type) {
Node* control() { return start(); }
- void CheckPureBinop(IrOpcode::Value expected, Node* node) {
+ void CheckBinop(IrOpcode::Value expected, Node* node) {
CHECK_EQ(expected, node->opcode());
- CHECK_EQ(2, node->InputCount()); // should not have context, effect, etc.
}
- void CheckPureBinop(const Operator* expected, Node* node) {
+ void CheckBinop(const Operator* expected, Node* node) {
CHECK_EQ(expected->opcode(), node->op()->opcode());
- CHECK_EQ(2, node->InputCount()); // should not have context, effect, etc.
}
Node* ReduceUnop(const Operator* op, Type* input_type) {
Node* add = R.Binop(R.javascript.Add(language_mode), p0, p1);
Node* r = R.reduce(add);
- R.CheckPureBinop(IrOpcode::kStringAdd, r);
+ R.CheckBinop(IrOpcode::kStringAdd, r);
CHECK_EQ(p0, r->InputAt(0));
CHECK_EQ(p1, r->InputAt(1));
}
Node* add = R.Binop(R.javascript.Add(language_mode), p0, p1);
Node* r = R.reduce(add);
- R.CheckPureBinop(IrOpcode::kNumberAdd, r);
+ R.CheckBinop(IrOpcode::kNumberAdd, r);
CHECK_EQ(p0, r->InputAt(0));
CHECK_EQ(p1, r->InputAt(1));
}
Node* add = R.Binop(ops[k], p0, p1);
Node* r = R.reduce(add);
- R.CheckPureBinop(ops[k + 1], r);
+ R.CheckBinop(ops[k + 1], r);
CHECK_EQ(p0, r->InputAt(0));
CHECK_EQ(p1, r->InputAt(1));
}
Node* add = R.Binop(R.ops[k], p0, p1);
Node* r = R.reduce(add);
- R.CheckPureBinop(R.ops[k + 1], r);
+ R.CheckBinop(R.ops[k + 1], r);
Node* r0 = r->InputAt(0);
Node* r1 = r->InputAt(1);
Node* add = R.Binop(R.ops[k], p0, p1);
Node* r = R.reduce(add);
- R.CheckPureBinop(R.ops[k + 1], r);
+ R.CheckBinop(R.ops[k + 1], r);
CheckToI32(p0, r->InputAt(0), R.signedness[k]);
CheckToI32(p1, r->InputAt(1), R.signedness[k + 1]);
Node* cmp = R.Binop(ops[k], p0, p1);
Node* r = R.reduce(cmp);
- R.CheckPureBinop(ops[k + 1], r);
+ R.CheckBinop(ops[k + 1], r);
if (k >= 4) {
// GreaterThan and GreaterThanOrEqual commute the inputs
// and use the LessThan and LessThanOrEqual operators.
Node* cmp = R.Binop(ops[k], p0, p1);
Node* r = R.reduce(cmp);
- R.CheckPureBinop(ops[k + 1], r);
+ R.CheckBinop(ops[k + 1], r);
if (k >= 4) {
// GreaterThan and GreaterThanOrEqual commute the inputs
// and use the LessThan and LessThanOrEqual operators.
Node* cmp = R.Binop(less_than, p0, p1);
Node* r = R.reduce(cmp);
if (types[i]->Is(Type::String()) && types[j]->Is(Type::String())) {
- R.CheckPureBinop(R.simplified.StringLessThan(), r);
+ R.CheckBinop(R.simplified.StringLessThan(), r);
} else if ((types[i]->Is(Type::Number()) &&
types[j]->Is(Type::Number())) ||
(!is_strong(language_mode) &&
(!types[i]->Maybe(Type::String()) ||
!types[j]->Maybe(Type::String())))) {
- R.CheckPureBinop(R.simplified.NumberLessThan(), r);
+ R.CheckBinop(R.simplified.NumberLessThan(), r);
} else {
// No reduction of mixed types.
CHECK_EQ(r->op(), less_than);
strict ? R->javascript.StrictEqual() : R->javascript.Equal();
Node* eq = R->Binop(op, p0, p1);
Node* r = R->reduce(eq);
- R->CheckPureBinop(expected, r);
+ R->CheckBinop(expected, r);
}
{
Node* n = R->reduce(ne);
CHECK_EQ(IrOpcode::kBooleanNot, n->opcode());
Node* r = n->InputAt(0);
- R->CheckPureBinop(expected, r);
+ R->CheckBinop(expected, r);
}
}
}
BinopEffectsTester B(ops[j], Type::Number(), Type::Number());
CHECK_EQ(ops[j + 1]->opcode(), B.result->op()->opcode());
- B.R.CheckPureBinop(B.result->opcode(), B.result);
+ B.R.CheckBinop(B.result->opcode(), B.result);
B.CheckNoOp(0);
B.CheckNoOp(1);
BinopEffectsTester B(R.ops[j], I32Type(signed_left), I32Type(signed_right));
CHECK_EQ(R.ops[j + 1]->opcode(), B.result->op()->opcode());
- B.R.CheckPureBinop(B.result->opcode(), B.result);
+ B.R.CheckBinop(B.result->opcode(), B.result);
B.CheckNoOp(0);
B.CheckNoOp(1);
BinopEffectsTester B(R.ops[j], Type::Number(), Type::Number());
CHECK_EQ(R.ops[j + 1]->opcode(), B.result->op()->opcode());
- B.R.CheckPureBinop(B.result->opcode(), B.result);
+ B.R.CheckBinop(B.result->opcode(), B.result);
B.CheckConvertedInput(NumberToI32(signed_left), 0, false);
B.CheckConvertedInput(NumberToI32(signed_right), 1, false);
bool signed_left = R.signedness[j], signed_right = R.signedness[j + 1];
BinopEffectsTester B(R.ops[j], Type::Number(), Type::Primitive());
- B.R.CheckPureBinop(B.result->opcode(), B.result);
+ B.R.CheckBinop(B.result->opcode(), B.result);
Node* i0 = B.CheckConvertedInput(NumberToI32(signed_left), 0, false);
Node* i1 = B.CheckConvertedInput(NumberToI32(signed_right), 1, false);
bool signed_left = R.signedness[j], signed_right = R.signedness[j + 1];
BinopEffectsTester B(R.ops[j], Type::Primitive(), Type::Number());
- B.R.CheckPureBinop(B.result->opcode(), B.result);
+ B.R.CheckBinop(B.result->opcode(), B.result);
Node* i0 = B.CheckConvertedInput(NumberToI32(signed_left), 0, false);
Node* i1 = B.CheckConvertedInput(NumberToI32(signed_right), 1, false);
bool signed_left = R.signedness[j], signed_right = R.signedness[j + 1];
BinopEffectsTester B(R.ops[j], Type::Primitive(), Type::Primitive());
- B.R.CheckPureBinop(B.result->opcode(), B.result);
+ B.R.CheckBinop(B.result->opcode(), B.result);
Node* i0 = B.CheckConvertedInput(NumberToI32(signed_left), 0, false);
Node* i1 = B.CheckConvertedInput(NumberToI32(signed_right), 1, false);
} else {
expected = ops[o].num_op;
}
- R.CheckPureBinop(expected, r);
+ R.CheckBinop(expected, r);
if (ops[o].commute) {
CHECK_EQ(p1, r->InputAt(0));
CHECK_EQ(p0, r->InputAt(1));
CHECK_EQ(expected, node->opcode());
}
+ void CheckLoweringStringBinop(IrOpcode::Value expected, const Operator* op) {
+ Node* node = Return(
+ graph()->NewNode(op, p0, p1, graph()->start(), graph()->start()));
+ Lower();
+ CHECK_EQ(expected, node->opcode());
+ }
+
void CheckLoweringTruncatedBinop(IrOpcode::Value expected, const Operator* op,
const Operator* trunc) {
Node* node = graph()->NewNode(op, p0, p1);
static_cast<IrOpcode::Value>(t.machine()->IntLessThan()->opcode());
IrOpcode::Value compare_le = static_cast<IrOpcode::Value>(
t.machine()->IntLessThanOrEqual()->opcode());
- t.CheckLoweringBinop(compare_eq, t.simplified()->StringEqual());
- t.CheckLoweringBinop(compare_lt, t.simplified()->StringLessThan());
- t.CheckLoweringBinop(compare_le, t.simplified()->StringLessThanOrEqual());
+ t.CheckLoweringStringBinop(compare_eq, t.simplified()->StringEqual());
+ t.CheckLoweringStringBinop(compare_lt, t.simplified()->StringLessThan());
+ t.CheckLoweringStringBinop(compare_le,
+ t.simplified()->StringLessThanOrEqual());
}
PURE(NumberToInt32, Operator::kNoProperties, 1),
PURE(NumberToUint32, Operator::kNoProperties, 1),
PURE(PlainPrimitiveToNumber, Operator::kNoProperties, 1),
- PURE(StringEqual, Operator::kCommutative, 2),
- PURE(StringLessThan, Operator::kNoProperties, 2),
- PURE(StringLessThanOrEqual, Operator::kNoProperties, 2),
PURE(ChangeTaggedToInt32, Operator::kNoProperties, 1),
PURE(ChangeTaggedToUint32, Operator::kNoProperties, 1),
PURE(ChangeTaggedToFloat64, Operator::kNoProperties, 1),