Commit c9efff3f authored by Adam Klein's avatar Adam Klein Committed by Commit Bot

[bigint] Add bytecodes for unary-minus and bitwise-not

This continues to move the "desugaring" of unary operators further
down the pipeline, in this case into the bytecode handlers for new
bytecodes `Negate` and `BitwiseNot` and the corresponding TF code
in BytecodeGraphBuilder.

Bug: v8:6971
Tbr: yangguo@chromium.org
Change-Id: If6b5d6b239a09ef8b4dbde49321614503c0f5beb
Reviewed-on: https://chromium-review.googlesource.com/661146
Commit-Queue: Adam Klein <adamk@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Reviewed-by: 's avatarRoss McIlroy <rmcilroy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#47980}
parent 59f5e12e
...@@ -1866,9 +1866,6 @@ class CountOperation final : public Expression { ...@@ -1866,9 +1866,6 @@ class CountOperation final : public Expression {
bool is_postfix() const { return !is_prefix(); } bool is_postfix() const { return !is_prefix(); }
Token::Value op() const { return TokenField::decode(bit_field_); } Token::Value op() const { return TokenField::decode(bit_field_); }
Token::Value binary_op() {
return (op() == Token::INC) ? Token::ADD : Token::SUB;
}
Expression* expression() const { return expression_; } Expression* expression() const { return expression_; }
void set_expression(Expression* e) { expression_ = e; } void set_expression(Expression* e) { expression_ = e; }
......
...@@ -2071,6 +2071,58 @@ CallFrequency BytecodeGraphBuilder::ComputeCallFrequency(int slot_id) const { ...@@ -2071,6 +2071,58 @@ CallFrequency BytecodeGraphBuilder::ComputeCallFrequency(int slot_id) const {
invocation_frequency_.value()); invocation_frequency_.value());
} }
void BytecodeGraphBuilder::VisitNegate() {
PrepareEagerCheckpoint();
// TODO(adamk): Create a JSNegate operator, as this desugaring is
// invalid for BigInts.
const Operator* op = javascript()->Multiply();
Node* operand = environment()->LookupAccumulator();
Node* multiplier = jsgraph()->SmiConstant(-1);
FeedbackSlot slot = feedback_vector()->ToSlot(
bytecode_iterator().GetIndexOperand(kUnaryOperationHintIndex));
JSTypeHintLowering::LoweringResult lowering =
TryBuildSimplifiedBinaryOp(op, operand, multiplier, slot);
if (lowering.IsExit()) return;
Node* node = nullptr;
if (lowering.IsSideEffectFree()) {
node = lowering.value();
} else {
DCHECK(!lowering.Changed());
node = NewNode(op, operand, multiplier);
}
environment()->BindAccumulator(node, Environment::kAttachFrameState);
}
void BytecodeGraphBuilder::VisitBitwiseNot() {
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));
JSTypeHintLowering::LoweringResult lowering =
TryBuildSimplifiedBinaryOp(op, operand, xor_value, slot);
if (lowering.IsExit()) return;
Node* node = nullptr;
if (lowering.IsSideEffectFree()) {
node = lowering.value();
} else {
DCHECK(!lowering.Changed());
node = NewNode(op, operand, xor_value);
}
environment()->BindAccumulator(node, Environment::kAttachFrameState);
}
void BytecodeGraphBuilder::VisitAdd() { void BytecodeGraphBuilder::VisitAdd() {
BuildBinaryOp( BuildBinaryOp(
javascript()->Add(GetBinaryOperationHint(kBinaryOperationHintIndex))); javascript()->Add(GetBinaryOperationHint(kBinaryOperationHintIndex)));
......
...@@ -400,6 +400,7 @@ class BytecodeGraphBuilder { ...@@ -400,6 +400,7 @@ class BytecodeGraphBuilder {
static int const kBinaryOperationHintIndex = 1; static int const kBinaryOperationHintIndex = 1;
static int const kCountOperationHintIndex = 0; static int const kCountOperationHintIndex = 0;
static int const kBinaryOperationSmiHintIndex = 1; static int const kBinaryOperationSmiHintIndex = 1;
static int const kUnaryOperationHintIndex = 0;
DISALLOW_COPY_AND_ASSIGN(BytecodeGraphBuilder); DISALLOW_COPY_AND_ASSIGN(BytecodeGraphBuilder);
}; };
......
...@@ -372,8 +372,10 @@ bool BytecodeHasNoSideEffect(interpreter::Bytecode bytecode) { ...@@ -372,8 +372,10 @@ bool BytecodeHasNoSideEffect(interpreter::Bytecode bytecode) {
case Bytecode::kDivSmi: case Bytecode::kDivSmi:
case Bytecode::kMod: case Bytecode::kMod:
case Bytecode::kModSmi: case Bytecode::kModSmi:
case Bytecode::kNegate:
case Bytecode::kBitwiseAnd: case Bytecode::kBitwiseAnd:
case Bytecode::kBitwiseAndSmi: case Bytecode::kBitwiseAndSmi:
case Bytecode::kBitwiseNot:
case Bytecode::kBitwiseOr: case Bytecode::kBitwiseOr:
case Bytecode::kBitwiseOrSmi: case Bytecode::kBitwiseOrSmi:
case Bytecode::kBitwiseXor: case Bytecode::kBitwiseXor:
......
...@@ -428,13 +428,26 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::BinaryOperationSmiLiteral( ...@@ -428,13 +428,26 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::BinaryOperationSmiLiteral(
return *this; return *this;
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::CountOperation(Token::Value op, BytecodeArrayBuilder& BytecodeArrayBuilder::UnaryOperation(Token::Value op,
int feedback_slot) { int feedback_slot) {
if (op == Token::Value::ADD) { switch (op) {
OutputInc(feedback_slot); case Token::Value::INC:
} else { OutputInc(feedback_slot);
DCHECK_EQ(op, Token::Value::SUB); break;
OutputDec(feedback_slot); case Token::Value::DEC:
OutputDec(feedback_slot);
break;
case Token::Value::ADD:
OutputToNumber(feedback_slot);
break;
case Token::Value::SUB:
OutputNegate(feedback_slot);
break;
case Token::Value::BIT_NOT:
OutputBitwiseNot(feedback_slot);
break;
default:
UNREACHABLE();
} }
return *this; return *this;
} }
......
...@@ -317,9 +317,9 @@ class V8_EXPORT_PRIVATE BytecodeArrayBuilder final ...@@ -317,9 +317,9 @@ class V8_EXPORT_PRIVATE BytecodeArrayBuilder final
Smi* literal, Smi* literal,
int feedback_slot); int feedback_slot);
// Count Operators (value stored in accumulator). // Unary and Count Operators (value stored in accumulator).
// Type feedback will be recorded in the |feedback_slot| // Type feedback will be recorded in the |feedback_slot|
BytecodeArrayBuilder& CountOperation(Token::Value op, int feedback_slot); BytecodeArrayBuilder& UnaryOperation(Token::Value op, int feedback_slot);
enum class ToBooleanMode { enum class ToBooleanMode {
kConvertToBoolean, // Perform ToBoolean conversion on accumulator. kConvertToBoolean, // Perform ToBoolean conversion on accumulator.
......
...@@ -3429,21 +3429,6 @@ void BytecodeGenerator::VisitNot(UnaryOperation* expr) { ...@@ -3429,21 +3429,6 @@ void BytecodeGenerator::VisitNot(UnaryOperation* expr) {
} }
} }
void BytecodeGenerator::VisitPlus(UnaryOperation* expr) {
VisitForAccumulatorValue(expr->expression());
builder()->SetExpressionPosition(expr);
builder()->ToNumber(feedback_index(expr->UnaryOperationFeedbackSlot()));
}
void BytecodeGenerator::BuildBinaryOperationForUnaryOperation(
UnaryOperation* expr, Token::Value binop, int rhs) {
VisitForAccumulatorValue(expr->expression());
builder()->SetExpressionPosition(expr);
builder()->BinaryOperationSmiLiteral(
binop, Smi::FromInt(rhs),
feedback_index(expr->UnaryOperationFeedbackSlot()));
}
void BytecodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { void BytecodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
switch (expr->op()) { switch (expr->op()) {
case Token::Value::NOT: case Token::Value::NOT:
...@@ -3459,15 +3444,12 @@ void BytecodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { ...@@ -3459,15 +3444,12 @@ void BytecodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
VisitDelete(expr); VisitDelete(expr);
break; break;
case Token::Value::ADD: case Token::Value::ADD:
VisitPlus(expr);
break;
// TODO(adamk): Output specific bytecodes for SUB and BIT_NOT
// instead of transforming them to binary operations.
case Token::Value::SUB: case Token::Value::SUB:
BuildBinaryOperationForUnaryOperation(expr, Token::Value::MUL, -1);
break;
case Token::Value::BIT_NOT: case Token::Value::BIT_NOT:
BuildBinaryOperationForUnaryOperation(expr, Token::Value::BIT_XOR, -1); VisitForAccumulatorValue(expr->expression());
builder()->SetExpressionPosition(expr);
builder()->UnaryOperation(
expr->op(), feedback_index(expr->UnaryOperationFeedbackSlot()));
break; break;
default: default:
UNREACHABLE(); UNREACHABLE();
...@@ -3604,7 +3586,7 @@ void BytecodeGenerator::VisitCountOperation(CountOperation* expr) { ...@@ -3604,7 +3586,7 @@ void BytecodeGenerator::VisitCountOperation(CountOperation* expr) {
} }
// Perform +1/-1 operation. // Perform +1/-1 operation.
builder()->CountOperation(expr->binary_op(), feedback_index(count_slot)); builder()->UnaryOperation(expr->op(), feedback_index(count_slot));
// Store the value. // Store the value.
builder()->SetExpressionPosition(expr); builder()->SetExpressionPosition(expr);
......
...@@ -78,7 +78,6 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> { ...@@ -78,7 +78,6 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
void VisitTypeOf(UnaryOperation* expr); void VisitTypeOf(UnaryOperation* expr);
void VisitNot(UnaryOperation* expr); void VisitNot(UnaryOperation* expr);
void VisitDelete(UnaryOperation* expr); void VisitDelete(UnaryOperation* expr);
void VisitPlus(UnaryOperation* expr);
// Visits a typeof expression for the value on which to perform the typeof. // Visits a typeof expression for the value on which to perform the typeof.
void VisitForTypeOfValue(Expression* expr); void VisitForTypeOfValue(Expression* expr);
...@@ -195,9 +194,6 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> { ...@@ -195,9 +194,6 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
void BuildTest(ToBooleanMode mode, BytecodeLabels* then_labels, void BuildTest(ToBooleanMode mode, BytecodeLabels* then_labels,
BytecodeLabels* else_labels, TestFallthrough fallthrough); BytecodeLabels* else_labels, TestFallthrough fallthrough);
void BuildBinaryOperationForUnaryOperation(UnaryOperation* expr,
Token::Value binop, int rhs);
// Visitors for obtaining expression result in the accumulator, in a // Visitors for obtaining expression result in the accumulator, in a
// register, or just getting the effect. Some visitors return a TypeHint which // register, or just getting the effect. Some visitors return a TypeHint which
// specifies the type of the result of the visited expression. // specifies the type of the result of the visited expression.
......
...@@ -144,6 +144,8 @@ namespace interpreter { ...@@ -144,6 +144,8 @@ namespace interpreter {
/* Unary Operators */ \ /* Unary Operators */ \
V(Inc, AccumulatorUse::kReadWrite, OperandType::kIdx) \ V(Inc, AccumulatorUse::kReadWrite, OperandType::kIdx) \
V(Dec, AccumulatorUse::kReadWrite, OperandType::kIdx) \ V(Dec, AccumulatorUse::kReadWrite, OperandType::kIdx) \
V(Negate, AccumulatorUse::kReadWrite, OperandType::kIdx) \
V(BitwiseNot, AccumulatorUse::kReadWrite, OperandType::kIdx) \
V(ToBooleanLogicalNot, AccumulatorUse::kReadWrite) \ V(ToBooleanLogicalNot, AccumulatorUse::kReadWrite) \
V(LogicalNot, AccumulatorUse::kReadWrite) \ V(LogicalNot, AccumulatorUse::kReadWrite) \
V(TypeOf, AccumulatorUse::kReadWrite) \ V(TypeOf, AccumulatorUse::kReadWrite) \
......
...@@ -1130,6 +1130,29 @@ IGNITION_HANDLER(BitwiseAndSmi, InterpreterAssembler) { ...@@ -1130,6 +1130,29 @@ IGNITION_HANDLER(BitwiseAndSmi, InterpreterAssembler) {
Dispatch(); Dispatch();
} }
// BitwiseNot <feedback_slot>
//
// Perform bitwise-not on the accumulator.
IGNITION_HANDLER(BitwiseNot, InterpreterAssembler) {
Node* operand = GetAccumulator();
Node* slot_index = BytecodeOperandIdx(0);
Node* feedback_vector = LoadFeedbackVector();
Node* context = GetContext();
Variable var_type_feedback(this, MachineRepresentation::kTaggedSigned);
Node* truncated_value =
TruncateTaggedToWord32WithFeedback(context, operand, &var_type_feedback);
Node* value = Word32Not(truncated_value);
Node* result = ChangeInt32ToTagged(value);
Node* result_type = SelectSmiConstant(TaggedIsSmi(result),
BinaryOperationFeedback::kSignedSmall,
BinaryOperationFeedback::kNumber);
UpdateFeedback(SmiOr(result_type, var_type_feedback.value()), feedback_vector,
slot_index);
SetAccumulator(result);
Dispatch();
}
// ShiftLeftSmi <imm> // ShiftLeftSmi <imm>
// //
// Left shifts accumulator by the count specified in <imm>. // Left shifts accumulator by the count specified in <imm>.
...@@ -1214,6 +1237,69 @@ IGNITION_HANDLER(ShiftRightLogicalSmi, InterpreterAssembler) { ...@@ -1214,6 +1237,69 @@ IGNITION_HANDLER(ShiftRightLogicalSmi, InterpreterAssembler) {
Dispatch(); Dispatch();
} }
// Negate <feedback_slot>
//
// Perform arithmetic negation on the accumulator.
IGNITION_HANDLER(Negate, InterpreterAssembler) {
Node* operand = GetAccumulator();
Label end(this);
VARIABLE(var_type_feedback, MachineRepresentation::kTaggedSigned);
VARIABLE(var_result, MachineRepresentation::kTagged);
Label if_smi(this), if_heapnumber(this), if_notnumber(this, Label::kDeferred);
GotoIf(TaggedIsSmi(operand), &if_smi);
Branch(IsHeapNumber(operand), &if_heapnumber, &if_notnumber);
BIND(&if_smi);
{
// TODO(adamk): Use something more efficient than multiplication for this
// operation, being careful to maintain float behavior regarding -0.
Node* result = SmiMul(operand, SmiConstant(-1));
var_type_feedback.Bind(SelectSmiConstant(
TaggedIsSmi(result), BinaryOperationFeedback::kSignedSmall,
BinaryOperationFeedback::kNumber));
var_result.Bind(result);
Goto(&end);
}
BIND(&if_heapnumber);
{
// TODO(adamk): Use something more efficient than multiplication for this
// operation, being careful to maintain float behavior regarding -0.
Node* result =
Float64Mul(LoadHeapNumberValue(operand), Float64Constant(-1.0));
var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kNumber));
var_result.Bind(AllocateHeapNumberWithValue(result));
Goto(&end);
}
BIND(&if_notnumber);
{
Node* instance_type = LoadInstanceType(operand);
Node* is_oddball = Word32Equal(instance_type, Int32Constant(ODDBALL_TYPE));
var_type_feedback.Bind(
SelectSmiConstant(is_oddball, BinaryOperationFeedback::kNumberOrOddball,
BinaryOperationFeedback::kAny));
Node* context = GetContext();
Node* result =
CallBuiltin(Builtins::kMultiply, context, operand, SmiConstant(-1));
var_result.Bind(result);
Goto(&end);
}
BIND(&end);
Node* slot_index = BytecodeOperandIdx(0);
Node* feedback_vector = LoadFeedbackVector();
UpdateFeedback(var_type_feedback.value(), feedback_vector, slot_index);
SetAccumulator(var_result.value());
Dispatch();
}
// ToName <dst> // ToName <dst>
// //
// Convert the object referenced by the accumulator to a name. // Convert the object referenced by the accumulator to a name.
......
...@@ -119,12 +119,12 @@ snippet: " ...@@ -119,12 +119,12 @@ snippet: "
" "
frame size: 1 frame size: 1
parameter count: 1 parameter count: 1
bytecode array length: 9 bytecode array length: 8
bytecodes: [ bytecodes: [
/* 30 E> */ B(StackCheck), /* 30 E> */ B(StackCheck),
/* 42 S> */ B(LdaSmi), I8(13), /* 42 S> */ B(LdaSmi), I8(13),
B(Star), R(0), B(Star), R(0),
/* 53 S> */ B(BitwiseXorSmi), I8(-1), U8(0), /* 53 S> */ B(BitwiseNot), U8(0),
/* 56 S> */ B(Return), /* 56 S> */ B(Return),
] ]
constant pool: [ constant pool: [
...@@ -159,12 +159,12 @@ snippet: " ...@@ -159,12 +159,12 @@ snippet: "
" "
frame size: 1 frame size: 1
parameter count: 1 parameter count: 1
bytecode array length: 9 bytecode array length: 8
bytecodes: [ bytecodes: [
/* 30 E> */ B(StackCheck), /* 30 E> */ B(StackCheck),
/* 42 S> */ B(LdaSmi), I8(13), /* 42 S> */ B(LdaSmi), I8(13),
B(Star), R(0), B(Star), R(0),
/* 53 S> */ B(MulSmi), I8(-1), U8(0), /* 53 S> */ B(Negate), U8(0),
/* 56 S> */ B(Return), /* 56 S> */ B(Return),
] ]
constant pool: [ constant pool: [
......
...@@ -811,8 +811,8 @@ TEST(InterpreterUnaryOpFeedback) { ...@@ -811,8 +811,8 @@ TEST(InterpreterUnaryOpFeedback) {
Handle<Object> any_feedback_value; Handle<Object> any_feedback_value;
}; };
TestCase const kTestCases[] = { TestCase const kTestCases[] = {
{Token::Value::ADD, smi_one, smi_max, number, str}, {Token::Value::INC, smi_one, smi_max, number, str},
{Token::Value::SUB, smi_one, smi_min, number, str}}; {Token::Value::DEC, smi_one, smi_min, number, str}};
for (TestCase const& test_case : kTestCases) { for (TestCase const& test_case : kTestCases) {
BytecodeArrayBuilder builder(isolate, zone, 4, 0); BytecodeArrayBuilder builder(isolate, zone, 4, 0);
...@@ -826,13 +826,13 @@ TEST(InterpreterUnaryOpFeedback) { ...@@ -826,13 +826,13 @@ TEST(InterpreterUnaryOpFeedback) {
i::NewFeedbackMetadata(isolate, &feedback_spec); i::NewFeedbackMetadata(isolate, &feedback_spec);
builder.LoadAccumulatorWithRegister(builder.Receiver()) builder.LoadAccumulatorWithRegister(builder.Receiver())
.CountOperation(test_case.op, GetIndex(slot0)) .UnaryOperation(test_case.op, GetIndex(slot0))
.LoadAccumulatorWithRegister(builder.Parameter(0)) .LoadAccumulatorWithRegister(builder.Parameter(0))
.CountOperation(test_case.op, GetIndex(slot1)) .UnaryOperation(test_case.op, GetIndex(slot1))
.LoadAccumulatorWithRegister(builder.Parameter(1)) .LoadAccumulatorWithRegister(builder.Parameter(1))
.CountOperation(test_case.op, GetIndex(slot2)) .UnaryOperation(test_case.op, GetIndex(slot2))
.LoadAccumulatorWithRegister(builder.Parameter(2)) .LoadAccumulatorWithRegister(builder.Parameter(2))
.CountOperation(test_case.op, GetIndex(slot3)) .UnaryOperation(test_case.op, GetIndex(slot3))
.Return(); .Return();
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate); Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
......
...@@ -57,6 +57,8 @@ function listener(event, exec_state, event_data, data) { ...@@ -57,6 +57,8 @@ function listener(event, exec_state, event_data, data) {
success(true, `T||F`); success(true, `T||F`);
success(false, `T?F:T`); success(false, `T?F:T`);
success(false, `!T`); success(false, `!T`);
success(1, `+one`);
success(-1, `-one`);
success(-2, `~one`); success(-2, `~one`);
success(4, `one << two`); success(4, `one << two`);
success(1, `two >> one`); success(1, `two >> one`);
......
...@@ -190,9 +190,12 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { ...@@ -190,9 +190,12 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
.BinaryOperationSmiLiteral(Token::Value::SAR, Smi::FromInt(42), 2) .BinaryOperationSmiLiteral(Token::Value::SAR, Smi::FromInt(42), 2)
.BinaryOperationSmiLiteral(Token::Value::SHR, Smi::FromInt(42), 2); .BinaryOperationSmiLiteral(Token::Value::SHR, Smi::FromInt(42), 2);
// Emit count operatior invocations // Emit unary and count operator invocations.
builder.CountOperation(Token::Value::ADD, 1) builder.UnaryOperation(Token::Value::INC, 1)
.CountOperation(Token::Value::SUB, 1); .UnaryOperation(Token::Value::DEC, 1)
.UnaryOperation(Token::Value::ADD, 1)
.UnaryOperation(Token::Value::SUB, 1)
.UnaryOperation(Token::Value::BIT_NOT, 1);
// Emit unary operator invocations. // Emit unary operator invocations.
builder.LogicalNot(ToBooleanMode::kConvertToBoolean) builder.LogicalNot(ToBooleanMode::kConvertToBoolean)
......
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