Commit c958c98c authored by oth's avatar oth Committed by Commit bot

[Interpreter] Bytecodes for exchanging registers.

New bytecodes for making registers with indicies wider than 1-byte
accessible.

BUG=v8:4280
LOG=N

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

Cr-Commit-Position: refs/heads/master@{#33091}
parent 5b4626ad
...@@ -164,12 +164,23 @@ void BytecodeGraphBuilder::Environment::BindAccumulator( ...@@ -164,12 +164,23 @@ void BytecodeGraphBuilder::Environment::BindAccumulator(
values()->at(accumulator_base_) = node; values()->at(accumulator_base_) = node;
} }
void BytecodeGraphBuilder::Environment::RecordAfterState( void BytecodeGraphBuilder::Environment::RecordAfterState(
Node* node, FrameStateBeforeAndAfter* states) { Node* node, FrameStateBeforeAndAfter* states) {
states->AddToNode(node, AccumulatorUpdateMode::kOutputIgnored); states->AddToNode(node, AccumulatorUpdateMode::kOutputIgnored);
} }
void BytecodeGraphBuilder::Environment::ExchangeRegisters(
interpreter::Register reg0, interpreter::Register reg1) {
int reg0_index = RegisterToValuesIndex(reg0);
int reg1_index = RegisterToValuesIndex(reg1);
Node* saved_reg0_value = values()->at(reg0_index);
values()->at(reg0_index) = values()->at(reg1_index);
values()->at(reg1_index) = saved_reg0_value;
}
Node* BytecodeGraphBuilder::Environment::LookupAccumulator() const { Node* BytecodeGraphBuilder::Environment::LookupAccumulator() const {
return values()->at(accumulator_base_); return values()->at(accumulator_base_);
} }
...@@ -561,6 +572,20 @@ void BytecodeGraphBuilder::VisitMov( ...@@ -561,6 +572,20 @@ void BytecodeGraphBuilder::VisitMov(
} }
void BytecodeGraphBuilder::VisitExchange(
const interpreter::BytecodeArrayIterator& iterator) {
environment()->ExchangeRegisters(iterator.GetRegisterOperand(0),
iterator.GetRegisterOperand(1));
}
void BytecodeGraphBuilder::VisitExchangeWide(
const interpreter::BytecodeArrayIterator& iterator) {
environment()->ExchangeRegisters(iterator.GetRegisterOperand(0),
iterator.GetRegisterOperand(1));
}
void BytecodeGraphBuilder::BuildLoadGlobal( void BytecodeGraphBuilder::BuildLoadGlobal(
const interpreter::BytecodeArrayIterator& iterator, const interpreter::BytecodeArrayIterator& iterator,
TypeofMode typeof_mode) { TypeofMode typeof_mode) {
......
...@@ -267,6 +267,8 @@ class BytecodeGraphBuilder::Environment : public ZoneObject { ...@@ -267,6 +267,8 @@ class BytecodeGraphBuilder::Environment : public ZoneObject {
void BindRegister(interpreter::Register the_register, Node* node); void BindRegister(interpreter::Register the_register, Node* node);
Node* LookupRegister(interpreter::Register the_register) const; Node* LookupRegister(interpreter::Register the_register) const;
void ExchangeRegisters(interpreter::Register reg0,
interpreter::Register reg1);
void BindAccumulator(Node* node, FrameStateBeforeAndAfter* states = nullptr); void BindAccumulator(Node* node, FrameStateBeforeAndAfter* states = nullptr);
Node* LookupAccumulator() const; Node* LookupAccumulator() const;
......
...@@ -209,6 +209,46 @@ Node* InterpreterAssembler::BytecodeOperandShort(int operand_index) { ...@@ -209,6 +209,46 @@ Node* InterpreterAssembler::BytecodeOperandShort(int operand_index) {
} }
Node* InterpreterAssembler::BytecodeOperandShortSignExtended(
int operand_index) {
DCHECK_LT(operand_index, interpreter::Bytecodes::NumberOfOperands(bytecode_));
DCHECK_EQ(interpreter::OperandSize::kShort,
interpreter::Bytecodes::GetOperandSize(bytecode_, operand_index));
int operand_offset =
interpreter::Bytecodes::GetOperandOffset(bytecode_, operand_index);
Node* load;
if (TargetSupportsUnalignedAccess()) {
load = raw_assembler_->Load(
MachineType::Int16(), BytecodeArrayTaggedPointer(),
IntPtrAdd(BytecodeOffset(), Int32Constant(operand_offset)));
} else {
#if V8_TARGET_LITTLE_ENDIAN
Node* hi_byte_offset = Int32Constant(operand_offset + 1);
Node* lo_byte_offset = Int32Constant(operand_offset);
#elif V8_TARGET_BIG_ENDIAN
Node* hi_byte_offset = Int32Constant(operand_offset);
Node* lo_byte_offset = Int32Constant(operand_offset + 1);
#else
#error "Unknown Architecture"
#endif
Node* hi_byte =
raw_assembler_->Load(MachineType::Int8(), BytecodeArrayTaggedPointer(),
IntPtrAdd(BytecodeOffset(), hi_byte_offset));
Node* lo_byte =
raw_assembler_->Load(MachineType::Uint8(), BytecodeArrayTaggedPointer(),
IntPtrAdd(BytecodeOffset(), lo_byte_offset));
hi_byte = raw_assembler_->Word32Shl(hi_byte, Int32Constant(kBitsPerByte));
load = raw_assembler_->Word32Or(hi_byte, lo_byte);
}
// Ensure that we sign extend to full pointer size
if (kPointerSize == 8) {
load = raw_assembler_->ChangeInt32ToInt64(load);
}
return load;
}
Node* InterpreterAssembler::BytecodeOperandCount(int operand_index) { Node* InterpreterAssembler::BytecodeOperandCount(int operand_index) {
switch (interpreter::Bytecodes::GetOperandSize(bytecode_, operand_index)) { switch (interpreter::Bytecodes::GetOperandSize(bytecode_, operand_index)) {
case interpreter::OperandSize::kByte: case interpreter::OperandSize::kByte:
...@@ -255,13 +295,22 @@ Node* InterpreterAssembler::BytecodeOperandIdx(int operand_index) { ...@@ -255,13 +295,22 @@ Node* InterpreterAssembler::BytecodeOperandIdx(int operand_index) {
Node* InterpreterAssembler::BytecodeOperandReg(int operand_index) { Node* InterpreterAssembler::BytecodeOperandReg(int operand_index) {
#ifdef DEBUG switch (interpreter::Bytecodes::GetOperandType(bytecode_, operand_index)) {
interpreter::OperandType operand_type = case interpreter::OperandType::kReg8:
interpreter::Bytecodes::GetOperandType(bytecode_, operand_index); case interpreter::OperandType::kMaybeReg8:
DCHECK(operand_type == interpreter::OperandType::kReg8 || DCHECK_EQ(
operand_type == interpreter::OperandType::kMaybeReg8); interpreter::OperandSize::kByte,
#endif interpreter::Bytecodes::GetOperandSize(bytecode_, operand_index));
return BytecodeOperandSignExtended(operand_index); return BytecodeOperandSignExtended(operand_index);
case interpreter::OperandType::kReg16:
DCHECK_EQ(
interpreter::OperandSize::kShort,
interpreter::Bytecodes::GetOperandSize(bytecode_, operand_index));
return BytecodeOperandShortSignExtended(operand_index);
default:
UNREACHABLE();
return nullptr;
}
} }
......
...@@ -181,6 +181,7 @@ class InterpreterAssembler { ...@@ -181,6 +181,7 @@ class InterpreterAssembler {
Node* BytecodeOperand(int operand_index); Node* BytecodeOperand(int operand_index);
Node* BytecodeOperandSignExtended(int operand_index); Node* BytecodeOperandSignExtended(int operand_index);
Node* BytecodeOperandShort(int operand_index); Node* BytecodeOperandShort(int operand_index);
Node* BytecodeOperandShortSignExtended(int operand_index);
Node* CallN(CallDescriptor* descriptor, Node* code_target, Node** args); Node* CallN(CallDescriptor* descriptor, Node* code_target, Node** args);
Node* CallIC(CallInterfaceDescriptor descriptor, Node* target, Node** args); Node* CallIC(CallInterfaceDescriptor descriptor, Node* target, Node** args);
......
...@@ -379,6 +379,20 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::MoveRegister(Register from, ...@@ -379,6 +379,20 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::MoveRegister(Register from,
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::ExchangeRegisters(Register reg0,
Register reg1) {
DCHECK(reg0 != reg1);
if (FitsInReg8Operand(reg0)) {
Output(Bytecode::kExchange, reg0.ToOperand(), reg1.ToWideOperand());
} else if (FitsInReg8Operand(reg1)) {
Output(Bytecode::kExchange, reg1.ToOperand(), reg0.ToWideOperand());
} else {
Output(Bytecode::kExchangeWide, reg0.ToWideOperand(), reg1.ToWideOperand());
}
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadGlobal( BytecodeArrayBuilder& BytecodeArrayBuilder::LoadGlobal(
const Handle<String> name, int feedback_slot, LanguageMode language_mode, const Handle<String> name, int feedback_slot, LanguageMode language_mode,
TypeofMode typeof_mode) { TypeofMode typeof_mode) {
...@@ -1163,6 +1177,24 @@ bool BytecodeArrayBuilder::OperandIsValid(Bytecode bytecode, int operand_index, ...@@ -1163,6 +1177,24 @@ bool BytecodeArrayBuilder::OperandIsValid(Bytecode bytecode, int operand_index,
return TemporaryRegisterIsLive(reg); return TemporaryRegisterIsLive(reg);
} }
} }
case OperandType::kReg16: {
if (bytecode != Bytecode::kExchange &&
bytecode != Bytecode::kExchangeWide) {
return false;
}
Register reg =
Register::FromWideOperand(static_cast<uint16_t>(operand_value));
if (reg.is_function_context() || reg.is_function_closure() ||
reg.is_new_target()) {
return false;
} else if (reg.is_parameter()) {
return false;
} else if (reg.index() < fixed_register_count()) {
return true;
} else {
return TemporaryRegisterIsLive(reg);
}
}
} }
UNREACHABLE(); UNREACHABLE();
return false; return false;
...@@ -1468,7 +1500,7 @@ bool BytecodeArrayBuilder::FitsInIdx8Operand(size_t value) { ...@@ -1468,7 +1500,7 @@ bool BytecodeArrayBuilder::FitsInIdx8Operand(size_t value) {
// static // static
bool BytecodeArrayBuilder::FitsInImm8Operand(int value) { bool BytecodeArrayBuilder::FitsInImm8Operand(int value) {
return kMinInt8 <= value && value < kMaxInt8; return kMinInt8 <= value && value <= kMaxInt8;
} }
...@@ -1484,6 +1516,18 @@ bool BytecodeArrayBuilder::FitsInIdx16Operand(size_t value) { ...@@ -1484,6 +1516,18 @@ bool BytecodeArrayBuilder::FitsInIdx16Operand(size_t value) {
} }
// static
bool BytecodeArrayBuilder::FitsInReg8Operand(Register value) {
return kMinInt8 <= value.index() && value.index() <= kMaxInt8;
}
// static
bool BytecodeArrayBuilder::FitsInReg16Operand(Register value) {
return kMinInt16 <= value.index() && value.index() <= kMaxInt16;
}
TemporaryRegisterScope::TemporaryRegisterScope(BytecodeArrayBuilder* builder) TemporaryRegisterScope::TemporaryRegisterScope(BytecodeArrayBuilder* builder)
: builder_(builder), : builder_(builder),
allocated_(builder->zone()), allocated_(builder->zone()),
......
...@@ -100,6 +100,7 @@ class BytecodeArrayBuilder final { ...@@ -100,6 +100,7 @@ class BytecodeArrayBuilder final {
// Register-register transfer. // Register-register transfer.
BytecodeArrayBuilder& MoveRegister(Register from, Register to); BytecodeArrayBuilder& MoveRegister(Register from, Register to);
BytecodeArrayBuilder& ExchangeRegisters(Register reg0, Register reg1);
// Named load property. // Named load property.
BytecodeArrayBuilder& LoadNamedProperty(Register object, BytecodeArrayBuilder& LoadNamedProperty(Register object,
...@@ -249,12 +250,17 @@ class BytecodeArrayBuilder final { ...@@ -249,12 +250,17 @@ class BytecodeArrayBuilder final {
static bool FitsInImm8Operand(int value); static bool FitsInImm8Operand(int value);
static bool FitsInIdx16Operand(int value); static bool FitsInIdx16Operand(int value);
static bool FitsInIdx16Operand(size_t value); static bool FitsInIdx16Operand(size_t value);
static bool FitsInReg8Operand(Register value);
static bool FitsInReg16Operand(Register value);
static Bytecode GetJumpWithConstantOperand(Bytecode jump_with_smi8_operand); static Bytecode GetJumpWithConstantOperand(Bytecode jump_with_smi8_operand);
static Bytecode GetJumpWithToBoolean(Bytecode jump); static Bytecode GetJumpWithToBoolean(Bytecode jump);
Register MapRegister(Register reg);
Register MapRegisters(Register reg, Register args_base, int args_length = 1);
template <size_t N> template <size_t N>
INLINE(void Output(Bytecode bytecode, uint32_t(&oprands)[N])); INLINE(void Output(Bytecode bytecode, uint32_t(&operands)[N]));
void Output(Bytecode bytecode, uint32_t operand0, uint32_t operand1, void Output(Bytecode bytecode, uint32_t operand0, uint32_t operand1,
uint32_t operand2, uint32_t operand3); uint32_t operand2, uint32_t operand3);
void Output(Bytecode bytecode, uint32_t operand0, uint32_t operand1, void Output(Bytecode bytecode, uint32_t operand0, uint32_t operand1,
......
...@@ -75,11 +75,11 @@ int BytecodeArrayIterator::GetCountOperand(int operand_index) const { ...@@ -75,11 +75,11 @@ int BytecodeArrayIterator::GetCountOperand(int operand_index) const {
int BytecodeArrayIterator::GetIndexOperand(int operand_index) const { int BytecodeArrayIterator::GetIndexOperand(int operand_index) const {
OperandSize size = OperandType operand_type =
Bytecodes::GetOperandSize(current_bytecode(), operand_index); Bytecodes::GetOperandType(current_bytecode(), operand_index);
OperandType type = DCHECK(operand_type == OperandType::kIdx8 ||
(size == OperandSize::kByte) ? OperandType::kIdx8 : OperandType::kIdx16; operand_type == OperandType::kIdx16);
uint32_t operand = GetRawOperand(operand_index, type); uint32_t operand = GetRawOperand(operand_index, operand_type);
return static_cast<int>(operand); return static_cast<int>(operand);
} }
...@@ -88,7 +88,8 @@ Register BytecodeArrayIterator::GetRegisterOperand(int operand_index) const { ...@@ -88,7 +88,8 @@ Register BytecodeArrayIterator::GetRegisterOperand(int operand_index) const {
OperandType operand_type = OperandType operand_type =
Bytecodes::GetOperandType(current_bytecode(), operand_index); Bytecodes::GetOperandType(current_bytecode(), operand_index);
DCHECK(operand_type == OperandType::kReg8 || DCHECK(operand_type == OperandType::kReg8 ||
operand_type == OperandType::kMaybeReg8); operand_type == OperandType::kMaybeReg8 ||
operand_type == OperandType::kReg16);
uint32_t operand = GetRawOperand(operand_index, operand_type); uint32_t operand = GetRawOperand(operand_index, operand_type);
return Register::FromOperand(operand); return Register::FromOperand(operand);
} }
......
...@@ -273,6 +273,18 @@ std::ostream& Bytecodes::Decode(std::ostream& os, const uint8_t* bytecode_start, ...@@ -273,6 +273,18 @@ std::ostream& Bytecodes::Decode(std::ostream& os, const uint8_t* bytecode_start,
} }
break; break;
} }
case interpreter::OperandType::kReg16: {
Register reg =
Register::FromWideOperand(ReadUnalignedUInt16(operand_start));
if (reg.is_parameter()) {
int parameter_index = reg.ToParameterIndex(parameter_count);
DCHECK_NE(parameter_index, 0);
os << "a" << parameter_index - 1;
} else {
os << "r" << reg.index();
}
break;
}
case interpreter::OperandType::kNone: case interpreter::OperandType::kNone:
UNREACHABLE(); UNREACHABLE();
break; break;
...@@ -322,7 +334,7 @@ Register Register::FromParameterIndex(int index, int parameter_count) { ...@@ -322,7 +334,7 @@ Register Register::FromParameterIndex(int index, int parameter_count) {
DCHECK_LE(parameter_count, kMaxParameterIndex + 1); DCHECK_LE(parameter_count, kMaxParameterIndex + 1);
int register_index = kLastParamRegisterIndex - parameter_count + index + 1; int register_index = kLastParamRegisterIndex - parameter_count + index + 1;
DCHECK_LT(register_index, 0); DCHECK_LT(register_index, 0);
DCHECK_GE(register_index, Register::kMinRegisterIndex); DCHECK_GE(register_index, kMinInt8);
return Register(register_index); return Register(register_index);
} }
...@@ -364,7 +376,11 @@ bool Register::is_new_target() const { ...@@ -364,7 +376,11 @@ bool Register::is_new_target() const {
int Register::MaxParameterIndex() { return kMaxParameterIndex; } int Register::MaxParameterIndex() { return kMaxParameterIndex; }
uint8_t Register::ToOperand() const { return static_cast<uint8_t>(-index_); } uint8_t Register::ToOperand() const {
DCHECK_GE(index_, kMinInt8);
DCHECK_LE(index_, kMaxInt8);
return static_cast<uint8_t>(-index_);
}
Register Register::FromOperand(uint8_t operand) { Register Register::FromOperand(uint8_t operand) {
...@@ -372,6 +388,18 @@ Register Register::FromOperand(uint8_t operand) { ...@@ -372,6 +388,18 @@ Register Register::FromOperand(uint8_t operand) {
} }
uint16_t Register::ToWideOperand() const {
DCHECK_GE(index_, kMinInt16);
DCHECK_LE(index_, kMaxInt16);
return static_cast<uint16_t>(-index_);
}
Register Register::FromWideOperand(uint16_t operand) {
return Register(-static_cast<int16_t>(operand));
}
bool Register::AreContiguous(Register reg1, Register reg2, Register reg3, bool Register::AreContiguous(Register reg1, Register reg2, Register reg3,
Register reg4, Register reg5) { Register reg4, Register reg5) {
if (reg1.index() + 1 != reg2.index()) { if (reg1.index() + 1 != reg2.index()) {
......
...@@ -25,12 +25,13 @@ namespace interpreter { ...@@ -25,12 +25,13 @@ namespace interpreter {
V(Count8, OperandSize::kByte) \ V(Count8, OperandSize::kByte) \
V(Imm8, OperandSize::kByte) \ V(Imm8, OperandSize::kByte) \
V(Idx8, OperandSize::kByte) \ V(Idx8, OperandSize::kByte) \
V(Reg8, OperandSize::kByte) \
V(MaybeReg8, OperandSize::kByte) \ V(MaybeReg8, OperandSize::kByte) \
V(Reg8, OperandSize::kByte) \
\ \
/* Short operands. */ \ /* Short operands. */ \
V(Count16, OperandSize::kShort) \ V(Count16, OperandSize::kShort) \
V(Idx16, OperandSize::kShort) V(Idx16, OperandSize::kShort) \
V(Reg16, OperandSize::kShort)
// The list of bytecodes which are interpreted by the interpreter. // The list of bytecodes which are interpreted by the interpreter.
#define BYTECODE_LIST(V) \ #define BYTECODE_LIST(V) \
...@@ -78,6 +79,8 @@ namespace interpreter { ...@@ -78,6 +79,8 @@ namespace interpreter {
\ \
/* Register-register transfers */ \ /* Register-register transfers */ \
V(Mov, OperandType::kReg8, OperandType::kReg8) \ V(Mov, OperandType::kReg8, OperandType::kReg8) \
V(Exchange, OperandType::kReg8, OperandType::kReg16) \
V(ExchangeWide, OperandType::kReg16, OperandType::kReg16) \
\ \
/* LoadIC operations */ \ /* LoadIC operations */ \
V(LoadICSloppy, OperandType::kReg8, OperandType::kIdx8, OperandType::kIdx8) \ V(LoadICSloppy, OperandType::kReg8, OperandType::kIdx8, OperandType::kIdx8) \
...@@ -249,15 +252,9 @@ enum class Bytecode : uint8_t { ...@@ -249,15 +252,9 @@ enum class Bytecode : uint8_t {
// in its stack-frame. Register hold parameters, this, and expression values. // in its stack-frame. Register hold parameters, this, and expression values.
class Register { class Register {
public: public:
static const int kMaxRegisterIndex = 127;
static const int kMinRegisterIndex = -128;
Register() : index_(kIllegalIndex) {} Register() : index_(kIllegalIndex) {}
explicit Register(int index) : index_(index) { explicit Register(int index) : index_(index) {}
DCHECK_LE(index_, kMaxRegisterIndex);
DCHECK_GE(index_, kMinRegisterIndex);
}
int index() const { int index() const {
DCHECK(index_ != kIllegalIndex); DCHECK(index_ != kIllegalIndex);
...@@ -285,6 +282,9 @@ class Register { ...@@ -285,6 +282,9 @@ class Register {
static Register FromOperand(uint8_t operand); static Register FromOperand(uint8_t operand);
uint8_t ToOperand() const; uint8_t ToOperand() const;
static Register FromWideOperand(uint16_t operand);
uint16_t ToWideOperand() const;
static bool AreContiguous(Register reg1, Register reg2, static bool AreContiguous(Register reg1, Register reg2,
Register reg3 = Register(), Register reg3 = Register(),
Register reg4 = Register(), Register reg4 = Register(),
......
...@@ -201,6 +201,28 @@ void Interpreter::DoStar(compiler::InterpreterAssembler* assembler) { ...@@ -201,6 +201,28 @@ void Interpreter::DoStar(compiler::InterpreterAssembler* assembler) {
} }
// Exchange <reg8> <reg16>
//
// Exchange two registers.
void Interpreter::DoExchange(compiler::InterpreterAssembler* assembler) {
Node* reg0_index = __ BytecodeOperandReg(0);
Node* reg1_index = __ BytecodeOperandReg(1);
Node* reg0_value = __ LoadRegister(reg0_index);
Node* reg1_value = __ LoadRegister(reg1_index);
__ StoreRegister(reg1_value, reg0_index);
__ StoreRegister(reg0_value, reg1_index);
__ Dispatch();
}
// ExchangeWide <reg16> <reg16>
//
// Exchange two registers.
void Interpreter::DoExchangeWide(compiler::InterpreterAssembler* assembler) {
return DoExchange(assembler);
}
// Mov <src> <dst> // Mov <src> <dst>
// //
// Stores the value of register <src> to register <dst>. // Stores the value of register <src> to register <dst>.
......
...@@ -340,7 +340,7 @@ TEST(InterpreterLoadLiteral) { ...@@ -340,7 +340,7 @@ TEST(InterpreterLoadLiteral) {
TEST(InterpreterLoadStoreRegisters) { TEST(InterpreterLoadStoreRegisters) {
HandleAndZoneScope handles; HandleAndZoneScope handles;
Handle<Object> true_value = handles.main_isolate()->factory()->true_value(); Handle<Object> true_value = handles.main_isolate()->factory()->true_value();
for (int i = 0; i <= Register::kMaxRegisterIndex; i++) { for (int i = 0; i <= kMaxInt8; i++) {
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
builder.set_locals_count(i + 1); builder.set_locals_count(i + 1);
builder.set_context_count(0); builder.set_context_count(0);
...@@ -361,6 +361,117 @@ TEST(InterpreterLoadStoreRegisters) { ...@@ -361,6 +361,117 @@ TEST(InterpreterLoadStoreRegisters) {
} }
TEST(InterpreterExchangeRegisters) {
for (int locals_count = 2; locals_count < 300; locals_count += 126) {
HandleAndZoneScope handles;
for (int exchanges = 1; exchanges < 4; exchanges++) {
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
builder.set_locals_count(locals_count);
builder.set_context_count(0);
builder.set_parameter_count(0);
Register r0(0);
Register r1(locals_count - 1);
builder.LoadTrue();
builder.StoreAccumulatorInRegister(r0);
builder.ExchangeRegisters(r0, r1);
builder.LoadFalse();
builder.StoreAccumulatorInRegister(r0);
bool expected = false;
for (int i = 0; i < exchanges; i++) {
builder.ExchangeRegisters(r0, r1);
expected = !expected;
}
builder.LoadAccumulatorWithRegister(r0);
builder.Return();
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
InterpreterTester tester(handles.main_isolate(), bytecode_array);
auto callable = tester.GetCallable<>();
Handle<Object> return_val = callable().ToHandleChecked();
Handle<Object> expected_val =
handles.main_isolate()->factory()->ToBoolean(expected);
CHECK(return_val.is_identical_to(expected_val));
}
}
}
TEST(InterpreterExchangeRegistersWithParameter) {
for (int locals_count = 2; locals_count < 300; locals_count += 126) {
HandleAndZoneScope handles;
for (int exchanges = 1; exchanges < 4; exchanges++) {
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
builder.set_locals_count(locals_count);
builder.set_context_count(0);
builder.set_parameter_count(3);
Register r0 = Register::FromParameterIndex(2, 3);
Register r1(locals_count - 1);
builder.LoadTrue();
builder.StoreAccumulatorInRegister(r0);
builder.ExchangeRegisters(r0, r1);
builder.LoadFalse();
builder.StoreAccumulatorInRegister(r0);
bool expected = false;
for (int i = 0; i < exchanges; i++) {
builder.ExchangeRegisters(r0, r1);
expected = !expected;
}
builder.LoadAccumulatorWithRegister(r0);
builder.Return();
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
InterpreterTester tester(handles.main_isolate(), bytecode_array);
auto callable = tester.GetCallable<>();
Handle<Object> return_val = callable().ToHandleChecked();
Handle<Object> expected_val =
handles.main_isolate()->factory()->ToBoolean(expected);
CHECK(return_val.is_identical_to(expected_val));
}
}
}
TEST(InterpreterExchangeWideRegisters) {
for (int locals_count = 3; locals_count < 300; locals_count += 126) {
HandleAndZoneScope handles;
for (int exchanges = 0; exchanges < 7; exchanges++) {
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
builder.set_locals_count(locals_count);
builder.set_context_count(0);
builder.set_parameter_count(0);
Register r0(0);
Register r1(locals_count - 1);
Register r2(locals_count - 2);
builder.LoadLiteral(Smi::FromInt(200));
builder.StoreAccumulatorInRegister(r0);
builder.ExchangeRegisters(r0, r1);
builder.LoadLiteral(Smi::FromInt(100));
builder.StoreAccumulatorInRegister(r0);
builder.ExchangeRegisters(r0, r2);
builder.LoadLiteral(Smi::FromInt(0));
builder.StoreAccumulatorInRegister(r0);
for (int i = 0; i < exchanges; i++) {
builder.ExchangeRegisters(r1, r2);
builder.ExchangeRegisters(r0, r1);
}
builder.LoadAccumulatorWithRegister(r0);
builder.Return();
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
InterpreterTester tester(handles.main_isolate(), bytecode_array);
auto callable = tester.GetCallable<>();
Handle<Object> return_val = callable().ToHandleChecked();
Handle<Object> expected_val =
handles.main_isolate()->factory()->NewNumberFromInt(100 *
(exchanges % 3));
CHECK(return_val.is_identical_to(expected_val));
}
}
}
static const Token::Value kShiftOperators[] = { static const Token::Value kShiftOperators[] = {
Token::Value::SHL, Token::Value::SAR, Token::Value::SHR}; Token::Value::SHL, Token::Value::SAR, Token::Value::SHR};
......
...@@ -140,6 +140,47 @@ InterpreterAssemblerTest::InterpreterAssemblerForTest::IsBytecodeOperandShort( ...@@ -140,6 +140,47 @@ InterpreterAssemblerTest::InterpreterAssemblerForTest::IsBytecodeOperandShort(
} }
Matcher<Node*> InterpreterAssemblerTest::InterpreterAssemblerForTest::
IsBytecodeOperandShortSignExtended(int offset) {
Matcher<Node*> load_matcher;
if (TargetSupportsUnalignedAccess()) {
load_matcher = IsLoad(
MachineType::Int16(),
IsParameter(Linkage::kInterpreterBytecodeArrayParameter),
IsIntPtrAdd(IsParameter(Linkage::kInterpreterBytecodeOffsetParameter),
IsInt32Constant(offset)));
} else {
#if V8_TARGET_LITTLE_ENDIAN
int hi_byte_offset = offset + 1;
int lo_byte_offset = offset;
#elif V8_TARGET_BIG_ENDIAN
int hi_byte_offset = offset;
int lo_byte_offset = offset + 1;
#else
#error "Unknown Architecture"
#endif
Matcher<Node*> hi_byte = IsLoad(
MachineType::Int8(),
IsParameter(Linkage::kInterpreterBytecodeArrayParameter),
IsIntPtrAdd(IsParameter(Linkage::kInterpreterBytecodeOffsetParameter),
IsInt32Constant(hi_byte_offset)));
hi_byte = IsWord32Shl(hi_byte, IsInt32Constant(kBitsPerByte));
Matcher<Node*> lo_byte = IsLoad(
MachineType::Uint8(),
IsParameter(Linkage::kInterpreterBytecodeArrayParameter),
IsIntPtrAdd(IsParameter(Linkage::kInterpreterBytecodeOffsetParameter),
IsInt32Constant(lo_byte_offset)));
load_matcher = IsWord32Or(hi_byte, lo_byte);
}
if (kPointerSize == 8) {
load_matcher = IsChangeInt32ToInt64(load_matcher);
}
return load_matcher;
}
TARGET_TEST_F(InterpreterAssemblerTest, Dispatch) { TARGET_TEST_F(InterpreterAssemblerTest, Dispatch) {
TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
InterpreterAssemblerForTest m(this, bytecode); InterpreterAssemblerForTest m(this, bytecode);
...@@ -320,6 +361,10 @@ TARGET_TEST_F(InterpreterAssemblerTest, BytecodeOperand) { ...@@ -320,6 +361,10 @@ TARGET_TEST_F(InterpreterAssemblerTest, BytecodeOperand) {
EXPECT_THAT(m.BytecodeOperandIdx(i), EXPECT_THAT(m.BytecodeOperandIdx(i),
m.IsBytecodeOperandShort(offset)); m.IsBytecodeOperandShort(offset));
break; break;
case interpreter::OperandType::kReg16:
EXPECT_THAT(m.BytecodeOperandReg(i),
m.IsBytecodeOperandShortSignExtended(offset));
break;
case interpreter::OperandType::kNone: case interpreter::OperandType::kNone:
UNREACHABLE(); UNREACHABLE();
break; break;
......
...@@ -40,6 +40,7 @@ class InterpreterAssemblerTest : public TestWithIsolateAndZone { ...@@ -40,6 +40,7 @@ class InterpreterAssemblerTest : public TestWithIsolateAndZone {
Matcher<Node*> IsBytecodeOperand(int offset); Matcher<Node*> IsBytecodeOperand(int offset);
Matcher<Node*> IsBytecodeOperandSignExtended(int offset); Matcher<Node*> IsBytecodeOperandSignExtended(int offset);
Matcher<Node*> IsBytecodeOperandShort(int offset); Matcher<Node*> IsBytecodeOperandShort(int offset);
Matcher<Node*> IsBytecodeOperandShortSignExtended(int offset);
using InterpreterAssembler::call_descriptor; using InterpreterAssembler::call_descriptor;
using InterpreterAssembler::graph; using InterpreterAssembler::graph;
......
...@@ -22,12 +22,12 @@ class BytecodeArrayBuilderTest : public TestWithIsolateAndZone { ...@@ -22,12 +22,12 @@ class BytecodeArrayBuilderTest : public TestWithIsolateAndZone {
TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
BytecodeArrayBuilder builder(isolate(), zone()); BytecodeArrayBuilder builder(isolate(), zone());
builder.set_locals_count(2); builder.set_locals_count(200);
builder.set_context_count(1); builder.set_context_count(1);
builder.set_parameter_count(0); builder.set_parameter_count(0);
CHECK_EQ(builder.locals_count(), 2); CHECK_EQ(builder.locals_count(), 200);
CHECK_EQ(builder.context_count(), 1); CHECK_EQ(builder.context_count(), 1);
CHECK_EQ(builder.fixed_register_count(), 3); CHECK_EQ(builder.fixed_register_count(), 201);
// Emit constant loads. // Emit constant loads.
builder.LoadLiteral(Smi::FromInt(0)) builder.LoadLiteral(Smi::FromInt(0))
...@@ -50,6 +50,13 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { ...@@ -50,6 +50,13 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
Register other(1); Register other(1);
builder.MoveRegister(reg, other); builder.MoveRegister(reg, other);
// Emit register-register exchanges.
Register wide(150);
builder.ExchangeRegisters(reg, wide);
builder.ExchangeRegisters(wide, reg);
Register wider(151);
builder.ExchangeRegisters(wide, wider);
// Emit global load / store operations. // Emit global load / store operations.
Factory* factory = isolate()->factory(); Factory* factory = isolate()->factory();
Handle<String> name = factory->NewStringFromStaticChars("var_name"); Handle<String> name = factory->NewStringFromStaticChars("var_name");
......
...@@ -42,7 +42,7 @@ TEST(OperandConversion, Parameters) { ...@@ -42,7 +42,7 @@ TEST(OperandConversion, Parameters) {
TEST(OperandConversion, RegistersParametersNoOverlap) { TEST(OperandConversion, RegistersParametersNoOverlap) {
std::vector<uint8_t> operand_count(256); std::vector<uint8_t> operand_count(256);
for (int i = 0; i <= Register::kMaxRegisterIndex; i++) { for (int i = 0; i <= kMaxInt8; i++) {
Register r = Register(i); Register r = Register(i);
uint8_t operand = r.ToOperand(); uint8_t operand = r.ToOperand();
operand_count[operand] += 1; operand_count[operand] += 1;
......
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