1 //! Common support compiling to either 32- or 64-bit Pulley bytecode. 2 3 mod abi; 4 mod inst; 5 mod lower; 6 mod settings; 7 8 use self::inst::EmitInfo; 9 use super::{Builder as IsaBuilder, FunctionAlignment}; 10 use crate::{ 11 MachTextSectionBuilder, TextSectionBuilder, 12 dominator_tree::DominatorTree, 13 ir, 14 isa::{self, IsaFlagsHashKey, OwnedTargetIsa, TargetIsa}, 15 machinst::{self, CompiledCodeStencil, MachInst, SigSet, VCode}, 16 result::CodegenResult, 17 settings::{self as shared_settings, Flags}, 18 }; 19 use alloc::boxed::Box; 20 use alloc::string::String; 21 use alloc::vec::Vec; 22 use core::fmt::Debug; 23 use core::marker::PhantomData; 24 use cranelift_control::ControlPlane; 25 use target_lexicon::{Architecture, Triple}; 26 27 pub use settings::Flags as PulleyFlags; 28 29 /// A trait to abstract over the different kinds of Pulley targets that exist 30 /// (32- vs 64-bit). 31 pub trait PulleyTargetKind: 'static + Clone + Debug + Default + Send + Sync { 32 // Required types and methods. 33 34 fn pointer_width() -> PointerWidth; 35 36 // Provided methods. Don't overwrite. 37 38 fn name() -> &'static str { 39 match Self::pointer_width() { 40 PointerWidth::PointerWidth32 => "pulley32", 41 PointerWidth::PointerWidth64 => "pulley64", 42 } 43 } 44 } 45 46 pub enum PointerWidth { 47 PointerWidth32, 48 PointerWidth64, 49 } 50 51 impl PointerWidth { 52 pub fn bits(self) -> u8 { 53 match self { 54 PointerWidth::PointerWidth32 => 32, 55 PointerWidth::PointerWidth64 => 64, 56 } 57 } 58 59 pub fn bytes(self) -> u8 { 60 self.bits() / 8 61 } 62 } 63 64 /// A Pulley backend. 65 pub struct PulleyBackend<P> 66 where 67 P: PulleyTargetKind, 68 { 69 pulley_target: PhantomData<P>, 70 triple: Triple, 71 flags: Flags, 72 isa_flags: PulleyFlags, 73 } 74 75 impl<P> core::fmt::Debug for PulleyBackend<P> 76 where 77 P: PulleyTargetKind, 78 { 79 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 80 let PulleyBackend { 81 pulley_target: _, 82 triple, 83 flags: _, 84 isa_flags: _, 85 } = self; 86 f.debug_struct("PulleyBackend") 87 .field("triple", triple) 88 .finish_non_exhaustive() 89 } 90 } 91 92 impl<P> core::fmt::Display for PulleyBackend<P> 93 where 94 P: PulleyTargetKind, 95 { 96 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 97 core::fmt::Debug::fmt(self, f) 98 } 99 } 100 101 impl<P> PulleyBackend<P> 102 where 103 P: PulleyTargetKind, 104 { 105 /// Create a new pulley backend with the given (shared) flags. 106 pub fn new_with_flags( 107 triple: Triple, 108 flags: shared_settings::Flags, 109 isa_flags: PulleyFlags, 110 ) -> Self { 111 PulleyBackend { 112 pulley_target: PhantomData, 113 triple, 114 flags, 115 isa_flags, 116 } 117 } 118 119 /// This performs lowering to VCode, register-allocates the code, computes block layout and 120 /// finalizes branches. The result is ready for binary emission. 121 fn compile_vcode( 122 &self, 123 func: &ir::Function, 124 domtree: &DominatorTree, 125 ctrl_plane: &mut ControlPlane, 126 ) -> CodegenResult<(VCode<inst::InstAndKind<P>>, regalloc2::Output)> { 127 let emit_info = EmitInfo::new( 128 func.signature.call_conv, 129 self.flags.clone(), 130 self.isa_flags.clone(), 131 ); 132 let sigs = SigSet::new::<abi::PulleyMachineDeps<P>>(func, &self.flags)?; 133 let abi = abi::PulleyCallee::new(func, self, &self.isa_flags, &sigs)?; 134 machinst::compile::<Self>(func, domtree, self, abi, emit_info, sigs, ctrl_plane) 135 } 136 } 137 138 impl<P> TargetIsa for PulleyBackend<P> 139 where 140 P: PulleyTargetKind, 141 { 142 fn name(&self) -> &'static str { 143 P::name() 144 } 145 146 fn triple(&self) -> &Triple { 147 &self.triple 148 } 149 150 fn flags(&self) -> &Flags { 151 &self.flags 152 } 153 154 fn isa_flags(&self) -> Vec<shared_settings::Value> { 155 self.isa_flags.iter().collect() 156 } 157 158 fn isa_flags_hash_key(&self) -> IsaFlagsHashKey<'_> { 159 IsaFlagsHashKey(self.isa_flags.hash_key()) 160 } 161 162 fn dynamic_vector_bytes(&self, _dynamic_ty: ir::Type) -> u32 { 163 512 164 } 165 166 fn page_size_align_log2(&self) -> u8 { 167 // Claim 64KiB pages to be conservative. 168 16 169 } 170 171 fn compile_function( 172 &self, 173 func: &ir::Function, 174 domtree: &DominatorTree, 175 want_disasm: bool, 176 ctrl_plane: &mut cranelift_control::ControlPlane, 177 ) -> CodegenResult<CompiledCodeStencil> { 178 let (vcode, regalloc_result) = self.compile_vcode(func, domtree, ctrl_plane)?; 179 180 let want_disasm = 181 want_disasm || (cfg!(feature = "trace-log") && log::log_enabled!(log::Level::Debug)); 182 let emit_result = vcode.emit(®alloc_result, want_disasm, &self.flags, ctrl_plane); 183 let value_labels_ranges = emit_result.value_labels_ranges; 184 let buffer = emit_result.buffer; 185 186 if let Some(disasm) = emit_result.disasm.as_ref() { 187 log::debug!("disassembly:\n{disasm}"); 188 } 189 190 Ok(CompiledCodeStencil { 191 buffer, 192 vcode: emit_result.disasm, 193 value_labels_ranges, 194 bb_starts: emit_result.bb_offsets, 195 bb_edges: emit_result.bb_edges, 196 }) 197 } 198 199 fn emit_unwind_info( 200 &self, 201 _result: &crate::CompiledCode, 202 _kind: super::unwind::UnwindInfoKind, 203 ) -> CodegenResult<Option<isa::unwind::UnwindInfo>> { 204 // TODO: actually support unwind info? 205 Ok(None) 206 } 207 208 fn text_section_builder( 209 &self, 210 num_labeled_funcs: usize, 211 ) -> alloc::boxed::Box<dyn TextSectionBuilder> { 212 Box::new(MachTextSectionBuilder::<inst::InstAndKind<P>>::new( 213 num_labeled_funcs, 214 )) 215 } 216 217 fn function_alignment(&self) -> FunctionAlignment { 218 inst::InstAndKind::<P>::function_alignment() 219 } 220 221 fn pretty_print_reg(&self, reg: crate::Reg, _size: u8) -> String { 222 format!("{reg:?}") 223 } 224 225 fn has_native_fma(&self) -> bool { 226 // The pulley interpreter does have fma opcodes. 227 true 228 } 229 230 fn has_round(&self) -> bool { 231 // The pulley interpreter does have rounding opcodes. 232 true 233 } 234 235 fn has_blendv_lowering(&self, _ty: ir::Type) -> bool { 236 false 237 } 238 239 fn has_x86_pshufb_lowering(&self) -> bool { 240 false 241 } 242 243 fn has_x86_pmulhrsw_lowering(&self) -> bool { 244 false 245 } 246 247 fn has_x86_pmaddubsw_lowering(&self) -> bool { 248 false 249 } 250 251 fn default_argument_extension(&self) -> ir::ArgumentExtension { 252 ir::ArgumentExtension::None 253 } 254 } 255 256 /// Create a new Pulley ISA builder. 257 pub fn isa_builder(triple: Triple) -> IsaBuilder { 258 let constructor = match triple.architecture { 259 Architecture::Pulley32 | Architecture::Pulley32be => isa_constructor_32, 260 Architecture::Pulley64 | Architecture::Pulley64be => isa_constructor_64, 261 other => panic!("unexpected architecture {other:?}"), 262 }; 263 IsaBuilder { 264 triple, 265 setup: self::settings::builder(), 266 constructor, 267 } 268 } 269 270 fn isa_constructor_32( 271 triple: Triple, 272 shared_flags: Flags, 273 builder: &shared_settings::Builder, 274 ) -> CodegenResult<OwnedTargetIsa> { 275 use crate::settings::Configurable; 276 let mut builder = builder.clone(); 277 builder.set("pointer_width", "pointer32").unwrap(); 278 if triple.endianness().unwrap() == target_lexicon::Endianness::Big { 279 builder.enable("big_endian").unwrap(); 280 } 281 let isa_flags = PulleyFlags::new(&shared_flags, &builder); 282 283 let backend = 284 PulleyBackend::<super::pulley32::Pulley32>::new_with_flags(triple, shared_flags, isa_flags); 285 Ok(backend.wrapped()) 286 } 287 288 fn isa_constructor_64( 289 triple: Triple, 290 shared_flags: Flags, 291 builder: &shared_settings::Builder, 292 ) -> CodegenResult<OwnedTargetIsa> { 293 use crate::settings::Configurable; 294 let mut builder = builder.clone(); 295 builder.set("pointer_width", "pointer64").unwrap(); 296 if triple.endianness().unwrap() == target_lexicon::Endianness::Big { 297 builder.enable("big_endian").unwrap(); 298 } 299 let isa_flags = PulleyFlags::new(&shared_flags, &builder); 300 301 let backend = 302 PulleyBackend::<super::pulley64::Pulley64>::new_with_flags(triple, shared_flags, isa_flags); 303 Ok(backend.wrapped()) 304 } 305 306 impl PulleyFlags { 307 fn endianness(&self) -> ir::Endianness { 308 if self.big_endian() { 309 ir::Endianness::Big 310 } else { 311 ir::Endianness::Little 312 } 313 } 314 } 315