cranelift_codegen/isa/aarch64/
mod.rs1use crate::dominator_tree::DominatorTree;
4use crate::ir::{Function, Type};
5use crate::isa::aarch64::settings as aarch64_settings;
6#[cfg(feature = "unwind")]
7use crate::isa::unwind::systemv;
8use crate::isa::{Builder as IsaBuilder, FunctionAlignment, TargetIsa};
9use crate::machinst::{
10 compile, CompiledCode, CompiledCodeStencil, MachInst, MachTextSectionBuilder, Reg, SigSet,
11 TextSectionBuilder, VCode,
12};
13use crate::result::CodegenResult;
14use crate::settings as shared_settings;
15use alloc::{boxed::Box, vec::Vec};
16use core::fmt;
17use cranelift_control::ControlPlane;
18use target_lexicon::{Aarch64Architecture, Architecture, OperatingSystem, Triple};
19
20mod abi;
22pub mod inst;
23mod lower;
24mod pcc;
25pub mod settings;
26
27use self::inst::EmitInfo;
28
29pub struct AArch64Backend {
31 triple: Triple,
32 flags: shared_settings::Flags,
33 isa_flags: aarch64_settings::Flags,
34}
35
36impl AArch64Backend {
37 pub fn new_with_flags(
39 triple: Triple,
40 flags: shared_settings::Flags,
41 isa_flags: aarch64_settings::Flags,
42 ) -> AArch64Backend {
43 AArch64Backend {
44 triple,
45 flags,
46 isa_flags,
47 }
48 }
49
50 fn compile_vcode(
53 &self,
54 func: &Function,
55 domtree: &DominatorTree,
56 ctrl_plane: &mut ControlPlane,
57 ) -> CodegenResult<(VCode<inst::Inst>, regalloc2::Output)> {
58 let emit_info = EmitInfo::new(self.flags.clone());
59 let sigs = SigSet::new::<abi::AArch64MachineDeps>(func, &self.flags)?;
60 let abi = abi::AArch64Callee::new(func, self, &self.isa_flags, &sigs)?;
61 compile::compile::<AArch64Backend>(func, domtree, self, abi, emit_info, sigs, ctrl_plane)
62 }
63}
64
65impl TargetIsa for AArch64Backend {
66 fn compile_function(
67 &self,
68 func: &Function,
69 domtree: &DominatorTree,
70 want_disasm: bool,
71 ctrl_plane: &mut ControlPlane,
72 ) -> CodegenResult<CompiledCodeStencil> {
73 let (vcode, regalloc_result) = self.compile_vcode(func, domtree, ctrl_plane)?;
74
75 let emit_result = vcode.emit(®alloc_result, want_disasm, &self.flags, ctrl_plane);
76 let frame_size = emit_result.frame_size;
77 let value_labels_ranges = emit_result.value_labels_ranges;
78 let buffer = emit_result.buffer;
79 let sized_stackslot_offsets = emit_result.sized_stackslot_offsets;
80 let dynamic_stackslot_offsets = emit_result.dynamic_stackslot_offsets;
81
82 if let Some(disasm) = emit_result.disasm.as_ref() {
83 log::debug!("disassembly:\n{}", disasm);
84 }
85
86 Ok(CompiledCodeStencil {
87 buffer,
88 frame_size,
89 vcode: emit_result.disasm,
90 value_labels_ranges,
91 sized_stackslot_offsets,
92 dynamic_stackslot_offsets,
93 bb_starts: emit_result.bb_offsets,
94 bb_edges: emit_result.bb_edges,
95 })
96 }
97
98 fn name(&self) -> &'static str {
99 "aarch64"
100 }
101
102 fn triple(&self) -> &Triple {
103 &self.triple
104 }
105
106 fn flags(&self) -> &shared_settings::Flags {
107 &self.flags
108 }
109
110 fn isa_flags(&self) -> Vec<shared_settings::Value> {
111 self.isa_flags.iter().collect()
112 }
113
114 fn is_branch_protection_enabled(&self) -> bool {
115 self.isa_flags.use_bti()
116 }
117
118 fn dynamic_vector_bytes(&self, _dyn_ty: Type) -> u32 {
119 16
120 }
121
122 #[cfg(feature = "unwind")]
123 fn emit_unwind_info(
124 &self,
125 result: &CompiledCode,
126 kind: crate::isa::unwind::UnwindInfoKind,
127 ) -> CodegenResult<Option<crate::isa::unwind::UnwindInfo>> {
128 use crate::isa::unwind::UnwindInfo;
129 use crate::isa::unwind::UnwindInfoKind;
130 Ok(match kind {
131 UnwindInfoKind::SystemV => {
132 let mapper = self::inst::unwind::systemv::RegisterMapper;
133 Some(UnwindInfo::SystemV(
134 crate::isa::unwind::systemv::create_unwind_info_from_insts(
135 &result.buffer.unwind_info[..],
136 result.buffer.data().len(),
137 &mapper,
138 )?,
139 ))
140 }
141 UnwindInfoKind::Windows => {
142 None
144 }
145 _ => None,
146 })
147 }
148
149 #[cfg(feature = "unwind")]
150 fn create_systemv_cie(&self) -> Option<gimli::write::CommonInformationEntry> {
151 let is_apple_os = match self.triple.operating_system {
152 OperatingSystem::Darwin
153 | OperatingSystem::Ios
154 | OperatingSystem::MacOSX { .. }
155 | OperatingSystem::Tvos => true,
156 _ => false,
157 };
158
159 if self.isa_flags.sign_return_address()
160 && self.isa_flags.sign_return_address_with_bkey()
161 && !is_apple_os
162 {
163 unimplemented!("Specifying that the B key is used with pointer authentication instructions in the CIE is not implemented.");
164 }
165
166 Some(inst::unwind::systemv::create_cie())
167 }
168
169 fn text_section_builder(&self, num_funcs: usize) -> Box<dyn TextSectionBuilder> {
170 Box::new(MachTextSectionBuilder::<inst::Inst>::new(num_funcs))
171 }
172
173 #[cfg(feature = "unwind")]
174 fn map_regalloc_reg_to_dwarf(&self, reg: Reg) -> Result<u16, systemv::RegisterMappingError> {
175 inst::unwind::systemv::map_reg(reg).map(|reg| reg.0)
176 }
177
178 fn function_alignment(&self) -> FunctionAlignment {
179 inst::Inst::function_alignment()
180 }
181
182 fn page_size_align_log2(&self) -> u8 {
183 use target_lexicon::*;
184 match self.triple().operating_system {
185 OperatingSystem::MacOSX { .. }
186 | OperatingSystem::Darwin
187 | OperatingSystem::Ios
188 | OperatingSystem::Tvos => {
189 debug_assert_eq!(1 << 14, 0x4000);
190 14
191 }
192 _ => {
193 debug_assert_eq!(1 << 16, 0x10000);
194 16
195 }
196 }
197 }
198
199 #[cfg(feature = "disas")]
200 fn to_capstone(&self) -> Result<capstone::Capstone, capstone::Error> {
201 use capstone::prelude::*;
202 let mut cs = Capstone::new()
203 .arm64()
204 .mode(arch::arm64::ArchMode::Arm)
205 .detail(true)
206 .build()?;
207 cs.set_skipdata(true)?;
213 Ok(cs)
214 }
215
216 fn has_native_fma(&self) -> bool {
217 true
218 }
219
220 fn has_x86_blendv_lowering(&self, _: Type) -> bool {
221 false
222 }
223
224 fn has_x86_pshufb_lowering(&self) -> bool {
225 false
226 }
227
228 fn has_x86_pmulhrsw_lowering(&self) -> bool {
229 false
230 }
231
232 fn has_x86_pmaddubsw_lowering(&self) -> bool {
233 false
234 }
235}
236
237impl fmt::Display for AArch64Backend {
238 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
239 f.debug_struct("MachBackend")
240 .field("name", &self.name())
241 .field("triple", &self.triple())
242 .field("flags", &format!("{}", self.flags()))
243 .finish()
244 }
245}
246
247pub fn isa_builder(triple: Triple) -> IsaBuilder {
249 assert!(triple.architecture == Architecture::Aarch64(Aarch64Architecture::Aarch64));
250 IsaBuilder {
251 triple,
252 setup: aarch64_settings::builder(),
253 constructor: |triple, shared_flags, builder| {
254 let isa_flags = aarch64_settings::Flags::new(&shared_flags, builder);
255 let backend = AArch64Backend::new_with_flags(triple, shared_flags, isa_flags);
256 Ok(backend.wrapped())
257 },
258 }
259}