winch_codegen/isa/x64/
mod.rs

1use crate::{
2    abi::{wasm_sig, ABI},
3    codegen::{BuiltinFunctions, CodeGen, CodeGenContext, FuncEnv, TypeConverter},
4};
5
6use crate::frame::{DefinedLocals, Frame};
7use crate::isa::x64::masm::MacroAssembler as X64Masm;
8use crate::masm::MacroAssembler;
9use crate::regalloc::RegAlloc;
10use crate::stack::Stack;
11use crate::{
12    isa::{Builder, TargetIsa},
13    regset::RegBitSet,
14};
15use anyhow::Result;
16use cranelift_codegen::settings::{self, Flags};
17use cranelift_codegen::{isa::x64::settings as x64_settings, Final, MachBufferFinalized};
18use cranelift_codegen::{MachTextSectionBuilder, TextSectionBuilder};
19use target_lexicon::Triple;
20use wasmparser::{FuncValidator, FunctionBody, ValidatorResources};
21use wasmtime_cranelift::CompiledFunction;
22use wasmtime_environ::{ModuleTranslation, ModuleTypesBuilder, Tunables, VMOffsets, WasmFuncType};
23
24use self::regs::{ALL_FPR, ALL_GPR, MAX_FPR, MAX_GPR, NON_ALLOCATABLE_FPR, NON_ALLOCATABLE_GPR};
25
26mod abi;
27mod address;
28mod asm;
29mod 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)]
34mod regs;
35
36/// Create an ISA builder.
37pub(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.
52pub(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
61impl 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
72impl 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        tunables: &Tunables,
98    ) -> Result<CompiledFunction> {
99        let pointer_bytes = self.pointer_bytes();
100        let vmoffsets = VMOffsets::new(pointer_bytes, &translation.module);
101
102        let mut body = body.get_binary_reader();
103        let mut masm = X64Masm::new(
104            pointer_bytes,
105            self.shared_flags.clone(),
106            self.isa_flags.clone(),
107        )?;
108        let stack = Stack::new();
109
110        let abi_sig = wasm_sig::<abi::X64ABI>(sig)?;
111
112        let env = FuncEnv::new(
113            &vmoffsets,
114            translation,
115            types,
116            builtins,
117            self,
118            abi::X64ABI::ptr_type(),
119        );
120        let type_converter = TypeConverter::new(env.translation, env.types);
121        let defined_locals =
122            DefinedLocals::new::<abi::X64ABI>(&type_converter, &mut body, validator)?;
123        let frame = Frame::new::<abi::X64ABI>(&abi_sig, &defined_locals)?;
124        let gpr = RegBitSet::int(
125            ALL_GPR.into(),
126            NON_ALLOCATABLE_GPR.into(),
127            usize::try_from(MAX_GPR).unwrap(),
128        );
129        let fpr = RegBitSet::float(
130            ALL_FPR.into(),
131            NON_ALLOCATABLE_FPR.into(),
132            usize::try_from(MAX_FPR).unwrap(),
133        );
134
135        let regalloc = RegAlloc::from(gpr, fpr);
136        let codegen_context = CodeGenContext::new(regalloc, stack, frame, &vmoffsets);
137        let codegen = CodeGen::new(tunables, &mut masm, codegen_context, env, abi_sig);
138
139        let mut body_codegen = codegen.emit_prologue()?;
140
141        body_codegen.emit(&mut body, validator)?;
142        let base = body_codegen.source_location.base;
143
144        let names = body_codegen.env.take_name_map();
145        Ok(CompiledFunction::new(
146            masm.finalize(base)?,
147            names,
148            self.function_alignment(),
149        ))
150    }
151
152    fn text_section_builder(&self, num_funcs: usize) -> Box<dyn TextSectionBuilder> {
153        Box::new(MachTextSectionBuilder::<cranelift_codegen::isa::x64::Inst>::new(num_funcs))
154    }
155
156    fn function_alignment(&self) -> u32 {
157        // See `cranelift_codegen`'s value of this for more information.
158        16
159    }
160
161    fn emit_unwind_info(
162        &self,
163        buffer: &MachBufferFinalized<Final>,
164        kind: cranelift_codegen::isa::unwind::UnwindInfoKind,
165    ) -> Result<Option<cranelift_codegen::isa::unwind::UnwindInfo>> {
166        Ok(cranelift_codegen::isa::x64::emit_unwind_info(buffer, kind)?)
167    }
168
169    fn create_systemv_cie(&self) -> Option<gimli::write::CommonInformationEntry> {
170        Some(cranelift_codegen::isa::x64::create_cie())
171    }
172
173    fn page_size_align_log2(&self) -> u8 {
174        12
175    }
176}