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 {
TFC(Equal, Compare, 1) \
TFC(SameValue, Compare, 1) \
TFC(StrictEqual, Compare, 1) \
TFS(BitwiseNot, kValue) \
TFS(Negate, kValue) \
\
/* Object */ \
......
......@@ -602,7 +602,8 @@ void NumberBuiltinsAssembler::UnaryOp(Variable* var_input, Label* do_smi,
Variable* var_input_double,
Label* do_bigint) {
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);
var_input->Bind(Parameter(Descriptor::kValue));
......@@ -616,7 +617,9 @@ void NumberBuiltinsAssembler::UnaryOp(Variable* var_input, Label* do_smi,
Label not_number(this);
GotoIf(TaggedIsSmi(input), do_smi);
GotoIfNot(IsHeapNumber(input), &not_number);
var_input_double->Bind(LoadHeapNumberValue(input));
if (var_input_double != nullptr) {
var_input_double->Bind(LoadHeapNumberValue(input));
}
Goto(do_double);
BIND(&not_number);
......@@ -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) {
VARIABLE(var_input, MachineRepresentation::kTagged);
VARIABLE(var_input_double, MachineRepresentation::kFloat64);
......
......@@ -2083,12 +2083,13 @@ CallFrequency BytecodeGraphBuilder::ComputeCallFrequency(int slot_id) const {
invocation_frequency_.value());
}
void BytecodeGraphBuilder::VisitNegate() {
void BytecodeGraphBuilder::VisitBitwiseNot() {
// TODO(neis): Define a BuildUnaryOp helper function.
PrepareEagerCheckpoint();
FeedbackSlot slot = feedback_vector()->ToSlot(
bytecode_iterator().GetIndexOperand(kUnaryOperationHintIndex));
const Operator* op = javascript()->Negate();
const Operator* op = javascript()->BitwiseNot();
Node* operand = environment()->LookupAccumulator();
JSTypeHintLowering::LoweringResult lowering =
......@@ -2105,27 +2106,23 @@ void BytecodeGraphBuilder::VisitNegate() {
environment()->BindAccumulator(node, Environment::kAttachFrameState);
}
void BytecodeGraphBuilder::VisitBitwiseNot() {
void BytecodeGraphBuilder::VisitNegate() {
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(
bytecode_iterator().GetIndexOperand(kUnaryOperationHintIndex));
const Operator* op = javascript()->Negate();
Node* operand = environment()->LookupAccumulator();
JSTypeHintLowering::LoweringResult lowering =
TryBuildSimplifiedBinaryOp(op, operand, xor_value, slot);
TryBuildSimplifiedUnaryOp(op, operand, slot);
if (lowering.IsExit()) return;
Node* node = nullptr;
if (lowering.IsSideEffectFree()) {
node = lowering.value();
} else {
DCHECK(!lowering.Changed());
node = NewNode(op, operand, xor_value);
node = NewNode(op, operand);
}
environment()->BindAccumulator(node, Environment::kAttachFrameState);
......
......@@ -70,6 +70,7 @@ REPLACE_STUB_CALL(LessThan)
REPLACE_STUB_CALL(LessThanOrEqual)
REPLACE_STUB_CALL(GreaterThan)
REPLACE_STUB_CALL(GreaterThanOrEqual)
REPLACE_STUB_CALL(BitwiseNot)
REPLACE_STUB_CALL(Negate)
REPLACE_STUB_CALL(HasProperty)
REPLACE_STUB_CALL(Equal)
......
......@@ -577,6 +577,7 @@ CompareOperationHint CompareOperationHintOf(const Operator* op) {
V(Multiply, Operator::kNoProperties, 2, 1) \
V(Divide, Operator::kNoProperties, 2, 1) \
V(Modulus, Operator::kNoProperties, 2, 1) \
V(BitwiseNot, Operator::kNoProperties, 1, 1) \
V(Negate, Operator::kNoProperties, 1, 1) \
V(ToInteger, Operator::kNoProperties, 1, 1) \
V(ToLength, Operator::kNoProperties, 1, 1) \
......
......@@ -652,6 +652,7 @@ class V8_EXPORT_PRIVATE JSOperatorBuilder final
const Operator* Divide();
const Operator* Modulus();
const Operator* BitwiseNot();
const Operator* Negate();
const Operator* ToInteger();
......
......@@ -215,30 +215,44 @@ JSTypeHintLowering::JSTypeHintLowering(JSGraph* jsgraph,
JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceUnaryOperation(
const Operator* op, Node* operand, Node* effect, Node* control,
FeedbackSlot slot) const {
DCHECK(!slot.IsInvalid());
BinaryOpICNexus nexus(feedback_vector(), slot);
if (Node* node = TryBuildSoftDeopt(
nexus, effect, control,
DeoptimizeReason::kInsufficientTypeFeedbackForUnaryOperation)) {
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: {
DCHECK(!slot.IsInvalid());
BinaryOpICNexus nexus(feedback_vector(), slot);
if (Node* node = TryBuildSoftDeopt(
nexus, effect, control,
DeoptimizeReason::kInsufficientTypeFeedbackForUnaryOperation)) {
return LoweringResult::Exit(node);
}
// Lower to a speculative multiplication with -1 if we have some kind of
// Number feedback.
JSSpeculativeBinopBuilder b(this, jsgraph()->javascript()->Multiply(),
operand, jsgraph()->SmiConstant(-1), effect,
control, slot);
if (Node* node = b.TryBuildNumberBinop()) {
return LoweringResult::SideEffectFree(node, node, control);
}
node = b.TryBuildNumberBinop();
break;
}
default:
UNREACHABLE();
break;
}
return LoweringResult::NoChange();
if (node != nullptr) {
return LoweringResult::SideEffectFree(node, node, control);
} else {
return LoweringResult::NoChange();
}
}
JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceBinaryOperation(
......
......@@ -426,6 +426,21 @@ Reduction JSTypedLowering::ReduceSpeculativeNumberAdd(Node* node) {
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) {
Node* input = NodeProperties::GetValueInput(node, 0);
Type* input_type = NodeProperties::GetType(input);
......@@ -2078,6 +2093,8 @@ Reduction JSTypedLowering::Reduce(Node* node) {
case IrOpcode::kJSDivide:
case IrOpcode::kJSModulus:
return ReduceNumberBinop(node);
case IrOpcode::kJSBitwiseNot:
return ReduceJSBitwiseNot(node);
case IrOpcode::kJSNegate:
return ReduceJSNegate(node);
case IrOpcode::kJSHasInPrototypeChain:
......
......@@ -40,6 +40,7 @@ class V8_EXPORT_PRIVATE JSTypedLowering final
friend class JSBinopReduction;
Reduction ReduceJSAdd(Node* node);
Reduction ReduceJSBitwiseNot(Node* node);
Reduction ReduceJSNegate(Node* node);
Reduction ReduceJSComparison(Node* node);
Reduction ReduceJSLoadNamed(Node* node);
......
......@@ -126,6 +126,7 @@
#define JS_SIMPLE_UNOP_LIST(V) \
JS_CONVERSION_UNOP_LIST(V) \
V(JSBitwiseNot) \
V(JSNegate)
#define JS_OBJECT_OP_LIST(V) \
......
......@@ -113,6 +113,7 @@ bool OperatorProperties::HasFrameStateInput(const Operator* op) {
case IrOpcode::kJSStackCheck:
case IrOpcode::kJSDebugger:
case IrOpcode::kJSGetSuperConstructor:
case IrOpcode::kJSBitwiseNot:
case IrOpcode::kJSNegate:
return true;
......
......@@ -3045,6 +3045,7 @@ class RepresentationSelector {
JS_CONTEXT_OP_LIST(OPCODE_CASE)
JS_OTHER_OP_LIST(OPCODE_CASE)
#undef OPCODE_CASE
case IrOpcode::kJSBitwiseNot:
case IrOpcode::kJSNegate:
case IrOpcode::kJSToInteger:
case IrOpcode::kJSToLength:
......
......@@ -264,6 +264,7 @@ class Typer::Visitor : public Reducer {
static ComparisonOutcome Invert(ComparisonOutcome, Typer*);
static Type* FalsifyUndefined(ComparisonOutcome, Typer*);
static Type* BitwiseNot(Type*, Typer*);
static Type* Negate(Type*, Typer*);
static Type* ToPrimitive(Type*, Typer*);
......@@ -426,6 +427,14 @@ Type* Typer::Visitor::FalsifyUndefined(ComparisonOutcome outcome, Typer* t) {
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 = ToNumeric(type, t);
if (type->Is(Type::Number())) {
......@@ -1079,6 +1088,10 @@ Type* Typer::Visitor::JSModulusTyper(Type* lhs, Type* rhs, Typer* t) {
// JS unary operators.
Type* Typer::Visitor::TypeJSBitwiseNot(Node* node) {
return TypeUnaryOp(node, BitwiseNot);
}
Type* Typer::Visitor::TypeJSNegate(Node* node) {
return TypeUnaryOp(node, Negate);
}
......
......@@ -612,6 +612,7 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) {
CheckTypeIs(node, Type::Number());
break;
case IrOpcode::kJSBitwiseNot:
case IrOpcode::kJSNegate:
// Type is 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