winch_codegen/isa/x64/
mod.rs

1use crate::{
2    abi::{ABI, wasm_sig},
3    codegen::{BuiltinFunctions, CodeGen, CodeGenContext, FuncEnv, TypeConverter},
4};
5
6use crate::frame::{DefinedLocals, Frame};
7use crate::isa::x64::masm::MacroAssembler as X64Masm;
8use crate::isa::{Builder, TargetIsa};
9use crate::masm::MacroAssembler;
10use crate::regalloc::RegAlloc;
11use crate::stack::Stack;
12use anyhow::Result;
13use cranelift_codegen::settings::{self, Flags};
14use cranelift_codegen::{Final, MachBufferFinalized, isa::x64::settings as x64_settings};
15use cranelift_codegen::{MachTextSectionBuilder, TextSectionBuilder};
16use target_lexicon::Triple;
17use wasmparser::{FuncValidator, FunctionBody, ValidatorResources};
18use wasmtime_cranelift::CompiledFunction;
19use wasmtime_environ::{ModuleTranslation, ModuleTypesBuilder, Tunables, VMOffsets, WasmFuncType};
20
21use self::regs::{fpr_bit_set, gpr_bit_set};
22
23mod abi;
24mod address;
25mod asm;
26mod masm;
27// Not all the fpr and gpr constructors are used at the moment;
28// in that sense, this directive is a temporary measure to avoid
29// dead code warnings.
30#[expect(dead_code, reason = "not everything used yet, will be in the future")]
31mod regs;
32
33/// Create an ISA builder.
34pub(crate) fn isa_builder(triple: Triple) -> Builder {
35    Builder::new(
36        triple,
37        x64_settings::builder(),
38        |triple, shared_flags, settings| {
39            // TODO: Once enabling/disabling flags is allowed, and once features like SIMD are supported
40            // ensure compatibility between shared flags and ISA flags.
41            let isa_flags = x64_settings::Flags::new(&shared_flags, settings);
42            let isa = X64::new(triple, shared_flags, isa_flags);
43            Ok(Box::new(isa))
44        },
45    )
46}
47
48/// x64 ISA.
49pub(crate) struct X64 {
50    /// The target triple.
51    triple: Triple,
52    /// ISA specific flags.
53    isa_flags: x64_settings::Flags,
54    /// Shared flags.
55    shared_flags: Flags,
56}
57
58impl X64 {
59    /// Create a x64 ISA.
60    pub fn new(triple: Triple, shared_flags: Flags, isa_flags: x64_settings::Flags) -> Self {
61        Self {
62            isa_flags,
63            shared_flags,
64            triple,
65        }
66    }
67}
68
69impl TargetIsa for X64 {
70    fn name(&self) -> &'static str {
71        "x64"
72    }
73
74    fn triple(&self) -> &Triple {
75        &self.triple
76    }
77
78    fn flags(&self) -> &settings::Flags {
79        &self.shared_flags
80    }
81
82    fn isa_flags(&self) -> Vec<settings::Value> {
83        self.isa_flags.iter().collect()
84    }
85
86    fn compile_function(
87        &self,
88        sig: &WasmFuncType,
89        body: &FunctionBody,
90        translation: &ModuleTranslation,
91        types: &ModuleTypesBuilder,
92        builtins: &mut BuiltinFunctions,
93        validator: &mut FuncValidator<ValidatorResources>,
94        tunables: &Tunables,
95    ) -> Result<CompiledFunction> {
96        let pointer_bytes = self.pointer_bytes();
97        let vmoffsets = VMOffsets::new(pointer_bytes, &translation.module);
98
99        let mut body = body.get_binary_reader();
100        let mut masm = X64Masm::new(
101            pointer_bytes,
102            self.shared_flags.clone(),
103            self.isa_flags.clone(),
104        )?;
105        let stack = Stack::new();
106
107        let abi_sig = wasm_sig::<abi::X64ABI>(sig)?;
108
109        let env = FuncEnv::new(
110            &vmoffsets,
111            translation,
112            types,
113            builtins,
114            self,
115            abi::X64ABI::ptr_type(),
116        );
117        let type_converter = TypeConverter::new(env.translation, env.types);
118        let defined_locals =
119            DefinedLocals::new::<abi::X64ABI>(&type_converter, &mut body, validator)?;
120        let frame = Frame::new::<abi::X64ABI>(&abi_sig, &defined_locals)?;
121        let regalloc = RegAlloc::from(gpr_bit_set(), fpr_bit_set());
122        let codegen_context = CodeGenContext::new(regalloc, stack, frame, &vmoffsets);
123        let codegen = CodeGen::new(tunables, &mut masm, codegen_context, env, abi_sig);
124
125        let mut body_codegen = codegen.emit_prologue()?;
126
127        body_codegen.emit(body, validator)?;
128        let base = body_codegen.source_location.base;
129
130        let names = body_codegen.env.take_name_map();
131        Ok(CompiledFunction::new(
132            masm.finalize(base)?,
133            names,
134            self.function_alignment(),
135        ))
136    }
137
138    fn text_section_builder(&self, num_funcs: usize) -> Box<dyn TextSectionBuilder> {
139        Box::new(MachTextSectionBuilder::<cranelift_codegen::isa::x64::Inst>::new(num_funcs))
140    }
141
142    fn function_alignment(&self) -> u32 {
143        // See `cranelift_codegen`'s value of this for more information.
144        16
145    }
146
147    fn emit_unwind_info(
148        &self,
149        buffer: &MachBufferFinalized<Final>,
150        kind: cranelift_codegen::isa::unwind::UnwindInfoKind,
151    ) -> Result<Option<cranelift_codegen::isa::unwind::UnwindInfo>> {
152        Ok(cranelift_codegen::isa::x64::emit_unwind_info(buffer, kind)?)
153    }
154
155    fn create_systemv_cie(&self) -> Option<gimli::write::CommonInformationEntry> {
156        Some(cranelift_codegen::isa::x64::create_cie())
157    }
158
159    fn page_size_align_log2(&self) -> u8 {
160        12
161    }
162}