1 use rustc_index
::vec
::IndexVec
;
2 use rustc_middle
::ty
::SymbolName
;
3 use rustc_target
::abi
::call
::FnAbi
;
4 use rustc_target
::abi
::{Integer, Primitive}
;
5 use rustc_target
::spec
::{HasTargetSpec, Target}
;
7 use crate::constant
::ConstantCx
;
10 pub(crate) fn pointer_ty(tcx
: TyCtxt
<'_
>) -> types
::Type
{
11 match tcx
.data_layout
.pointer_size
.bits() {
15 bits
=> bug
!("ptr_sized_integer: unknown pointer bit size {}", bits
),
19 pub(crate) fn scalar_to_clif_type(tcx
: TyCtxt
<'_
>, scalar
: Scalar
) -> Type
{
21 Primitive
::Int(int
, _sign
) => match int
{
22 Integer
::I8
=> types
::I8
,
23 Integer
::I16
=> types
::I16
,
24 Integer
::I32
=> types
::I32
,
25 Integer
::I64
=> types
::I64
,
26 Integer
::I128
=> types
::I128
,
28 Primitive
::F32
=> types
::F32
,
29 Primitive
::F64
=> types
::F64
,
30 Primitive
::Pointer
=> pointer_ty(tcx
),
34 fn clif_type_from_ty
<'tcx
>(tcx
: TyCtxt
<'tcx
>, ty
: Ty
<'tcx
>) -> Option
<types
::Type
> {
35 Some(match ty
.kind() {
36 ty
::Bool
=> types
::I8
,
37 ty
::Uint(size
) => match size
{
38 UintTy
::U8
=> types
::I8
,
39 UintTy
::U16
=> types
::I16
,
40 UintTy
::U32
=> types
::I32
,
41 UintTy
::U64
=> types
::I64
,
42 UintTy
::U128
=> types
::I128
,
43 UintTy
::Usize
=> pointer_ty(tcx
),
45 ty
::Int(size
) => match size
{
46 IntTy
::I8
=> types
::I8
,
47 IntTy
::I16
=> types
::I16
,
48 IntTy
::I32
=> types
::I32
,
49 IntTy
::I64
=> types
::I64
,
50 IntTy
::I128
=> types
::I128
,
51 IntTy
::Isize
=> pointer_ty(tcx
),
53 ty
::Char
=> types
::I32
,
54 ty
::Float(size
) => match size
{
55 FloatTy
::F32
=> types
::F32
,
56 FloatTy
::F64
=> types
::F64
,
58 ty
::FnPtr(_
) => pointer_ty(tcx
),
59 ty
::RawPtr(TypeAndMut { ty: pointee_ty, mutbl: _ }
) | ty
::Ref(_
, pointee_ty
, _
) => {
60 if has_ptr_meta(tcx
, pointee_ty
) {
66 ty
::Adt(adt_def
, _
) if adt_def
.repr
.simd() => {
67 let (element
, count
) = match &tcx
.layout_of(ParamEnv
::reveal_all().and(ty
)).unwrap().abi
69 Abi
::Vector { element, count }
=> (element
.clone(), *count
),
73 match scalar_to_clif_type(tcx
, element
).by(u16::try_from(count
).unwrap()) {
74 // Cranelift currently only implements icmp for 128bit vectors.
75 Some(vector_ty
) if vector_ty
.bits() == 128 => vector_ty
,
79 ty
::Param(_
) => bug
!("ty param {:?}", ty
),
84 fn clif_pair_type_from_ty
<'tcx
>(
87 ) -> Option
<(types
::Type
, types
::Type
)> {
88 Some(match ty
.kind() {
89 ty
::Tuple(substs
) if substs
.len() == 2 => {
90 let mut types
= substs
.types();
91 let a
= clif_type_from_ty(tcx
, types
.next().unwrap())?
;
92 let b
= clif_type_from_ty(tcx
, types
.next().unwrap())?
;
93 if a
.is_vector() || b
.is_vector() {
98 ty
::RawPtr(TypeAndMut { ty: pointee_ty, mutbl: _ }
) | ty
::Ref(_
, pointee_ty
, _
) => {
99 if has_ptr_meta(tcx
, pointee_ty
) {
100 (pointer_ty(tcx
), pointer_ty(tcx
))
109 /// Is a pointer to this type a fat ptr?
110 pub(crate) fn has_ptr_meta
<'tcx
>(tcx
: TyCtxt
<'tcx
>, ty
: Ty
<'tcx
>) -> bool
{
111 let ptr_ty
= tcx
.mk_ptr(TypeAndMut { ty, mutbl: rustc_hir::Mutability::Not }
);
112 match &tcx
.layout_of(ParamEnv
::reveal_all().and(ptr_ty
)).unwrap().abi
{
113 Abi
::Scalar(_
) => false,
114 Abi
::ScalarPair(_
, _
) => true,
115 abi
=> unreachable
!("Abi of ptr to {:?} is {:?}???", ty
, abi
),
119 pub(crate) fn codegen_icmp_imm(
120 fx
: &mut FunctionCx
<'_
, '_
, '_
>,
125 let lhs_ty
= fx
.bcx
.func
.dfg
.value_type(lhs
);
126 if lhs_ty
== types
::I128
{
127 // FIXME legalize `icmp_imm.i128` in Cranelift
129 let (lhs_lsb
, lhs_msb
) = fx
.bcx
.ins().isplit(lhs
);
130 let (rhs_lsb
, rhs_msb
) = (rhs
as u128
as u64 as i64, (rhs
as u128
>> 64) as u64 as i64);
134 let lsb_eq
= fx
.bcx
.ins().icmp_imm(IntCC
::Equal
, lhs_lsb
, rhs_lsb
);
135 let msb_eq
= fx
.bcx
.ins().icmp_imm(IntCC
::Equal
, lhs_msb
, rhs_msb
);
136 fx
.bcx
.ins().band(lsb_eq
, msb_eq
)
139 let lsb_ne
= fx
.bcx
.ins().icmp_imm(IntCC
::NotEqual
, lhs_lsb
, rhs_lsb
);
140 let msb_ne
= fx
.bcx
.ins().icmp_imm(IntCC
::NotEqual
, lhs_msb
, rhs_msb
);
141 fx
.bcx
.ins().bor(lsb_ne
, msb_ne
)
150 let msb_eq
= fx
.bcx
.ins().icmp_imm(IntCC
::Equal
, lhs_msb
, rhs_msb
);
151 let lsb_cc
= fx
.bcx
.ins().icmp_imm(intcc
, lhs_lsb
, rhs_lsb
);
152 let msb_cc
= fx
.bcx
.ins().icmp_imm(intcc
, lhs_msb
, rhs_msb
);
154 fx
.bcx
.ins().select(msb_eq
, lsb_cc
, msb_cc
)
158 let rhs
= i64::try_from(rhs
).expect("codegen_icmp_imm rhs out of range for <128bit int");
159 fx
.bcx
.ins().icmp_imm(intcc
, lhs
, rhs
)
163 pub(crate) fn type_min_max_value(
164 bcx
: &mut FunctionBuilder
<'_
>,
167 ) -> (Value
, Value
) {
168 assert
!(ty
.is_int());
170 if ty
== types
::I128
{
172 let min
= i128
::MIN
as u128
;
173 let min_lsb
= bcx
.ins().iconst(types
::I64
, min
as u64 as i64);
174 let min_msb
= bcx
.ins().iconst(types
::I64
, (min
>> 64) as u64 as i64);
175 let min
= bcx
.ins().iconcat(min_lsb
, min_msb
);
177 let max
= i128
::MAX
as u128
;
178 let max_lsb
= bcx
.ins().iconst(types
::I64
, max
as u64 as i64);
179 let max_msb
= bcx
.ins().iconst(types
::I64
, (max
>> 64) as u64 as i64);
180 let max
= bcx
.ins().iconcat(max_lsb
, max_msb
);
184 let min_half
= bcx
.ins().iconst(types
::I64
, 0);
185 let min
= bcx
.ins().iconcat(min_half
, min_half
);
187 let max_half
= bcx
.ins().iconst(types
::I64
, u64::MAX
as i64);
188 let max
= bcx
.ins().iconcat(max_half
, max_half
);
194 let min
= match (ty
, signed
) {
195 (types
::I8
, false) | (types
::I16
, false) | (types
::I32
, false) | (types
::I64
, false) => {
198 (types
::I8
, true) => i64::from(i8::MIN
),
199 (types
::I16
, true) => i64::from(i16::MIN
),
200 (types
::I32
, true) => i64::from(i32::MIN
),
201 (types
::I64
, true) => i64::MIN
,
205 let max
= match (ty
, signed
) {
206 (types
::I8
, false) => i64::from(u8::MAX
),
207 (types
::I16
, false) => i64::from(u16::MAX
),
208 (types
::I32
, false) => i64::from(u32::MAX
),
209 (types
::I64
, false) => u64::MAX
as i64,
210 (types
::I8
, true) => i64::from(i8::MAX
),
211 (types
::I16
, true) => i64::from(i16::MAX
),
212 (types
::I32
, true) => i64::from(i32::MAX
),
213 (types
::I64
, true) => i64::MAX
,
217 let (min
, max
) = (bcx
.ins().iconst(ty
, min
), bcx
.ins().iconst(ty
, max
));
222 pub(crate) fn type_sign(ty
: Ty
<'_
>) -> bool
{
224 ty
::Ref(..) | ty
::RawPtr(..) | ty
::FnPtr(..) | ty
::Char
| ty
::Uint(..) | ty
::Bool
=> false,
226 ty
::Float(..) => false, // `signed` is unused for floats
227 _
=> panic
!("{}", ty
),
231 pub(crate) struct FunctionCx
<'m
, 'clif
, 'tcx
: 'm
> {
232 pub(crate) cx
: &'clif
mut crate::CodegenCx
<'tcx
>,
233 pub(crate) module
: &'m
mut dyn Module
,
234 pub(crate) tcx
: TyCtxt
<'tcx
>,
235 pub(crate) pointer_type
: Type
, // Cached from module
236 pub(crate) constants_cx
: ConstantCx
,
238 pub(crate) instance
: Instance
<'tcx
>,
239 pub(crate) symbol_name
: SymbolName
<'tcx
>,
240 pub(crate) mir
: &'tcx Body
<'tcx
>,
241 pub(crate) fn_abi
: Option
<FnAbi
<'tcx
, Ty
<'tcx
>>>,
243 pub(crate) bcx
: FunctionBuilder
<'clif
>,
244 pub(crate) block_map
: IndexVec
<BasicBlock
, Block
>,
245 pub(crate) local_map
: IndexVec
<Local
, CPlace
<'tcx
>>,
247 /// When `#[track_caller]` is used, the implicit caller location is stored in this variable.
248 pub(crate) caller_location
: Option
<CValue
<'tcx
>>,
250 pub(crate) clif_comments
: crate::pretty_clif
::CommentWriter
,
251 pub(crate) source_info_set
: indexmap
::IndexSet
<SourceInfo
>,
253 /// This should only be accessed by `CPlace::new_var`.
254 pub(crate) next_ssa_var
: u32,
256 pub(crate) inline_asm_index
: u32,
259 impl<'tcx
> LayoutOf
for FunctionCx
<'_
, '_
, 'tcx
> {
261 type TyAndLayout
= TyAndLayout
<'tcx
>;
263 fn layout_of(&self, ty
: Ty
<'tcx
>) -> TyAndLayout
<'tcx
> {
264 RevealAllLayoutCx(self.tcx
).layout_of(ty
)
268 impl<'tcx
> layout
::HasTyCtxt
<'tcx
> for FunctionCx
<'_
, '_
, 'tcx
> {
269 fn tcx
<'b
>(&'b
self) -> TyCtxt
<'tcx
> {
274 impl<'tcx
> rustc_target
::abi
::HasDataLayout
for FunctionCx
<'_
, '_
, 'tcx
> {
275 fn data_layout(&self) -> &rustc_target
::abi
::TargetDataLayout
{
276 &self.tcx
.data_layout
280 impl<'tcx
> layout
::HasParamEnv
<'tcx
> for FunctionCx
<'_
, '_
, 'tcx
> {
281 fn param_env(&self) -> ParamEnv
<'tcx
> {
282 ParamEnv
::reveal_all()
286 impl<'tcx
> HasTargetSpec
for FunctionCx
<'_
, '_
, 'tcx
> {
287 fn target_spec(&self) -> &Target
{
288 &self.tcx
.sess
.target
292 impl<'tcx
> FunctionCx
<'_
, '_
, 'tcx
> {
293 pub(crate) fn monomorphize
<T
>(&self, value
: T
) -> T
295 T
: TypeFoldable
<'tcx
> + Copy
,
297 self.instance
.subst_mir_and_normalize_erasing_regions(
299 ty
::ParamEnv
::reveal_all(),
304 pub(crate) fn clif_type(&self, ty
: Ty
<'tcx
>) -> Option
<Type
> {
305 clif_type_from_ty(self.tcx
, ty
)
308 pub(crate) fn clif_pair_type(&self, ty
: Ty
<'tcx
>) -> Option
<(Type
, Type
)> {
309 clif_pair_type_from_ty(self.tcx
, ty
)
312 pub(crate) fn get_block(&self, bb
: BasicBlock
) -> Block
{
313 *self.block_map
.get(bb
).unwrap()
316 pub(crate) fn get_local_place(&mut self, local
: Local
) -> CPlace
<'tcx
> {
317 *self.local_map
.get(local
).unwrap_or_else(|| {
318 panic
!("Local {:?} doesn't exist", local
);
322 pub(crate) fn set_debug_loc(&mut self, source_info
: mir
::SourceInfo
) {
323 let (index
, _
) = self.source_info_set
.insert_full(source_info
);
324 self.bcx
.set_srcloc(SourceLoc
::new(index
as u32));
327 pub(crate) fn get_caller_location(&mut self, span
: Span
) -> CValue
<'tcx
> {
328 if let Some(loc
) = self.caller_location
{
329 // `#[track_caller]` is used; return caller location instead of current location.
333 let topmost
= span
.ctxt().outer_expn().expansion_cause().unwrap_or(span
);
334 let caller
= self.tcx
.sess
.source_map().lookup_char_pos(topmost
.lo());
335 let const_loc
= self.tcx
.const_caller_location((
336 rustc_span
::symbol
::Symbol
::intern(
337 &caller
.file
.name
.prefer_remapped().to_string_lossy(),
340 caller
.col_display
as u32 + 1,
342 crate::constant
::codegen_const_value(self, const_loc
, self.tcx
.caller_location_ty())
345 pub(crate) fn triple(&self) -> &target_lexicon
::Triple
{
346 self.module
.isa().triple()
349 pub(crate) fn anonymous_str(&mut self, msg
: &str) -> Value
{
350 let mut data_ctx
= DataContext
::new();
351 data_ctx
.define(msg
.as_bytes().to_vec().into_boxed_slice());
352 let msg_id
= self.module
.declare_anonymous_data(false, false).unwrap();
354 // Ignore DuplicateDefinition error, as the data will be the same
355 let _
= self.module
.define_data(msg_id
, &data_ctx
);
357 let local_msg_id
= self.module
.declare_data_in_func(msg_id
, self.bcx
.func
);
358 if self.clif_comments
.enabled() {
359 self.add_comment(local_msg_id
, msg
);
361 self.bcx
.ins().global_value(self.pointer_type
, local_msg_id
)
365 pub(crate) struct RevealAllLayoutCx
<'tcx
>(pub(crate) TyCtxt
<'tcx
>);
367 impl<'tcx
> LayoutOf
for RevealAllLayoutCx
<'tcx
> {
369 type TyAndLayout
= TyAndLayout
<'tcx
>;
371 fn layout_of(&self, ty
: Ty
<'tcx
>) -> TyAndLayout
<'tcx
> {
372 assert
!(!ty
.still_further_specializable());
373 self.0.layout_of(ParamEnv
::reveal_all().and(&ty
)).unwrap_or_else(|e
| {
374 if let layout
::LayoutError
::SizeOverflow(_
) = e
{
375 self.0.sess
.fatal(&e
.to_string())
377 bug
!("failed to get layout for `{}`: {}", ty
, e
)
383 impl<'tcx
> layout
::HasTyCtxt
<'tcx
> for RevealAllLayoutCx
<'tcx
> {
384 fn tcx
<'b
>(&'b
self) -> TyCtxt
<'tcx
> {
389 impl<'tcx
> rustc_target
::abi
::HasDataLayout
for RevealAllLayoutCx
<'tcx
> {
390 fn data_layout(&self) -> &rustc_target
::abi
::TargetDataLayout
{
395 impl<'tcx
> layout
::HasParamEnv
<'tcx
> for RevealAllLayoutCx
<'tcx
> {
396 fn param_env(&self) -> ParamEnv
<'tcx
> {
397 ParamEnv
::reveal_all()
401 impl<'tcx
> HasTargetSpec
for RevealAllLayoutCx
<'tcx
> {
402 fn target_spec(&self) -> &Target
{