// JSToNumber(null) => #0
return ReplaceWith(jsgraph()->ZeroConstant());
}
- // TODO(turbofan): js-typed-lowering of ToNumber(x:boolean)
+ if (input_type->Is(Type::Boolean())) {
+ // JSToNumber(x:boolean) => BooleanToNumber(x)
+ return ReplaceWith(
+ graph()->NewNode(simplified()->BooleanToNumber(), input));
+ }
// TODO(turbofan): js-typed-lowering of ToNumber(x:string)
return NoChange();
}
// Opcodes for VirtuaMachine-level operators.
#define SIMPLIFIED_OP_LIST(V) \
V(BooleanNot) \
+ V(BooleanToNumber) \
V(NumberEqual) \
V(NumberLessThan) \
V(NumberLessThanOrEqual) \
}
break;
}
+ case IrOpcode::kBooleanToNumber: {
+ if (lower()) {
+ MachineTypeUnion input = GetInfo(node->InputAt(0))->output;
+ if (input & kRepBit) {
+ // 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());
+ }
+ } else {
+ // No input representation requirement; adapt during lowering.
+ ProcessInput(node, 0, kTypeBool);
+ SetOutput(node, kMachInt32);
+ }
+ break;
+ }
case IrOpcode::kNumberEqual:
case IrOpcode::kNumberLessThan:
case IrOpcode::kNumberLessThanOrEqual: {
#define PURE_OP_LIST(V) \
V(BooleanNot, Operator::kNoProperties, 1) \
+ V(BooleanToNumber, Operator::kNoProperties, 1) \
V(NumberEqual, Operator::kCommutative, 2) \
V(NumberLessThan, Operator::kNoProperties, 2) \
V(NumberLessThanOrEqual, Operator::kNoProperties, 2) \
explicit SimplifiedOperatorBuilder(Zone* zone);
const Operator* BooleanNot();
+ const Operator* BooleanToNumber();
const Operator* NumberEqual();
const Operator* NumberLessThan();
}
+Bounds Typer::Visitor::TypeBooleanToNumber(Node* node) {
+ return Bounds(Type::Number(zone()));
+}
+
+
Bounds Typer::Visitor::TypeNumberEqual(Node* node) {
return Bounds(Type::Boolean(zone()));
}
static void CheckIsConvertedToNumber(Node* val, Node* converted) {
if (NodeProperties::GetBounds(val).upper->Is(Type::Number())) {
CHECK_EQ(val, converted);
+ } else if (NodeProperties::GetBounds(val).upper->Is(Type::Boolean())) {
+ CHECK_EQ(IrOpcode::kBooleanToNumber, converted->opcode());
+ CHECK_EQ(val, converted->InputAt(0));
} else {
if (converted->opcode() == IrOpcode::kNumberConstant) return;
CHECK_EQ(IrOpcode::kJSToNumber, converted->opcode());
};
for (size_t j = 0; j < arraysize(ops); j += 2) {
- BinopEffectsTester B(ops[j], Type::Number(), Type::Boolean());
+ BinopEffectsTester B(ops[j], Type::Number(), Type::Symbol());
Node* i0 = B.CheckNoOp(0);
Node* i1 = B.CheckConvertedInput(IrOpcode::kJSToNumber, 1, true);
}
for (size_t j = 0; j < arraysize(ops); j += 2) {
- BinopEffectsTester B(ops[j], Type::Boolean(), Type::Number());
+ BinopEffectsTester B(ops[j], Type::Symbol(), Type::Number());
Node* i0 = B.CheckConvertedInput(IrOpcode::kJSToNumber, 0, true);
Node* i1 = B.CheckNoOp(1);
};
for (size_t j = 0; j < arraysize(ops); j += 2) {
- BinopEffectsTester B(ops[j], Type::Boolean(), Type::String());
+ BinopEffectsTester B(ops[j], Type::Symbol(), Type::String());
CHECK_EQ(ops[j + 1]->opcode(), B.result->op()->opcode());
Node* i0 = B.CheckConvertedInput(IrOpcode::kJSToNumber, 0, true);
}
for (size_t j = 0; j < arraysize(ops); j += 2) {
- BinopEffectsTester B(ops[j], Type::Number(), Type::Boolean());
+ BinopEffectsTester B(ops[j], Type::Number(), Type::Symbol());
Node* i0 = B.CheckConvertedInput(IrOpcode::kJSToNumber, 0, true);
Node* i1 = B.result->InputAt(1);
}
for (size_t j = 0; j < arraysize(ops); j += 2) {
- BinopEffectsTester B(ops[j], Type::Boolean(), Type::Number());
+ BinopEffectsTester B(ops[j], Type::Symbol(), Type::Number());
Node* i0 = B.result->InputAt(0);
Node* i1 = B.CheckConvertedInput(IrOpcode::kJSToNumber, 1, true);
}
+TEST(LowerBooleanToNumber_bit_int32) {
+ // BooleanToNumber(x: kRepBit) used as kMachInt32
+ TestingGraph t(Type::Boolean());
+ Node* b = t.ExampleWithOutput(kRepBit);
+ Node* cnv = t.graph()->NewNode(t.simplified()->BooleanToNumber(), b);
+ Node* use = t.Use(cnv, kMachInt32);
+ t.Return(use);
+ t.Lower();
+ CHECK_EQ(b, use->InputAt(0));
+}
+
+
+TEST(LowerBooleanToNumber_tagged_int32) {
+ // BooleanToNumber(x: kRepTagged) used as kMachInt32
+ TestingGraph t(Type::Boolean());
+ Node* b = t.p0;
+ Node* cnv = t.graph()->NewNode(t.simplified()->BooleanToNumber(), b);
+ Node* use = t.Use(cnv, kMachInt32);
+ t.Return(use);
+ t.Lower();
+ CHECK_EQ(t.machine()->WordEqual()->opcode(), cnv->opcode());
+ CHECK(b == cnv->InputAt(0) || b == cnv->InputAt(1));
+ Node* c = t.jsgraph.TrueConstant();
+ CHECK(c == cnv->InputAt(0) || c == cnv->InputAt(1));
+}
+
+
+TEST(LowerBooleanToNumber_bit_tagged) {
+ // BooleanToNumber(x: kRepBit) used as kMachAnyTagged
+ TestingGraph t(Type::Boolean());
+ Node* b = t.ExampleWithOutput(kRepBit);
+ Node* cnv = t.graph()->NewNode(t.simplified()->BooleanToNumber(), b);
+ Node* use = t.Use(cnv, kMachAnyTagged);
+ t.Return(use);
+ t.Lower();
+ CHECK_EQ(b, use->InputAt(0)->InputAt(0));
+ CHECK_EQ(IrOpcode::kChangeInt32ToTagged, use->InputAt(0)->opcode());
+}
+
+
+TEST(LowerBooleanToNumber_tagged_tagged) {
+ // BooleanToNumber(x: kRepTagged) used as kMachAnyTagged
+ TestingGraph t(Type::Boolean());
+ Node* b = t.p0;
+ Node* cnv = t.graph()->NewNode(t.simplified()->BooleanToNumber(), b);
+ Node* use = t.Use(cnv, kMachAnyTagged);
+ t.Return(use);
+ t.Lower();
+ CHECK_EQ(cnv, use->InputAt(0)->InputAt(0));
+ CHECK_EQ(IrOpcode::kChangeInt32ToTagged, use->InputAt(0)->opcode());
+ CHECK_EQ(t.machine()->WordEqual()->opcode(), cnv->opcode());
+ CHECK(b == cnv->InputAt(0) || b == cnv->InputAt(1));
+ Node* c = t.jsgraph.TrueConstant();
+ CHECK(c == cnv->InputAt(0) || c == cnv->InputAt(1));
+}
+
+
static Type* test_types[] = {Type::Signed32(), Type::Unsigned32(),
Type::Number(), Type::Any()};