wasmer_compiler_cranelift/translator/
translation_utils.rs

1//! Helper functions and structures for the translation.
2
3use crate::func_environ::FuncEnvironment;
4use crate::translator::EXN_REF_TYPE;
5use cranelift_codegen::{
6    binemit::Reloc,
7    cursor::FuncCursor,
8    ir::{self, AbiParam, InstBuilder},
9    isa::TargetFrontendConfig,
10};
11use cranelift_frontend::FunctionBuilder;
12use wasmer_compiler::{
13    types::relocation::RelocationKind,
14    wasmparser::{self, RefType},
15};
16use wasmer_types::{FunctionType, LibCall, Type, WasmError, WasmResult};
17
18/// Materialize a global value as CLIF instructions.
19pub(crate) fn materialize_global_value(
20    pos: &mut FuncCursor<'_>,
21    pointer_type: ir::Type,
22    global_value: ir::GlobalValue,
23) -> ir::Value {
24    match pos.func.global_values[global_value] {
25        ir::GlobalValueData::VMContext => pos
26            .func
27            .special_param(ir::ArgumentPurpose::VMContext)
28            .expect("missing vmctx parameter"),
29        ir::GlobalValueData::IAddImm {
30            base,
31            offset,
32            global_type,
33        } => {
34            let base = materialize_global_value(pos, global_type, base);
35            pos.ins().iadd_imm_s(base, i64::from(offset))
36        }
37        ir::GlobalValueData::Load {
38            base,
39            offset,
40            global_type,
41            flags,
42        } => {
43            let base = materialize_global_value(pos, pointer_type, base);
44            let flags = pos.func.dfg.mem_flags[flags];
45            pos.ins().load(global_type, flags, base, offset)
46        }
47        ir::GlobalValueData::Symbol { tls, .. } => {
48            if tls {
49                pos.ins().tls_value(pointer_type, global_value)
50            } else {
51                pos.ins().symbol_value(pointer_type, global_value)
52            }
53        }
54        ir::GlobalValueData::DynScaleTargetConst { .. } => {
55            unreachable!("dynamic vector-scale global values are not created by Wasmer")
56        }
57    }
58}
59
60/// Helper function translate a Function signature into Cranelift Ir
61pub fn signature_to_cranelift_ir(
62    signature: &FunctionType,
63    target_config: TargetFrontendConfig,
64) -> ir::Signature {
65    let mut sig = ir::Signature::new(target_config.default_call_conv);
66    sig.params.extend(signature.params().iter().map(|&ty| {
67        let cret_arg: ir::Type = type_to_irtype(ty, target_config)
68            .expect("only numeric types are supported in function signatures");
69        AbiParam::new(cret_arg)
70    }));
71    sig.returns.extend(signature.results().iter().map(|&ty| {
72        let cret_arg: ir::Type = type_to_irtype(ty, target_config)
73            .expect("only numeric types are supported in function signatures");
74        AbiParam::new(cret_arg)
75    }));
76    // The Vmctx signature
77    sig.params.insert(
78        0,
79        AbiParam::special(target_config.pointer_type(), ir::ArgumentPurpose::VMContext),
80    );
81    sig
82}
83
84/// Helper function translating wasmparser types to Cranelift types when possible.
85pub fn reference_type(target_config: TargetFrontendConfig) -> WasmResult<ir::Type> {
86    Ok(target_config.pointer_type())
87}
88
89/// Helper function translating wasmparser types to Cranelift types when possible.
90pub fn type_to_irtype(ty: Type, target_config: TargetFrontendConfig) -> WasmResult<ir::Type> {
91    match ty {
92        Type::I32 => Ok(ir::types::I32),
93        Type::I64 => Ok(ir::types::I64),
94        Type::F32 => Ok(ir::types::F32),
95        Type::F64 => Ok(ir::types::F64),
96        Type::V128 => Ok(ir::types::I8X16),
97        Type::ExternRef | Type::FuncRef => reference_type(target_config),
98        Type::ExceptionRef => Ok(EXN_REF_TYPE),
99        // ty => Err(wasm_unsupported!("type_to_type: wasm type {:?}", ty)),
100    }
101}
102
103/// Transform Cranelift LibCall into runtime LibCall
104pub fn irlibcall_to_libcall(libcall: ir::LibCall) -> LibCall {
105    match libcall {
106        ir::LibCall::Probestack => LibCall::Probestack,
107        ir::LibCall::CeilF32 => LibCall::CeilF32,
108        ir::LibCall::CeilF64 => LibCall::CeilF64,
109        ir::LibCall::FloorF32 => LibCall::FloorF32,
110        ir::LibCall::FloorF64 => LibCall::FloorF64,
111        ir::LibCall::TruncF32 => LibCall::TruncF32,
112        ir::LibCall::TruncF64 => LibCall::TruncF64,
113        ir::LibCall::NearestF32 => LibCall::NearestF32,
114        ir::LibCall::NearestF64 => LibCall::NearestF64,
115        _ => panic!("Unsupported libcall"),
116    }
117}
118
119/// Transform Cranelift Reloc to compiler Relocation
120pub fn irreloc_to_relocationkind(reloc: Reloc) -> RelocationKind {
121    match reloc {
122        Reloc::Abs4 => RelocationKind::Abs4,
123        Reloc::Abs8 => RelocationKind::Abs8,
124        Reloc::X86PCRel4 => RelocationKind::PCRel4,
125        Reloc::X86CallPCRel4 => RelocationKind::X86CallPCRel4,
126        Reloc::X86CallPLTRel4 => RelocationKind::X86CallPLTRel4,
127        Reloc::X86GOTPCRel4 => RelocationKind::X86GOTPCRel4,
128        Reloc::Arm64Call => RelocationKind::Arm64Call,
129        Reloc::RiscvCallPlt => RelocationKind::RiscvCall,
130        _ => panic!("The relocation {reloc} is not yet supported."),
131    }
132}
133
134/// Create a `Block` with the given Wasm parameters.
135pub fn block_with_params<'a>(
136    builder: &mut FunctionBuilder,
137    params: impl Iterator<Item = &'a wasmparser::ValType>,
138    environ: &FuncEnvironment<'_>,
139) -> WasmResult<ir::Block> {
140    let block = builder.create_block();
141    for ty in params.into_iter() {
142        match ty {
143            wasmparser::ValType::I32 => {
144                builder.append_block_param(block, ir::types::I32);
145            }
146            wasmparser::ValType::I64 => {
147                builder.append_block_param(block, ir::types::I64);
148            }
149            wasmparser::ValType::F32 => {
150                builder.append_block_param(block, ir::types::F32);
151            }
152            wasmparser::ValType::F64 => {
153                builder.append_block_param(block, ir::types::F64);
154            }
155            wasmparser::ValType::Ref(ty) => {
156                if ty.is_extern_ref() || ty.is_func_ref() {
157                    builder.append_block_param(block, environ.reference_type());
158                } else if ty == &RefType::EXNREF || ty == &RefType::EXN {
159                    // no `.is_exnref` yet
160                    builder.append_block_param(block, EXN_REF_TYPE);
161                } else {
162                    return Err(WasmError::Unsupported(format!(
163                        "unsupported reference type: {ty:?}"
164                    )));
165                }
166            }
167            wasmparser::ValType::V128 => {
168                builder.append_block_param(block, ir::types::I8X16);
169            }
170        }
171    }
172    Ok(block)
173}
174
175/// Turns a `wasmparser` `f32` into a `Cranelift` one.
176pub fn f32_translation(x: wasmparser::Ieee32) -> ir::immediates::Ieee32 {
177    ir::immediates::Ieee32::with_bits(x.bits())
178}
179
180/// Turns a `wasmparser` `f64` into a `Cranelift` one.
181pub fn f64_translation(x: wasmparser::Ieee64) -> ir::immediates::Ieee64 {
182    ir::immediates::Ieee64::with_bits(x.bits())
183}
184
185/// Special VMContext value label. It is tracked as 0xffff_fffe label.
186pub fn get_vmctx_value_label() -> ir::ValueLabel {
187    const VMCTX_LABEL: u32 = 0xffff_fffe;
188    ir::ValueLabel::from_u32(VMCTX_LABEL)
189}