Commit fae23618 authored by Georg Neis's avatar Georg Neis Committed by Commit Bot

[bigint,compiler] Support bigints in bitwise-not (~) operator.

This introduces a JSBitwiseNot operator and lowers it either to a
speculative xor with -1 (when we have Number feedback) or to
a stub call. The stub is also new.

Bug: v8:6791
Change-Id: I362e52de8a741dc5db044c406543878e407eb2ed
Reviewed-on: https://chromium-review.googlesource.com/778839
Commit-Queue: Georg Neis <neis@chromium.org>
Reviewed-by: 's avatarJaroslav Sevcik <jarin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#49539}
parent 06b79ee9
...@@ -701,6 +701,7 @@ namespace internal { ...@@ -701,6 +701,7 @@ namespace internal {
TFC(Equal, Compare, 1) \ TFC(Equal, Compare, 1) \
TFC(SameValue, Compare, 1) \ TFC(SameValue, Compare, 1) \
TFC(StrictEqual, Compare, 1) \ TFC(StrictEqual, Compare, 1) \
TFS(BitwiseNot, kValue) \
TFS(Negate, kValue) \ TFS(Negate, kValue) \
\ \
/* Object */ \ /* Object */ \
......
...@@ -602,7 +602,8 @@ void NumberBuiltinsAssembler::UnaryOp(Variable* var_input, Label* do_smi, ...@@ -602,7 +602,8 @@ void NumberBuiltinsAssembler::UnaryOp(Variable* var_input, Label* do_smi,
Variable* var_input_double, Variable* var_input_double,
Label* do_bigint) { Label* do_bigint) {
DCHECK_EQ(var_input->rep(), MachineRepresentation::kTagged); DCHECK_EQ(var_input->rep(), MachineRepresentation::kTagged);
DCHECK_EQ(var_input_double->rep(), MachineRepresentation::kFloat64); DCHECK_IMPLIES(var_input_double != nullptr,
var_input_double->rep() == MachineRepresentation::kFloat64);
Node* context = Parameter(Descriptor::kContext); Node* context = Parameter(Descriptor::kContext);
var_input->Bind(Parameter(Descriptor::kValue)); var_input->Bind(Parameter(Descriptor::kValue));
...@@ -616,7 +617,9 @@ void NumberBuiltinsAssembler::UnaryOp(Variable* var_input, Label* do_smi, ...@@ -616,7 +617,9 @@ void NumberBuiltinsAssembler::UnaryOp(Variable* var_input, Label* do_smi,
Label not_number(this); Label not_number(this);
GotoIf(TaggedIsSmi(input), do_smi); GotoIf(TaggedIsSmi(input), do_smi);
GotoIfNot(IsHeapNumber(input), &not_number); GotoIfNot(IsHeapNumber(input), &not_number);
if (var_input_double != nullptr) {
var_input_double->Bind(LoadHeapNumberValue(input)); var_input_double->Bind(LoadHeapNumberValue(input));
}
Goto(do_double); Goto(do_double);
BIND(&not_number); BIND(&not_number);
...@@ -748,6 +751,26 @@ TF_BUILTIN(Subtract, NumberBuiltinsAssembler) { ...@@ -748,6 +751,26 @@ TF_BUILTIN(Subtract, NumberBuiltinsAssembler) {
} }
} }
TF_BUILTIN(BitwiseNot, NumberBuiltinsAssembler) {
Node* context = Parameter(Descriptor::kContext);
VARIABLE(var_input, MachineRepresentation::kTagged);
Label do_number(this), do_bigint(this);
UnaryOp<Descriptor>(&var_input, &do_number, &do_number, nullptr, &do_bigint);
BIND(&do_number);
{
TailCallBuiltin(Builtins::kBitwiseXor, context, var_input.value(),
SmiConstant(-1));
}
BIND(&do_bigint);
{
Return(CallRuntime(Runtime::kBigIntUnaryOp, context, var_input.value(),
SmiConstant(Operation::kBitwiseNot)));
}
}
TF_BUILTIN(Negate, NumberBuiltinsAssembler) { TF_BUILTIN(Negate, NumberBuiltinsAssembler) {
VARIABLE(var_input, MachineRepresentation::kTagged); VARIABLE(var_input, MachineRepresentation::kTagged);
VARIABLE(var_input_double, MachineRepresentation::kFloat64); VARIABLE(var_input_double, MachineRepresentation::kFloat64);
......
...@@ -2083,12 +2083,13 @@ CallFrequency BytecodeGraphBuilder::ComputeCallFrequency(int slot_id) const { ...@@ -2083,12 +2083,13 @@ CallFrequency BytecodeGraphBuilder::ComputeCallFrequency(int slot_id) const {
invocation_frequency_.value()); invocation_frequency_.value());
} }
void BytecodeGraphBuilder::VisitNegate() { void BytecodeGraphBuilder::VisitBitwiseNot() {
// TODO(neis): Define a BuildUnaryOp helper function.
PrepareEagerCheckpoint(); PrepareEagerCheckpoint();
FeedbackSlot slot = feedback_vector()->ToSlot( FeedbackSlot slot = feedback_vector()->ToSlot(
bytecode_iterator().GetIndexOperand(kUnaryOperationHintIndex)); bytecode_iterator().GetIndexOperand(kUnaryOperationHintIndex));
const Operator* op = javascript()->Negate(); const Operator* op = javascript()->BitwiseNot();
Node* operand = environment()->LookupAccumulator(); Node* operand = environment()->LookupAccumulator();
JSTypeHintLowering::LoweringResult lowering = JSTypeHintLowering::LoweringResult lowering =
...@@ -2105,27 +2106,23 @@ void BytecodeGraphBuilder::VisitNegate() { ...@@ -2105,27 +2106,23 @@ void BytecodeGraphBuilder::VisitNegate() {
environment()->BindAccumulator(node, Environment::kAttachFrameState); environment()->BindAccumulator(node, Environment::kAttachFrameState);
} }
void BytecodeGraphBuilder::VisitBitwiseNot() { void BytecodeGraphBuilder::VisitNegate() {
PrepareEagerCheckpoint(); PrepareEagerCheckpoint();
// TODO(adamk): Create a JSBitwiseNot operator, as this desugaring is
// invalid for BigInts.
const Operator* op = javascript()->BitwiseXor();
Node* operand = environment()->LookupAccumulator();
Node* xor_value = jsgraph()->SmiConstant(-1);
FeedbackSlot slot = feedback_vector()->ToSlot( FeedbackSlot slot = feedback_vector()->ToSlot(
bytecode_iterator().GetIndexOperand(kUnaryOperationHintIndex)); bytecode_iterator().GetIndexOperand(kUnaryOperationHintIndex));
const Operator* op = javascript()->Negate();
Node* operand = environment()->LookupAccumulator();
JSTypeHintLowering::LoweringResult lowering = JSTypeHintLowering::LoweringResult lowering =
TryBuildSimplifiedBinaryOp(op, operand, xor_value, slot); TryBuildSimplifiedUnaryOp(op, operand, slot);
if (lowering.IsExit()) return; if (lowering.IsExit()) return;
Node* node = nullptr; Node* node = nullptr;
if (lowering.IsSideEffectFree()) { if (lowering.IsSideEffectFree()) {
node = lowering.value(); node = lowering.value();
} else { } else {
DCHECK(!lowering.Changed()); DCHECK(!lowering.Changed());
node = NewNode(op, operand, xor_value); node = NewNode(op, operand);
} }
environment()->BindAccumulator(node, Environment::kAttachFrameState); environment()->BindAccumulator(node, Environment::kAttachFrameState);
......
...@@ -70,6 +70,7 @@ REPLACE_STUB_CALL(LessThan) ...@@ -70,6 +70,7 @@ REPLACE_STUB_CALL(LessThan)
REPLACE_STUB_CALL(LessThanOrEqual) REPLACE_STUB_CALL(LessThanOrEqual)
REPLACE_STUB_CALL(GreaterThan) REPLACE_STUB_CALL(GreaterThan)
REPLACE_STUB_CALL(GreaterThanOrEqual) REPLACE_STUB_CALL(GreaterThanOrEqual)
REPLACE_STUB_CALL(BitwiseNot)
REPLACE_STUB_CALL(Negate) REPLACE_STUB_CALL(Negate)
REPLACE_STUB_CALL(HasProperty) REPLACE_STUB_CALL(HasProperty)
REPLACE_STUB_CALL(Equal) REPLACE_STUB_CALL(Equal)
......
...@@ -577,6 +577,7 @@ CompareOperationHint CompareOperationHintOf(const Operator* op) { ...@@ -577,6 +577,7 @@ CompareOperationHint CompareOperationHintOf(const Operator* op) {
V(Multiply, Operator::kNoProperties, 2, 1) \ V(Multiply, Operator::kNoProperties, 2, 1) \
V(Divide, Operator::kNoProperties, 2, 1) \ V(Divide, Operator::kNoProperties, 2, 1) \
V(Modulus, Operator::kNoProperties, 2, 1) \ V(Modulus, Operator::kNoProperties, 2, 1) \
V(BitwiseNot, Operator::kNoProperties, 1, 1) \
V(Negate, Operator::kNoProperties, 1, 1) \ V(Negate, Operator::kNoProperties, 1, 1) \
V(ToInteger, Operator::kNoProperties, 1, 1) \ V(ToInteger, Operator::kNoProperties, 1, 1) \
V(ToLength, Operator::kNoProperties, 1, 1) \ V(ToLength, Operator::kNoProperties, 1, 1) \
......
...@@ -652,6 +652,7 @@ class V8_EXPORT_PRIVATE JSOperatorBuilder final ...@@ -652,6 +652,7 @@ class V8_EXPORT_PRIVATE JSOperatorBuilder final
const Operator* Divide(); const Operator* Divide();
const Operator* Modulus(); const Operator* Modulus();
const Operator* BitwiseNot();
const Operator* Negate(); const Operator* Negate();
const Operator* ToInteger(); const Operator* ToInteger();
......
...@@ -215,8 +215,6 @@ JSTypeHintLowering::JSTypeHintLowering(JSGraph* jsgraph, ...@@ -215,8 +215,6 @@ JSTypeHintLowering::JSTypeHintLowering(JSGraph* jsgraph,
JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceUnaryOperation( JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceUnaryOperation(
const Operator* op, Node* operand, Node* effect, Node* control, const Operator* op, Node* operand, Node* effect, Node* control,
FeedbackSlot slot) const { FeedbackSlot slot) const {
switch (op->opcode()) {
case IrOpcode::kJSNegate: {
DCHECK(!slot.IsInvalid()); DCHECK(!slot.IsInvalid());
BinaryOpICNexus nexus(feedback_vector(), slot); BinaryOpICNexus nexus(feedback_vector(), slot);
if (Node* node = TryBuildSoftDeopt( if (Node* node = TryBuildSoftDeopt(
...@@ -224,21 +222,37 @@ JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceUnaryOperation( ...@@ -224,21 +222,37 @@ JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceUnaryOperation(
DeoptimizeReason::kInsufficientTypeFeedbackForUnaryOperation)) { DeoptimizeReason::kInsufficientTypeFeedbackForUnaryOperation)) {
return LoweringResult::Exit(node); return LoweringResult::Exit(node);
} }
Node* node;
switch (op->opcode()) {
case IrOpcode::kJSBitwiseNot: {
// Lower to a speculative xor with -1 if we have some kind of Number
// feedback.
JSSpeculativeBinopBuilder b(this, jsgraph()->javascript()->BitwiseXor(),
operand, jsgraph()->SmiConstant(-1), effect,
control, slot);
node = b.TryBuildNumberBinop();
break;
}
case IrOpcode::kJSNegate: {
// Lower to a speculative multiplication with -1 if we have some kind of // Lower to a speculative multiplication with -1 if we have some kind of
// Number feedback. // Number feedback.
JSSpeculativeBinopBuilder b(this, jsgraph()->javascript()->Multiply(), JSSpeculativeBinopBuilder b(this, jsgraph()->javascript()->Multiply(),
operand, jsgraph()->SmiConstant(-1), effect, operand, jsgraph()->SmiConstant(-1), effect,
control, slot); control, slot);
if (Node* node = b.TryBuildNumberBinop()) { node = b.TryBuildNumberBinop();
return LoweringResult::SideEffectFree(node, node, control);
}
break; break;
} }
default: default:
UNREACHABLE(); UNREACHABLE();
break; break;
} }
if (node != nullptr) {
return LoweringResult::SideEffectFree(node, node, control);
} else {
return LoweringResult::NoChange(); return LoweringResult::NoChange();
}
} }
JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceBinaryOperation( JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceBinaryOperation(
......
...@@ -426,6 +426,21 @@ Reduction JSTypedLowering::ReduceSpeculativeNumberAdd(Node* node) { ...@@ -426,6 +426,21 @@ Reduction JSTypedLowering::ReduceSpeculativeNumberAdd(Node* node) {
return NoChange(); return NoChange();
} }
Reduction JSTypedLowering::ReduceJSBitwiseNot(Node* node) {
Node* input = NodeProperties::GetValueInput(node, 0);
Type* input_type = NodeProperties::GetType(input);
if (input_type->Is(Type::PlainPrimitive())) {
// JSBitwiseNot(x) => NumberBitwiseXor(ToInt32(x), -1)
node->InsertInput(graph()->zone(), 1, jsgraph()->SmiConstant(-1));
NodeProperties::ChangeOp(node, javascript()->BitwiseXor());
JSBinopReduction r(this, node);
r.ConvertInputsToNumber();
r.ConvertInputsToUI32(kSigned, kSigned);
return r.ChangeToPureOperator(r.NumberOp(), Type::Signed32());
}
return NoChange();
}
Reduction JSTypedLowering::ReduceJSNegate(Node* node) { Reduction JSTypedLowering::ReduceJSNegate(Node* node) {
Node* input = NodeProperties::GetValueInput(node, 0); Node* input = NodeProperties::GetValueInput(node, 0);
Type* input_type = NodeProperties::GetType(input); Type* input_type = NodeProperties::GetType(input);
...@@ -2078,6 +2093,8 @@ Reduction JSTypedLowering::Reduce(Node* node) { ...@@ -2078,6 +2093,8 @@ Reduction JSTypedLowering::Reduce(Node* node) {
case IrOpcode::kJSDivide: case IrOpcode::kJSDivide:
case IrOpcode::kJSModulus: case IrOpcode::kJSModulus:
return ReduceNumberBinop(node); return ReduceNumberBinop(node);
case IrOpcode::kJSBitwiseNot:
return ReduceJSBitwiseNot(node);
case IrOpcode::kJSNegate: case IrOpcode::kJSNegate:
return ReduceJSNegate(node); return ReduceJSNegate(node);
case IrOpcode::kJSHasInPrototypeChain: case IrOpcode::kJSHasInPrototypeChain:
......
...@@ -40,6 +40,7 @@ class V8_EXPORT_PRIVATE JSTypedLowering final ...@@ -40,6 +40,7 @@ class V8_EXPORT_PRIVATE JSTypedLowering final
friend class JSBinopReduction; friend class JSBinopReduction;
Reduction ReduceJSAdd(Node* node); Reduction ReduceJSAdd(Node* node);
Reduction ReduceJSBitwiseNot(Node* node);
Reduction ReduceJSNegate(Node* node); Reduction ReduceJSNegate(Node* node);
Reduction ReduceJSComparison(Node* node); Reduction ReduceJSComparison(Node* node);
Reduction ReduceJSLoadNamed(Node* node); Reduction ReduceJSLoadNamed(Node* node);
......
...@@ -126,6 +126,7 @@ ...@@ -126,6 +126,7 @@
#define JS_SIMPLE_UNOP_LIST(V) \ #define JS_SIMPLE_UNOP_LIST(V) \
JS_CONVERSION_UNOP_LIST(V) \ JS_CONVERSION_UNOP_LIST(V) \
V(JSBitwiseNot) \
V(JSNegate) V(JSNegate)
#define JS_OBJECT_OP_LIST(V) \ #define JS_OBJECT_OP_LIST(V) \
......
...@@ -113,6 +113,7 @@ bool OperatorProperties::HasFrameStateInput(const Operator* op) { ...@@ -113,6 +113,7 @@ bool OperatorProperties::HasFrameStateInput(const Operator* op) {
case IrOpcode::kJSStackCheck: case IrOpcode::kJSStackCheck:
case IrOpcode::kJSDebugger: case IrOpcode::kJSDebugger:
case IrOpcode::kJSGetSuperConstructor: case IrOpcode::kJSGetSuperConstructor:
case IrOpcode::kJSBitwiseNot:
case IrOpcode::kJSNegate: case IrOpcode::kJSNegate:
return true; return true;
......
...@@ -3045,6 +3045,7 @@ class RepresentationSelector { ...@@ -3045,6 +3045,7 @@ class RepresentationSelector {
JS_CONTEXT_OP_LIST(OPCODE_CASE) JS_CONTEXT_OP_LIST(OPCODE_CASE)
JS_OTHER_OP_LIST(OPCODE_CASE) JS_OTHER_OP_LIST(OPCODE_CASE)
#undef OPCODE_CASE #undef OPCODE_CASE
case IrOpcode::kJSBitwiseNot:
case IrOpcode::kJSNegate: case IrOpcode::kJSNegate:
case IrOpcode::kJSToInteger: case IrOpcode::kJSToInteger:
case IrOpcode::kJSToLength: case IrOpcode::kJSToLength:
......
...@@ -264,6 +264,7 @@ class Typer::Visitor : public Reducer { ...@@ -264,6 +264,7 @@ class Typer::Visitor : public Reducer {
static ComparisonOutcome Invert(ComparisonOutcome, Typer*); static ComparisonOutcome Invert(ComparisonOutcome, Typer*);
static Type* FalsifyUndefined(ComparisonOutcome, Typer*); static Type* FalsifyUndefined(ComparisonOutcome, Typer*);
static Type* BitwiseNot(Type*, Typer*);
static Type* Negate(Type*, Typer*); static Type* Negate(Type*, Typer*);
static Type* ToPrimitive(Type*, Typer*); static Type* ToPrimitive(Type*, Typer*);
...@@ -426,6 +427,14 @@ Type* Typer::Visitor::FalsifyUndefined(ComparisonOutcome outcome, Typer* t) { ...@@ -426,6 +427,14 @@ Type* Typer::Visitor::FalsifyUndefined(ComparisonOutcome outcome, Typer* t) {
return t->singleton_true_; return t->singleton_true_;
} }
Type* Typer::Visitor::BitwiseNot(Type* type, Typer* t) {
type = ToNumeric(type, t);
if (type->Is(Type::Number())) {
return NumberBitwiseXor(type, t->cache_.kSingletonMinusOne, t);
}
return Type::Numeric();
}
Type* Typer::Visitor::Negate(Type* type, Typer* t) { Type* Typer::Visitor::Negate(Type* type, Typer* t) {
type = ToNumeric(type, t); type = ToNumeric(type, t);
if (type->Is(Type::Number())) { if (type->Is(Type::Number())) {
...@@ -1079,6 +1088,10 @@ Type* Typer::Visitor::JSModulusTyper(Type* lhs, Type* rhs, Typer* t) { ...@@ -1079,6 +1088,10 @@ Type* Typer::Visitor::JSModulusTyper(Type* lhs, Type* rhs, Typer* t) {
// JS unary operators. // JS unary operators.
Type* Typer::Visitor::TypeJSBitwiseNot(Node* node) {
return TypeUnaryOp(node, BitwiseNot);
}
Type* Typer::Visitor::TypeJSNegate(Node* node) { Type* Typer::Visitor::TypeJSNegate(Node* node) {
return TypeUnaryOp(node, Negate); return TypeUnaryOp(node, Negate);
} }
......
...@@ -612,6 +612,7 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) { ...@@ -612,6 +612,7 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) {
CheckTypeIs(node, Type::Number()); CheckTypeIs(node, Type::Number());
break; break;
case IrOpcode::kJSBitwiseNot:
case IrOpcode::kJSNegate: case IrOpcode::kJSNegate:
// Type is Numeric. // Type is Numeric.
CheckTypeIs(node, Type::Numeric()); CheckTypeIs(node, Type::Numeric());
......
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