1 //! IBM Z 64-bit Instruction Set Architecture. 2 3 use crate::dominator_tree::DominatorTree; 4 use crate::ir::{self, Function, Type}; 5 use crate::isa::s390x::settings as s390x_settings; 6 #[cfg(feature = "unwind")] 7 use crate::isa::unwind::systemv::RegisterMappingError; 8 use crate::isa::{Builder as IsaBuilder, FunctionAlignment, IsaFlagsHashKey, TargetIsa}; 9 use crate::machinst::{ 10 CompiledCode, CompiledCodeStencil, MachInst, MachTextSectionBuilder, Reg, SigSet, 11 TextSectionBuilder, VCode, compile, 12 }; 13 use crate::result::CodegenResult; 14 use crate::settings as shared_settings; 15 use alloc::string::String; 16 use alloc::{boxed::Box, vec::Vec}; 17 use core::fmt; 18 use cranelift_control::ControlPlane; 19 use target_lexicon::{Architecture, Triple}; 20 21 // New backend: 22 mod abi; 23 pub(crate) mod inst; 24 mod lower; 25 mod settings; 26 27 use self::inst::EmitInfo; 28 29 /// A IBM Z backend. 30 pub struct S390xBackend { 31 triple: Triple, 32 flags: shared_settings::Flags, 33 isa_flags: s390x_settings::Flags, 34 } 35 36 impl S390xBackend { 37 /// Create a new IBM Z backend with the given (shared) flags. 38 pub fn new_with_flags( 39 triple: Triple, 40 flags: shared_settings::Flags, 41 isa_flags: s390x_settings::Flags, 42 ) -> S390xBackend { 43 S390xBackend { 44 triple, 45 flags, 46 isa_flags, 47 } 48 } 49 50 /// This performs lowering to VCode, register-allocates the code, computes block layout and 51 /// finalizes branches. The result is ready for binary emission. 52 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.isa_flags.clone()); 59 let sigs = SigSet::new::<abi::S390xMachineDeps>(func, &self.flags)?; 60 let abi = abi::S390xCallee::new(func, self, &self.isa_flags, &sigs)?; 61 compile::compile::<S390xBackend>(func, domtree, self, abi, emit_info, sigs, ctrl_plane) 62 } 63 } 64 65 impl TargetIsa for S390xBackend { 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 flags = self.flags(); 74 let (vcode, regalloc_result) = self.compile_vcode(func, domtree, ctrl_plane)?; 75 76 let emit_result = vcode.emit(®alloc_result, want_disasm, flags, ctrl_plane); 77 let value_labels_ranges = emit_result.value_labels_ranges; 78 let buffer = emit_result.buffer; 79 80 if let Some(disasm) = emit_result.disasm.as_ref() { 81 log::debug!("disassembly:\n{disasm}"); 82 } 83 84 Ok(CompiledCodeStencil { 85 buffer, 86 vcode: emit_result.disasm, 87 value_labels_ranges, 88 bb_starts: emit_result.bb_offsets, 89 bb_edges: emit_result.bb_edges, 90 }) 91 } 92 93 fn name(&self) -> &'static str { 94 "s390x" 95 } 96 97 fn triple(&self) -> &Triple { 98 &self.triple 99 } 100 101 fn flags(&self) -> &shared_settings::Flags { 102 &self.flags 103 } 104 105 fn isa_flags(&self) -> Vec<shared_settings::Value> { 106 self.isa_flags.iter().collect() 107 } 108 109 fn isa_flags_hash_key(&self) -> IsaFlagsHashKey<'_> { 110 IsaFlagsHashKey(self.isa_flags.hash_key()) 111 } 112 113 fn dynamic_vector_bytes(&self, _dyn_ty: Type) -> u32 { 114 16 115 } 116 117 #[cfg(feature = "unwind")] 118 fn emit_unwind_info( 119 &self, 120 result: &CompiledCode, 121 kind: crate::isa::unwind::UnwindInfoKind, 122 ) -> CodegenResult<Option<crate::isa::unwind::UnwindInfo>> { 123 use crate::isa::unwind::UnwindInfo; 124 use crate::isa::unwind::UnwindInfoKind; 125 Ok(match kind { 126 UnwindInfoKind::SystemV => { 127 let mapper = self::inst::unwind::systemv::RegisterMapper; 128 Some(UnwindInfo::SystemV( 129 crate::isa::unwind::systemv::create_unwind_info_from_insts( 130 &result.buffer.unwind_info[..], 131 result.buffer.data().len(), 132 &mapper, 133 )?, 134 )) 135 } 136 _ => None, 137 }) 138 } 139 140 #[cfg(feature = "unwind")] 141 fn create_systemv_cie(&self) -> Option<gimli::write::CommonInformationEntry> { 142 Some(inst::unwind::systemv::create_cie()) 143 } 144 145 #[cfg(feature = "unwind")] 146 fn map_regalloc_reg_to_dwarf(&self, reg: Reg) -> Result<u16, RegisterMappingError> { 147 inst::unwind::systemv::map_reg(reg).map(|reg| reg.0) 148 } 149 150 fn text_section_builder(&self, num_funcs: usize) -> Box<dyn TextSectionBuilder> { 151 Box::new(MachTextSectionBuilder::<inst::Inst>::new(num_funcs)) 152 } 153 154 fn function_alignment(&self) -> FunctionAlignment { 155 inst::Inst::function_alignment() 156 } 157 158 fn page_size_align_log2(&self) -> u8 { 159 debug_assert_eq!(1 << 12, 0x1000); 160 12 161 } 162 163 #[cfg(feature = "disas")] 164 fn to_capstone(&self) -> Result<capstone::Capstone, capstone::Error> { 165 use capstone::prelude::*; 166 let mut cs = Capstone::new() 167 .sysz() 168 .mode(arch::sysz::ArchMode::Default) 169 .build()?; 170 171 cs.set_skipdata(true)?; 172 173 Ok(cs) 174 } 175 176 fn pretty_print_reg(&self, reg: Reg, _size: u8) -> String { 177 inst::regs::pretty_print_reg(reg) 178 } 179 180 fn has_native_fma(&self) -> bool { 181 true 182 } 183 184 fn has_round(&self) -> bool { 185 true 186 } 187 188 fn has_blendv_lowering(&self, _: Type) -> bool { 189 self.isa_flags.has_vxrs_ext3() 190 } 191 192 fn has_x86_pshufb_lowering(&self) -> bool { 193 false 194 } 195 196 fn has_x86_pmulhrsw_lowering(&self) -> bool { 197 false 198 } 199 200 fn has_x86_pmaddubsw_lowering(&self) -> bool { 201 false 202 } 203 204 fn default_argument_extension(&self) -> ir::ArgumentExtension { 205 // This is copied/carried over from a historical piece of code in 206 // Wasmtime: 207 // 208 // https://github.com/bytecodealliance/wasmtime/blob/a018a5a9addb77d5998021a0150192aa955c71bf/crates/cranelift/src/lib.rs#L366-L374 209 // 210 // Whether or not it is still applicable here is unsure, but it's left 211 // the same as-is for now to reduce the likelihood of problems arising. 212 ir::ArgumentExtension::Uext 213 } 214 } 215 216 impl fmt::Display for S390xBackend { 217 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 218 f.debug_struct("MachBackend") 219 .field("name", &self.name()) 220 .field("triple", &self.triple()) 221 .field("flags", &format!("{}", self.flags())) 222 .finish() 223 } 224 } 225 226 /// Create a new `isa::Builder`. 227 pub fn isa_builder(triple: Triple) -> IsaBuilder { 228 assert!(triple.architecture == Architecture::S390x); 229 IsaBuilder { 230 triple, 231 setup: s390x_settings::builder(), 232 constructor: |triple, shared_flags, builder| { 233 let isa_flags = s390x_settings::Flags::new(&shared_flags, builder); 234 let backend = S390xBackend::new_with_flags(triple, shared_flags, isa_flags); 235 Ok(backend.wrapped()) 236 }, 237 } 238 } 239