1 use self::regs::{ALL_GPR, MAX_FPR, MAX_GPR, NON_ALLOCATABLE_GPR};
2 use crate::isa::aarch64::regs::{ALL_FPR, NON_ALLOCATABLE_FPR};
3 use crate::{
4     abi::{wasm_sig, ABI},
5     codegen::{CodeGen, CodeGenContext, FuncEnv, TypeConverter},
6     frame::{DefinedLocals, Frame},
7     isa::{Builder, TargetIsa},
8     masm::MacroAssembler,
9     regalloc::RegAlloc,
10     regset::RegBitSet,
11     stack::Stack,
12     BuiltinFunctions,
13 };
14 use anyhow::Result;
15 use cranelift_codegen::settings::{self, Flags};
16 use cranelift_codegen::{isa::aarch64::settings as aarch64_settings, Final, MachBufferFinalized};
17 use cranelift_codegen::{MachTextSectionBuilder, TextSectionBuilder};
18 use masm::MacroAssembler as Aarch64Masm;
19 use target_lexicon::Triple;
20 use wasmparser::{FuncValidator, FunctionBody, ValidatorResources};
21 use wasmtime_cranelift::CompiledFunction;
22 use wasmtime_environ::{ModuleTranslation, ModuleTypesBuilder, Tunables, VMOffsets, WasmFuncType};
23 
24 mod abi;
25 mod address;
26 mod asm;
27 mod masm;
28 mod regs;
29 
30 /// Create an ISA from the given triple.
31 pub(crate) fn isa_builder(triple: Triple) -> Builder {
32     Builder::new(
33         triple,
34         aarch64_settings::builder(),
35         |triple, shared_flags, settings| {
36             let isa_flags = aarch64_settings::Flags::new(&shared_flags, settings);
37             let isa = Aarch64::new(triple, shared_flags, isa_flags);
38             Ok(Box::new(isa))
39         },
40     )
41 }
42 
43 /// Aarch64 ISA.
44 pub(crate) struct Aarch64 {
45     /// The target triple.
46     triple: Triple,
47     /// ISA specific flags.
48     isa_flags: aarch64_settings::Flags,
49     /// Shared flags.
50     shared_flags: Flags,
51 }
52 
53 impl Aarch64 {
54     /// Create an Aarch64 ISA.
55     pub fn new(triple: Triple, shared_flags: Flags, isa_flags: aarch64_settings::Flags) -> Self {
56         Self {
57             isa_flags,
58             shared_flags,
59             triple,
60         }
61     }
62 }
63 
64 impl TargetIsa for Aarch64 {
65     fn name(&self) -> &'static str {
66         "aarch64"
67     }
68 
69     fn triple(&self) -> &Triple {
70         &self.triple
71     }
72 
73     fn flags(&self) -> &settings::Flags {
74         &self.shared_flags
75     }
76 
77     fn isa_flags(&self) -> Vec<settings::Value> {
78         self.isa_flags.iter().collect()
79     }
80 
81     fn is_branch_protection_enabled(&self) -> bool {
82         self.isa_flags.use_bti()
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         let mut body = body.get_binary_reader();
98         let mut masm = Aarch64Masm::new(pointer_bytes, self.shared_flags.clone());
99         let stack = Stack::new();
100         let abi_sig = wasm_sig::<abi::Aarch64ABI>(sig);
101 
102         let env = FuncEnv::new(
103             &vmoffsets,
104             translation,
105             types,
106             builtins,
107             self,
108             abi::Aarch64ABI::ptr_type(),
109         );
110         let type_converter = TypeConverter::new(env.translation, env.types);
111         let defined_locals =
112             DefinedLocals::new::<abi::Aarch64ABI>(&type_converter, &mut body, validator)?;
113         let frame = Frame::new::<abi::Aarch64ABI>(&abi_sig, &defined_locals)?;
114         let gpr = RegBitSet::int(
115             ALL_GPR.into(),
116             NON_ALLOCATABLE_GPR.into(),
117             usize::try_from(MAX_GPR).unwrap(),
118         );
119         let fpr = RegBitSet::float(
120             ALL_FPR.into(),
121             NON_ALLOCATABLE_FPR.into(),
122             usize::try_from(MAX_FPR).unwrap(),
123         );
124         let regalloc = RegAlloc::from(gpr, fpr);
125         let codegen_context = CodeGenContext::new(regalloc, stack, frame, &vmoffsets);
126         let codegen = CodeGen::new(tunables, &mut masm, codegen_context, env, abi_sig);
127 
128         let mut body_codegen = codegen.emit_prologue()?;
129         body_codegen.emit(&mut body, validator)?;
130         let names = body_codegen.env.take_name_map();
131         let base = body_codegen.source_location.base;
132         Ok(CompiledFunction::new(
133             masm.finalize(base),
134             names,
135             self.function_alignment(),
136         ))
137     }
138 
139     fn text_section_builder(&self, num_funcs: usize) -> Box<dyn TextSectionBuilder> {
140         Box::new(MachTextSectionBuilder::<
141             cranelift_codegen::isa::aarch64::inst::Inst,
142         >::new(num_funcs))
143     }
144 
145     fn function_alignment(&self) -> u32 {
146         // See `cranelift_codegen::isa::TargetIsa::function_alignment`.
147         32
148     }
149 
150     fn emit_unwind_info(
151         &self,
152         _result: &MachBufferFinalized<Final>,
153         _kind: cranelift_codegen::isa::unwind::UnwindInfoKind,
154     ) -> Result<Option<cranelift_codegen::isa::unwind::UnwindInfo>> {
155         // TODO: should fill this in with an actual implementation
156         Ok(None)
157     }
158 
159     fn page_size_align_log2(&self) -> u8 {
160         use target_lexicon::*;
161         match self.triple().operating_system {
162             OperatingSystem::MacOSX { .. }
163             | OperatingSystem::Darwin
164             | OperatingSystem::Ios
165             | OperatingSystem::Tvos => {
166                 debug_assert_eq!(1 << 14, 0x4000);
167                 14
168             }
169             _ => {
170                 debug_assert_eq!(1 << 16, 0x10000);
171                 16
172             }
173         }
174     }
175 }
176