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