xref: /wasmtime-44.0.1/winch/codegen/src/isa/x64/mod.rs (revision fee9be21)
1 use crate::{
2     abi::{ABI, wasm_sig},
3     codegen::{BuiltinFunctions, CodeGen, CodeGenContext, FuncEnv, TypeConverter},
4 };
5 
6 use crate::frame::{DefinedLocals, Frame};
7 use crate::isa::x64::masm::MacroAssembler as X64Masm;
8 use crate::isa::{Builder, TargetIsa};
9 use crate::masm::MacroAssembler;
10 use crate::regalloc::RegAlloc;
11 use crate::stack::Stack;
12 use anyhow::Result;
13 use cranelift_codegen::settings::{self, Flags};
14 use cranelift_codegen::{Final, MachBufferFinalized, isa::x64::settings as x64_settings};
15 use cranelift_codegen::{MachTextSectionBuilder, TextSectionBuilder};
16 use target_lexicon::Triple;
17 use wasmparser::{FuncValidator, FunctionBody, ValidatorResources};
18 use wasmtime_cranelift::CompiledFunction;
19 use wasmtime_environ::{ModuleTranslation, ModuleTypesBuilder, Tunables, VMOffsets, WasmFuncType};
20 
21 use self::regs::{fpr_bit_set, gpr_bit_set};
22 
23 mod abi;
24 mod address;
25 mod asm;
26 mod 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")]
31 mod regs;
32 
33 /// Create an ISA builder.
34 pub(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.
49 pub(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 
58 impl 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 
69 impl 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 }
163