Skip to content

Conversation

@kristjanvalur
Copy link
Collaborator

Summary

Adds RISC-V 64-bit (LP64D ABI) platform support to stackman.

Changes

  • ✅ Full RISC-V RV64 implementation in platforms/switch_riscv64_gcc.S
    • stackman_switch with full register preservation (s0-s11, fs0-fs11, ra)
    • stackman_call with minimal overhead
    • 16-byte stack alignment per RISC-V ABI
  • ✅ Platform detection in platforms/platform.h
  • ✅ CI integration with qemu-riscv64 emulation
  • ✅ All 4 test suites passing
  • ✅ Documentation updated (README, CHANGELOG)
  • ✅ Version bumped to 1.2.0

Testing

All tests pass under QEMU emulation:

  • test (6 tests)
  • test_cc (C++ compatibility)
  • test_static
  • test_asm

This brings the total platform count to 10 ABIs (was 9).

Platforms Supported

  • Linux: sysv_amd64, sysv_i386, arm32, aarch64, riscv64 (new)
  • macOS: darwin_x86_64, darwin_arm64
  • Windows: win_x86, win_x64, win_arm64

- Added platform detection for RISC-V 64-bit (__riscv && __riscv_xlen == 64)
- Created skeleton assembly implementation (switch_riscv64_gcc.S)
- Added RISC-V header file (switch_riscv64_gcc.h)
- Updated CI workflow to build and test riscv64 with QEMU
- Added riscv64 to release archives
- Uses LP64D ABI (64-bit pointers, hardware floating point)

TODO: Implement actual stack switching logic in assembly file
- Triggers on push to riscv-support branch
- Installs RISC-V toolchain and QEMU
- Builds and tests riscv64 platform only
- Fast feedback for RISC-V development
The Makefile adds the dash automatically, so PLATFORM_PREFIX should be
'riscv64-linux-gnu' not 'riscv64-linux-gnu-'
- Implement stackman_switch with full register save/restore
- Implement stackman_call with minimal frame
- Save/restore callee-saved registers: s0-s11, fs0-fs11, ra
- Follow RISC-V LP64D calling convention
- Based on ARM64 implementation pattern
Critical bug fix: Save old stack pointer in s2 before switching stacks,
then restore it after callback returns. Previously tried to restore
registers from the new stack where they were never saved.
No need to preserve callback and context in callee-saved registers
since they're used immediately. Only need to save old sp and ra.
Reduced frame from 32 to 16 bytes.
CRITICAL FIX: Must save old stack pointer in s0 (callee-saved register),
not on the stack. After switching to new stack, can't access old stack
memory. The callback won't clobber s0, so it's safe across the call.
Added __ASSEMBLER__ check and proper assembly source inclusion,
following the pattern used in ARM64. This ensures the assembly
file is actually compiled into the object file.
Should only use STACKMAN_STACK_ALIGN like all other platforms.
Should be .LFE1 (function end) not .LFB1 (function begin).
- Move STACKMAN_ASSEMBLY_SRC definition outside STACKMAN_SWITCH_IMPL
  so it's always defined (prevents inline asm fallback)
- Add #undef before redefining STACKMAN_STACK_ALIGN to avoid warning
Callback signature is: callback(context, opcode, sp)
Was incorrectly calling: callback(context, sp, opcode)

Fixed for both stackman_switch (two calls) and stackman_call.
- Bump version to 1.2.0
- Add riscv64 to supported platforms list in README
- Add v1.2.0 changelog entry with RISC-V details
RISC-V is now part of the main buildcommit.yml workflow.
@kristjanvalur kristjanvalur merged commit e05c3cb into stackless-dev:master Nov 16, 2025
12 checks passed
@kristjanvalur kristjanvalur deleted the riscv-support branch November 16, 2025 18:42
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.

1 participant