• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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