// FIXME: add wasm32-unknown when the wasm32-unknown-unknown ABI is fixed // see https://github.com/rust-lang/rust/issues/115666 //@ revisions: wasm64-unknown wasm32-wasip1 //@ add-core-stubs //@ assembly-output: emit-asm //@ [wasm64-unknown] compile-flags: --target wasm64-unknown-unknown //@ [wasm32-wasip1] compile-flags: --target wasm32-wasip1 //@ [wasm64-unknown] needs-llvm-components: webassembly //@ [wasm32-wasip1] needs-llvm-components: webassembly #![crate_type = "lib"] #![feature(no_core, naked_functions, asm_experimental_arch, f128, linkage, fn_align)] #![no_core] extern crate minicore; use minicore::*; // CHECK: .section .text.nop,"",@ // CHECK: .globl nop // CHECK-LABEL: nop: // CHECK: .functype nop () -> () // CHECK-NOT: .size // CHECK: end_function #[no_mangle] #[unsafe(naked)] extern "C" fn nop() { naked_asm!("nop") } // CHECK: .section .text.weak_aligned_nop,"",@ // CHECK: .weak weak_aligned_nop // CHECK-LABEL: nop: // CHECK: .functype weak_aligned_nop () -> () // CHECK-NOT: .size // CHECK: end_function #[no_mangle] #[unsafe(naked)] #[linkage = "weak"] // wasm functions cannot be aligned, so this has no effect #[repr(align(32))] extern "C" fn weak_aligned_nop() { naked_asm!("nop") } // CHECK-LABEL: fn_i8_i8: // CHECK-NEXT: .functype fn_i8_i8 (i32) -> (i32) // // CHECK-NEXT: local.get 0 // CHECK-NEXT: local.get 0 // CHECK-NEXT: i32.mul // // CHECK-NEXT: end_function #[no_mangle] #[unsafe(naked)] extern "C" fn fn_i8_i8(num: i8) -> i8 { naked_asm!("local.get 0", "local.get 0", "i32.mul") } // CHECK-LABEL: fn_i8_i8_i8: // CHECK: .functype fn_i8_i8_i8 (i32, i32) -> (i32) #[no_mangle] #[unsafe(naked)] extern "C" fn fn_i8_i8_i8(a: i8, b: i8) -> i8 { naked_asm!("local.get 1", "local.get 0", "i32.mul") } // CHECK-LABEL: fn_unit_i8: // CHECK: .functype fn_unit_i8 () -> (i32) #[no_mangle] #[unsafe(naked)] extern "C" fn fn_unit_i8() -> i8 { naked_asm!("i32.const 42") } // CHECK-LABEL: fn_i8_unit: // CHECK: .functype fn_i8_unit (i32) -> () #[no_mangle] #[unsafe(naked)] extern "C" fn fn_i8_unit(_: i8) { naked_asm!("nop") } // CHECK-LABEL: fn_i32_i32: // CHECK: .functype fn_i32_i32 (i32) -> (i32) #[no_mangle] #[unsafe(naked)] extern "C" fn fn_i32_i32(num: i32) -> i32 { naked_asm!("local.get 0", "local.get 0", "i32.mul") } // CHECK-LABEL: fn_i64_i64: // CHECK: .functype fn_i64_i64 (i64) -> (i64) #[no_mangle] #[unsafe(naked)] extern "C" fn fn_i64_i64(num: i64) -> i64 { naked_asm!("local.get 0", "local.get 0", "i64.mul") } // CHECK-LABEL: fn_i128_i128: // wasm32-wasip1: .functype fn_i128_i128 (i32, i64, i64) -> () // wasm64-unknown: .functype fn_i128_i128 (i64, i64, i64) -> () #[allow(improper_ctypes_definitions)] #[no_mangle] #[unsafe(naked)] extern "C" fn fn_i128_i128(num: i128) -> i128 { naked_asm!( "local.get 0", "local.get 2", "i64.store 8", "local.get 0", "local.get 1", "i64.store 0", ) } // CHECK-LABEL: fn_f128_f128: // wasm32-wasip1: .functype fn_f128_f128 (i32, i64, i64) -> () // wasm64-unknown: .functype fn_f128_f128 (i64, i64, i64) -> () #[no_mangle] #[unsafe(naked)] extern "C" fn fn_f128_f128(num: f128) -> f128 { naked_asm!( "local.get 0", "local.get 2", "i64.store 8", "local.get 0", "local.get 1", "i64.store 0", ) } #[repr(C)] struct Compound { a: u16, b: i64, } // CHECK-LABEL: fn_compound_compound: // wasm32-wasip1: .functype fn_compound_compound (i32, i32) -> () // wasm64-unknown: .functype fn_compound_compound (i64, i64) -> () #[no_mangle] #[unsafe(naked)] extern "C" fn fn_compound_compound(_: Compound) -> Compound { // this is the wasm32-wasip1 assembly naked_asm!( "local.get 0", "local.get 1", "i64.load 8", "i64.store 8", "local.get 0", "local.get 1", "i32.load16_u 0", "i32.store16 0", ) } #[repr(C)] struct WrapperI32(i32); // CHECK-LABEL: fn_wrapperi32_wrapperi32: // CHECK: .functype fn_wrapperi32_wrapperi32 (i32) -> (i32) #[no_mangle] #[unsafe(naked)] extern "C" fn fn_wrapperi32_wrapperi32(_: WrapperI32) -> WrapperI32 { naked_asm!("local.get 0") } #[repr(C)] struct WrapperI64(i64); // CHECK-LABEL: fn_wrapperi64_wrapperi64: // CHECK: .functype fn_wrapperi64_wrapperi64 (i64) -> (i64) #[no_mangle] #[unsafe(naked)] extern "C" fn fn_wrapperi64_wrapperi64(_: WrapperI64) -> WrapperI64 { naked_asm!("local.get 0") } #[repr(C)] struct WrapperF32(f32); // CHECK-LABEL: fn_wrapperf32_wrapperf32: // CHECK: .functype fn_wrapperf32_wrapperf32 (f32) -> (f32) #[no_mangle] #[unsafe(naked)] extern "C" fn fn_wrapperf32_wrapperf32(_: WrapperF32) -> WrapperF32 { naked_asm!("local.get 0") } #[repr(C)] struct WrapperF64(f64); // CHECK-LABEL: fn_wrapperf64_wrapperf64: // CHECK: .functype fn_wrapperf64_wrapperf64 (f64) -> (f64) #[no_mangle] #[unsafe(naked)] extern "C" fn fn_wrapperf64_wrapperf64(_: WrapperF64) -> WrapperF64 { naked_asm!("local.get 0") }