Skip to main content

winch_codegen/isa/x64/
mod.rs

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