Skip to content

Commit 81a708a

Browse files
committed
feat: Enable rv32 target in LLVM engine
Note that simple turning on rv32 target can be trivial in LLVM setting, all we need is just tweaking a few configs. However, this change also comes with several bug fixes that are required in rv32 (possibly other 32 bit target targets as well), and in rv64: * Certain pointer width are hardcoded to be 8, which will break on 32-bit platforms * Metadata require an alignment of 8 * RISC-V relocations are not properly handled * Certain floating-point & 64-bit routine functions are required in libcalls * Previous transmute-based way of setting ABI in rv64 platform would crash, this change also fixes it
1 parent 3c64875 commit 81a708a

File tree

10 files changed

+540
-93
lines changed

10 files changed

+540
-93
lines changed

lib/compiler-llvm/src/compiler.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,8 @@ impl LLVMCompiler {
102102
let merged_bitcode = function_body_inputs.into_iter().par_bridge().map_init(
103103
|| {
104104
let target_machine = self.config().target_machine(target);
105-
FuncTranslator::new(target_machine, binary_format).unwrap()
105+
let pointer_width = target.triple().pointer_width().unwrap().bytes();
106+
FuncTranslator::new(target_machine, binary_format, pointer_width).unwrap()
106107
},
107108
|func_translator, (i, input)| {
108109
let module = func_translator.translate_to_module(
@@ -280,7 +281,8 @@ impl Compiler for LLVMCompiler {
280281
.map_init(
281282
|| {
282283
let target_machine = self.config().target_machine(target);
283-
FuncTranslator::new(target_machine, binary_format).unwrap()
284+
let pointer_width = target.triple().pointer_width().unwrap().bytes();
285+
FuncTranslator::new(target_machine, binary_format, pointer_width).unwrap()
284286
},
285287
|func_translator, (i, input)| {
286288
// TODO: remove (to serialize)

lib/compiler-llvm/src/config.rs

Lines changed: 39 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::compiler::LLVMCompiler;
22
use inkwell::targets::{
33
CodeModel, InitializationConfig, RelocMode, Target as InkwellTarget, TargetMachine,
4-
TargetTriple,
4+
TargetMachineOptions, TargetTriple,
55
};
66
pub use inkwell::OptimizationLevel as LLVMOptLevel;
77
use itertools::Itertools;
@@ -193,6 +193,14 @@ impl LLVM {
193193
info: true,
194194
machine_code: true,
195195
}),
196+
Architecture::Riscv32(_) => InkwellTarget::initialize_riscv(&InitializationConfig {
197+
asm_parser: true,
198+
asm_printer: true,
199+
base: true,
200+
disassembler: true,
201+
info: true,
202+
machine_code: true,
203+
}),
196204
Architecture::LoongArch64 => {
197205
InkwellTarget::initialize_loongarch(&InitializationConfig {
198206
asm_parser: true,
@@ -224,61 +232,38 @@ impl LLVM {
224232

225233
let target_triple = self.target_triple(target);
226234
let llvm_target = InkwellTarget::from_triple(&target_triple).unwrap();
227-
let llvm_target_machine = llvm_target
228-
.create_target_machine(
229-
&target_triple,
230-
match triple.architecture {
231-
Architecture::Riscv64(_) => "generic-rv64",
232-
Architecture::LoongArch64 => "generic-la64",
233-
_ => "generic",
234-
},
235-
match triple.architecture {
236-
Architecture::Riscv64(_) => "+m,+a,+c,+d,+f",
237-
Architecture::LoongArch64 => "+f,+d",
238-
_ => &llvm_cpu_features,
239-
},
240-
self.opt_level,
241-
self.reloc_mode(self.target_binary_format(target)),
242-
match triple.architecture {
243-
Architecture::LoongArch64 | Architecture::Riscv64(_) => CodeModel::Medium,
244-
_ => self.code_model(self.target_binary_format(target)),
245-
},
246-
)
247-
.unwrap();
248-
249-
if let Architecture::Riscv64(_) = triple.architecture {
250-
// TODO: totally non-portable way to change ABI
251-
unsafe {
252-
// This structure mimic the internal structure from inkwell
253-
// that is defined as
254-
// #[derive(Debug)]
255-
// pub struct TargetMachine {
256-
// pub(crate) target_machine: LLVMTargetMachineRef,
257-
// }
258-
pub struct MyTargetMachine {
259-
pub target_machine: *const u8,
235+
let mut llvm_target_machine_options = TargetMachineOptions::new()
236+
.set_cpu(match triple.architecture {
237+
Architecture::Riscv64(_) => "generic-rv64",
238+
Architecture::Riscv32(_) => "generic-rv32",
239+
Architecture::LoongArch64 => "generic-la64",
240+
_ => "generic",
241+
})
242+
.set_features(match triple.architecture {
243+
Architecture::Riscv64(_) => "+m,+a,+c,+d,+f",
244+
// TODO: WASM modules requires these features to function, however,
245+
// it is also possible to disable those features by generating floating
246+
// point routine functions and multiplication routine functions. It might
247+
// be worthwhile to allow turning them off, and generate references to
248+
// proper routine functions.
249+
Architecture::Riscv32(_) => "+m,+d,+f",
250+
Architecture::LoongArch64 => "+f,+d",
251+
_ => &llvm_cpu_features,
252+
})
253+
.set_level(self.opt_level)
254+
.set_reloc_mode(self.reloc_mode(self.target_binary_format(target)))
255+
.set_code_model(match triple.architecture {
256+
Architecture::LoongArch64 | Architecture::Riscv64(_) | Architecture::Riscv32(_) => {
257+
CodeModel::Medium
260258
}
261-
// It is use to live patch the create LLVMTargetMachine
262-
// to hard change the ABI and force "-mabi=lp64d" ABI
263-
// instead of the default that don't use float registers
264-
// because there is no current way to do this change
265-
266-
let my_target_machine: MyTargetMachine = std::mem::transmute(llvm_target_machine);
267-
268-
*((my_target_machine.target_machine as *mut u8).offset(0x410) as *mut u64) = 5;
269-
std::ptr::copy_nonoverlapping(
270-
"lp64d\0".as_ptr(),
271-
(my_target_machine.target_machine as *mut u8).offset(0x418),
272-
6,
273-
);
274-
275-
std::mem::transmute::<MyTargetMachine, inkwell::targets::TargetMachine>(
276-
my_target_machine,
277-
)
278-
}
279-
} else {
280-
llvm_target_machine
259+
_ => self.code_model(self.target_binary_format(target)),
260+
});
261+
if let Architecture::Riscv64(_) = triple.architecture {
262+
llvm_target_machine_options = llvm_target_machine_options.set_abi("lp64d");
281263
}
264+
llvm_target
265+
.create_target_machine_from_options(&target_triple, llvm_target_machine_options)
266+
.unwrap()
282267
}
283268
}
284269

lib/compiler-llvm/src/object_file.rs

Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,64 @@ static LIBCALLS_ELF: phf::Map<&'static str, LibCall> = phf::phf_map! {
8484
"wasmer_vm_read_exception" => LibCall::ReadException,
8585
"wasmer_vm_dbg_usize" => LibCall::DebugUsize,
8686
"wasmer_eh_personality" => LibCall::EHPersonality,
87+
// Floating-point & 64-bit mul/div routie functions. Those might
88+
// be generated by LLVM when generating objects for 32-bit platforms,
89+
// or platforms without floating point supports. Modern Rust & C toolchains
90+
// provide implementations for thos functions by default.
91+
"__adddf3" => LibCall::Adddf3,
92+
"__addsf3" => LibCall::Addsf3,
93+
"__divdf3" => LibCall::Divdf3,
94+
"__divdi3" => LibCall::Divdi3,
95+
"__divsf3" => LibCall::Divsf3,
96+
"__divsi3" => LibCall::Divsi3,
97+
"__eqdf2" => LibCall::Eqdf2,
98+
"__eqsf2" => LibCall::Eqsf2,
99+
"__extendsfdf2" => LibCall::Extendsfdf2,
100+
"__fixdfdi" => LibCall::Fixdfdi,
101+
"__fixdfsi" => LibCall::Fixdfsi,
102+
"__fixsfdi" => LibCall::Fixsfdi,
103+
"__fixsfsi" => LibCall::Fixsfsi,
104+
"__fixunsdfdi" => LibCall::Fixunsdfdi,
105+
"__fixunsdfsi" => LibCall::Fixunsdfsi,
106+
"__fixunssfdi" => LibCall::Fixunssfdi,
107+
"__fixunssfsi" => LibCall::Fixunssfsi,
108+
"__floatdidf" => LibCall::Floatdidf,
109+
"__floatdisf" => LibCall::Floatdisf,
110+
"__floatsidf" => LibCall::Floatsidf,
111+
"__floatsisf" => LibCall::Floatsisf,
112+
"__floatundidf" => LibCall::Floatundidf,
113+
"__floatundisf" => LibCall::Floatundisf,
114+
"__floatunsidf" => LibCall::Floatunsidf,
115+
"__floatunsisf" => LibCall::Floatunsisf,
116+
"__gedf2" => LibCall::Gedf2,
117+
"__gesf2" => LibCall::Gesf2,
118+
"__gtdf2" => LibCall::Gtdf2,
119+
"__gtsf2" => LibCall::Gtsf2,
120+
"__ledf2" => LibCall::Ledf2,
121+
"__lesf2" => LibCall::Lesf2,
122+
"__ltdf2" => LibCall::Ltdf2,
123+
"__ltsf2" => LibCall::Ltsf2,
124+
"__moddi3" => LibCall::Moddi3,
125+
"__modsi3" => LibCall::Modsi3,
126+
"__muldf3" => LibCall::Muldf3,
127+
"__muldi3" => LibCall::Muldi3,
128+
"__mulsf3" => LibCall::Mulsf3,
129+
"__mulsi3" => LibCall::Mulsi3,
130+
"__nedf2" => LibCall::Nedf2,
131+
"__negdf2" => LibCall::Negdf2,
132+
"__negsf2" => LibCall::Negsf2,
133+
"__nesf2" => LibCall::Nesf2,
134+
"__subdf3" => LibCall::Subdf3,
135+
"__subsf3" => LibCall::Subsf3,
136+
"__truncdfsf2" => LibCall::Truncdfsf2,
137+
"__udivdi3" => LibCall::Udivdi3,
138+
"__udivsi3" => LibCall::Udivsi3,
139+
"__umoddi3" => LibCall::Umoddi3,
140+
"__umodsi3" => LibCall::Umodsi3,
141+
"__unorddf2" => LibCall::Unorddf2,
142+
"__unordsf2" => LibCall::Unordsf2,
143+
"memset" => LibCall::Memset,
144+
"sqrt" => LibCall::Sqrt,
87145
};
88146

89147
static LIBCALLS_MACHO: phf::Map<&'static str, LibCall> = phf::phf_map! {
@@ -401,17 +459,17 @@ where
401459
0,
402460
) => RelocationKind::Arm64Movw3,
403461
(
404-
object::Architecture::Riscv64,
462+
object::Architecture::Riscv64 | object::Architecture::Riscv32,
405463
object::RelocationKind::Elf(object::elf::R_RISCV_CALL_PLT),
406464
0,
407465
) => RelocationKind::RiscvCall,
408466
(
409-
object::Architecture::Riscv64,
467+
object::Architecture::Riscv64 | object::Architecture::Riscv32,
410468
object::RelocationKind::Elf(object::elf::R_RISCV_PCREL_HI20),
411469
0,
412470
) => RelocationKind::RiscvPCRelHi20,
413471
(
414-
object::Architecture::Riscv64,
472+
object::Architecture::Riscv64 | object::Architecture::Riscv32,
415473
object::RelocationKind::Elf(object::elf::R_RISCV_PCREL_LO12_I),
416474
0,
417475
) => RelocationKind::RiscvPCRelLo12I,

lib/compiler-llvm/src/translator/code.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,14 @@ pub struct FuncTranslator {
5858
abi: Box<dyn Abi>,
5959
binary_fmt: BinaryFormat,
6060
func_section: String,
61+
pointer_width: u8,
6162
}
6263

6364
impl FuncTranslator {
6465
pub fn new(
6566
target_machine: TargetMachine,
6667
binary_fmt: BinaryFormat,
68+
pointer_width: u8,
6769
) -> Result<Self, CompileError> {
6870
let abi = get_abi(&target_machine);
6971
Ok(Self {
@@ -80,6 +82,7 @@ impl FuncTranslator {
8082
}
8183
},
8284
binary_fmt,
85+
pointer_width,
8386
})
8487
}
8588

@@ -116,8 +119,7 @@ impl FuncTranslator {
116119
.get(wasm_module.functions[func_index])
117120
.unwrap();
118121

119-
// TODO: pointer width
120-
let offsets = VMOffsets::new(8, wasm_module);
122+
let offsets = VMOffsets::new(self.pointer_width, wasm_module);
121123
let intrinsics = Intrinsics::declare(&module, &self.ctx, &target_data, &self.binary_fmt);
122124
let (func_type, func_attrs) =
123125
self.abi
@@ -238,7 +240,13 @@ impl FuncTranslator {
238240
state,
239241
function: func,
240242
locals: params_locals,
241-
ctx: CtxType::new(wasm_module, &func, &cache_builder, &*self.abi),
243+
ctx: CtxType::new(
244+
wasm_module,
245+
&func,
246+
&cache_builder,
247+
&*self.abi,
248+
self.pointer_width,
249+
),
242250
unreachable_depth: 0,
243251
memory_styles,
244252
_table_styles,

lib/compiler-llvm/src/translator/intrinsics.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1232,6 +1232,7 @@ impl<'ctx, 'a> CtxType<'ctx, 'a> {
12321232
func_value: &FunctionValue<'ctx>,
12331233
cache_builder: &'a Builder<'ctx>,
12341234
abi: &'a dyn Abi,
1235+
pointer_width: u8,
12351236
) -> CtxType<'ctx, 'a> {
12361237
CtxType {
12371238
ctx_ptr_value: abi.get_vmctx_ptr_param(func_value),
@@ -1248,8 +1249,7 @@ impl<'ctx, 'a> CtxType<'ctx, 'a> {
12481249
cached_memory_grow: HashMap::new(),
12491250
cached_memory_size: HashMap::new(),
12501251

1251-
// TODO: pointer width
1252-
offsets: VMOffsets::new(8, wasm_module),
1252+
offsets: VMOffsets::new(pointer_width, wasm_module),
12531253
}
12541254
}
12551255

lib/compiler/src/engine/artifact.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1107,11 +1107,13 @@ impl Artifact {
11071107
_ => 1,
11081108
};
11091109

1110+
// MetadataHeader::parse requires that metadata must be aligned
1111+
// by 8 bytes.
11101112
emit_data(
11111113
&mut obj,
11121114
object_name.as_bytes(),
11131115
&metadata_binary,
1114-
default_align,
1116+
std::cmp::max(8, default_align),
11151117
)
11161118
.map_err(to_compile_error)?;
11171119

0 commit comments

Comments
 (0)