wasmer_compiler_cranelift/translator/
translation_utils.rs

1//! Helper functions and structures for the translation.
2
3use super::func_environ::TargetEnvironment;
4use cranelift_codegen::{
5    binemit::Reloc,
6    ir::{self, AbiParam},
7    isa::TargetFrontendConfig,
8};
9use cranelift_frontend::FunctionBuilder;
10use wasmer_compiler::{types::relocation::RelocationKind, wasm_unsupported, wasmparser};
11use wasmer_types::{FunctionType, LibCall, Type, WasmError, WasmResult};
12
13/// Helper function translate a Function signature into Cranelift Ir
14pub fn signature_to_cranelift_ir(
15    signature: &FunctionType,
16    target_config: TargetFrontendConfig,
17) -> ir::Signature {
18    let mut sig = ir::Signature::new(target_config.default_call_conv);
19    sig.params.extend(signature.params().iter().map(|&ty| {
20        let cret_arg: ir::Type = type_to_irtype(ty, target_config)
21            .expect("only numeric types are supported in function signatures");
22        AbiParam::new(cret_arg)
23    }));
24    sig.returns.extend(signature.results().iter().map(|&ty| {
25        let cret_arg: ir::Type = type_to_irtype(ty, target_config)
26            .expect("only numeric types are supported in function signatures");
27        AbiParam::new(cret_arg)
28    }));
29    // The Vmctx signature
30    sig.params.insert(
31        0,
32        AbiParam::special(target_config.pointer_type(), ir::ArgumentPurpose::VMContext),
33    );
34    sig
35}
36
37/// Helper function translating wasmparser types to Cranelift types when possible.
38pub fn reference_type(target_config: TargetFrontendConfig) -> WasmResult<ir::Type> {
39    Ok(target_config.pointer_type())
40}
41
42/// Helper function translating wasmparser types to Cranelift types when possible.
43pub fn type_to_irtype(ty: Type, target_config: TargetFrontendConfig) -> WasmResult<ir::Type> {
44    match ty {
45        Type::I32 => Ok(ir::types::I32),
46        Type::I64 => Ok(ir::types::I64),
47        Type::F32 => Ok(ir::types::F32),
48        Type::F64 => Ok(ir::types::F64),
49        Type::V128 => Ok(ir::types::I8X16),
50        Type::ExternRef | Type::FuncRef => reference_type(target_config),
51        Type::ExceptionRef => Err(wasm_unsupported!(
52            "exnrefs are not supported yet in cranelift"
53        )),
54        // ty => Err(wasm_unsupported!("type_to_type: wasm type {:?}", ty)),
55    }
56}
57
58/// Transform Cranelift LibCall into runtime LibCall
59pub fn irlibcall_to_libcall(libcall: ir::LibCall) -> LibCall {
60    match libcall {
61        ir::LibCall::Probestack => LibCall::Probestack,
62        ir::LibCall::CeilF32 => LibCall::CeilF32,
63        ir::LibCall::CeilF64 => LibCall::CeilF64,
64        ir::LibCall::FloorF32 => LibCall::FloorF32,
65        ir::LibCall::FloorF64 => LibCall::FloorF64,
66        ir::LibCall::TruncF32 => LibCall::TruncF32,
67        ir::LibCall::TruncF64 => LibCall::TruncF64,
68        ir::LibCall::NearestF32 => LibCall::NearestF32,
69        ir::LibCall::NearestF64 => LibCall::NearestF64,
70        _ => panic!("Unsupported libcall"),
71    }
72}
73
74/// Transform Cranelift Reloc to compiler Relocation
75pub fn irreloc_to_relocationkind(reloc: Reloc) -> RelocationKind {
76    match reloc {
77        Reloc::Abs4 => RelocationKind::Abs4,
78        Reloc::Abs8 => RelocationKind::Abs8,
79        Reloc::X86PCRel4 => RelocationKind::X86PCRel4,
80        Reloc::X86CallPCRel4 => RelocationKind::X86CallPCRel4,
81        Reloc::X86CallPLTRel4 => RelocationKind::X86CallPLTRel4,
82        Reloc::X86GOTPCRel4 => RelocationKind::X86GOTPCRel4,
83        Reloc::Arm64Call => RelocationKind::Arm64Call,
84        Reloc::RiscvCallPlt => RelocationKind::RiscvCall,
85        _ => panic!("The relocation {reloc} is not yet supported."),
86    }
87}
88
89/// Create a `Block` with the given Wasm parameters.
90pub fn block_with_params<'a, PE: TargetEnvironment + ?Sized>(
91    builder: &mut FunctionBuilder,
92    params: impl Iterator<Item = &'a wasmparser::ValType>,
93    environ: &PE,
94) -> WasmResult<ir::Block> {
95    let block = builder.create_block();
96    for ty in params.into_iter() {
97        match ty {
98            wasmparser::ValType::I32 => {
99                builder.append_block_param(block, ir::types::I32);
100            }
101            wasmparser::ValType::I64 => {
102                builder.append_block_param(block, ir::types::I64);
103            }
104            wasmparser::ValType::F32 => {
105                builder.append_block_param(block, ir::types::F32);
106            }
107            wasmparser::ValType::F64 => {
108                builder.append_block_param(block, ir::types::F64);
109            }
110            wasmparser::ValType::Ref(ty) => {
111                if ty.is_extern_ref() || ty.is_func_ref() {
112                    builder.append_block_param(block, environ.reference_type());
113                } else {
114                    return Err(WasmError::Unsupported(format!(
115                        "unsupported reference type: {ty:?}"
116                    )));
117                }
118            }
119            wasmparser::ValType::V128 => {
120                builder.append_block_param(block, ir::types::I8X16);
121            }
122        }
123    }
124    Ok(block)
125}
126
127/// Turns a `wasmparser` `f32` into a `Cranelift` one.
128pub fn f32_translation(x: wasmparser::Ieee32) -> ir::immediates::Ieee32 {
129    ir::immediates::Ieee32::with_bits(x.bits())
130}
131
132/// Turns a `wasmparser` `f64` into a `Cranelift` one.
133pub fn f64_translation(x: wasmparser::Ieee64) -> ir::immediates::Ieee64 {
134    ir::immediates::Ieee64::with_bits(x.bits())
135}
136
137/// Special VMContext value label. It is tracked as 0xffff_fffe label.
138pub fn get_vmctx_value_label() -> ir::ValueLabel {
139    const VMCTX_LABEL: u32 = 0xffff_fffe;
140    ir::ValueLabel::from_u32(VMCTX_LABEL)
141}