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 {
bool is_postfix() const { return !is_prefix(); }
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_; }
void set_expression(Expression* e) { expression_ = e; }
......
......@@ -2071,6 +2071,58 @@ CallFrequency BytecodeGraphBuilder::ComputeCallFrequency(int slot_id) const {
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() {
BuildBinaryOp(
javascript()->Add(GetBinaryOperationHint(kBinaryOperationHintIndex)));
......
......@@ -400,6 +400,7 @@ class BytecodeGraphBuilder {
static int const kBinaryOperationHintIndex = 1;
static int const kCountOperationHintIndex = 0;
static int const kBinaryOperationSmiHintIndex = 1;
static int const kUnaryOperationHintIndex = 0;
DISALLOW_COPY_AND_ASSIGN(BytecodeGraphBuilder);
};
......
......@@ -372,8 +372,10 @@ bool BytecodeHasNoSideEffect(interpreter::Bytecode bytecode) {
case Bytecode::kDivSmi:
case Bytecode::kMod:
case Bytecode::kModSmi:
case Bytecode::kNegate:
case Bytecode::kBitwiseAnd:
case Bytecode::kBitwiseAndSmi:
case Bytecode::kBitwiseNot:
case Bytecode::kBitwiseOr:
case Bytecode::kBitwiseOrSmi:
case Bytecode::kBitwiseXor:
......
......@@ -428,13 +428,26 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::BinaryOperationSmiLiteral(
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::CountOperation(Token::Value op,
BytecodeArrayBuilder& BytecodeArrayBuilder::UnaryOperation(Token::Value op,
int feedback_slot) {
if (op == Token::Value::ADD) {
OutputInc(feedback_slot);
} else {
DCHECK_EQ(op, Token::Value::SUB);
OutputDec(feedback_slot);
switch (op) {
case Token::Value::INC:
OutputInc(feedback_slot);
break;
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;
}
......
......@@ -317,9 +317,9 @@ class V8_EXPORT_PRIVATE BytecodeArrayBuilder final
Smi* literal,
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|
BytecodeArrayBuilder& CountOperation(Token::Value op, int feedback_slot);
BytecodeArrayBuilder& UnaryOperation(Token::Value op, int feedback_slot);
enum class ToBooleanMode {
kConvertToBoolean, // Perform ToBoolean conversion on accumulator.
......
......@@ -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) {
switch (expr->op()) {
case Token::Value::NOT:
......@@ -3459,15 +3444,12 @@ void BytecodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
VisitDelete(expr);
break;
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:
BuildBinaryOperationForUnaryOperation(expr, Token::Value::MUL, -1);
break;
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;
default:
UNREACHABLE();
......@@ -3604,7 +3586,7 @@ void BytecodeGenerator::VisitCountOperation(CountOperation* expr) {
}
// Perform +1/-1 operation.
builder()->CountOperation(expr->binary_op(), feedback_index(count_slot));
builder()->UnaryOperation(expr->op(), feedback_index(count_slot));
// Store the value.
builder()->SetExpressionPosition(expr);
......
......@@ -78,7 +78,6 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
void VisitTypeOf(UnaryOperation* expr);
void VisitNot(UnaryOperation* expr);
void VisitDelete(UnaryOperation* expr);
void VisitPlus(UnaryOperation* expr);
// Visits a typeof expression for the value on which to perform the typeof.
void VisitForTypeOfValue(Expression* expr);
......@@ -195,9 +194,6 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
void BuildTest(ToBooleanMode mode, BytecodeLabels* then_labels,
BytecodeLabels* else_labels, TestFallthrough fallthrough);
void BuildBinaryOperationForUnaryOperation(UnaryOperation* expr,
Token::Value binop, int rhs);
// Visitors for obtaining expression result in the accumulator, in a
// register, or just getting the effect. Some visitors return a TypeHint which
// specifies the type of the result of the visited expression.
......
......@@ -144,6 +144,8 @@ namespace interpreter {
/* Unary Operators */ \
V(Inc, 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(LogicalNot, AccumulatorUse::kReadWrite) \
V(TypeOf, AccumulatorUse::kReadWrite) \
......
......@@ -1130,6 +1130,29 @@ IGNITION_HANDLER(BitwiseAndSmi, InterpreterAssembler) {
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>
//
// Left shifts accumulator by the count specified in <imm>.
......@@ -1214,6 +1237,69 @@ IGNITION_HANDLER(ShiftRightLogicalSmi, InterpreterAssembler) {
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>
//
// Convert the object referenced by the accumulator to a name.
......
......@@ -119,12 +119,12 @@ snippet: "
"
frame size: 1
parameter count: 1
bytecode array length: 9
bytecode array length: 8
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 42 S> */ B(LdaSmi), I8(13),
B(Star), R(0),
/* 53 S> */ B(BitwiseXorSmi), I8(-1), U8(0),
/* 53 S> */ B(BitwiseNot), U8(0),
/* 56 S> */ B(Return),
]
constant pool: [
......@@ -159,12 +159,12 @@ snippet: "
"
frame size: 1
parameter count: 1
bytecode array length: 9
bytecode array length: 8
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 42 S> */ B(LdaSmi), I8(13),
B(Star), R(0),
/* 53 S> */ B(MulSmi), I8(-1), U8(0),
/* 53 S> */ B(Negate), U8(0),
/* 56 S> */ B(Return),
]
constant pool: [
......
......@@ -811,8 +811,8 @@ TEST(InterpreterUnaryOpFeedback) {
Handle<Object> any_feedback_value;
};
TestCase const kTestCases[] = {
{Token::Value::ADD, smi_one, smi_max, number, str},
{Token::Value::SUB, smi_one, smi_min, number, str}};
{Token::Value::INC, smi_one, smi_max, number, str},
{Token::Value::DEC, smi_one, smi_min, number, str}};
for (TestCase const& test_case : kTestCases) {
BytecodeArrayBuilder builder(isolate, zone, 4, 0);
......@@ -826,13 +826,13 @@ TEST(InterpreterUnaryOpFeedback) {
i::NewFeedbackMetadata(isolate, &feedback_spec);
builder.LoadAccumulatorWithRegister(builder.Receiver())
.CountOperation(test_case.op, GetIndex(slot0))
.UnaryOperation(test_case.op, GetIndex(slot0))
.LoadAccumulatorWithRegister(builder.Parameter(0))
.CountOperation(test_case.op, GetIndex(slot1))
.UnaryOperation(test_case.op, GetIndex(slot1))
.LoadAccumulatorWithRegister(builder.Parameter(1))
.CountOperation(test_case.op, GetIndex(slot2))
.UnaryOperation(test_case.op, GetIndex(slot2))
.LoadAccumulatorWithRegister(builder.Parameter(2))
.CountOperation(test_case.op, GetIndex(slot3))
.UnaryOperation(test_case.op, GetIndex(slot3))
.Return();
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
......
......@@ -57,6 +57,8 @@ function listener(event, exec_state, event_data, data) {
success(true, `T||F`);
success(false, `T?F:T`);
success(false, `!T`);
success(1, `+one`);
success(-1, `-one`);
success(-2, `~one`);
success(4, `one << two`);
success(1, `two >> one`);
......
......@@ -190,9 +190,12 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
.BinaryOperationSmiLiteral(Token::Value::SAR, Smi::FromInt(42), 2)
.BinaryOperationSmiLiteral(Token::Value::SHR, Smi::FromInt(42), 2);
// Emit count operatior invocations
builder.CountOperation(Token::Value::ADD, 1)
.CountOperation(Token::Value::SUB, 1);
// Emit unary and count operator invocations.
builder.UnaryOperation(Token::Value::INC, 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.
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