Commit 0dbcfe1f authored by Lu Yahan's avatar Lu Yahan Committed by V8 LUCI CQ

[riscv64] Improve unaligned memory accesses

This commit allows using unaligned load/store, which is more efficient
for 2 bytes,4 bytes and 8 bytes memory access.
Use RISCV_HAS_NO_UNALIGNED to control whether enable the fast path or not.

Change-Id: I1d321e6e5fa5bc31541c8dbfe582881d80743483
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3329803Reviewed-by: 's avatarji qiu <qiuji@iscas.ac.cn>
Commit-Queue: Yahan Lu <yahan@iscas.ac.cn>
Cr-Commit-Position: refs/heads/main@{#78427}
parent 64a23393
...@@ -3306,8 +3306,13 @@ InstructionSelector::SupportedMachineOperatorFlags() { ...@@ -3306,8 +3306,13 @@ InstructionSelector::SupportedMachineOperatorFlags() {
// static // static
MachineOperatorBuilder::AlignmentRequirements MachineOperatorBuilder::AlignmentRequirements
InstructionSelector::AlignmentRequirements() { InstructionSelector::AlignmentRequirements() {
#ifdef RISCV_HAS_NO_UNALIGNED
return MachineOperatorBuilder::AlignmentRequirements:: return MachineOperatorBuilder::AlignmentRequirements::
NoUnalignedAccessSupport(); NoUnalignedAccessSupport();
#else
return MachineOperatorBuilder::AlignmentRequirements::
FullUnalignedAccessSupport();
#endif
} }
#undef SIMD_BINOP_LIST #undef SIMD_BINOP_LIST
......
...@@ -2413,14 +2413,14 @@ T Simulator::ReadMem(int64_t addr, Instruction* instr) { ...@@ -2413,14 +2413,14 @@ T Simulator::ReadMem(int64_t addr, Instruction* instr) {
addr, reinterpret_cast<intptr_t>(instr)); addr, reinterpret_cast<intptr_t>(instr));
DieOrDebug(); DieOrDebug();
} }
#ifndef V8_COMPRESS_POINTERS // TODO(RISCV): v8:11812 #if !defined(V8_COMPRESS_POINTERS) && defined(RISCV_HAS_NO_UNALIGNED)
// // check for natural alignment // check for natural alignment
// if (!FLAG_riscv_c_extension && ((addr & (sizeof(T) - 1)) != 0)) { if (!FLAG_riscv_c_extension && ((addr & (sizeof(T) - 1)) != 0)) {
// PrintF("Unaligned read at 0x%08" PRIx64 " , pc=0x%08" V8PRIxPTR "\n", PrintF("Unaligned read at 0x%08" PRIx64 " , pc=0x%08" V8PRIxPTR "\n",
// addr, addr,
// reinterpret_cast<intptr_t>(instr)); reinterpret_cast<intptr_t>(instr));
// DieOrDebug(); DieOrDebug();
// } }
#endif #endif
T* ptr = reinterpret_cast<T*>(addr); T* ptr = reinterpret_cast<T*>(addr);
T value = *ptr; T value = *ptr;
...@@ -2436,7 +2436,7 @@ void Simulator::WriteMem(int64_t addr, T value, Instruction* instr) { ...@@ -2436,7 +2436,7 @@ void Simulator::WriteMem(int64_t addr, T value, Instruction* instr) {
addr, reinterpret_cast<intptr_t>(instr)); addr, reinterpret_cast<intptr_t>(instr));
DieOrDebug(); DieOrDebug();
} }
#ifndef V8_COMPRESS_POINTERS // TODO(RISCV): v8:11812 #if !defined(V8_COMPRESS_POINTERS) && defined(RISCV_HAS_NO_UNALIGNED)
// check for natural alignment // check for natural alignment
if (!FLAG_riscv_c_extension && ((addr & (sizeof(T) - 1)) != 0)) { if (!FLAG_riscv_c_extension && ((addr & (sizeof(T) - 1)) != 0)) {
PrintF("Unaligned write at 0x%08" PRIx64 " , pc=0x%08" V8PRIxPTR "\n", addr, PrintF("Unaligned write at 0x%08" PRIx64 " , pc=0x%08" V8PRIxPTR "\n", addr,
......
...@@ -1144,9 +1144,9 @@ void RegExpMacroAssemblerRISCV::ClearRegisters(int reg_from, int reg_to) { ...@@ -1144,9 +1144,9 @@ void RegExpMacroAssemblerRISCV::ClearRegisters(int reg_from, int reg_to) {
__ Sd(a0, register_location(reg)); __ Sd(a0, register_location(reg));
} }
} }
#ifdef RISCV_HAS_NO_UNALIGNED
bool RegExpMacroAssemblerRISCV::CanReadUnaligned() const { return false; } bool RegExpMacroAssemblerRISCV::CanReadUnaligned() const { return false; }
#endif
// Private methods: // Private methods:
void RegExpMacroAssemblerRISCV::CallCheckStackGuardState(Register scratch) { void RegExpMacroAssemblerRISCV::CallCheckStackGuardState(Register scratch) {
...@@ -1328,20 +1328,40 @@ void RegExpMacroAssemblerRISCV::CheckStackLimit() { ...@@ -1328,20 +1328,40 @@ void RegExpMacroAssemblerRISCV::CheckStackLimit() {
void RegExpMacroAssemblerRISCV::LoadCurrentCharacterUnchecked(int cp_offset, void RegExpMacroAssemblerRISCV::LoadCurrentCharacterUnchecked(int cp_offset,
int characters) { int characters) {
Register offset = current_input_offset(); Register offset = current_input_offset();
// If unaligned load/stores are not supported then this function must only
// be used to load a single character at a time.
if (!CanReadUnaligned()) {
DCHECK_EQ(1, characters);
}
if (cp_offset != 0) { if (cp_offset != 0) {
// s3 is not being used to store the capture start index at this point. // t3 is not being used to store the capture start index at this point.
__ Add64(s3, current_input_offset(), Operand(cp_offset * char_size())); __ Add64(t3, current_input_offset(), Operand(cp_offset * char_size()));
offset = s3; offset = t3;
} }
// We assume that we cannot do unaligned loads on RISC-V, so this function
// must only be used to load a single character at a time.
DCHECK_EQ(1, characters);
__ Add64(t1, end_of_input_address(), Operand(offset));
if (mode_ == LATIN1) { if (mode_ == LATIN1) {
__ Lbu(current_character(), MemOperand(t1, 0)); if (characters == 4) {
__ Add64(kScratchReg, end_of_input_address(), offset);
__ Lwu(current_character(), MemOperand(kScratchReg));
} else if (characters == 2) {
__ Add64(kScratchReg, end_of_input_address(), offset);
__ Lhu(current_character(), MemOperand(kScratchReg));
} else {
DCHECK_EQ(1, characters);
__ Add64(kScratchReg, end_of_input_address(), offset);
__ Lbu(current_character(), MemOperand(kScratchReg));
}
} else { } else {
DCHECK(mode_ == UC16); DCHECK(mode_ == UC16);
__ Lhu(current_character(), MemOperand(t1, 0)); if (characters == 2) {
__ Add64(kScratchReg, end_of_input_address(), offset);
__ Lwu(current_character(), MemOperand(kScratchReg));
} else {
DCHECK_EQ(1, characters);
__ Add64(kScratchReg, end_of_input_address(), offset);
__ Lhu(current_character(), MemOperand(kScratchReg));
}
} }
} }
......
...@@ -83,8 +83,9 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerRISCV ...@@ -83,8 +83,9 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerRISCV
void WriteCurrentPositionToRegister(int reg, int cp_offset) override; void WriteCurrentPositionToRegister(int reg, int cp_offset) override;
void ClearRegisters(int reg_from, int reg_to) override; void ClearRegisters(int reg_from, int reg_to) override;
void WriteStackPointerToRegister(int reg) override; void WriteStackPointerToRegister(int reg) override;
#ifdef RISCV_HAS_NO_UNALIGNED
bool CanReadUnaligned() const override; bool CanReadUnaligned() const override;
#endif
// Called from RegExp if the stack-guard is triggered. // Called from RegExp if the stack-guard is triggered.
// If the code object is relocated, the return address is fixed before // If the code object is relocated, the return address is fixed before
// returning. // returning.
......
...@@ -123,19 +123,19 @@ inline void Store(LiftoffAssembler* assm, Register base, int32_t offset, ...@@ -123,19 +123,19 @@ inline void Store(LiftoffAssembler* assm, Register base, int32_t offset,
MemOperand dst(base, offset); MemOperand dst(base, offset);
switch (kind) { switch (kind) {
case kI32: case kI32:
assm->Usw(src.gp(), dst); assm->Sw(src.gp(), dst);
break; break;
case kI64: case kI64:
case kOptRef: case kOptRef:
case kRef: case kRef:
case kRtt: case kRtt:
assm->Usd(src.gp(), dst); assm->Sd(src.gp(), dst);
break; break;
case kF32: case kF32:
assm->UStoreFloat(src.fp(), dst, kScratchReg); assm->StoreFloat(src.fp(), dst);
break; break;
case kF64: case kF64:
assm->UStoreDouble(src.fp(), dst, kScratchReg); assm->StoreDouble(src.fp(), dst);
break; break;
default: default:
UNREACHABLE(); UNREACHABLE();
...@@ -539,27 +539,27 @@ void LiftoffAssembler::Load(LiftoffRegister dst, Register src_addr, ...@@ -539,27 +539,27 @@ void LiftoffAssembler::Load(LiftoffRegister dst, Register src_addr,
break; break;
case LoadType::kI32Load16U: case LoadType::kI32Load16U:
case LoadType::kI64Load16U: case LoadType::kI64Load16U:
TurboAssembler::Ulhu(dst.gp(), src_op); TurboAssembler::Lhu(dst.gp(), src_op);
break; break;
case LoadType::kI32Load16S: case LoadType::kI32Load16S:
case LoadType::kI64Load16S: case LoadType::kI64Load16S:
TurboAssembler::Ulh(dst.gp(), src_op); TurboAssembler::Lh(dst.gp(), src_op);
break; break;
case LoadType::kI64Load32U: case LoadType::kI64Load32U:
TurboAssembler::Ulwu(dst.gp(), src_op); TurboAssembler::Lwu(dst.gp(), src_op);
break; break;
case LoadType::kI32Load: case LoadType::kI32Load:
case LoadType::kI64Load32S: case LoadType::kI64Load32S:
TurboAssembler::Ulw(dst.gp(), src_op); TurboAssembler::Lw(dst.gp(), src_op);
break; break;
case LoadType::kI64Load: case LoadType::kI64Load:
TurboAssembler::Uld(dst.gp(), src_op); TurboAssembler::Ld(dst.gp(), src_op);
break; break;
case LoadType::kF32Load: case LoadType::kF32Load:
TurboAssembler::ULoadFloat(dst.fp(), src_op, kScratchReg); TurboAssembler::LoadFloat(dst.fp(), src_op);
break; break;
case LoadType::kF64Load: case LoadType::kF64Load:
TurboAssembler::ULoadDouble(dst.fp(), src_op, kScratchReg); TurboAssembler::LoadDouble(dst.fp(), src_op);
break; break;
case LoadType::kS128Load: { case LoadType::kS128Load: {
VU.set(kScratchReg, E8, m1); VU.set(kScratchReg, E8, m1);
...@@ -610,20 +610,20 @@ void LiftoffAssembler::Store(Register dst_addr, Register offset_reg, ...@@ -610,20 +610,20 @@ void LiftoffAssembler::Store(Register dst_addr, Register offset_reg,
break; break;
case StoreType::kI32Store16: case StoreType::kI32Store16:
case StoreType::kI64Store16: case StoreType::kI64Store16:
TurboAssembler::Ush(src.gp(), dst_op); TurboAssembler::Sh(src.gp(), dst_op);
break; break;
case StoreType::kI32Store: case StoreType::kI32Store:
case StoreType::kI64Store32: case StoreType::kI64Store32:
TurboAssembler::Usw(src.gp(), dst_op); TurboAssembler::Sw(src.gp(), dst_op);
break; break;
case StoreType::kI64Store: case StoreType::kI64Store:
TurboAssembler::Usd(src.gp(), dst_op); TurboAssembler::Sd(src.gp(), dst_op);
break; break;
case StoreType::kF32Store: case StoreType::kF32Store:
TurboAssembler::UStoreFloat(src.fp(), dst_op, kScratchReg); TurboAssembler::StoreFloat(src.fp(), dst_op);
break; break;
case StoreType::kF64Store: case StoreType::kF64Store:
TurboAssembler::UStoreDouble(src.fp(), dst_op, kScratchReg); TurboAssembler::StoreDouble(src.fp(), dst_op);
break; break;
case StoreType::kS128Store: { case StoreType::kS128Store: {
VU.set(kScratchReg, E8, m1); VU.set(kScratchReg, E8, m1);
...@@ -3575,7 +3575,7 @@ void LiftoffAssembler::emit_s128_set_if_nan(Register dst, LiftoffRegister src, ...@@ -3575,7 +3575,7 @@ void LiftoffAssembler::emit_s128_set_if_nan(Register dst, LiftoffRegister src,
} }
void LiftoffAssembler::StackCheck(Label* ool_code, Register limit_address) { void LiftoffAssembler::StackCheck(Label* ool_code, Register limit_address) {
TurboAssembler::Uld(limit_address, MemOperand(limit_address)); TurboAssembler::Ld(limit_address, MemOperand(limit_address));
TurboAssembler::Branch(ool_code, ule, sp, Operand(limit_address)); TurboAssembler::Branch(ool_code, ule, sp, Operand(limit_address));
} }
......
...@@ -1056,19 +1056,6 @@ std::ostream& operator<<(std::ostream& os, const MemoryAccessImm1& acc) { ...@@ -1056,19 +1056,6 @@ std::ostream& operator<<(std::ostream& os, const MemoryAccessImm1& acc) {
return os << acc.type; return os << acc.type;
} }
struct MemoryAccessImm2 {
MachineType type;
ArchOpcode store_opcode;
ArchOpcode store_opcode_unaligned;
bool (InstructionSelectorTest::Stream::*val_predicate)(
const InstructionOperand*) const;
const int32_t immediates[40];
};
std::ostream& operator<<(std::ostream& os, const MemoryAccessImm2& acc) {
return os << acc.type;
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Loads and stores immediate values // Loads and stores immediate values
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
...@@ -1181,6 +1168,20 @@ const MemoryAccessImm1 kMemoryAccessImmMoreThan16bit[] = { ...@@ -1181,6 +1168,20 @@ const MemoryAccessImm1 kMemoryAccessImmMoreThan16bit[] = {
&InstructionSelectorTest::Stream::IsInteger, &InstructionSelectorTest::Stream::IsInteger,
{-65000, -55000, 32777, 55000, 65000}}}; {-65000, -55000, 32777, 55000, 65000}}};
#ifdef RISCV_HAS_NO_UNALIGNED
struct MemoryAccessImm2 {
MachineType type;
ArchOpcode store_opcode;
ArchOpcode store_opcode_unaligned;
bool (InstructionSelectorTest::Stream::*val_predicate)(
const InstructionOperand*) const;
const int32_t immediates[40];
};
std::ostream& operator<<(std::ostream& os, const MemoryAccessImm2& acc) {
return os << acc.type;
}
const MemoryAccessImm2 kMemoryAccessesImmUnaligned[] = { const MemoryAccessImm2 kMemoryAccessesImmUnaligned[] = {
{MachineType::Int16(), {MachineType::Int16(),
kRiscvUsh, kRiscvUsh,
...@@ -1222,7 +1223,7 @@ const MemoryAccessImm2 kMemoryAccessesImmUnaligned[] = { ...@@ -1222,7 +1223,7 @@ const MemoryAccessImm2 kMemoryAccessesImmUnaligned[] = {
-89, -87, -86, -82, -44, -23, -3, 0, 7, 10, -89, -87, -86, -82, -44, -23, -3, 0, 7, 10,
39, 52, 69, 71, 91, 92, 107, 109, 115, 124, 39, 52, 69, 71, 91, 92, 107, 109, 115, 124,
286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}}}; 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}}};
#endif
} // namespace } // namespace
using InstructionSelectorMemoryAccessTest = using InstructionSelectorMemoryAccessTest =
...@@ -1327,6 +1328,7 @@ INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest, ...@@ -1327,6 +1328,7 @@ INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest,
InstructionSelectorMemoryAccessImmTest, InstructionSelectorMemoryAccessImmTest,
::testing::ValuesIn(kMemoryAccessesImm)); ::testing::ValuesIn(kMemoryAccessesImm));
#ifdef RISCV_HAS_NO_UNALIGNED
using InstructionSelectorMemoryAccessUnalignedImmTest = using InstructionSelectorMemoryAccessUnalignedImmTest =
InstructionSelectorTestWithParam<MemoryAccessImm2>; InstructionSelectorTestWithParam<MemoryAccessImm2>;
...@@ -1358,7 +1360,7 @@ TEST_P(InstructionSelectorMemoryAccessUnalignedImmTest, StoreZero) { ...@@ -1358,7 +1360,7 @@ TEST_P(InstructionSelectorMemoryAccessUnalignedImmTest, StoreZero) {
INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest, INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest,
InstructionSelectorMemoryAccessUnalignedImmTest, InstructionSelectorMemoryAccessUnalignedImmTest,
::testing::ValuesIn(kMemoryAccessesImmUnaligned)); ::testing::ValuesIn(kMemoryAccessesImmUnaligned));
#endif
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Load/store offsets more than 16 bits. // Load/store offsets more than 16 bits.
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
......
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