Commit 284e1108 authored by Benedikt Meurer's avatar Benedikt Meurer

[turbofan] Improve typed lowering of JSBitwiseAnd.

TEST=unittests
R=jarin@chromium.org

Review URL: https://codereview.chromium.org/811653004

Cr-Commit-Position: refs/heads/master@{#26046}
parent 3da5a729
...@@ -33,10 +33,11 @@ JSTypedLowering::JSTypedLowering(JSGraph* jsgraph, Zone* zone) ...@@ -33,10 +33,11 @@ JSTypedLowering::JSTypedLowering(JSGraph* jsgraph, Zone* zone)
: jsgraph_(jsgraph), simplified_(graph()->zone()), conversions_(zone) { : jsgraph_(jsgraph), simplified_(graph()->zone()), conversions_(zone) {
Handle<Object> zero = factory()->NewNumber(0.0); Handle<Object> zero = factory()->NewNumber(0.0);
Handle<Object> one = factory()->NewNumber(1.0); Handle<Object> one = factory()->NewNumber(1.0);
zero_range_ = Type::Range(zero, zero, graph()->zone()); zero_range_ = Type::Range(zero, zero, zone);
one_range_ = Type::Range(one, one, graph()->zone()); one_range_ = Type::Range(one, one, zone);
zero_one_range_ = Type::Range(zero, one, zone);
Handle<Object> thirtyone = factory()->NewNumber(31.0); Handle<Object> thirtyone = factory()->NewNumber(31.0);
zero_thirtyone_range_ = Type::Range(zero, thirtyone, graph()->zone()); zero_thirtyone_range_ = Type::Range(zero, thirtyone, zone);
// TODO(jarin): Can we have a correctification of the stupid type system? // TODO(jarin): Can we have a correctification of the stupid type system?
// These stupid work-arounds are just stupid! // These stupid work-arounds are just stupid!
shifted_int32_ranges_[0] = Type::Signed32(); shifted_int32_ranges_[0] = Type::Signed32();
...@@ -45,13 +46,13 @@ JSTypedLowering::JSTypedLowering(JSGraph* jsgraph, Zone* zone) ...@@ -45,13 +46,13 @@ JSTypedLowering::JSTypedLowering(JSGraph* jsgraph, Zone* zone)
for (size_t k = 2; k < arraysize(shifted_int32_ranges_); ++k) { for (size_t k = 2; k < arraysize(shifted_int32_ranges_); ++k) {
Handle<Object> min = factory()->NewNumber(kMinInt / (1 << k)); Handle<Object> min = factory()->NewNumber(kMinInt / (1 << k));
Handle<Object> max = factory()->NewNumber(kMaxInt / (1 << k)); Handle<Object> max = factory()->NewNumber(kMaxInt / (1 << k));
shifted_int32_ranges_[k] = Type::Range(min, max, graph()->zone()); shifted_int32_ranges_[k] = Type::Range(min, max, zone);
} }
} else { } else {
for (size_t k = 1; k < arraysize(shifted_int32_ranges_); ++k) { for (size_t k = 1; k < arraysize(shifted_int32_ranges_); ++k) {
Handle<Object> min = factory()->NewNumber(kMinInt / (1 << k)); Handle<Object> min = factory()->NewNumber(kMinInt / (1 << k));
Handle<Object> max = factory()->NewNumber(kMaxInt / (1 << k)); Handle<Object> max = factory()->NewNumber(kMaxInt / (1 << k));
shifted_int32_ranges_[k] = Type::Range(min, max, graph()->zone()); shifted_int32_ranges_[k] = Type::Range(min, max, zone);
} }
} }
} }
...@@ -111,6 +112,11 @@ class JSBinopReduction FINAL { ...@@ -111,6 +112,11 @@ class JSBinopReduction FINAL {
std::swap(left_type_, right_type_); std::swap(left_type_, right_type_);
} }
void ReplaceLeftInput(Node* l) {
node_->ReplaceInput(0, l);
left_type_ = NodeProperties::GetBounds(l).upper;
}
// Remove all effect and control inputs and outputs to this node and change // Remove all effect and control inputs and outputs to this node and change
// to the pure operator {op}, possibly inserting a boolean inversion. // to the pure operator {op}, possibly inserting a boolean inversion.
Reduction ChangeToPureOperator(const Operator* op, bool invert = false, Reduction ChangeToPureOperator(const Operator* op, bool invert = false,
...@@ -118,16 +124,17 @@ class JSBinopReduction FINAL { ...@@ -118,16 +124,17 @@ class JSBinopReduction FINAL {
DCHECK_EQ(0, op->EffectInputCount()); DCHECK_EQ(0, op->EffectInputCount());
DCHECK_EQ(false, OperatorProperties::HasContextInput(op)); DCHECK_EQ(false, OperatorProperties::HasContextInput(op));
DCHECK_EQ(0, op->ControlInputCount()); DCHECK_EQ(0, op->ControlInputCount());
DCHECK_EQ(2, op->ValueInputCount()); DCHECK_LE(1, op->ValueInputCount());
DCHECK_GE(2, op->ValueInputCount());
// Remove the effects from the node, if any, and update its effect usages. // Remove the effects from the node, if any, and update its effect usages.
if (node_->op()->EffectInputCount() > 0) { if (node_->op()->EffectInputCount() > 0) {
RelaxEffects(node_); RelaxEffects(node_);
} }
// Remove the inputs corresponding to context, effect, and control.
NodeProperties::RemoveNonValueInputs(node_);
// Finally, update the operator to the new one. // Finally, update the operator to the new one.
node_->set_op(op); node_->set_op(op);
// Remove the inputs corresponding to context, effect, and control.
NodeProperties::RemoveNonValueInputs(node_);
// TODO(jarin): Replace the explicit typing hack with a call to some method // TODO(jarin): Replace the explicit typing hack with a call to some method
// that encapsulates changing the operator and re-typing. // that encapsulates changing the operator and re-typing.
...@@ -149,12 +156,19 @@ class JSBinopReduction FINAL { ...@@ -149,12 +156,19 @@ class JSBinopReduction FINAL {
return ChangeToPureOperator(op, false, type); return ChangeToPureOperator(op, false, type);
} }
bool OneInputIs(Type* t) { return left_type_->Is(t) || right_type_->Is(t); } Reduction ReplaceWithLeftInput() {
// Remove the effects from the node, if any, and update its effect usages.
bool BothInputsAre(Type* t) { if (node_->op()->EffectInputCount() > 0) {
return left_type_->Is(t) && right_type_->Is(t); RelaxEffects(node_);
}
return lowering_->Replace(left());
} }
bool LeftInputIs(Type* t) { return left_type_->Is(t); }
bool RightInputIs(Type* t) { return right_type_->Is(t); }
bool OneInputIs(Type* t) { return LeftInputIs(t) || RightInputIs(t); }
bool BothInputsAre(Type* t) { return LeftInputIs(t) && RightInputIs(t); }
bool OneInputCannotBe(Type* t) { bool OneInputCannotBe(Type* t) {
return !left_type_->Maybe(t) || !right_type_->Maybe(t); return !left_type_->Maybe(t) || !right_type_->Maybe(t);
} }
...@@ -265,6 +279,41 @@ Reduction JSTypedLowering::ReduceJSAdd(Node* node) { ...@@ -265,6 +279,41 @@ Reduction JSTypedLowering::ReduceJSAdd(Node* node) {
} }
Reduction JSTypedLowering::ReduceJSBitwiseAnd(Node* node) {
JSBinopReduction r(this, node);
if (r.LeftInputIs(one_range_)) {
if (r.RightInputIs(zero_one_range_)) {
// JSBitwiseAnd(1, x:[0,1]) => x
r.SwapInputs();
return r.ReplaceWithLeftInput();
} else if (r.RightInputIs(Type::Boolean())) {
// JSBitwiseAnd(1, x:boolean) => BooleanToNumber(x)
r.SwapInputs();
return r.ChangeToPureOperator(simplified()->BooleanToNumber());
}
}
if (r.RightInputIs(one_range_)) {
if (r.LeftInputIs(zero_one_range_)) {
// JSBitwiseAnd(x:[0,1], 1) => x
return r.ReplaceWithLeftInput();
} else if (r.LeftInputIs(Type::Boolean())) {
// JSBitwiseAnd(x:boolean, 1) => BooleanToNumber(x)
return r.ChangeToPureOperator(simplified()->BooleanToNumber());
}
}
if (r.BothInputsAre(Type::Primitive())) {
// TODO(titzer): some Smi bitwise operations don't really require going
// all the way to int32, which can save tagging/untagging for some
// operations
// on some platforms.
// TODO(turbofan): make this heuristic configurable for code size.
r.ConvertInputsToUI32(kSigned, kSigned);
return r.ChangeToPureOperator(machine()->Word32And(), Type::Integral32());
}
return NoChange();
}
Reduction JSTypedLowering::ReduceJSBitwiseOr(Node* node) { Reduction JSTypedLowering::ReduceJSBitwiseOr(Node* node) {
JSBinopReduction r(this, node); JSBinopReduction r(this, node);
if (r.BothInputsAre(Type::Primitive()) || r.OneInputIs(zero_range_)) { if (r.BothInputsAre(Type::Primitive()) || r.OneInputIs(zero_range_)) {
...@@ -887,7 +936,7 @@ Reduction JSTypedLowering::Reduce(Node* node) { ...@@ -887,7 +936,7 @@ Reduction JSTypedLowering::Reduce(Node* node) {
case IrOpcode::kJSBitwiseXor: case IrOpcode::kJSBitwiseXor:
return ReduceInt32Binop(node, machine()->Word32Xor()); return ReduceInt32Binop(node, machine()->Word32Xor());
case IrOpcode::kJSBitwiseAnd: case IrOpcode::kJSBitwiseAnd:
return ReduceInt32Binop(node, machine()->Word32And()); return ReduceJSBitwiseAnd(node);
case IrOpcode::kJSShiftLeft: case IrOpcode::kJSShiftLeft:
return ReduceUI32Shift(node, kSigned, machine()->Word32Shl()); return ReduceUI32Shift(node, kSigned, machine()->Word32Shl());
case IrOpcode::kJSShiftRight: case IrOpcode::kJSShiftRight:
......
...@@ -32,6 +32,7 @@ class JSTypedLowering FINAL : public Reducer { ...@@ -32,6 +32,7 @@ class JSTypedLowering FINAL : public Reducer {
Reduction ReplaceEagerly(Node* old, Node* node); Reduction ReplaceEagerly(Node* old, Node* node);
Reduction ReduceJSAdd(Node* node); Reduction ReduceJSAdd(Node* node);
Reduction ReduceJSBitwiseAnd(Node* node);
Reduction ReduceJSBitwiseOr(Node* node); Reduction ReduceJSBitwiseOr(Node* node);
Reduction ReduceJSMultiply(Node* node); Reduction ReduceJSMultiply(Node* node);
Reduction ReduceJSComparison(Node* node); Reduction ReduceJSComparison(Node* node);
...@@ -72,6 +73,7 @@ class JSTypedLowering FINAL : public Reducer { ...@@ -72,6 +73,7 @@ class JSTypedLowering FINAL : public Reducer {
ZoneVector<Node*> conversions_; // Cache inserted JSToXXX() conversions. ZoneVector<Node*> conversions_; // Cache inserted JSToXXX() conversions.
Type* zero_range_; Type* zero_range_;
Type* one_range_; Type* one_range_;
Type* zero_one_range_;
Type* zero_thirtyone_range_; Type* zero_thirtyone_range_;
Type* shifted_int32_ranges_[4]; Type* shifted_int32_ranges_[4];
}; };
......
...@@ -396,6 +396,51 @@ TEST_F(JSTypedLoweringTest, JSStrictEqualWithTheHole) { ...@@ -396,6 +396,51 @@ TEST_F(JSTypedLoweringTest, JSStrictEqualWithTheHole) {
} }
// -----------------------------------------------------------------------------
// JSBitwiseAnd
TEST_F(JSTypedLoweringTest, JSBitwiseAndWithBitish) {
Node* const context = Parameter(Type::Any(), 2);
Node* const effect = graph()->start();
Node* const control = graph()->start();
Handle<Object> zero = factory()->NewNumber(0);
Handle<Object> one = factory()->NewNumber(1);
{
Node* const lhs = Parameter(Type::Range(one, one, zone()), 0);
Node* const rhs = Parameter(Type::Range(zero, one, zone()), 1);
Reduction r = Reduce(graph()->NewNode(javascript()->BitwiseAnd(), lhs, rhs,
context, effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_EQ(rhs, r.replacement());
}
{
Node* const lhs = Parameter(Type::Range(one, one, zone()), 0);
Node* const rhs = Parameter(Type::Boolean(), 1);
Reduction r = Reduce(graph()->NewNode(javascript()->BitwiseAnd(), lhs, rhs,
context, effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsBooleanToNumber(rhs));
}
{
Node* const lhs = Parameter(Type::Range(zero, one, zone()), 0);
Node* const rhs = Parameter(Type::Range(one, one, zone()), 1);
Reduction r = Reduce(graph()->NewNode(javascript()->BitwiseAnd(), lhs, rhs,
context, effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_EQ(lhs, r.replacement());
}
{
Node* const lhs = Parameter(Type::Boolean(), 0);
Node* const rhs = Parameter(Type::Range(one, one, zone()), 1);
Reduction r = Reduce(graph()->NewNode(javascript()->BitwiseAnd(), lhs, rhs,
context, effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsBooleanToNumber(lhs));
}
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// JSShiftLeft // JSShiftLeft
......
...@@ -1292,6 +1292,7 @@ IS_BINOP_MATCHER(Float64Sub) ...@@ -1292,6 +1292,7 @@ IS_BINOP_MATCHER(Float64Sub)
} }
IS_UNOP_MATCHER(AnyToBoolean) IS_UNOP_MATCHER(AnyToBoolean)
IS_UNOP_MATCHER(BooleanNot) IS_UNOP_MATCHER(BooleanNot)
IS_UNOP_MATCHER(BooleanToNumber)
IS_UNOP_MATCHER(ChangeFloat64ToInt32) IS_UNOP_MATCHER(ChangeFloat64ToInt32)
IS_UNOP_MATCHER(ChangeFloat64ToUint32) IS_UNOP_MATCHER(ChangeFloat64ToUint32)
IS_UNOP_MATCHER(ChangeInt32ToFloat64) IS_UNOP_MATCHER(ChangeInt32ToFloat64)
......
...@@ -77,6 +77,7 @@ Matcher<Node*> IsCall(const Matcher<CallDescriptor*>& descriptor_matcher, ...@@ -77,6 +77,7 @@ Matcher<Node*> IsCall(const Matcher<CallDescriptor*>& descriptor_matcher,
Matcher<Node*> IsAnyToBoolean(const Matcher<Node*>& value_matcher); Matcher<Node*> IsAnyToBoolean(const Matcher<Node*>& value_matcher);
Matcher<Node*> IsBooleanNot(const Matcher<Node*>& value_matcher); Matcher<Node*> IsBooleanNot(const Matcher<Node*>& value_matcher);
Matcher<Node*> IsBooleanToNumber(const Matcher<Node*>& value_matcher);
Matcher<Node*> IsNumberEqual(const Matcher<Node*>& lhs_matcher, Matcher<Node*> IsNumberEqual(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher); const Matcher<Node*>& rhs_matcher);
Matcher<Node*> IsNumberLessThan(const Matcher<Node*>& lhs_matcher, Matcher<Node*> IsNumberLessThan(const Matcher<Node*>& lhs_matcher,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment