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