From b79936496c7409370476eba13ee5187f6d869055 Mon Sep 17 00:00:00 2001 From: WANG Rui Date: Wed, 17 Jun 2026 16:11:36 +0800 Subject: [PATCH 1/2] Add fiber implementation for LoongArch64 --- crates/fiber/src/stackswitch.rs | 4 + crates/fiber/src/stackswitch/loongarch64.rs | 168 ++++++++++++++++++++ 2 files changed, 172 insertions(+) create mode 100644 crates/fiber/src/stackswitch/loongarch64.rs diff --git a/crates/fiber/src/stackswitch.rs b/crates/fiber/src/stackswitch.rs index a249e86c9563..172160c2c1e5 100644 --- a/crates/fiber/src/stackswitch.rs +++ b/crates/fiber/src/stackswitch.rs @@ -33,6 +33,10 @@ cfg_if::cfg_if! { mod riscv32imac; pub(crate) use supported::*; pub(crate) use riscv32imac::*; + } else if #[cfg(target_arch = "loongarch64")] { + mod loongarch64; + pub(crate) use supported::*; + pub(crate) use loongarch64::*; } else { // No support for this platform. Don't fail compilation though and // instead defer the error to happen at runtime when a fiber is created. diff --git a/crates/fiber/src/stackswitch/loongarch64.rs b/crates/fiber/src/stackswitch/loongarch64.rs new file mode 100644 index 000000000000..5b04e8e48332 --- /dev/null +++ b/crates/fiber/src/stackswitch/loongarch64.rs @@ -0,0 +1,168 @@ +// A WORD OF CAUTION +// +// This entire file basically needs to be kept in sync with itself. It's not +// really possible to modify just one bit of this file without understanding +// all the other bits. Documentation tries to reference various bits here and +// there but try to make sure to read over everything before tweaking things! + +use core::arch::naked_asm; + +#[inline(never)] // FIXME(rust-lang/rust#148307) +pub(crate) unsafe extern "C" fn wasmtime_fiber_switch(top_of_stack: *mut u8) { + unsafe { wasmtime_fiber_switch_(top_of_stack) } +} + +#[unsafe(naked)] +unsafe extern "C" fn wasmtime_fiber_switch_(top_of_stack: *mut u8 /* a0 */) { + naked_asm!( + " + // Save all callee-saved registers on the stack since we're + // assuming they're clobbered as a result of the stack switch. + st.d $ra, $sp, -0x08 + st.d $fp, $sp, -0x10 + st.d $s0, $sp, -0x18 + st.d $s1, $sp, -0x20 + st.d $s2, $sp, -0x28 + st.d $s3, $sp, -0x30 + st.d $s4, $sp, -0x38 + st.d $s5, $sp, -0x40 + st.d $s6, $sp, -0x48 + st.d $s7, $sp, -0x50 + st.d $s8, $sp, -0x58 + fst.d $fs0, $sp, -0x60 + fst.d $fs1, $sp, -0x68 + fst.d $fs2, $sp, -0x70 + fst.d $fs3, $sp, -0x78 + fst.d $fs4, $sp, -0x80 + fst.d $fs5, $sp, -0x88 + fst.d $fs6, $sp, -0x90 + fst.d $fs7, $sp, -0x98 + addi.d $sp, $sp, -0xa0 + + // Load our previously saved stack pointer to resume to, and save + // off our current stack pointer on where to come back to + // eventually. + ld.d $t0, $a0, -0x10 + st.d $sp, $a0, -0x10 + + // Switch to the new stack and restore all our callee-saved + // registers after the switch and return to our new stack. + move $sp, $t0 + + fld.d $fs7, $sp, 0x08 + fld.d $fs6, $sp, 0x10 + fld.d $fs5, $sp, 0x18 + fld.d $fs4, $sp, 0x20 + fld.d $fs3, $sp, 0x28 + fld.d $fs2, $sp, 0x30 + fld.d $fs1, $sp, 0x38 + fld.d $fs0, $sp, 0x40 + ld.d $s8, $sp, 0x48 + ld.d $s7, $sp, 0x50 + ld.d $s6, $sp, 0x58 + ld.d $s5, $sp, 0x60 + ld.d $s4, $sp, 0x68 + ld.d $s3, $sp, 0x70 + ld.d $s2, $sp, 0x78 + ld.d $s1, $sp, 0x80 + ld.d $s0, $sp, 0x88 + ld.d $fp, $sp, 0x90 + ld.d $ra, $sp, 0x98 + addi.d $sp, $sp, 0xa0 + ret + ", + ); +} + +pub(crate) unsafe fn wasmtime_fiber_init( + top_of_stack: *mut u8, + entry_point: extern "C" fn(*mut u8, *mut u8) -> *mut u8, + entry_arg0: *mut u8, +) { + #[repr(C)] + #[derive(Default)] + struct InitialStack { + align_to_16_byte_size: u64, + + fs: [f64; 8], + + s8: *mut u8, + s7: *mut u8, + s6: *mut u8, + s5: *mut u8, + s4: *mut u8, + s3: *mut u8, + s2: *mut u8, + s1: *mut u8, + s0: *mut u8, + + fp: *mut u8, + ra: *mut u8, + + // unix.rs reserved space + last_sp: *mut u8, + run_result: *mut u8, + } + + unsafe { + let initial_stack = top_of_stack.cast::().sub(1); + initial_stack.write(InitialStack { + s0: entry_point as *mut u8, + s1: entry_arg0, + s2: wasmtime_fiber_switch_ as *mut u8, + fp: top_of_stack, + ra: wasmtime_fiber_start as *mut u8, + last_sp: initial_stack.cast(), + ..InitialStack::default() + }); + } +} + +#[unsafe(naked)] +unsafe extern "C" fn wasmtime_fiber_start() -> ! { + naked_asm!( + " + .cfi_startproc simple + .cfi_def_cfa_offset 0 + + + .cfi_escape 0x0f, /* DW_CFA_def_cfa_expression */ \ + 5, /* the byte length of this expression */ \ + 0x53, /* DW_OP_reg3 (sp) */ \ + 0x06, /* DW_OP_deref */ \ + 0x08, 0xa0, /* DW_OP_const1u 0x98 */ \ + 0x22 /* DW_OP_plus */ + + + .cfi_rel_offset ra, -0x8 + .cfi_rel_offset fp, -0x10 + .cfi_rel_offset s0, -0x18 + .cfi_rel_offset s1, -0x20 + .cfi_rel_offset s2, -0x28 + .cfi_rel_offset s3, -0x30 + .cfi_rel_offset s4, -0x38 + .cfi_rel_offset s5, -0x40 + .cfi_rel_offset s6, -0x48 + .cfi_rel_offset s7, -0x50 + .cfi_rel_offset s8, -0x58 + .cfi_rel_offset fs0, -0x60 + .cfi_rel_offset fs1, -0x68 + .cfi_rel_offset fs2, -0x70 + .cfi_rel_offset fs3, -0x78 + .cfi_rel_offset fs4, -0x80 + .cfi_rel_offset fs5, -0x88 + .cfi_rel_offset fs6, -0x90 + .cfi_rel_offset fs7, -0x98 + + move $a0, $s1 + move $a1, $fp + jirl $ra, $s0, 0 // entry_point + jirl $ra, $s2, 0 // wasmtime_fiber_switch_ + + // .4byte 0 will cause panic. + // for safety just like x86_64.rs. + .4byte 0 + .cfi_endproc + ", + ); +} From 2bd88fef007a119e81c34d545c89c7b2c53bcc12 Mon Sep 17 00:00:00 2001 From: WANG Rui Date: Thu, 18 Jun 2026 15:38:26 +0800 Subject: [PATCH 2/2] CI: Add LoongArch64 build check prtest:platform-checks --- .github/workflows/main.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 65a356356399..b971ba8510a0 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -648,6 +648,11 @@ jobs: - target: riscv32imac-unknown-none-elf os: ubuntu-latest test: cargo check -p wasmtime --no-default-features --features runtime,gc,component-model,async + # Use `cross` for loongarch64 to have a C compiler/linker available. + - target: loongarch64-unknown-linux-gnu + os: ubuntu-latest + cross: true + test: cross build --target loongarch64-unknown-linux-gnu env: ${{ matrix.env || fromJSON('{}') }} steps: - uses: actions/checkout@v6 @@ -656,9 +661,7 @@ jobs: - uses: ./.github/actions/install-rust - run: rustup target add ${{ matrix.target }} - name: Install cross - run: | - curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash - cargo binstall --no-confirm cross + run: cargo install cross --git https://github.com/cross-rs/cross if: ${{ matrix.cross }} - uses: ./.github/actions/apt-get-install if: ${{ matrix.apt_packages }}