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