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