From fa7b9bd24ed71d71e6a82e8b5942477b0d0989da Mon Sep 17 00:00:00 2001 From: WANG Rui Date: Wed, 10 May 2023 23:39:23 +0800 Subject: [PATCH] Add support for LoongArch64 (LLVM compiler) --- Makefile | 13 ++++++---- lib/cli/Cargo.toml | 4 ++-- lib/compiler-llvm/Cargo.toml | 6 ++--- lib/compiler-llvm/src/config.rs | 12 ++++++++++ lib/compiler-llvm/src/object_file.rs | 20 ++++++++++++++++ .../src/artifact_builders/trampoline.rs | 19 +++++++++++++++ lib/compiler/src/engine/link.rs | 24 +++++++++++++++++++ lib/object/src/module.rs | 1 + lib/types/src/compilation/relocation.rs | 12 ++++++++++ lib/vm/src/trap/traphandlers.rs | 11 +++++++++ lib/wasix/Cargo.toml | 4 ++-- tests/ignores.txt | 20 ++++++++++++++++ tests/lib/compiler-test-derive/src/ignores.rs | 2 +- 13 files changed, 136 insertions(+), 12 deletions(-) diff --git a/Makefile b/Makefile index 1c2cd8912c9..4a6ce47a7a0 100644 --- a/Makefile +++ b/Makefile @@ -18,15 +18,15 @@ SHELL=/usr/bin/env bash # # Here is what works and what doesn't: # -# * Cranelift works everywhere, +# * Cranelift works everywhere except */`loongarch64`, # # * LLVM works on Linux+Darwin/`amd64`, -# and linux+`aarch64`, linux+`riscv` +# and linux+`aarch64`, linux+`riscv`, linux+`loongarch64` # but it doesn't work on Darwin/`aarch64` or Windows/`aarch64`. # # * Singlepass works on Linux+Darwin+Windows/`amd64`, # and Linux+Darwin/`aarch64` -# it doesn't work on */`riscv`. +# it doesn't work on */`riscv` or */`loongarch64`. # # * Windows isn't tested on `aarch64`, that's why we consider it's not # working, but it might possibly be. @@ -48,6 +48,7 @@ IS_WINDOWS := 0 IS_AMD64 := 0 IS_AARCH64 := 0 IS_RISCV64 := 0 +IS_LOONGARCH64 := 0 # Test Windows apart because it doesn't support `uname -s`. ifeq ($(OS), Windows_NT) @@ -80,11 +81,13 @@ else IS_AARCH64 := 1 else ifneq (, $(filter $(uname), riscv64)) IS_RISCV64 := 1 + else ifneq (, $(filter $(uname), loongarch64)) + IS_LOONGARCH64 := 1 else # We use spaces instead of tabs to indent `$(error)` # otherwise it's considered as a command outside a # target and it will fail. - $(error Unrecognized architecture, expect `x86_64`, `aarch64`, `arm64`, 'riscv64') + $(error Unrecognized architecture, expect `x86_64`, `aarch64`, `arm64`, 'riscv64', 'loongarch64') endif # Libc @@ -243,6 +246,8 @@ ifeq ($(ENABLE_LLVM), 1) compilers_engines += llvm-universal else ifeq ($(IS_RISCV64), 1) compilers_engines += llvm-universal + else ifeq ($(IS_LOONGARCH64), 1) + compilers_engines += llvm-universal endif endif endif diff --git a/lib/cli/Cargo.toml b/lib/cli/Cargo.toml index 2e86ee190ac..7c714bd4d2d 100644 --- a/lib/cli/Cargo.toml +++ b/lib/cli/Cargo.toml @@ -187,7 +187,7 @@ clap = { version = "4.2.7", default-features = false, features = [ "env", ] } -[target.'cfg(not(target_arch = "riscv64"))'.dependencies] +[target.'cfg(not(any(target_arch = "riscv64", target_arch = "loongarch64")))'.dependencies] reqwest = { version = "^0.11", default-features = false, features = [ "rustls-tls", "json", @@ -195,7 +195,7 @@ reqwest = { version = "^0.11", default-features = false, features = [ "gzip", ] } -[target.'cfg(target_arch = "riscv64")'.dependencies] +[target.'cfg(any(target_arch = "riscv64", target_arch = "loongarch64"))'.dependencies] reqwest = { version = "^0.11", default-features = false, features = [ "native-tls", "json", diff --git a/lib/compiler-llvm/Cargo.toml b/lib/compiler-llvm/Cargo.toml index 3c7f3e0eae2..460d8e770da 100644 --- a/lib/compiler-llvm/Cargo.toml +++ b/lib/compiler-llvm/Cargo.toml @@ -21,7 +21,7 @@ wasmer-vm = { path = "../vm", version = "=4.2.5" } wasmer-types = { path = "../types", version = "=4.2.5" } target-lexicon = { version = "0.12.2", default-features = false } smallvec = "1.6" -object = { version = "0.28.3", default-features = false, features = ["read"] } +object = { version = "0.30.3", default-features = false, features = ["read"] } libc = { version = "^0.2", default-features = false } byteorder = "1" itertools = "0.10" @@ -29,9 +29,9 @@ rayon = "1.5" [dependencies.inkwell] package = "inkwell" -version = "0.1.1" +version = "0.2.0" default-features = false -features = ["llvm15-0", "target-x86", "target-aarch64", "target-riscv"] +features = ["llvm15-0", "target-x86", "target-aarch64", "target-riscv", "target-loongarch"] [build-dependencies] cc = "1.0" diff --git a/lib/compiler-llvm/src/config.rs b/lib/compiler-llvm/src/config.rs index a4c5ebf6e1c..e60c5afe9dd 100644 --- a/lib/compiler-llvm/src/config.rs +++ b/lib/compiler-llvm/src/config.rs @@ -171,6 +171,16 @@ impl LLVM { info: true, machine_code: true, }), + Architecture::LoongArch64 => { + InkwellTarget::initialize_loongarch(&InitializationConfig { + asm_parser: true, + asm_printer: true, + base: true, + disassembler: true, + info: true, + machine_code: true, + }) + } // Architecture::Arm(_) => InkwellTarget::initialize_arm(&InitializationConfig { // asm_parser: true, // asm_printer: true, @@ -197,10 +207,12 @@ impl LLVM { &target_triple, match triple.architecture { Architecture::Riscv64(_) => "generic-rv64", + Architecture::LoongArch64 => "generic-la64", _ => "generic", }, match triple.architecture { Architecture::Riscv64(_) => "+m,+a,+c,+d,+f", + Architecture::LoongArch64 => "+f,+d", _ => &llvm_cpu_features, }, self.opt_level, diff --git a/lib/compiler-llvm/src/object_file.rs b/lib/compiler-llvm/src/object_file.rs index de8702b44c9..06b196326ed 100644 --- a/lib/compiler-llvm/src/object_file.rs +++ b/lib/compiler-llvm/src/object_file.rs @@ -231,6 +231,26 @@ where object::RelocationKind::Elf(object::elf::R_RISCV_PCREL_LO12_I), 0, ) => RelocationKind::RiscvPCRelLo12I, + ( + object::Architecture::LoongArch64, + object::RelocationKind::Elf(object::elf::R_LARCH_ABS_HI20), + 0, + ) => RelocationKind::LArchAbsHi20, + ( + object::Architecture::LoongArch64, + object::RelocationKind::Elf(object::elf::R_LARCH_ABS_LO12), + 0, + ) => RelocationKind::LArchAbsLo12, + ( + object::Architecture::LoongArch64, + object::RelocationKind::Elf(object::elf::R_LARCH_ABS64_HI12), + 0, + ) => RelocationKind::LArchAbs64Hi12, + ( + object::Architecture::LoongArch64, + object::RelocationKind::Elf(object::elf::R_LARCH_ABS64_LO20), + 0, + ) => RelocationKind::LArchAbs64Lo20, _ => { return Err(CompileError::Codegen(format!( "unknown relocation {:?}", diff --git a/lib/compiler/src/artifact_builders/trampoline.rs b/lib/compiler/src/artifact_builders/trampoline.rs index 387b62608a2..3fbfa245a9e 100644 --- a/lib/compiler/src/artifact_builders/trampoline.rs +++ b/lib/compiler/src/artifact_builders/trampoline.rs @@ -36,6 +36,15 @@ const RISCV64_TRAMPOLINE: [u8; 24] = [ 0, 0, 0, 0, ]; +// PCADDI r12, 0 0c 00 00 18 +// LD.D r12, r12, 16 8c 41 c0 28 +// JR r12 80 01 00 4c [00 00 00 00] +// JMPADDR 00 00 00 00 00 00 00 00 +const LOONGARCH64_TRAMPOLINE: [u8; 24] = [ + 0x0c, 0x00, 0x00, 0x0c, 0x8c, 0x41, 0xc0, 0x28, 0x80, 0x01, 0x00, 0x4c, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, +]; + fn make_trampoline( target: &Target, libcall: LibCall, @@ -70,6 +79,15 @@ fn make_trampoline( addend: 0, }); } + Architecture::LoongArch64 => { + code.extend(LOONGARCH64_TRAMPOLINE); + relocations.push(Relocation { + kind: RelocationKind::Abs8, + reloc_target: RelocationTarget::LibCall(libcall), + offset: code.len() as u32 - 8, + addend: 0, + }); + } arch => panic!("Unsupported architecture: {}", arch), }; } @@ -80,6 +98,7 @@ pub fn libcall_trampoline_len(target: &Target) -> usize { Architecture::Aarch64(_) => AARCH64_TRAMPOLINE.len(), Architecture::X86_64 => X86_64_TRAMPOLINE.len(), Architecture::Riscv64(_) => RISCV64_TRAMPOLINE.len(), + Architecture::LoongArch64 => LOONGARCH64_TRAMPOLINE.len(), arch => panic!("Unsupported architecture: {}", arch), } } diff --git a/lib/compiler/src/engine/link.rs b/lib/compiler/src/engine/link.rs index 92a0357be90..a3fc64dd2da 100644 --- a/lib/compiler/src/engine/link.rs +++ b/lib/compiler/src/engine/link.rs @@ -122,6 +122,30 @@ fn apply_relocation( | read_unaligned(reloc_address as *mut u64); write_unaligned(reloc_address as *mut u64, reloc_delta); }, + RelocationKind::LArchAbsHi20 => unsafe { + let (reloc_address, reloc_abs) = r.for_address(body, target_func_address as u64); + let reloc_abs = ((((reloc_abs >> 12) & 0xfffff) as u32) << 5) + | read_unaligned(reloc_address as *mut u32); + write_unaligned(reloc_address as *mut u32, reloc_abs); + }, + RelocationKind::LArchAbsLo12 => unsafe { + let (reloc_address, reloc_abs) = r.for_address(body, target_func_address as u64); + let reloc_abs = + (((reloc_abs & 0xfff) as u32) << 10) | read_unaligned(reloc_address as *mut u32); + write_unaligned(reloc_address as *mut u32, reloc_abs); + }, + RelocationKind::LArchAbs64Hi12 => unsafe { + let (reloc_address, reloc_abs) = r.for_address(body, target_func_address as u64); + let reloc_abs = ((((reloc_abs >> 52) & 0xfff) as u32) << 10) + | read_unaligned(reloc_address as *mut u32); + write_unaligned(reloc_address as *mut u32, reloc_abs); + }, + RelocationKind::LArchAbs64Lo20 => unsafe { + let (reloc_address, reloc_abs) = r.for_address(body, target_func_address as u64); + let reloc_abs = ((((reloc_abs >> 32) & 0xfffff) as u32) << 5) + | read_unaligned(reloc_address as *mut u32); + write_unaligned(reloc_address as *mut u32, reloc_abs); + }, kind => panic!( "Relocation kind unsupported in the current architecture {}", kind diff --git a/lib/object/src/module.rs b/lib/object/src/module.rs index 333980e30d5..af1017b13b7 100644 --- a/lib/object/src/module.rs +++ b/lib/object/src/module.rs @@ -47,6 +47,7 @@ pub fn get_object_for_target(triple: &Triple) -> Result { Architecture::X86_64 => object::Architecture::X86_64, Architecture::Aarch64(_) => object::Architecture::Aarch64, Architecture::Riscv64(_) => object::Architecture::Riscv64, + Architecture::LoongArch64 => object::Architecture::LoongArch64, architecture => { return Err(ObjectError::UnsupportedArchitecture(format!( "{}", diff --git a/lib/types/src/compilation/relocation.rs b/lib/types/src/compilation/relocation.rs index a1abd445ff1..b257da4f201 100644 --- a/lib/types/src/compilation/relocation.rs +++ b/lib/types/src/compilation/relocation.rs @@ -59,6 +59,14 @@ pub enum RelocationKind { RiscvPCRelLo12I, /// RISC-V call target RiscvCall, + /// LoongArch absolute high 20bit + LArchAbsHi20, + /// LoongArch absolute low 12bit + LArchAbsLo12, + /// LoongArch absolute high 12bit + LArchAbs64Hi12, + /// LoongArch absolute low 20bit + LArchAbs64Lo20, /// Elf x86_64 32 bit signed PC relative offset to two GOT entries for GD symbol. ElfX86_64TlsGd, // /// Mach-O x86_64 32 bit signed PC relative offset to a `__thread_vars` entry. @@ -85,6 +93,10 @@ impl fmt::Display for RelocationKind { Self::ElfX86_64TlsGd => write!(f, "ElfX86_64TlsGd"), Self::RiscvPCRelHi20 => write!(f, "RiscvPCRelHi20"), Self::RiscvPCRelLo12I => write!(f, "RiscvPCRelLo12I"), + Self::LArchAbsHi20 => write!(f, "LArchAbsHi20"), + Self::LArchAbsLo12 => write!(f, "LArchAbsLo12"), + Self::LArchAbs64Hi12 => write!(f, "LArchAbs64Hi12"), + Self::LArchAbs64Lo20 => write!(f, "LArchAbs64Lo20"), // Self::MachOX86_64Tlv => write!(f, "MachOX86_64Tlv"), } } diff --git a/lib/vm/src/trap/traphandlers.rs b/lib/vm/src/trap/traphandlers.rs index 00627b990cd..8295b039df7 100644 --- a/lib/vm/src/trap/traphandlers.rs +++ b/lib/vm/src/trap/traphandlers.rs @@ -339,6 +339,9 @@ cfg_if::cfg_if! { } else if #[cfg(all(target_os = "freebsd", target_arch = "aarch64"))] { pc = context.uc_mcontext.mc_gpregs.gp_elr as usize; sp = context.uc_mcontext.mc_gpregs.gp_sp as usize; + } else if #[cfg(all(target_os = "linux", target_arch = "loongarch64"))] { + pc = context.uc_mcontext.__gregs[1] as usize; + sp = context.uc_mcontext.__gregs[3] as usize; } else { compile_error!("Unsupported platform"); } @@ -459,6 +462,14 @@ cfg_if::cfg_if! { context.uc_mcontext.mc_gpregs.gp_x[1] = x1 as libc::register_t; context.uc_mcontext.mc_gpregs.gp_x[29] = x29 as libc::register_t; context.uc_mcontext.mc_gpregs.gp_x[30] = lr as libc::register_t; + } else if #[cfg(all(target_os = "linux", target_arch = "loongarch64"))] { + let TrapHandlerRegs { pc, sp, a0, a1, fp, ra } = regs; + context.uc_mcontext.__pc = pc; + context.uc_mcontext.__gregs[1] = ra; + context.uc_mcontext.__gregs[3] = sp; + context.uc_mcontext.__gregs[4] = a0; + context.uc_mcontext.__gregs[5] = a1; + context.uc_mcontext.__gregs[22] = fp; } else { compile_error!("Unsupported platform"); } diff --git a/lib/wasix/Cargo.toml b/lib/wasix/Cargo.toml index b1507f3184e..1846a204b83 100644 --- a/lib/wasix/Cargo.toml +++ b/lib/wasix/Cargo.toml @@ -99,13 +99,13 @@ web-sys = { version = "0.3.64", features = [ "Headers", ], optional = true } -[target.'cfg(not(target_arch = "riscv64"))'.dependencies.reqwest] +[target.'cfg(not(any(target_arch = "riscv64", target_arch = "loongarch64")))'.dependencies.reqwest] version = "0.11" default-features = false features = ["rustls-tls", "json", "stream"] optional = true -[target.'cfg(target_arch = "riscv64")'.dependencies.reqwest] +[target.'cfg(any(target_arch = "riscv64", target_arch = "loongarch64"))'.dependencies.reqwest] version = "0.11" default-features = false features = ["native-tls", "json", "stream"] diff --git a/tests/ignores.txt b/tests/ignores.txt index d32e3e1eb56..0b8ea53081c 100644 --- a/tests/ignores.txt +++ b/tests/ignores.txt @@ -9,6 +9,7 @@ singlepass+aarch64+macos traps::test_trap_trace cranelift+aarch64+macos traps::test_trap_trace llvm+aarch64 traps::test_trap_trace llvm+riscv64 traps::test_trap_trace +llvm+loongarch64 traps::test_trap_trace singlepass+aarch64+macos traps::test_trap_stack_overflow # Need to investigate singlepass+aarch64+macos traps::trap_display_pretty llvm traps::trap_display_pretty @@ -29,6 +30,7 @@ cranelift+aarch64+macos traps::start_trap_pretty # https://github.com/wasmerio/wasmer/issues/2808 llvm+aarch64 spec::skip_stack_guard_page llvm+riscv64 spec::skip_stack_guard_page +llvm+loongarch64 spec::skip_stack_guard_page # riscv support is still early, function call ABI needs some work llvm+riscv64 static_function::llvm::universal @@ -56,6 +58,24 @@ cranelift+riscv64 spec::r#if::cranelift::universal # no SIMD on riscv, Cranelift will not handle them cranelift+riscv64 spec::simd +# loongarch64 support is still early, function call ABI needs some work +llvm+loongarch64 static_function::llvm::universal +llvm+loongarch64 static_function_with_env::llvm::universal +llvm+loongarch64 static_function_with_results::llvm::universal +llvm+loongarch64 spec::f32::llvm::universal +llvm+loongarch64 spec::f64::llvm::universal +llvm+loongarch64 spec::float_misc::llvm::universal +llvm+loongarch64 spec::memory_copy::llvm::universal +llvm+loongarch64 spec::memory_init::llvm::universal +llvm+loongarch64 spec::memory_trap::llvm::universal +llvm+loongarch64 spec::multi_value::binary::llvm::universal +llvm+loongarch64 spec::multi_value::block::llvm::universal +llvm+loongarch64 spec::simd::simd_align::llvm::universal +llvm+loongarch64 spec::simd::simd_f32x4_rounding::llvm::universal +llvm+loongarch64 spec::simd::simd_f64x2_rounding::llvm::universal +llvm+loongarch64 wasmer::nan_canonicalization::llvm::universal +llvm+loongarch64 wasmer::stack_overflow_sret::llvm::universal + # Windows doesn't overcommit and fails to allocate 4GB of memory windows wasmer::max_size_of_memory diff --git a/tests/lib/compiler-test-derive/src/ignores.rs b/tests/lib/compiler-test-derive/src/ignores.rs index 12364cf2191..268f11e4e41 100644 --- a/tests/lib/compiler-test-derive/src/ignores.rs +++ b/tests/lib/compiler-test-derive/src/ignores.rs @@ -111,7 +111,7 @@ impl Ignores { target_env = Some(alias.to_string()); } // Chipset architectures - "aarch64" | "x86" | "x64" | "riscv64" => { + "aarch64" | "x86" | "x64" | "riscv64" | "loongarch64" => { arch = Some(alias.to_string()); } // Engines