1 use super::misc::MiscMethods; 2 use super::Backend; 3 use super::HasCodegen; 4 use crate::common::TypeKind; 5 use crate::mir::place::PlaceRef; 6 use rustc_middle::ty::layout::TyAndLayout; 7 use rustc_middle::ty::{self, Ty}; 8 use rustc_target::abi::call::{ArgAbi, CastTarget, FnAbi, Reg}; 9 use rustc_target::abi::{AddressSpace, Integer}; 10 11 // This depends on `Backend` and not `BackendTypes`, because consumers will probably want to use 12 // `LayoutOf` or `HasTyCtxt`. This way, they don't have to add a constraint on it themselves. 13 pub trait BaseTypeMethods<'tcx>: Backend<'tcx> { type_i1(&self) -> Self::Type14 fn type_i1(&self) -> Self::Type; type_i8(&self) -> Self::Type15 fn type_i8(&self) -> Self::Type; type_i16(&self) -> Self::Type16 fn type_i16(&self) -> Self::Type; type_i32(&self) -> Self::Type17 fn type_i32(&self) -> Self::Type; type_i64(&self) -> Self::Type18 fn type_i64(&self) -> Self::Type; type_i128(&self) -> Self::Type19 fn type_i128(&self) -> Self::Type; type_isize(&self) -> Self::Type20 fn type_isize(&self) -> Self::Type; 21 type_f32(&self) -> Self::Type22 fn type_f32(&self) -> Self::Type; type_f64(&self) -> Self::Type23 fn type_f64(&self) -> Self::Type; 24 type_array(&self, ty: Self::Type, len: u64) -> Self::Type25 fn type_array(&self, ty: Self::Type, len: u64) -> Self::Type; type_func(&self, args: &[Self::Type], ret: Self::Type) -> Self::Type26 fn type_func(&self, args: &[Self::Type], ret: Self::Type) -> Self::Type; type_struct(&self, els: &[Self::Type], packed: bool) -> Self::Type27 fn type_struct(&self, els: &[Self::Type], packed: bool) -> Self::Type; type_kind(&self, ty: Self::Type) -> TypeKind28 fn type_kind(&self, ty: Self::Type) -> TypeKind; type_ptr_to(&self, ty: Self::Type) -> Self::Type29 fn type_ptr_to(&self, ty: Self::Type) -> Self::Type; type_ptr_to_ext(&self, ty: Self::Type, address_space: AddressSpace) -> Self::Type30 fn type_ptr_to_ext(&self, ty: Self::Type, address_space: AddressSpace) -> Self::Type; element_type(&self, ty: Self::Type) -> Self::Type31 fn element_type(&self, ty: Self::Type) -> Self::Type; 32 33 /// Returns the number of elements in `self` if it is a LLVM vector type. vector_length(&self, ty: Self::Type) -> usize34 fn vector_length(&self, ty: Self::Type) -> usize; 35 float_width(&self, ty: Self::Type) -> usize36 fn float_width(&self, ty: Self::Type) -> usize; 37 38 /// Retrieves the bit width of the integer type `self`. int_width(&self, ty: Self::Type) -> u6439 fn int_width(&self, ty: Self::Type) -> u64; 40 val_ty(&self, v: Self::Value) -> Self::Type41 fn val_ty(&self, v: Self::Value) -> Self::Type; 42 } 43 44 pub trait DerivedTypeMethods<'tcx>: BaseTypeMethods<'tcx> + MiscMethods<'tcx> { type_i8p(&self) -> Self::Type45 fn type_i8p(&self) -> Self::Type { 46 self.type_i8p_ext(AddressSpace::DATA) 47 } 48 type_i8p_ext(&self, address_space: AddressSpace) -> Self::Type49 fn type_i8p_ext(&self, address_space: AddressSpace) -> Self::Type { 50 self.type_ptr_to_ext(self.type_i8(), address_space) 51 } 52 type_int(&self) -> Self::Type53 fn type_int(&self) -> Self::Type { 54 match &self.sess().target.c_int_width[..] { 55 "16" => self.type_i16(), 56 "32" => self.type_i32(), 57 "64" => self.type_i64(), 58 width => bug!("Unsupported c_int_width: {}", width), 59 } 60 } 61 type_from_integer(&self, i: Integer) -> Self::Type62 fn type_from_integer(&self, i: Integer) -> Self::Type { 63 use Integer::*; 64 match i { 65 I8 => self.type_i8(), 66 I16 => self.type_i16(), 67 I32 => self.type_i32(), 68 I64 => self.type_i64(), 69 I128 => self.type_i128(), 70 } 71 } 72 type_needs_drop(&self, ty: Ty<'tcx>) -> bool73 fn type_needs_drop(&self, ty: Ty<'tcx>) -> bool { 74 ty.needs_drop(self.tcx(), ty::ParamEnv::reveal_all()) 75 } 76 type_is_sized(&self, ty: Ty<'tcx>) -> bool77 fn type_is_sized(&self, ty: Ty<'tcx>) -> bool { 78 ty.is_sized(self.tcx(), ty::ParamEnv::reveal_all()) 79 } 80 type_is_freeze(&self, ty: Ty<'tcx>) -> bool81 fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool { 82 ty.is_freeze(self.tcx(), ty::ParamEnv::reveal_all()) 83 } 84 type_has_metadata(&self, ty: Ty<'tcx>) -> bool85 fn type_has_metadata(&self, ty: Ty<'tcx>) -> bool { 86 let param_env = ty::ParamEnv::reveal_all(); 87 if ty.is_sized(self.tcx(), param_env) { 88 return false; 89 } 90 91 let tail = self.tcx().struct_tail_erasing_lifetimes(ty, param_env); 92 match tail.kind() { 93 ty::Foreign(..) => false, 94 ty::Str | ty::Slice(..) | ty::Dynamic(..) => true, 95 _ => bug!("unexpected unsized tail: {:?}", tail), 96 } 97 } 98 } 99 100 impl<'tcx, T> DerivedTypeMethods<'tcx> for T where Self: BaseTypeMethods<'tcx> + MiscMethods<'tcx> {} 101 102 pub trait LayoutTypeMethods<'tcx>: Backend<'tcx> { 103 /// The backend type used for a rust type when it's in memory, 104 /// such as when it's stack-allocated or when it's being loaded or stored. backend_type(&self, layout: TyAndLayout<'tcx>) -> Self::Type105 fn backend_type(&self, layout: TyAndLayout<'tcx>) -> Self::Type; cast_backend_type(&self, ty: &CastTarget) -> Self::Type106 fn cast_backend_type(&self, ty: &CastTarget) -> Self::Type; fn_decl_backend_type(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Self::Type107 fn fn_decl_backend_type(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Self::Type; fn_ptr_backend_type(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Self::Type108 fn fn_ptr_backend_type(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Self::Type; reg_backend_type(&self, ty: &Reg) -> Self::Type109 fn reg_backend_type(&self, ty: &Reg) -> Self::Type; 110 /// The backend type used for a rust type when it's in an SSA register. 111 /// 112 /// For nearly all types this is the same as the [`Self::backend_type`], however 113 /// `bool` (and other `0`-or-`1` values) are kept as [`BaseTypeMethods::type_i1`] 114 /// in registers but as [`BaseTypeMethods::type_i8`] in memory. 115 /// 116 /// Converting values between the two different backend types is done using 117 /// [`from_immediate`](super::BuilderMethods::from_immediate) and 118 /// [`to_immediate_scalar`](super::BuilderMethods::to_immediate_scalar). immediate_backend_type(&self, layout: TyAndLayout<'tcx>) -> Self::Type119 fn immediate_backend_type(&self, layout: TyAndLayout<'tcx>) -> Self::Type; is_backend_immediate(&self, layout: TyAndLayout<'tcx>) -> bool120 fn is_backend_immediate(&self, layout: TyAndLayout<'tcx>) -> bool; is_backend_scalar_pair(&self, layout: TyAndLayout<'tcx>) -> bool121 fn is_backend_scalar_pair(&self, layout: TyAndLayout<'tcx>) -> bool; backend_field_index(&self, layout: TyAndLayout<'tcx>, index: usize) -> u64122 fn backend_field_index(&self, layout: TyAndLayout<'tcx>, index: usize) -> u64; scalar_pair_element_backend_type( &self, layout: TyAndLayout<'tcx>, index: usize, immediate: bool, ) -> Self::Type123 fn scalar_pair_element_backend_type( 124 &self, 125 layout: TyAndLayout<'tcx>, 126 index: usize, 127 immediate: bool, 128 ) -> Self::Type; 129 130 /// A type that can be used in a [`super::BuilderMethods::load`] + 131 /// [`super::BuilderMethods::store`] pair to implement a *typed* copy, 132 /// such as a MIR `*_0 = *_1`. 133 /// 134 /// It's always legal to return `None` here, as the provided impl does, 135 /// in which case callers should use [`super::BuilderMethods::memcpy`] 136 /// instead of the `load`+`store` pair. 137 /// 138 /// This can be helpful for things like arrays, where the LLVM backend type 139 /// `[3 x i16]` optimizes to three separate loads and stores, but it can 140 /// instead be copied via an `i48` that stays as the single `load`+`store`. 141 /// (As of 2023-05 LLVM cannot necessarily optimize away a `memcpy` in these 142 /// cases, due to `poison` handling, but in codegen we have more information 143 /// about the type invariants, so can emit something better instead.) 144 /// 145 /// This *should* return `None` for particularly-large types, where leaving 146 /// the `memcpy` may well be important to avoid code size explosion. scalar_copy_backend_type(&self, layout: TyAndLayout<'tcx>) -> Option<Self::Type>147 fn scalar_copy_backend_type(&self, layout: TyAndLayout<'tcx>) -> Option<Self::Type> { 148 let _ = layout; 149 None 150 } 151 } 152 153 // For backends that support CFI using type membership (i.e., testing whether a given pointer is 154 // associated with a type identifier). 155 pub trait TypeMembershipMethods<'tcx>: Backend<'tcx> { add_type_metadata(&self, _function: Self::Function, _typeid: String)156 fn add_type_metadata(&self, _function: Self::Function, _typeid: String) {} set_type_metadata(&self, _function: Self::Function, _typeid: String)157 fn set_type_metadata(&self, _function: Self::Function, _typeid: String) {} typeid_metadata(&self, _typeid: String) -> Option<Self::Value>158 fn typeid_metadata(&self, _typeid: String) -> Option<Self::Value> { 159 None 160 } add_kcfi_type_metadata(&self, _function: Self::Function, _typeid: u32)161 fn add_kcfi_type_metadata(&self, _function: Self::Function, _typeid: u32) {} set_kcfi_type_metadata(&self, _function: Self::Function, _typeid: u32)162 fn set_kcfi_type_metadata(&self, _function: Self::Function, _typeid: u32) {} 163 } 164 165 pub trait ArgAbiMethods<'tcx>: HasCodegen<'tcx> { store_fn_arg( &mut self, arg_abi: &ArgAbi<'tcx, Ty<'tcx>>, idx: &mut usize, dst: PlaceRef<'tcx, Self::Value>, )166 fn store_fn_arg( 167 &mut self, 168 arg_abi: &ArgAbi<'tcx, Ty<'tcx>>, 169 idx: &mut usize, 170 dst: PlaceRef<'tcx, Self::Value>, 171 ); store_arg( &mut self, arg_abi: &ArgAbi<'tcx, Ty<'tcx>>, val: Self::Value, dst: PlaceRef<'tcx, Self::Value>, )172 fn store_arg( 173 &mut self, 174 arg_abi: &ArgAbi<'tcx, Ty<'tcx>>, 175 val: Self::Value, 176 dst: PlaceRef<'tcx, Self::Value>, 177 ); arg_memory_ty(&self, arg_abi: &ArgAbi<'tcx, Ty<'tcx>>) -> Self::Type178 fn arg_memory_ty(&self, arg_abi: &ArgAbi<'tcx, Ty<'tcx>>) -> Self::Type; 179 } 180 181 pub trait TypeMethods<'tcx>: 182 DerivedTypeMethods<'tcx> + LayoutTypeMethods<'tcx> + TypeMembershipMethods<'tcx> 183 { 184 } 185 186 impl<'tcx, T> TypeMethods<'tcx> for T where 187 Self: DerivedTypeMethods<'tcx> + LayoutTypeMethods<'tcx> + TypeMembershipMethods<'tcx> 188 { 189 } 190