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