Skip to main content

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