Skip to content

Commit

Permalink
[vm] Add support for the Zalasr extension.
Browse files Browse the repository at this point in the history
TEST=ci
Change-Id: Ic1a98751ac6b46310e420b44f487720f0dc237c8
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/366162
Commit-Queue: Ryan Macnak <rmacnak@google.com>
Reviewed-by: Alexander Aprelev <aam@google.com>
  • Loading branch information
rmacnak-google authored and Commit Queue committed May 14, 2024
1 parent d73f534 commit d45304c
Show file tree
Hide file tree
Showing 7 changed files with 385 additions and 5 deletions.
131 changes: 127 additions & 4 deletions runtime/vm/compiler/assembler/assembler_riscv.cc
Expand Up @@ -1634,6 +1634,72 @@ void MicroAssembler::bseti(Register rd, Register rs1, intx_t shamt) {
EmitRType(BSET, shamt, rs1, F3_BSET, rd, OPIMM);
}

void MicroAssembler::lb(Register rd, Address addr, std::memory_order order) {
ASSERT(addr.offset() == 0);
ASSERT((order == std::memory_order_acquire) ||
(order == std::memory_order_acq_rel));
ASSERT(Supports(RV_Zalasr));
EmitRType(LOADORDERED, order, ZR, addr.base(), WIDTH8, rd, AMO);
}

void MicroAssembler::lh(Register rd, Address addr, std::memory_order order) {
ASSERT(addr.offset() == 0);
ASSERT((order == std::memory_order_acquire) ||
(order == std::memory_order_acq_rel));
ASSERT(Supports(RV_Zalasr));
EmitRType(LOADORDERED, order, ZR, addr.base(), WIDTH16, rd, AMO);
}

void MicroAssembler::lw(Register rd, Address addr, std::memory_order order) {
ASSERT(addr.offset() == 0);
ASSERT((order == std::memory_order_acquire) ||
(order == std::memory_order_acq_rel));
ASSERT(Supports(RV_Zalasr));
EmitRType(LOADORDERED, order, ZR, addr.base(), WIDTH32, rd, AMO);
}

void MicroAssembler::sb(Register rs2, Address addr, std::memory_order order) {
ASSERT(addr.offset() == 0);
ASSERT((order == std::memory_order_release) ||
(order == std::memory_order_acq_rel));
ASSERT(Supports(RV_Zalasr));
EmitRType(STOREORDERED, order, rs2, addr.base(), WIDTH8, ZR, AMO);
}

void MicroAssembler::sh(Register rs2, Address addr, std::memory_order order) {
ASSERT(addr.offset() == 0);
ASSERT((order == std::memory_order_release) ||
(order == std::memory_order_acq_rel));
ASSERT(Supports(RV_Zalasr));
EmitRType(STOREORDERED, order, rs2, addr.base(), WIDTH16, ZR, AMO);
}

void MicroAssembler::sw(Register rs2, Address addr, std::memory_order order) {
ASSERT(addr.offset() == 0);
ASSERT((order == std::memory_order_release) ||
(order == std::memory_order_acq_rel));
ASSERT(Supports(RV_Zalasr));
EmitRType(STOREORDERED, order, rs2, addr.base(), WIDTH32, ZR, AMO);
}

#if XLEN >= 64
void MicroAssembler::ld(Register rd, Address addr, std::memory_order order) {
ASSERT(addr.offset() == 0);
ASSERT((order == std::memory_order_acquire) ||
(order == std::memory_order_acq_rel));
ASSERT(Supports(RV_Zalasr));
EmitRType(LOADORDERED, order, ZR, addr.base(), WIDTH64, rd, AMO);
}

void MicroAssembler::sd(Register rs2, Address addr, std::memory_order order) {
ASSERT(addr.offset() == 0);
ASSERT((order == std::memory_order_release) ||
(order == std::memory_order_acq_rel));
ASSERT(Supports(RV_Zalasr));
EmitRType(STOREORDERED, order, rs2, addr.base(), WIDTH64, ZR, AMO);
}
#endif

void MicroAssembler::c_lwsp(Register rd, Address addr) {
ASSERT(rd != ZR);
ASSERT(addr.base() == SP);
Expand Down Expand Up @@ -2582,8 +2648,31 @@ void Assembler::LoadAcquire(Register dst,
const Address& address,
OperandSize size) {
ASSERT(dst != address.base());
Load(dst, address, size);
fence(HartEffects::kRead, HartEffects::kMemory);

if (Supports(RV_Zalasr)) {
Address addr = PrepareAtomicOffset(address.base(), address.offset());
switch (size) {
#if XLEN == 64
case kEightBytes:
ld(dst, addr, std::memory_order_acquire);
break;
#endif
case kFourBytes:
lw(dst, addr, std::memory_order_acquire);
break;
case kTwoBytes:
lh(dst, addr, std::memory_order_acquire);
break;
case kByte:
lb(dst, addr, std::memory_order_acquire);
break;
default:
UNREACHABLE();
}
} else {
Load(dst, address, size);
fence(HartEffects::kRead, HartEffects::kMemory);
}

if (FLAG_target_thread_sanitizer) {
if (address.offset() == 0) {
Expand All @@ -2598,8 +2687,33 @@ void Assembler::LoadAcquire(Register dst,
void Assembler::StoreRelease(Register src,
const Address& address,
OperandSize size) {
fence(HartEffects::kMemory, HartEffects::kWrite);
Store(src, address, size);
if (Supports(RV_Zalasr)) {
Address addr = PrepareAtomicOffset(address.base(), address.offset());
switch (size) {
#if XLEN == 64
case kEightBytes:
sd(src, addr, std::memory_order_release);
break;
#endif
case kUnsignedFourBytes:
case kFourBytes:
sw(src, addr, std::memory_order_release);
break;
case kUnsignedTwoBytes:
case kTwoBytes:
sh(src, addr, std::memory_order_release);
break;
case kUnsignedByte:
case kByte:
sb(src, addr, std::memory_order_release);
break;
default:
UNREACHABLE();
}
} else {
fence(HartEffects::kMemory, HartEffects::kWrite);
Store(src, address, size);
}
}

void Assembler::CompareWithMemoryValue(Register value,
Expand Down Expand Up @@ -3165,6 +3279,15 @@ Address Assembler::PrepareLargeOffset(Register base, int32_t offset) {
return Address(TMP2, lo);
}

Address Assembler::PrepareAtomicOffset(Register base, int32_t offset) {
ASSERT(base != TMP2);
if (offset == 0) {
return Address(base, 0);
}
AddImmediate(TMP2, base, offset);
return Address(TMP2, 0);
}

void Assembler::Load(Register dest, const Address& address, OperandSize sz) {
Address addr = PrepareLargeOffset(address.base(), address.offset());
switch (sz) {
Expand Down
14 changes: 14 additions & 0 deletions runtime/vm/compiler/assembler/assembler_riscv.h
Expand Up @@ -603,6 +603,19 @@ class MicroAssembler : public AssemblerBase {
void bset(Register rd, Register rs1, Register rs2);
void bseti(Register rd, Register rs1, intx_t shamt);

// ==== Zalasr: Load-acquire, store-release ====
void lb(Register rd, Address addr, std::memory_order order);
void lh(Register rd, Address addr, std::memory_order order);
void lw(Register rd, Address addr, std::memory_order order);
void sb(Register rs2, Address addr, std::memory_order order);
void sh(Register rs2, Address addr, std::memory_order order);
void sw(Register rs2, Address addr, std::memory_order order);

#if XLEN >= 64
void ld(Register rd, Address addr, std::memory_order order);
void sd(Register rs2, Address addr, std::memory_order order);
#endif

// ==== Dart Simulator Debugging ====
void SimulatorPrintObject(Register rs1);

Expand Down Expand Up @@ -1092,6 +1105,7 @@ class Assembler : public MicroAssembler {
OperandSize sz = kWordBytes) override;

Address PrepareLargeOffset(Register base, int32_t offset);
Address PrepareAtomicOffset(Register base, int32_t offset);
void Load(Register dest,
const Address& address,
OperandSize sz = kWordBytes) override;
Expand Down
118 changes: 118 additions & 0 deletions runtime/vm/compiler/assembler/assembler_riscv_test.cc
Expand Up @@ -7112,6 +7112,124 @@ ASSEMBLER_TEST_RUN(BitSetImmediate2, test) {
EXPECT_EQ(-1, Call(test->entry(), -1));
}

ASSEMBLER_TEST_GENERATE(LoadByteAcquire, assembler) {
__ SetExtensions(RV_GC | RV_Zalasr);
__ lb(A0, Address(A1), std::memory_order_acquire);
__ ret();
}
ASSEMBLER_TEST_RUN(LoadByteAcquire, test) {
EXPECT_DISASSEMBLY(
"3405852f lb.aq a0, (a1)\n"
" 8082 ret\n");

int8_t data = -42;
EXPECT_EQ(-42, Call(test->entry(), 0, reinterpret_cast<intx_t>(&data)));
}

ASSEMBLER_TEST_GENERATE(LoadHalfwordAcquire, assembler) {
__ SetExtensions(RV_GC | RV_Zalasr);
__ lh(A0, Address(A1), std::memory_order_acquire);
__ ret();
}
ASSEMBLER_TEST_RUN(LoadHalfwordAcquire, test) {
EXPECT_DISASSEMBLY(
"3405952f lh.aq a0, (a1)\n"
" 8082 ret\n");

int16_t data = -42;
EXPECT_EQ(-42, Call(test->entry(), 0, reinterpret_cast<intx_t>(&data)));
}

ASSEMBLER_TEST_GENERATE(LoadWordAcquire, assembler) {
__ SetExtensions(RV_GC | RV_Zalasr);
__ lw(A0, Address(A1), std::memory_order_acquire);
__ ret();
}
ASSEMBLER_TEST_RUN(LoadWordAcquire, test) {
EXPECT_DISASSEMBLY(
"3405a52f lw.aq a0, (a1)\n"
" 8082 ret\n");

int32_t data = -42;
EXPECT_EQ(-42, Call(test->entry(), 0, reinterpret_cast<intx_t>(&data)));
}

ASSEMBLER_TEST_GENERATE(StoreByteRelease, assembler) {
__ SetExtensions(RV_GC | RV_Zalasr);
__ sb(A0, Address(A1), std::memory_order_release);
__ ret();
}
ASSEMBLER_TEST_RUN(StoreByteRelease, test) {
EXPECT_DISASSEMBLY(
"3aa5802f sb.rl a0, (a1)\n"
" 8082 ret\n");

int8_t data = 0;
EXPECT_EQ(-42, Call(test->entry(), -42, reinterpret_cast<intx_t>(&data)));
EXPECT_EQ(-42, data);
}

ASSEMBLER_TEST_GENERATE(StoreHalfwordRelease, assembler) {
__ SetExtensions(RV_GC | RV_Zalasr);
__ sh(A0, Address(A1), std::memory_order_release);
__ ret();
}
ASSEMBLER_TEST_RUN(StoreHalfwordRelease, test) {
EXPECT_DISASSEMBLY(
"3aa5902f sh.rl a0, (a1)\n"
" 8082 ret\n");

int16_t data = 0;
EXPECT_EQ(-42, Call(test->entry(), -42, reinterpret_cast<intx_t>(&data)));
EXPECT_EQ(-42, data);
}

ASSEMBLER_TEST_GENERATE(StoreWordRelease, assembler) {
__ SetExtensions(RV_GC | RV_Zalasr);
__ sw(A0, Address(A1), std::memory_order_release);
__ ret();
}
ASSEMBLER_TEST_RUN(StoreWordRelease, test) {
EXPECT_DISASSEMBLY(
"3aa5a02f sw.rl a0, (a1)\n"
" 8082 ret\n");

int32_t data = 0;
EXPECT_EQ(-42, Call(test->entry(), -42, reinterpret_cast<intx_t>(&data)));
EXPECT_EQ(-42, data);
}

#if XLEN >= 64
ASSEMBLER_TEST_GENERATE(LoadDoubleWordAcquire, assembler) {
__ SetExtensions(RV_GC | RV_Zalasr);
__ ld(A0, Address(A1), std::memory_order_acquire);
__ ret();
}
ASSEMBLER_TEST_RUN(LoadDoubleWordAcquire, test) {
EXPECT_DISASSEMBLY(
"3405b52f ld.aq a0, (a1)\n"
" 8082 ret\n");

int64_t data = -42;
EXPECT_EQ(-42, Call(test->entry(), 0, reinterpret_cast<intx_t>(&data)));
}

ASSEMBLER_TEST_GENERATE(StoreDoubleWordRelease, assembler) {
__ SetExtensions(RV_GC | RV_Zalasr);
__ sd(A0, Address(A1), std::memory_order_release);
__ ret();
}
ASSEMBLER_TEST_RUN(StoreDoubleWordRelease, test) {
EXPECT_DISASSEMBLY(
"3aa5b02f sd.rl a0, (a1)\n"
" 8082 ret\n");

int64_t data = 0;
EXPECT_EQ(-42, Call(test->entry(), -42, reinterpret_cast<intx_t>(&data)));
EXPECT_EQ(-42, data);
}
#endif // XLEN >= 64

ASSEMBLER_TEST_GENERATE(LoadImmediate_MaxInt32, assembler) {
FLAG_use_compressed_instructions = true;
__ SetExtensions(RV_GC);
Expand Down
46 changes: 46 additions & 0 deletions runtime/vm/compiler/assembler/disassembler_riscv.cc
Expand Up @@ -79,6 +79,8 @@ class RISCVDisassembler {
void DisassembleMISCMEM(Instr instr);
void DisassembleSYSTEM(Instr instr);
void DisassembleAMO(Instr instr);
void DisassembleAMO8(Instr instr);
void DisassembleAMO16(Instr instr);
void DisassembleAMO32(Instr instr);
void DisassembleAMO64(Instr instr);
void DisassembleLOADFP(Instr instr);
Expand Down Expand Up @@ -1097,6 +1099,12 @@ void RISCVDisassembler::DisassembleSYSTEM(Instr instr) {

void RISCVDisassembler::DisassembleAMO(Instr instr) {
switch (instr.funct3()) {
case WIDTH8:
DisassembleAMO8(instr);
break;
case WIDTH16:
DisassembleAMO16(instr);
break;
case WIDTH32:
DisassembleAMO32(instr);
break;
Expand All @@ -1108,6 +1116,32 @@ void RISCVDisassembler::DisassembleAMO(Instr instr) {
}
}

void RISCVDisassembler::DisassembleAMO8(Instr instr) {
switch (instr.funct5()) {
case LOADORDERED:
Print("lb'order 'rd, ('rs1)", instr, RV_Zalasr);
break;
case STOREORDERED:
Print("sb'order 'rs2, ('rs1)", instr, RV_Zalasr);
break;
default:
UnknownInstruction(instr);
}
}

void RISCVDisassembler::DisassembleAMO16(Instr instr) {
switch (instr.funct5()) {
case LOADORDERED:
Print("lh'order 'rd, ('rs1)", instr, RV_Zalasr);
break;
case STOREORDERED:
Print("sh'order 'rs2, ('rs1)", instr, RV_Zalasr);
break;
default:
UnknownInstruction(instr);
}
}

void RISCVDisassembler::DisassembleAMO32(Instr instr) {
switch (instr.funct5()) {
case LR:
Expand Down Expand Up @@ -1143,6 +1177,12 @@ void RISCVDisassembler::DisassembleAMO32(Instr instr) {
case AMOMAXU:
Print("amomaxu.w'order 'rd, 'rs2, ('rs1)", instr, RV_A);
break;
case LOADORDERED:
Print("lw'order 'rd, ('rs1)", instr, RV_Zalasr);
break;
case STOREORDERED:
Print("sw'order 'rs2, ('rs1)", instr, RV_Zalasr);
break;
default:
UnknownInstruction(instr);
}
Expand Down Expand Up @@ -1184,6 +1224,12 @@ void RISCVDisassembler::DisassembleAMO64(Instr instr) {
case AMOMAXU:
Print("amomaxu.d'order 'rd, 'rs2, ('rs1)", instr, RV_A);
break;
case LOADORDERED:
Print("ld'order 'rd, ('rs1)", instr, RV_Zalasr);
break;
case STOREORDERED:
Print("sd'order 'rs2, ('rs1)", instr, RV_Zalasr);
break;
#endif
default:
UnknownInstruction(instr);
Expand Down

0 comments on commit d45304c

Please sign in to comment.