Commit 72a126b9 authored by sreten.kovacevic's avatar sreten.kovacevic Committed by Commit Bot

[Liftoff][mips] Add big endian support

Add big endian support for MIPS in Liftoff.

Bug: v8:6600
Change-Id: Ibd90e7b6a8f0f826bd70ef489135cabcadeed7b0
Reviewed-on: https://chromium-review.googlesource.com/995457
Commit-Queue: Sreten Kovacevic <sreten.kovacevic@mips.com>
Reviewed-by: 's avatarClemens Hammacher <clemensh@chromium.org>
Reviewed-by: 's avatarIvica Bogosavljevic <ivica.bogosavljevic@mips.com>
Cr-Commit-Position: refs/heads/master@{#52565}
parent 7f564f45
......@@ -44,17 +44,28 @@ void LiftoffAssembler::FillInstanceInto(Register dst) {
void LiftoffAssembler::Load(LiftoffRegister dst, Register src_addr,
Register offset_reg, uint32_t offset_imm,
LoadType type, LiftoffRegList pinned,
uint32_t* protected_load_pc) {
uint32_t* protected_load_pc, bool is_load_mem) {
BAILOUT("Load");
}
void LiftoffAssembler::Store(Register dst_addr, Register offset_reg,
uint32_t offset_imm, LiftoffRegister src,
StoreType type, LiftoffRegList pinned,
uint32_t* protected_store_pc) {
uint32_t* protected_store_pc, bool is_store_mem) {
BAILOUT("Store");
}
void LiftoffAssembler::ChangeEndiannessLoad(LiftoffRegister dst, LoadType type,
LiftoffRegList pinned) {
BAILOUT("ChangeEndiannessLoad");
}
void LiftoffAssembler::ChangeEndiannessStore(LiftoffRegister src,
StoreType type,
LiftoffRegList pinned) {
BAILOUT("ChangeEndiannessStore");
}
void LiftoffAssembler::LoadCallerFrameSlot(LiftoffRegister dst,
uint32_t caller_slot_idx,
ValueType type) {
......
......@@ -44,17 +44,28 @@ void LiftoffAssembler::FillInstanceInto(Register dst) {
void LiftoffAssembler::Load(LiftoffRegister dst, Register src_addr,
Register offset_reg, uint32_t offset_imm,
LoadType type, LiftoffRegList pinned,
uint32_t* protected_load_pc) {
uint32_t* protected_load_pc, bool is_load_mem) {
BAILOUT("Load");
}
void LiftoffAssembler::Store(Register dst_addr, Register offset_reg,
uint32_t offset_imm, LiftoffRegister src,
StoreType type, LiftoffRegList pinned,
uint32_t* protected_store_pc) {
uint32_t* protected_store_pc, bool is_store_mem) {
BAILOUT("Store");
}
void LiftoffAssembler::ChangeEndiannessLoad(LiftoffRegister dst, LoadType type,
LiftoffRegList pinned) {
BAILOUT("ChangeEndiannessLoad");
}
void LiftoffAssembler::ChangeEndiannessStore(LiftoffRegister src,
StoreType type,
LiftoffRegList pinned) {
BAILOUT("ChangeEndiannessStore");
}
void LiftoffAssembler::LoadCallerFrameSlot(LiftoffRegister dst,
uint32_t caller_slot_idx,
ValueType type) {
......
......@@ -156,7 +156,7 @@ void LiftoffAssembler::FillInstanceInto(Register dst) {
void LiftoffAssembler::Load(LiftoffRegister dst, Register src_addr,
Register offset_reg, uint32_t offset_imm,
LoadType type, LiftoffRegList pinned,
uint32_t* protected_load_pc) {
uint32_t* protected_load_pc, bool is_load_mem) {
DCHECK_EQ(type.value_type() == kWasmI64, dst.is_pair());
// Wasm memory is limited to a size <2GB, so all offsets can be encoded as
// immediate value (in 31 bits, interpreted as signed value).
......@@ -237,7 +237,7 @@ void LiftoffAssembler::Load(LiftoffRegister dst, Register src_addr,
void LiftoffAssembler::Store(Register dst_addr, Register offset_reg,
uint32_t offset_imm, LiftoffRegister src,
StoreType type, LiftoffRegList pinned,
uint32_t* protected_store_pc) {
uint32_t* protected_store_pc, bool is_store_mem) {
DCHECK_EQ(type.value_type() == kWasmI64, src.is_pair());
// Wasm memory is limited to a size <2GB, so all offsets can be encoded as
// immediate value (in 31 bits, interpreted as signed value).
......@@ -298,6 +298,17 @@ void LiftoffAssembler::Store(Register dst_addr, Register offset_reg,
}
}
void LiftoffAssembler::ChangeEndiannessLoad(LiftoffRegister dst, LoadType type,
LiftoffRegList pinned) {
// Nop.
}
void LiftoffAssembler::ChangeEndiannessStore(LiftoffRegister src,
StoreType type,
LiftoffRegList pinned) {
// Nop.
}
void LiftoffAssembler::LoadCallerFrameSlot(LiftoffRegister dst,
uint32_t caller_slot_idx,
ValueType type) {
......
......@@ -357,10 +357,16 @@ class LiftoffAssembler : public TurboAssembler {
inline void FillInstanceInto(Register dst);
inline void Load(LiftoffRegister dst, Register src_addr, Register offset_reg,
uint32_t offset_imm, LoadType type, LiftoffRegList pinned,
uint32_t* protected_load_pc = nullptr);
uint32_t* protected_load_pc = nullptr,
bool is_load_mem = false);
inline void Store(Register dst_addr, Register offset_reg, uint32_t offset_imm,
LiftoffRegister src, StoreType type, LiftoffRegList pinned,
uint32_t* protected_store_pc = nullptr);
uint32_t* protected_store_pc = nullptr,
bool is_store_mem = false);
inline void ChangeEndiannessLoad(LiftoffRegister dst, LoadType type,
LiftoffRegList pinned);
inline void ChangeEndiannessStore(LiftoffRegister src, StoreType type,
LiftoffRegList pinned);
inline void LoadCallerFrameSlot(LiftoffRegister, uint32_t caller_slot_idx,
ValueType);
inline void MoveStackValue(uint32_t dst_index, uint32_t src_index, ValueType);
......
......@@ -1353,7 +1353,7 @@ class LiftoffCompiler {
LiftoffRegister value = pinned.set(__ GetUnusedRegister(rc, pinned));
uint32_t protected_load_pc = 0;
__ Load(value, addr.gp(), index, operand.offset, type, pinned,
&protected_load_pc);
&protected_load_pc, true);
if (env_->use_trap_handler) {
AddOutOfLineTrap(decoder->position(),
Builtins::kThrowWasmTrapMemOutOfBounds,
......@@ -1382,7 +1382,7 @@ class LiftoffCompiler {
LOAD_INSTANCE_FIELD(addr, MemoryStart, kPointerLoadType);
uint32_t protected_store_pc = 0;
__ Store(addr.gp(), index, operand.offset, value, type, pinned,
&protected_store_pc);
&protected_store_pc, true);
if (env_->use_trap_handler) {
AddOutOfLineTrap(decoder->position(),
Builtins::kThrowWasmTrapMemOutOfBounds,
......
......@@ -148,7 +148,7 @@ void LiftoffAssembler::FillInstanceInto(Register dst) {
void LiftoffAssembler::Load(LiftoffRegister dst, Register src_addr,
Register offset_reg, uint32_t offset_imm,
LoadType type, LiftoffRegList pinned,
uint32_t* protected_load_pc) {
uint32_t* protected_load_pc, bool is_load_mem) {
// TODO(ksreten): Add check if unaligned memory access
Register src = no_reg;
if (offset_reg != no_reg) {
......@@ -219,12 +219,18 @@ void LiftoffAssembler::Load(LiftoffRegister dst, Register src_addr,
default:
UNREACHABLE();
}
#if defined(V8_TARGET_BIG_ENDIAN)
if (is_load_mem) {
ChangeEndiannessLoad(dst, type, pinned);
}
#endif
}
void LiftoffAssembler::Store(Register dst_addr, Register offset_reg,
uint32_t offset_imm, LiftoffRegister src,
StoreType type, LiftoffRegList pinned,
uint32_t* protected_store_pc) {
uint32_t* protected_store_pc, bool is_store_mem) {
// TODO(ksreten): Add check if unaligned memory access
Register dst = no_reg;
if (offset_reg != no_reg) {
......@@ -234,6 +240,18 @@ void LiftoffAssembler::Store(Register dst_addr, Register offset_reg,
MemOperand dst_op = (offset_reg != no_reg) ? MemOperand(dst, offset_imm)
: MemOperand(dst_addr, offset_imm);
#if defined(V8_TARGET_BIG_ENDIAN)
if (is_store_mem) {
LiftoffRegister tmp = GetUnusedRegister(src.reg_class(), pinned);
// Save original value.
Move(tmp, src, type.value_type());
src = tmp;
pinned.set(tmp);
ChangeEndiannessStore(src, type, pinned);
}
#endif
if (protected_store_pc) *protected_store_pc = pc_offset();
switch (type.value()) {
case StoreType::kI64Store8:
......@@ -273,6 +291,134 @@ void LiftoffAssembler::Store(Register dst_addr, Register offset_reg,
}
}
void LiftoffAssembler::ChangeEndiannessLoad(LiftoffRegister dst, LoadType type,
LiftoffRegList pinned) {
bool is_float = false;
LiftoffRegister tmp = dst;
switch (type.value()) {
case LoadType::kI64Load8U:
case LoadType::kI64Load8S:
// Swap low and high registers.
TurboAssembler::Move(at, tmp.low_gp());
TurboAssembler::Move(tmp.low_gp(), tmp.high_gp());
TurboAssembler::Move(tmp.high_gp(), at);
V8_FALLTHROUGH;
case LoadType::kI32Load8U:
case LoadType::kI32Load8S:
// No need to change endianness for byte size.
return;
case LoadType::kF32Load:
is_float = true;
tmp = GetUnusedRegister(kGpReg, pinned);
emit_type_conversion(kExprI32ReinterpretF32, tmp, dst);
V8_FALLTHROUGH;
case LoadType::kI32Load:
TurboAssembler::ByteSwapSigned(tmp.gp(), tmp.gp(), 4);
break;
case LoadType::kI32Load16S:
TurboAssembler::ByteSwapSigned(tmp.gp(), tmp.gp(), 2);
break;
case LoadType::kI32Load16U:
TurboAssembler::ByteSwapUnsigned(tmp.gp(), tmp.gp(), 2);
break;
case LoadType::kF64Load:
is_float = true;
tmp = GetUnusedRegister(kGpRegPair, pinned);
emit_type_conversion(kExprI64ReinterpretF64, tmp, dst);
V8_FALLTHROUGH;
case LoadType::kI64Load:
TurboAssembler::Move(at, tmp.low_gp());
TurboAssembler::ByteSwapSigned(tmp.low_gp(), tmp.high_gp(), 4);
TurboAssembler::ByteSwapSigned(tmp.high_gp(), at, 4);
break;
case LoadType::kI64Load16U:
TurboAssembler::ByteSwapUnsigned(tmp.low_gp(), tmp.high_gp(), 2);
TurboAssembler::Move(tmp.high_gp(), zero_reg);
break;
case LoadType::kI64Load16S:
TurboAssembler::ByteSwapSigned(tmp.low_gp(), tmp.high_gp(), 2);
sra(tmp.high_gp(), tmp.high_gp(), 31);
break;
case LoadType::kI64Load32U:
TurboAssembler::ByteSwapSigned(tmp.low_gp(), tmp.high_gp(), 4);
TurboAssembler::Move(tmp.high_gp(), zero_reg);
break;
case LoadType::kI64Load32S:
TurboAssembler::ByteSwapSigned(tmp.low_gp(), tmp.high_gp(), 4);
sra(tmp.high_gp(), tmp.high_gp(), 31);
break;
default:
UNREACHABLE();
}
if (is_float) {
switch (type.value()) {
case LoadType::kF32Load:
emit_type_conversion(kExprF32ReinterpretI32, dst, tmp);
break;
case LoadType::kF64Load:
emit_type_conversion(kExprF64ReinterpretI64, dst, tmp);
break;
default:
UNREACHABLE();
}
}
}
void LiftoffAssembler::ChangeEndiannessStore(LiftoffRegister src,
StoreType type,
LiftoffRegList pinned) {
bool is_float = false;
LiftoffRegister tmp = src;
switch (type.value()) {
case StoreType::kI64Store8:
// Swap low and high registers.
TurboAssembler::Move(at, tmp.low_gp());
TurboAssembler::Move(tmp.low_gp(), tmp.high_gp());
TurboAssembler::Move(tmp.high_gp(), at);
V8_FALLTHROUGH;
case StoreType::kI32Store8:
// No need to change endianness for byte size.
return;
case StoreType::kF32Store:
is_float = true;
tmp = GetUnusedRegister(kGpReg, pinned);
emit_type_conversion(kExprI32ReinterpretF32, tmp, src);
V8_FALLTHROUGH;
case StoreType::kI32Store:
case StoreType::kI32Store16:
TurboAssembler::ByteSwapSigned(tmp.gp(), tmp.gp(), 4);
break;
case StoreType::kF64Store:
is_float = true;
tmp = GetUnusedRegister(kGpRegPair, pinned);
emit_type_conversion(kExprI64ReinterpretF64, tmp, src);
V8_FALLTHROUGH;
case StoreType::kI64Store:
case StoreType::kI64Store32:
case StoreType::kI64Store16:
TurboAssembler::Move(at, tmp.low_gp());
TurboAssembler::ByteSwapSigned(tmp.low_gp(), tmp.high_gp(), 4);
TurboAssembler::ByteSwapSigned(tmp.high_gp(), at, 4);
break;
default:
UNREACHABLE();
}
if (is_float) {
switch (type.value()) {
case StoreType::kF32Store:
emit_type_conversion(kExprF32ReinterpretI32, src, tmp);
break;
case StoreType::kF64Store:
emit_type_conversion(kExprF64ReinterpretI64, src, tmp);
break;
default:
UNREACHABLE();
}
}
}
void LiftoffAssembler::LoadCallerFrameSlot(LiftoffRegister dst,
uint32_t caller_slot_idx,
ValueType type) {
......
......@@ -143,7 +143,7 @@ void LiftoffAssembler::FillInstanceInto(Register dst) {
void LiftoffAssembler::Load(LiftoffRegister dst, Register src_addr,
Register offset_reg, uint32_t offset_imm,
LoadType type, LiftoffRegList pinned,
uint32_t* protected_load_pc) {
uint32_t* protected_load_pc, bool is_load_mem) {
// TODO(ksreten): Add check if unaligned memory access
MemOperand src_op(src_addr, offset_imm);
if (offset_reg != no_reg) {
......@@ -189,12 +189,18 @@ void LiftoffAssembler::Load(LiftoffRegister dst, Register src_addr,
default:
UNREACHABLE();
}
#if defined(V8_TARGET_BIG_ENDIAN)
if (is_load_mem) {
ChangeEndiannessLoad(dst, type, pinned);
}
#endif
}
void LiftoffAssembler::Store(Register dst_addr, Register offset_reg,
uint32_t offset_imm, LiftoffRegister src,
StoreType type, LiftoffRegList pinned,
uint32_t* protected_store_pc) {
uint32_t* protected_store_pc, bool is_store_mem) {
// TODO(ksreten): Add check if unaligned memory access
Register dst = no_reg;
if (offset_reg != no_reg) {
......@@ -204,6 +210,18 @@ void LiftoffAssembler::Store(Register dst_addr, Register offset_reg,
MemOperand dst_op = (offset_reg != no_reg) ? MemOperand(dst, offset_imm)
: MemOperand(dst_addr, offset_imm);
#if defined(V8_TARGET_BIG_ENDIAN)
if (is_store_mem) {
LiftoffRegister tmp = GetUnusedRegister(src.reg_class(), pinned);
// Save original value.
Move(tmp, src, type.value_type());
src = tmp;
pinned.set(tmp);
ChangeEndiannessStore(src, type, pinned);
}
#endif
if (protected_store_pc) *protected_store_pc = pc_offset();
switch (type.value()) {
case StoreType::kI32Store8:
......@@ -232,6 +250,114 @@ void LiftoffAssembler::Store(Register dst_addr, Register offset_reg,
}
}
void LiftoffAssembler::ChangeEndiannessLoad(LiftoffRegister dst, LoadType type,
LiftoffRegList pinned) {
bool is_float = false;
LiftoffRegister tmp = dst;
switch (type.value()) {
case LoadType::kI64Load8U:
case LoadType::kI64Load8S:
case LoadType::kI32Load8U:
case LoadType::kI32Load8S:
// No need to change endianness for byte size.
return;
case LoadType::kF32Load:
is_float = true;
tmp = GetUnusedRegister(kGpReg, pinned);
emit_type_conversion(kExprI32ReinterpretF32, tmp, dst);
V8_FALLTHROUGH;
case LoadType::kI64Load32U:
TurboAssembler::ByteSwapUnsigned(tmp.gp(), tmp.gp(), 4);
dsrl32(tmp.gp(), tmp.gp(), 0);
break;
case LoadType::kI32Load:
case LoadType::kI64Load32S:
TurboAssembler::ByteSwapSigned(tmp.gp(), tmp.gp(), 4);
dsra32(tmp.gp(), tmp.gp(), 0);
break;
case LoadType::kI32Load16S:
case LoadType::kI64Load16S:
TurboAssembler::ByteSwapSigned(tmp.gp(), tmp.gp(), 2);
dsra32(tmp.gp(), tmp.gp(), 0);
break;
case LoadType::kI32Load16U:
case LoadType::kI64Load16U:
TurboAssembler::ByteSwapUnsigned(tmp.gp(), tmp.gp(), 2);
dsrl32(tmp.gp(), tmp.gp(), 0);
break;
case LoadType::kF64Load:
is_float = true;
tmp = GetUnusedRegister(kGpReg, pinned);
emit_type_conversion(kExprI64ReinterpretF64, tmp, dst);
V8_FALLTHROUGH;
case LoadType::kI64Load:
TurboAssembler::ByteSwapSigned(tmp.gp(), tmp.gp(), 8);
break;
default:
UNREACHABLE();
}
if (is_float) {
switch (type.value()) {
case LoadType::kF32Load:
emit_type_conversion(kExprF32ReinterpretI32, dst, tmp);
break;
case LoadType::kF64Load:
emit_type_conversion(kExprF64ReinterpretI64, dst, tmp);
break;
default:
UNREACHABLE();
}
}
}
void LiftoffAssembler::ChangeEndiannessStore(LiftoffRegister src,
StoreType type,
LiftoffRegList pinned) {
bool is_float = false;
LiftoffRegister tmp = src;
switch (type.value()) {
case StoreType::kI64Store8:
case StoreType::kI32Store8:
// No need to change endianness for byte size.
return;
case StoreType::kF32Store:
is_float = true;
tmp = GetUnusedRegister(kGpReg, pinned);
emit_type_conversion(kExprI32ReinterpretF32, tmp, src);
V8_FALLTHROUGH;
case StoreType::kI32Store:
case StoreType::kI32Store16:
TurboAssembler::ByteSwapSigned(tmp.gp(), tmp.gp(), 4);
break;
case StoreType::kF64Store:
is_float = true;
tmp = GetUnusedRegister(kGpReg, pinned);
emit_type_conversion(kExprI64ReinterpretF64, tmp, src);
V8_FALLTHROUGH;
case StoreType::kI64Store:
case StoreType::kI64Store32:
case StoreType::kI64Store16:
TurboAssembler::ByteSwapSigned(tmp.gp(), tmp.gp(), 8);
break;
default:
UNREACHABLE();
}
if (is_float) {
switch (type.value()) {
case StoreType::kF32Store:
emit_type_conversion(kExprF32ReinterpretI32, src, tmp);
break;
case StoreType::kF64Store:
emit_type_conversion(kExprF64ReinterpretI64, src, tmp);
break;
default:
UNREACHABLE();
}
}
}
void LiftoffAssembler::LoadCallerFrameSlot(LiftoffRegister dst,
uint32_t caller_slot_idx,
ValueType type) {
......
......@@ -44,17 +44,28 @@ void LiftoffAssembler::FillInstanceInto(Register dst) {
void LiftoffAssembler::Load(LiftoffRegister dst, Register src_addr,
Register offset_reg, uint32_t offset_imm,
LoadType type, LiftoffRegList pinned,
uint32_t* protected_load_pc) {
uint32_t* protected_load_pc, bool is_load_mem) {
BAILOUT("Load");
}
void LiftoffAssembler::Store(Register dst_addr, Register offset_reg,
uint32_t offset_imm, LiftoffRegister src,
StoreType type, LiftoffRegList pinned,
uint32_t* protected_store_pc) {
uint32_t* protected_store_pc, bool is_store_mem) {
BAILOUT("Store");
}
void LiftoffAssembler::ChangeEndiannessLoad(LiftoffRegister dst, LoadType type,
LiftoffRegList pinned) {
BAILOUT("ChangeEndiannessLoad");
}
void LiftoffAssembler::ChangeEndiannessStore(LiftoffRegister src,
StoreType type,
LiftoffRegList pinned) {
BAILOUT("ChangeEndiannessStore");
}
void LiftoffAssembler::LoadCallerFrameSlot(LiftoffRegister dst,
uint32_t caller_slot_idx,
ValueType type) {
......
......@@ -44,17 +44,28 @@ void LiftoffAssembler::FillInstanceInto(Register dst) {
void LiftoffAssembler::Load(LiftoffRegister dst, Register src_addr,
Register offset_reg, uint32_t offset_imm,
LoadType type, LiftoffRegList pinned,
uint32_t* protected_load_pc) {
uint32_t* protected_load_pc, bool is_load_mem) {
BAILOUT("Load");
}
void LiftoffAssembler::Store(Register dst_addr, Register offset_reg,
uint32_t offset_imm, LiftoffRegister src,
StoreType type, LiftoffRegList pinned,
uint32_t* protected_store_pc) {
uint32_t* protected_store_pc, bool is_store_mem) {
BAILOUT("Store");
}
void LiftoffAssembler::ChangeEndiannessLoad(LiftoffRegister dst, LoadType type,
LiftoffRegList pinned) {
BAILOUT("ChangeEndiannessLoad");
}
void LiftoffAssembler::ChangeEndiannessStore(LiftoffRegister src,
StoreType type,
LiftoffRegList pinned) {
BAILOUT("ChangeEndiannessStore");
}
void LiftoffAssembler::LoadCallerFrameSlot(LiftoffRegister dst,
uint32_t caller_slot_idx,
ValueType type) {
......
......@@ -158,7 +158,7 @@ void LiftoffAssembler::FillInstanceInto(Register dst) {
void LiftoffAssembler::Load(LiftoffRegister dst, Register src_addr,
Register offset_reg, uint32_t offset_imm,
LoadType type, LiftoffRegList pinned,
uint32_t* protected_load_pc) {
uint32_t* protected_load_pc, bool is_load_mem) {
if (emit_debug_code() && offset_reg != no_reg) {
AssertZeroExtended(offset_reg);
}
......@@ -210,7 +210,7 @@ void LiftoffAssembler::Load(LiftoffRegister dst, Register src_addr,
void LiftoffAssembler::Store(Register dst_addr, Register offset_reg,
uint32_t offset_imm, LiftoffRegister src,
StoreType type, LiftoffRegList pinned,
uint32_t* protected_store_pc) {
uint32_t* protected_store_pc, bool is_store_mem) {
if (emit_debug_code() && offset_reg != no_reg) {
AssertZeroExtended(offset_reg);
}
......@@ -244,6 +244,17 @@ void LiftoffAssembler::Store(Register dst_addr, Register offset_reg,
}
}
void LiftoffAssembler::ChangeEndiannessLoad(LiftoffRegister dst, LoadType type,
LiftoffRegList pinned) {
// Nop.
}
void LiftoffAssembler::ChangeEndiannessStore(LiftoffRegister src,
StoreType type,
LiftoffRegList pinned) {
// Nop.
}
void LiftoffAssembler::LoadCallerFrameSlot(LiftoffRegister dst,
uint32_t caller_slot_idx,
ValueType type) {
......
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