Skip to content

Initial RISC-V support#759

Draft
ogalland-tob wants to merge 33 commits intolifting-bits:masterfrom
brunoproduit:ogalland-tob/initial-riscv-support
Draft

Initial RISC-V support#759
ogalland-tob wants to merge 33 commits intolifting-bits:masterfrom
brunoproduit:ogalland-tob/initial-riscv-support

Conversation

@ogalland-tob
Copy link
Copy Markdown
Collaborator

Add initial support for RISC-V, as per #757, based on redthing1@001594a and redthing1@3055839. This branch also includes changes from #758.

Things that remain to be done:

  • Some RISC-V unit tests aren't passing and are thus disabled
  • End-to-end testing, besides unit tests
  • Test using official RISC-V ISA tests
  • Not all extensions are implemented
  • Implemented using Claude code heavily, code quality might be an issue

brunoproduit and others added 30 commits February 19, 2026 15:00
Add a Nix flake that builds remill and its XED dependency
using LLVM 17, with patched Ghidra sources for Sleigh.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace manual state manipulation (zero-init, set fields, ExecuteOne,
EXPECT_EQ) with the declarative TestOutputSpec pattern used by PPC and
Thumb tests. This gains randomized state testing, instruction category
validation, and consistency across architectures.

Reorganize test files by RISC-V extension (M, A, C, F, D, Zicsr) with
base integer tests in TestLifting{32,64}.cpp. Add RISCVTestSpec.h with
register accessor maps and RISCVTestSpecRunner template.

Atomic (A) and Zicsr tests keep the manual ExecuteOne pattern due to
uint8_t reserve fields and Sleigh CSRRW 64-bit padding respectively.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move base integer instruction tests from TestLifting32.cpp and
TestLifting64.cpp into RV32I.cpp and RV64I.cpp respectively, matching
the pattern used by other extensions (M, A, C, F, D, Zicsr). The
TestLifting files now contain only the main() entry point.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add test coverage for instructions that were not previously tested:
- SLTI/SLTIU (signed/unsigned compare with immediate)
- AND/OR/XOR register-register forms
- FENCE (memory ordering)
- RV64I W-ops: SUBW, SLLIW, SRLIW, SRAIW, SLLW, SRLW, SRAW

Also adds kOpcodeMiscMem constant to TestUtil.h for FENCE encoding.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Handle the Sleigh fence() CALLOTHER pcode operation in
SleighLifter::HandleCallOther by emitting a __remill_barrier_store_load
intrinsic call. Add no-op barrier stubs to the test runner so the JIT
can resolve barrier intrinsics at runtime.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add BitsFromFloat/BitsFromDouble type-punning utilities, FMA (R4-type)
instruction encoder and opcodes, and compressed instruction encoders
(C.LI, C.MV, C.ADD, C.SLLI, C.ADDI4SPN, C.ADDI16SP, C.LUI, C.SRLI,
C.SRAI, C.ANDI, C.SUB, C.XOR, C.OR, C.AND, C.SUBW, C.ADDW, C.LWSP,
C.SWSP, C.ADDIW, C.LD, C.SD, C.LDSP, C.SDSP, and floating-point
load/store variants) to TestUtil.h for use across all extension test
suites.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Cover all M-extension instructions: MULH, MULHSU, MULHU for RV32M;
MULW, DIVW, DIVUW, REMW, REMUW plus the RV32M set for RV64M.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Cover all A-extension instructions: LR.W, SC.W, AMOSWAP.W, AMOADD.W,
AMOAND.W, AMOOR.W, AMOXOR.W, AMOMIN.W, AMOMAX.W, AMOMINU.W,
AMOMAXU.W for RV32A; plus LR.D, SC.D and all doubleword AMO variants
for RV64A.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Cover all Zicsr instructions: CSRRW, CSRRS, CSRRC, CSRRWI, CSRRSI,
CSRRCI for both RV32 and RV64.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Cover all F-extension instructions: FDIV.S, FSQRT.S, FSGNJ.S,
FSGNJN.S, FSGNJX.S, FMIN.S, FMAX.S, FMV.X.W, FCVT.W.S, FCVT.WU.S,
FCVT.S.WU, FCLASS.S, FMADD.S, FMSUB.S, FNMSUB.S, FNMADD.S for RV32F;
plus FCVT.L.S, FCVT.LU.S, FCVT.S.L, FCVT.S.LU for RV64F.
Deduplicate BitsFromFloat into TestUtil.h.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Cover all D-extension instructions: FDIV.D, FSQRT.D, FSGNJ.D,
FSGNJN.D, FSGNJX.D, FMIN.D, FMAX.D, FCVT.S.D, FCVT.D.S, FCVT.W.D,
FCVT.WU.D, FCVT.D.W, FCVT.D.WU, FCLASS.D, FMADD.D, FMSUB.D,
FNMSUB.D, FNMADD.D for RV32D; plus FMV.X.D, FMV.D.X, FCVT.L.D,
FCVT.LU.D, FCVT.D.L, FCVT.D.LU for RV64D.
Deduplicate BitsFromFloat/BitsFromDouble into TestUtil.h.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Cover all C-extension instructions: C.ADDI4SPN, C.JAL, C.ADDI16SP,
C.LUI, C.SRLI, C.SRAI, C.ANDI, C.SUB, C.XOR, C.OR, C.AND, C.SLLI,
C.LWSP, C.SWSP, C.EBREAK, C.FLW, C.FSW, C.FLD, C.FSD, C.FLWSP,
C.FSWSP, C.FLDSP, C.FSDSP for RV32C; plus C.ADDIW, C.SUBW, C.ADDW,
C.LD, C.SD, C.LDSP, C.SDSP for RV64C.
Deduplicate BitsFromFloat/BitsFromDouble into TestUtil.h.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sleigh models ebreak/ecall with CALLOTHER pcode ops, which the generic
control-flow analysis cannot classify. Override DecodeInstruction to set
the correct category (kCategoryError for ebreak/c.ebreak,
kCategoryAsyncHyperCall for ecall).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
GetFloatTypeOfByteSize was called with input_var.size, so float-to-float
conversions like fcvt.s.d (double to single) produced the input type as
the target, making the FPCast a no-op. Use outvar->size to get the
correct target float type, matching how FLOAT_INT2FLOAT and FLOAT_TRUNC
already work.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix ebreak PC postcondition: ebreak advances PC past the instruction
  (0xAE00 -> 0xAE02), matching the lifter's actual behavior.
- Disable 5 tests that fail due to upstream Ghidra Sleigh spec bugs:
  - CompressedFlw: c.flw widens LOAD to 8 bytes instead of using fassignS
  - FcvtWD/FcvtWuD/FcvtWS/FcvtWuS on RV64: rdW doesn't sign-extend to
    XLEN as the RISC-V spec requires
  Both require patching the .sinc files in Ghidra's RISC-V processor.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When a Sleigh subconstructor exports a local variable initialized from
a register (e.g., rdW: r0711 is r0711 { local tmp = r0711; export tmp; }),
writes to the exported unique never propagated back to the actual register
in the State struct. This caused instructions like fcvt.w.d (which write
their result through rdW) to silently discard their output.

Detect register→unique COPY ops and alias the unique's storage to the
register's State pointer via UniqueRegSpace::MapToPointer, so subsequent
stores through the unique write directly to the register.

Fixes FcvtWD and FcvtWuD on RV32.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
fclass.s/fclass.d: Ghidra Sleigh spec body is #TODO (unimplemented).
c.flwsp: Same Sleigh encoding bug as c.flw, needs riscv.rvc.sinc patch.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Three fixes for RISC-V floating-point move instructions (fmv.x.w,
fmv.x.d, fmv.d.x, fmv.w.x):

1. Handle register-space LOAD/STORE pcode ops. Sleigh uses
   *[register]:N addr to load/store from the register address space
   (not RAM). Resolve the address to a State struct register when
   possible, falling back to the subconstructor's unique alloca when
   the address comes from &subconstructor.

2. Replace register→unique aliasing (MapToPointer) with deferred
   writeback. The alias approach broke instructions that save a
   register value before modifying it (e.g., csrrwi's local oldcsr =
   csr) because the alias made both variables share the same storage.
   The writeback approach keeps separate allocas and propagates writes
   from the unique back to the register.

3. Use the full register size for writebacks. On RV64, a 4-byte
   subconstructor write to an 8-byte register must zero-extend to
   avoid leaving stale upper bits.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace manual ExecuteOne + EXPECT_EQ pattern with the
TestOutputSpec + RunTestSpec pattern used by all other RISC-V tests.

Split multi-instruction LR/SC tests into individual single-instruction
specs with reservation state set via preconditions. AMO and CSR tests
use AddPrecWrite/AddPostRead for memory pre/postconditions.

Add ZeroVolatileFields to RISCVTestSpecRunner to zero FCSR, reservation,
and PC volatile padding after state randomization. Sleigh CSRRW on RV64
reads 64 bits spanning the fcsr field into adjacent frm/fflags/padding,
so randomized bytes in those slots must be zeroed before preconditions
are applied.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Reduces ~500 lines of near-identical boilerplate (kRV64RegAccessors and
kRV32RegAccessors) to ~90 lines using GPR/FPR/shared accessor macros
that expand the 32 GPR, 32 FPR, and common FCSR/reservation entries.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ogalland-tob and others added 3 commits February 20, 2026 18:01
Add run-riscv32-tests and run-riscv64-tests to the test_dependencies
target so CI actually builds and runs them.  Remove the accidentally
committed Testing/Temporary/CTestCostData.txt and gitignore the
Testing/ directory to prevent recurrence.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Every other architecture defines its own REMILL_ON_* macro in every
ifdef branch.  RISC-V was missing, which would break any downstream
code that checks REMILL_ON_RISCV.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Use idiomatic static const ordering in RISCVTestSpec.h
- Use PRIu64 instead of %lu for uint64_t in the integration harness
- Use $CLANG consistently instead of bare cc for harness compilation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@CLAassistant
Copy link
Copy Markdown

CLAassistant commented Feb 23, 2026

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
3 out of 4 committers have signed the CLA.

✅ redthing1
✅ ogalland-tob
✅ brunoproduit
❌ Bruno Produit


Bruno Produit seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

@Ninja3047
Copy link
Copy Markdown
Collaborator

This isn't documented anywhere unfortunately but you should also be generating a sleigh semantics patch for RISC-V using this script otherwise PC-relative semantics will be wrong

https://github.com/lifting-bits/remill/tree/master/scripts/replace_pc_relative_disactions

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants