Skip to content

Commit

Permalink
More macro-assembler.
Browse files Browse the repository at this point in the history
  • Loading branch information
rmacnak committed Nov 2, 2024
1 parent 953474e commit d1590bb
Show file tree
Hide file tree
Showing 2 changed files with 165 additions and 39 deletions.
140 changes: 103 additions & 37 deletions vm/macroassembler_riscv.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ namespace psoup {
constexpr Register TMP = A5;
constexpr Register TMP2 = A6;

inline intx_t ImmLo(intx_t imm) {
return imm << (XLEN - 12) >> (XLEN - 12);
}
inline intx_t ImmHi(intx_t imm) {
return imm - ImmLo(imm);
}

// Higher level functions that may produce multiple instructions.
class MacroAssembler : public Assembler {
public:
Expand All @@ -30,40 +37,67 @@ class MacroAssembler : public Assembler {
}

void LoadImmediate(Register rd, intx_t imm) {
#if XLEN > 32
ASSERT(Utils::IsInt(32, imm));
#endif
intx_t lo = imm << (XLEN - 12) >> (XLEN - 12);
intx_t hi = (imm - lo) << (XLEN - 32) >> (XLEN - 32);
intx_t lo = ImmLo(imm);
intx_t hi = ImmHi(imm);
uintx_t uhi = hi;
if (hi == 0) {
addi(rd, ZERO, lo);
} else {
addi(rd, ZERO, imm);
} else if (IsUTypeImm(hi)) {
lui(rd, hi);
if (lo != 0) {
#if XLEN == 32
addi(rd, rd, lo);
#else
addiw(rd, rd, lo);
#endif
}
} else if (IsUTypeImm(imm ^ lo)) {
lui(rd, imm ^ lo);
xori(rd, rd, lo);
} else if (Supports(RV_Zbs) && Utils::IsPowerOfTwo(uhi)) {
bseti(rd, ZERO, Utils::ShiftForPowerOfTwo(uhi));
if (lo != 0) {
addi(rd, rd, lo);
}
} else {
int shift = 12;
while ((hi >> (shift + 1) << (shift + 1)) == hi) {
shift++;
}
LoadImmediate(rd, hi >> shift);
slli(rd, rd, shift);
if (lo != 0) {
addi(rd, rd, lo);
}
}
}

void Load(Register rd, Address address) {
Address PrepareLargeOffset(Address address) {
if (IsITypeImm(address.offset())) {
lx(rd, address);
return address;
} else {
int32_t offset = address.offset();
int32_t lo = offset << 20 >> 20; // Sign extend low 12 bits.
int32_t hi = offset - lo;
intx_t lo = ImmLo(address.offset());
intx_t hi = ImmHi(address.offset());
lui(TMP, hi);
add(TMP, TMP, address.base());
lx(rd, Address(TMP, lo));
return Address(TMP, lo);
}
}

void Load(Register rd, Address address) {
lx(rd, PrepareLargeOffset(address));
}

void Store(Register rs, Address address) {
sx(rs, PrepareLargeOffset(address));
}

void Move(Register rd, Register rs) {
if (rd != rs) {
mv(rd, rs);
}
}

void AddImmediate(Register rd, Register rs1, intptr_t imm) {
if (IsITypeImm(imm)) {
if (imm == 0) {
Move(rd, rs1);
} else if (IsITypeImm(imm)) {
addi(rd, rs1, imm);
} else {
ASSERT(rs1 != TMP);
Expand All @@ -73,7 +107,9 @@ class MacroAssembler : public Assembler {
}

void SubImmediate(Register rd, Register rs1, intptr_t imm) {
if (IsITypeImm(-imm)) {
if (imm == 0) {
Move(rd, rs1);
} else if (IsITypeImm(-imm)) {
addi(rd, rs1, -imm);
} else {
ASSERT(rs1 != TMP);
Expand All @@ -82,9 +118,37 @@ class MacroAssembler : public Assembler {
}
}

void MulImmediate(Register rd, Register rs1, intptr_t imm) {
if (imm == 1) {
Move(rd, rs1);
} else if (Utils::IsPowerOfTwo(imm)) {
slli(rd, rs1, Utils::ShiftForPowerOfTwo(imm));
} else {
LoadImmediate(TMP, imm);
mul(rd, rs1, TMP);
}
}

void AndImmediate(Register rd, Register rs1, intptr_t imm) {
if (IsITypeImm(imm)) {
uintx_t uimm = imm;
if (imm == -1) {
Move(rd, rs1);
#if XLEN >= 64
} else if (static_cast<int32_t>(imm) == -1) {
sextw(rd, rs1);
#endif
} else if (IsITypeImm(imm)) {
andi(rd, rs1, imm);
} else if (Supports(RV_Zbs) && Utils::IsPowerOfTwo(~uimm)) {
bclri(rd, rs1, Utils::ShiftForPowerOfTwo(~uimm));
} else if (Utils::IsPowerOfTwo(uimm + 1)) {
intptr_t shift = Utils::ShiftForPowerOfTwo(uimm + 1);
if (Supports(RV_Zbb) && (shift == 16)) {
zexth(rd, rs1);
} else {
slli(rd, rs1, XLEN - shift);
srli(rd, rd, XLEN - shift);
}
} else {
ASSERT(rs1 != TMP);
LoadImmediate(TMP, imm);
Expand All @@ -93,8 +157,13 @@ class MacroAssembler : public Assembler {
}

void OrImmediate(Register rd, Register rs1, intptr_t imm) {
if (IsITypeImm(imm)) {
uintx_t uimm = imm;
if (imm == 0) {
Move(rd, rs1);
} else if (IsITypeImm(imm)) {
ori(rd, rs1, imm);
} else if (Supports(RV_Zbs) && Utils::IsPowerOfTwo(uimm)) {
bseti(rd, rs1, Utils::ShiftForPowerOfTwo(uimm));
} else {
ASSERT(rs1 != TMP);
LoadImmediate(TMP, imm);
Expand All @@ -103,23 +172,26 @@ class MacroAssembler : public Assembler {
}

void XorImmediate(Register rd, Register rs1, intptr_t imm) {
if (IsITypeImm(imm)) {
uintx_t uimm = imm;
if (imm == 0) {
Move(rd, rs1);
} else if (IsITypeImm(imm)) {
xori(rd, rs1, imm);
} else if (Supports(RV_Zbs) && Utils::IsPowerOfTwo(uimm)) {
binvi(rd, rs1, Utils::ShiftForPowerOfTwo(uimm));
} else {
ASSERT(rs1 != TMP);
LoadImmediate(TMP, imm);
xor_(rd, rs1, TMP);
}
}

void tbnz(Register rs1, intptr_t imm, Label* label) {
if (IsITypeImm(imm)) {
andi(TMP, rs1, imm);
bnez(TMP, label);
void tbnz(Register rs1, intptr_t bit, Label* label) {
if (bit == XLEN - 1) {
bltz(rs1, label);
} else {
LoadImmediate(TMP, imm);
and_(TMP, TMP, rs1);
bnez(TMP, label);
slli(TMP, rs1, XLEN - 1 - bit);
bltz(TMP, label);
}
}

Expand Down Expand Up @@ -323,12 +395,6 @@ constexpr Register BYTE = T6; // At call.

class JITAssembler : public MacroAssembler {
public:
void MoveRegister(Register rd, Register rs) {
if (rd != rs) {
mv(rd, rs);
}
}

void EnterFrame(intptr_t size) {
addi(SP, SP, 4 * kWordSize + size);
sw(RA, Address(SP, 3 * kWordSize + size));
Expand Down Expand Up @@ -476,7 +542,7 @@ class JITAssembler : public MacroAssembler {
}

void Return(Register result) {
MoveRegister(A0, result); // Likely no-op.
Move(A0, result); // Likely no-op.
lw(RA, Address(SP, 0));
lw(PP, Address(SP, 0));
lw(S0, Address(SP, 0));
Expand All @@ -488,7 +554,7 @@ class JITAssembler : public MacroAssembler {
}

void NonLocalReturn() {
// MoveRegister(A0, result); // Likely no-op.
// Move(A0, result); // Likely no-op.
lw(T0, Address(THR, 0));
jr(T0); // Maybe not a tail so the NLR stub can look at metadata for this
// method?
Expand Down
64 changes: 62 additions & 2 deletions vm/test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9310,6 +9310,23 @@ UNIT_TEST(BitSetImmediate2) {
EXPECT_EQ(-1, simulator.Call(buffer, -1));
}

UNIT_TEST(MacroLoadImmediate_LoadImmediates) {
for (intptr_t base = -8; base < 7; base++) {
for (intptr_t shift = 0; shift < XLEN; shift++) {
for (intptr_t offset = -16; offset < 15; offset++) {
intx_t imm = (base << shift) + offset;

MacroAssembler assembler(RV_GCB);
__ LoadImmediate(A0, imm);
__ ret();

Simulator simulator;
EXPECT_EQ(imm, simulator.Call(assembler.buffer()));
}
}
}
}

UNIT_TEST(MacroLoadImmediate_MaxInt32) {
MacroAssembler assembler(RV_GC);
__ LoadImmediate(A0, kMaxInt32);
Expand All @@ -9329,7 +9346,7 @@ UNIT_TEST(MacroLoadImmediate_MaxInt32) {
#elif XLEN == 64
EXPECT_STREQ(
" 80000537 lui a0, -2147483648\n"
" 357d addiw a0, a0, -1\n"
" fff54513 not a0, a0\n"
" 8082 ret\n",
disassembly);
#endif
Expand Down Expand Up @@ -9359,6 +9376,49 @@ UNIT_TEST(MacroLoadImmediate_MinInt32) {
EXPECT_EQ(kMinInt32, simulator.Call(buffer));
}

#if XLEN >= 64
UNIT_TEST(MacroLoadImmediate_MinInt64) {
MacroAssembler assembler(RV_GCB);
__ LoadImmediate(A0, kMinInt64);
__ ret();

void* buffer = assembler.buffer();
size_t size = assembler.size();

Disassembler disassembler(RV_GCB);
char* disassembly = disassembler.Disassemble(buffer, size);
EXPECT_STREQ(
" 2bf01513 bseti a0, zero, 0x3f\n"
" 8082 ret\n",
disassembly);
free(disassembly);

Simulator simulator;
EXPECT_EQ(kMinInt64, simulator.Call(buffer));
}

UNIT_TEST(MacroLoadImmediate_MaxInt64) {
MacroAssembler assembler(RV_GCB);
__ LoadImmediate(A0, kMaxInt64);
__ ret();

void* buffer = assembler.buffer();
size_t size = assembler.size();

Disassembler disassembler(RV_GCB);
char* disassembly = disassembler.Disassemble(buffer, size);
EXPECT_STREQ(
" 2bf01513 bseti a0, zero, 0x3f\n"
" 157d addi a0, a0, -1\n"
" 8082 ret\n",
disassembly);
free(disassembly);

Simulator simulator;
EXPECT_EQ(kMaxInt64, simulator.Call(buffer));
}
#endif // XLEN >= 64

UNIT_TEST(MacroAddBranchOverflow) {
MacroAssembler assembler(RV_GC);
Label overflow;
Expand Down Expand Up @@ -9526,7 +9586,7 @@ TEST_ENCODING(intptr_t, CShamt)
} // namespace psoup

int main(int argc, char** argv) {
psoup::Memory::Startup(4 * MB);
psoup::Memory::Startup(128 * MB);
for (psoup::UnitTest* test = psoup::tests_; test != nullptr;
test = test->next()) {
test->Run();
Expand Down

0 comments on commit d1590bb

Please sign in to comment.