Commit aacc18f0 authored by mythria's avatar mythria Committed by Commit bot

[Interpreter] Adds shift operators to interpreter

Adds support for following operators
 -Shift left
 -Shift right
 -Shift right logical

Adds the above bytecodes, support to BytecodeGenerator and BytecodeArrayBuilder
to enable it's use, it's implementation and tests.

BUG=v8:4280
LOG=N

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

Cr-Commit-Position: refs/heads/master@{#31205}
parent 2d4aeaad
......@@ -374,6 +374,24 @@ void BytecodeGraphBuilder::VisitMod(
}
void BytecodeGraphBuilder::VisitShiftLeft(
const interpreter::BytecodeArrayIterator& iterator) {
BuildBinaryOp(javascript()->ShiftLeft(language_mode()), iterator);
}
void BytecodeGraphBuilder::VisitShiftRight(
const interpreter::BytecodeArrayIterator& iterator) {
BuildBinaryOp(javascript()->ShiftRight(language_mode()), iterator);
}
void BytecodeGraphBuilder::VisitShiftRightLogical(
const interpreter::BytecodeArrayIterator& iterator) {
BuildBinaryOp(javascript()->ShiftRightLogical(language_mode()), iterator);
}
void BytecodeGraphBuilder::VisitLogicalNot(
const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED();
......
......@@ -604,6 +604,12 @@ Bytecode BytecodeArrayBuilder::BytecodeForBinaryOperation(Token::Value op) {
return Bytecode::kDiv;
case Token::Value::MOD:
return Bytecode::kMod;
case Token::Value::SHL:
return Bytecode::kShiftLeft;
case Token::Value::SAR:
return Bytecode::kShiftRight;
case Token::Value::SHR:
return Bytecode::kShiftRightLogical;
default:
UNREACHABLE();
return static_cast<Bytecode>(-1);
......
......@@ -74,6 +74,9 @@ namespace interpreter {
V(Mul, OperandType::kReg8) \
V(Div, OperandType::kReg8) \
V(Mod, OperandType::kReg8) \
V(ShiftLeft, OperandType::kReg8) \
V(ShiftRight, OperandType::kReg8) \
V(ShiftRightLogical, OperandType::kReg8) \
\
/* Unary Operators */ \
V(LogicalNot, OperandType::kNone) \
......
......@@ -400,6 +400,40 @@ void Interpreter::DoMod(compiler::InterpreterAssembler* assembler) {
}
// ShiftLeft <src>
//
// Left shifts register <src> by the count specified in the accumulator.
// Register <src> is converted to an int32 and the accumulator to uint32
// before the operation. 5 lsb bits from the accumulator are used as count
// i.e. <src> << (accumulator & 0x1F).
void Interpreter::DoShiftLeft(compiler::InterpreterAssembler* assembler) {
DoBinaryOp(Runtime::kShiftLeft, assembler);
}
// ShiftRight <src>
//
// Right shifts register <src> by the count specified in the accumulator.
// Result is sign extended. Register <src> is converted to an int32 and the
// accumulator to uint32 before the operation. 5 lsb bits from the accumulator
// are used as count i.e. <src> >> (accumulator & 0x1F).
void Interpreter::DoShiftRight(compiler::InterpreterAssembler* assembler) {
DoBinaryOp(Runtime::kShiftRight, assembler);
}
// ShiftRightLogical <src>
//
// Right Shifts register <src> by the count specified in the accumulator.
// Result is zero-filled. The accumulator and register <src> are converted to
// uint32 before the operation 5 lsb bits from the accumulator are used as
// count i.e. <src> << (accumulator & 0x1F).
void Interpreter::DoShiftRightLogical(
compiler::InterpreterAssembler* assembler) {
DoBinaryOp(Runtime::kShiftRightLogical, assembler);
}
// LogicalNot
//
// Perform logical-not on the accumulator, first casting the
......
......@@ -236,8 +236,7 @@ TEST(PrimitiveExpressions) {
B(Ldar), R(0), //
B(Return) //
},
0
},
0},
{"var x = 0; return x + 3;",
2 * kPointerSize,
1,
......@@ -251,8 +250,49 @@ TEST(PrimitiveExpressions) {
B(Add), R(1), //
B(Return) //
},
0
}};
0},
{"var x = 10; return x << 3;",
2 * kPointerSize,
1,
13,
{
B(LdaSmi8), U8(10), //
B(Star), R(0), //
B(Ldar), R(0), // Easy to spot r1 not really needed here.
B(Star), R(1), // Dead store.
B(LdaSmi8), U8(3), //
B(ShiftLeft), R(1), //
B(Return) //
},
0},
{"var x = 10; return x >> 3;",
2 * kPointerSize,
1,
13,
{
B(LdaSmi8), U8(10), //
B(Star), R(0), //
B(Ldar), R(0), // Easy to spot r1 not really needed here.
B(Star), R(1), // Dead store.
B(LdaSmi8), U8(3), //
B(ShiftRight), R(1), //
B(Return) //
},
0},
{"var x = 10; return x >>> 3;",
2 * kPointerSize,
1,
13,
{
B(LdaSmi8), U8(10), //
B(Star), R(0), //
B(Ldar), R(0), // Easy to spot r1 not really needed here.
B(Star), R(1), // Dead store.
B(LdaSmi8), U8(3), //
B(ShiftRightLogical), R(1), //
B(Return) //
},
0}};
for (size_t i = 0; i < arraysize(snippets); i++) {
Handle<BytecodeArray> bytecode_array =
......
......@@ -352,8 +352,12 @@ TEST(InterpreterLoadStoreRegisters) {
static const Token::Value kArithmeticOperators[] = {
Token::Value::ADD, Token::Value::SUB, Token::Value::MUL, Token::Value::DIV,
Token::Value::MOD};
Token::Value::SHL, Token::Value::SAR, Token::Value::SHR, Token::Value::ADD,
Token::Value::SUB, Token::Value::MUL, Token::Value::DIV, Token::Value::MOD};
static const Token::Value kShiftOperators[] = {
Token::Value::SHL, Token::Value::SAR, Token::Value::SHR};
static double BinaryOpC(Token::Value op, double lhs, double rhs) {
......@@ -368,6 +372,24 @@ static double BinaryOpC(Token::Value op, double lhs, double rhs) {
return lhs / rhs;
case Token::Value::MOD:
return std::fmod(lhs, rhs);
case Token::Value::SHL: {
int32_t val = v8::internal::DoubleToInt32(lhs);
uint32_t count = v8::internal::DoubleToUint32(rhs) & 0x1F;
int32_t result = val << count;
return result;
}
case Token::Value::SAR: {
int32_t val = v8::internal::DoubleToInt32(lhs);
uint32_t count = v8::internal::DoubleToUint32(rhs) & 0x1F;
int32_t result = val >> count;
return result;
}
case Token::Value::SHR: {
uint32_t val = v8::internal::DoubleToUint32(lhs);
uint32_t count = v8::internal::DoubleToUint32(rhs) & 0x1F;
uint32_t result = val >> count;
return result;
}
default:
UNREACHABLE();
return std::numeric_limits<double>::min();
......@@ -375,6 +397,40 @@ static double BinaryOpC(Token::Value op, double lhs, double rhs) {
}
TEST(InterpreterShiftOpsSmi) {
int lhs_inputs[] = {0, -17, -182, 1073741823, -1};
int rhs_inputs[] = {5, 2, 1, -1, -2, 0, 31, 32, -32, 64, 37};
for (size_t l = 0; l < arraysize(lhs_inputs); l++) {
for (size_t r = 0; r < arraysize(rhs_inputs); r++) {
for (size_t o = 0; o < arraysize(kShiftOperators); o++) {
HandleAndZoneScope handles;
i::Factory* factory = handles.main_isolate()->factory();
BytecodeArrayBuilder builder(handles.main_isolate(),
handles.main_zone());
builder.set_locals_count(1);
builder.set_parameter_count(1);
Register reg(0);
int lhs = lhs_inputs[l];
int rhs = rhs_inputs[r];
builder.LoadLiteral(Smi::FromInt(lhs))
.StoreAccumulatorInRegister(reg)
.LoadLiteral(Smi::FromInt(rhs))
.BinaryOperation(kArithmeticOperators[o], reg, Strength::WEAK)
.Return();
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
InterpreterTester tester(handles.main_isolate(), bytecode_array);
auto callable = tester.GetCallable<>();
Handle<Object> return_value = callable().ToHandleChecked();
Handle<Object> expected_value =
factory->NewNumber(BinaryOpC(kShiftOperators[o], lhs, rhs));
CHECK(return_value->SameValue(*expected_value));
}
}
}
}
TEST(InterpreterBinaryOpsSmi) {
int lhs_inputs[] = {3266, 1024, 0, -17, -18000};
int rhs_inputs[] = {3266, 5, 4, 3, 2, 1, -1, -2};
......
......@@ -68,6 +68,11 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
.BinaryOperation(Token::Value::DIV, reg, Strength::WEAK)
.BinaryOperation(Token::Value::MOD, reg, Strength::WEAK);
// Emit shift operator invocations
builder.BinaryOperation(Token::Value::SHL, reg, Strength::WEAK)
.BinaryOperation(Token::Value::SAR, reg, Strength::WEAK)
.BinaryOperation(Token::Value::SHR, reg, Strength::WEAK);
// Emit unary operator invocations.
builder.LogicalNot().TypeOf();
......
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