1 use rustc_index
::vec
::IndexVec
;
2 use rustc_target
::abi
::{Integer, Primitive}
;
3 use rustc_target
::spec
::{HasTargetSpec, Target}
;
5 use cranelift_codegen
::ir
::{InstructionData, Opcode, ValueDef}
;
9 pub(crate) fn pointer_ty(tcx
: TyCtxt
<'_
>) -> types
::Type
{
10 match tcx
.data_layout
.pointer_size
.bits() {
14 bits
=> bug
!("ptr_sized_integer: unknown pointer bit size {}", bits
),
18 pub(crate) fn scalar_to_clif_type(tcx
: TyCtxt
<'_
>, scalar
: Scalar
) -> Type
{
20 Primitive
::Int(int
, _sign
) => match int
{
21 Integer
::I8
=> types
::I8
,
22 Integer
::I16
=> types
::I16
,
23 Integer
::I32
=> types
::I32
,
24 Integer
::I64
=> types
::I64
,
25 Integer
::I128
=> types
::I128
,
27 Primitive
::F32
=> types
::F32
,
28 Primitive
::F64
=> types
::F64
,
29 Primitive
::Pointer
=> pointer_ty(tcx
),
33 fn clif_type_from_ty
<'tcx
>(tcx
: TyCtxt
<'tcx
>, ty
: Ty
<'tcx
>) -> Option
<types
::Type
> {
34 Some(match ty
.kind() {
35 ty
::Bool
=> types
::I8
,
36 ty
::Uint(size
) => match size
{
37 UintTy
::U8
=> types
::I8
,
38 UintTy
::U16
=> types
::I16
,
39 UintTy
::U32
=> types
::I32
,
40 UintTy
::U64
=> types
::I64
,
41 UintTy
::U128
=> types
::I128
,
42 UintTy
::Usize
=> pointer_ty(tcx
),
44 ty
::Int(size
) => match size
{
45 IntTy
::I8
=> types
::I8
,
46 IntTy
::I16
=> types
::I16
,
47 IntTy
::I32
=> types
::I32
,
48 IntTy
::I64
=> types
::I64
,
49 IntTy
::I128
=> types
::I128
,
50 IntTy
::Isize
=> pointer_ty(tcx
),
52 ty
::Char
=> types
::I32
,
53 ty
::Float(size
) => match size
{
54 FloatTy
::F32
=> types
::F32
,
55 FloatTy
::F64
=> types
::F64
,
57 ty
::FnPtr(_
) => pointer_ty(tcx
),
58 ty
::RawPtr(TypeAndMut
{
62 | ty
::Ref(_
, pointee_ty
, _
) => {
63 if has_ptr_meta(tcx
, pointee_ty
) {
69 ty
::Adt(adt_def
, _
) if adt_def
.repr
.simd() => {
70 let (element
, count
) = match &tcx
.layout_of(ParamEnv
::reveal_all().and(ty
)).unwrap().abi
72 Abi
::Vector { element, count }
=> (element
.clone(), *count
),
76 match scalar_to_clif_type(tcx
, element
).by(u16::try_from(count
).unwrap()) {
77 // Cranelift currently only implements icmp for 128bit vectors.
78 Some(vector_ty
) if vector_ty
.bits() == 128 => vector_ty
,
82 ty
::Param(_
) => bug
!("ty param {:?}", ty
),
87 fn clif_pair_type_from_ty
<'tcx
>(
90 ) -> Option
<(types
::Type
, types
::Type
)> {
91 Some(match ty
.kind() {
92 ty
::Tuple(substs
) if substs
.len() == 2 => {
93 let mut types
= substs
.types();
94 let a
= clif_type_from_ty(tcx
, types
.next().unwrap())?
;
95 let b
= clif_type_from_ty(tcx
, types
.next().unwrap())?
;
96 if a
.is_vector() || b
.is_vector() {
101 ty
::RawPtr(TypeAndMut
{
105 | ty
::Ref(_
, pointee_ty
, _
) => {
106 if has_ptr_meta(tcx
, pointee_ty
) {
107 (pointer_ty(tcx
), pointer_ty(tcx
))
116 /// Is a pointer to this type a fat ptr?
117 pub(crate) fn has_ptr_meta
<'tcx
>(tcx
: TyCtxt
<'tcx
>, ty
: Ty
<'tcx
>) -> bool
{
118 let ptr_ty
= tcx
.mk_ptr(TypeAndMut
{
120 mutbl
: rustc_hir
::Mutability
::Not
,
123 .layout_of(ParamEnv
::reveal_all().and(ptr_ty
))
127 Abi
::Scalar(_
) => false,
128 Abi
::ScalarPair(_
, _
) => true,
129 abi
=> unreachable
!("Abi of ptr to {:?} is {:?}???", ty
, abi
),
133 pub(crate) fn codegen_icmp_imm(
134 fx
: &mut FunctionCx
<'_
, '_
, impl Module
>,
139 let lhs_ty
= fx
.bcx
.func
.dfg
.value_type(lhs
);
140 if lhs_ty
== types
::I128
{
141 // FIXME legalize `icmp_imm.i128` in Cranelift
143 let (lhs_lsb
, lhs_msb
) = fx
.bcx
.ins().isplit(lhs
);
144 let (rhs_lsb
, rhs_msb
) = (rhs
as u128
as u64 as i64, (rhs
as u128
>> 64) as u64 as i64);
148 let lsb_eq
= fx
.bcx
.ins().icmp_imm(IntCC
::Equal
, lhs_lsb
, rhs_lsb
);
149 let msb_eq
= fx
.bcx
.ins().icmp_imm(IntCC
::Equal
, lhs_msb
, rhs_msb
);
150 fx
.bcx
.ins().band(lsb_eq
, msb_eq
)
153 let lsb_ne
= fx
.bcx
.ins().icmp_imm(IntCC
::NotEqual
, lhs_lsb
, rhs_lsb
);
154 let msb_ne
= fx
.bcx
.ins().icmp_imm(IntCC
::NotEqual
, lhs_msb
, rhs_msb
);
155 fx
.bcx
.ins().bor(lsb_ne
, msb_ne
)
164 let msb_eq
= fx
.bcx
.ins().icmp_imm(IntCC
::Equal
, lhs_msb
, rhs_msb
);
165 let lsb_cc
= fx
.bcx
.ins().icmp_imm(intcc
, lhs_lsb
, rhs_lsb
);
166 let msb_cc
= fx
.bcx
.ins().icmp_imm(intcc
, lhs_msb
, rhs_msb
);
168 fx
.bcx
.ins().select(msb_eq
, lsb_cc
, msb_cc
)
172 let rhs
= i64::try_from(rhs
).expect("codegen_icmp_imm rhs out of range for <128bit int");
173 fx
.bcx
.ins().icmp_imm(intcc
, lhs
, rhs
)
177 fn resolve_normal_value_imm(func
: &Function
, val
: Value
) -> Option
<i64> {
178 if let ValueDef
::Result(inst
, 0 /*param*/) = func
.dfg
.value_def(val
) {
179 if let InstructionData
::UnaryImm
{
180 opcode
: Opcode
::Iconst
,
193 fn resolve_128bit_value_imm(func
: &Function
, val
: Value
) -> Option
<u128
> {
194 let (lsb
, msb
) = if let ValueDef
::Result(inst
, 0 /*param*/) = func
.dfg
.value_def(val
) {
195 if let InstructionData
::Binary
{
196 opcode
: Opcode
::Iconcat
,
208 let lsb
= u128
::from(resolve_normal_value_imm(func
, lsb
)?
as u64);
209 let msb
= u128
::from(resolve_normal_value_imm(func
, msb
)?
as u64);
211 Some(msb
<< 64 | lsb
)
214 pub(crate) fn resolve_value_imm(func
: &Function
, val
: Value
) -> Option
<u128
> {
215 if func
.dfg
.value_type(val
) == types
::I128
{
216 resolve_128bit_value_imm(func
, val
)
218 resolve_normal_value_imm(func
, val
).map(|imm
| u128
::from(imm
as u64))
222 pub(crate) fn type_min_max_value(
223 bcx
: &mut FunctionBuilder
<'_
>,
226 ) -> (Value
, Value
) {
227 assert
!(ty
.is_int());
229 if ty
== types
::I128
{
231 let min
= i128
::MIN
as u128
;
232 let min_lsb
= bcx
.ins().iconst(types
::I64
, min
as u64 as i64);
233 let min_msb
= bcx
.ins().iconst(types
::I64
, (min
>> 64) as u64 as i64);
234 let min
= bcx
.ins().iconcat(min_lsb
, min_msb
);
236 let max
= i128
::MAX
as u128
;
237 let max_lsb
= bcx
.ins().iconst(types
::I64
, max
as u64 as i64);
238 let max_msb
= bcx
.ins().iconst(types
::I64
, (max
>> 64) as u64 as i64);
239 let max
= bcx
.ins().iconcat(max_lsb
, max_msb
);
243 let min_half
= bcx
.ins().iconst(types
::I64
, 0);
244 let min
= bcx
.ins().iconcat(min_half
, min_half
);
246 let max_half
= bcx
.ins().iconst(types
::I64
, u64::MAX
as i64);
247 let max
= bcx
.ins().iconcat(max_half
, max_half
);
253 let min
= match (ty
, signed
) {
254 (types
::I8
, false) | (types
::I16
, false) | (types
::I32
, false) | (types
::I64
, false) => {
257 (types
::I8
, true) => i64::from(i8::MIN
),
258 (types
::I16
, true) => i64::from(i16::MIN
),
259 (types
::I32
, true) => i64::from(i32::MIN
),
260 (types
::I64
, true) => i64::MIN
,
264 let max
= match (ty
, signed
) {
265 (types
::I8
, false) => i64::from(u8::MAX
),
266 (types
::I16
, false) => i64::from(u16::MAX
),
267 (types
::I32
, false) => i64::from(u32::MAX
),
268 (types
::I64
, false) => u64::MAX
as i64,
269 (types
::I8
, true) => i64::from(i8::MAX
),
270 (types
::I16
, true) => i64::from(i16::MAX
),
271 (types
::I32
, true) => i64::from(i32::MAX
),
272 (types
::I64
, true) => i64::MAX
,
276 let (min
, max
) = (bcx
.ins().iconst(ty
, min
), bcx
.ins().iconst(ty
, max
));
281 pub(crate) fn type_sign(ty
: Ty
<'_
>) -> bool
{
283 ty
::Ref(..) | ty
::RawPtr(..) | ty
::FnPtr(..) | ty
::Char
| ty
::Uint(..) | ty
::Bool
=> false,
285 ty
::Float(..) => false, // `signed` is unused for floats
286 _
=> panic
!("{}", ty
),
290 pub(crate) struct FunctionCx
<'clif
, 'tcx
, M
: Module
> {
291 pub(crate) cx
: &'clif
mut crate::CodegenCx
<'tcx
, M
>,
292 pub(crate) tcx
: TyCtxt
<'tcx
>,
293 pub(crate) pointer_type
: Type
, // Cached from module
295 pub(crate) instance
: Instance
<'tcx
>,
296 pub(crate) mir
: &'tcx Body
<'tcx
>,
298 pub(crate) bcx
: FunctionBuilder
<'clif
>,
299 pub(crate) block_map
: IndexVec
<BasicBlock
, Block
>,
300 pub(crate) local_map
: IndexVec
<Local
, CPlace
<'tcx
>>,
302 /// When `#[track_caller]` is used, the implicit caller location is stored in this variable.
303 pub(crate) caller_location
: Option
<CValue
<'tcx
>>,
305 /// See [`crate::optimize::code_layout`] for more information.
306 pub(crate) cold_blocks
: EntitySet
<Block
>,
308 pub(crate) clif_comments
: crate::pretty_clif
::CommentWriter
,
309 pub(crate) source_info_set
: indexmap
::IndexSet
<SourceInfo
>,
311 /// This should only be accessed by `CPlace::new_var`.
312 pub(crate) next_ssa_var
: u32,
314 pub(crate) inline_asm_index
: u32,
317 impl<'tcx
, M
: Module
> LayoutOf
for FunctionCx
<'_
, 'tcx
, M
> {
319 type TyAndLayout
= TyAndLayout
<'tcx
>;
321 fn layout_of(&self, ty
: Ty
<'tcx
>) -> TyAndLayout
<'tcx
> {
322 assert
!(!ty
.still_further_specializable());
324 .layout_of(ParamEnv
::reveal_all().and(&ty
))
325 .unwrap_or_else(|e
| {
326 if let layout
::LayoutError
::SizeOverflow(_
) = e
{
327 self.tcx
.sess
.fatal(&e
.to_string())
329 bug
!("failed to get layout for `{}`: {}", ty
, e
)
335 impl<'tcx
, M
: Module
> layout
::HasTyCtxt
<'tcx
> for FunctionCx
<'_
, 'tcx
, M
> {
336 fn tcx
<'b
>(&'b
self) -> TyCtxt
<'tcx
> {
341 impl<'tcx
, M
: Module
> rustc_target
::abi
::HasDataLayout
for FunctionCx
<'_
, 'tcx
, M
> {
342 fn data_layout(&self) -> &rustc_target
::abi
::TargetDataLayout
{
343 &self.tcx
.data_layout
347 impl<'tcx
, M
: Module
> layout
::HasParamEnv
<'tcx
> for FunctionCx
<'_
, 'tcx
, M
> {
348 fn param_env(&self) -> ParamEnv
<'tcx
> {
349 ParamEnv
::reveal_all()
353 impl<'tcx
, M
: Module
> HasTargetSpec
for FunctionCx
<'_
, 'tcx
, M
> {
354 fn target_spec(&self) -> &Target
{
355 &self.tcx
.sess
.target
359 impl<'tcx
, M
: Module
> FunctionCx
<'_
, 'tcx
, M
> {
360 pub(crate) fn monomorphize
<T
>(&self, value
: T
) -> T
362 T
: TypeFoldable
<'tcx
> + Copy
,
364 self.instance
.subst_mir_and_normalize_erasing_regions(
366 ty
::ParamEnv
::reveal_all(),
371 pub(crate) fn clif_type(&self, ty
: Ty
<'tcx
>) -> Option
<Type
> {
372 clif_type_from_ty(self.tcx
, ty
)
375 pub(crate) fn clif_pair_type(&self, ty
: Ty
<'tcx
>) -> Option
<(Type
, Type
)> {
376 clif_pair_type_from_ty(self.tcx
, ty
)
379 pub(crate) fn get_block(&self, bb
: BasicBlock
) -> Block
{
380 *self.block_map
.get(bb
).unwrap()
383 pub(crate) fn get_local_place(&mut self, local
: Local
) -> CPlace
<'tcx
> {
384 *self.local_map
.get(local
).unwrap_or_else(|| {
385 panic
!("Local {:?} doesn't exist", local
);
389 pub(crate) fn set_debug_loc(&mut self, source_info
: mir
::SourceInfo
) {
390 let (index
, _
) = self.source_info_set
.insert_full(source_info
);
391 self.bcx
.set_srcloc(SourceLoc
::new(index
as u32));
394 pub(crate) fn get_caller_location(&mut self, span
: Span
) -> CValue
<'tcx
> {
395 if let Some(loc
) = self.caller_location
{
396 // `#[track_caller]` is used; return caller location instead of current location.
400 let topmost
= span
.ctxt().outer_expn().expansion_cause().unwrap_or(span
);
401 let caller
= self.tcx
.sess
.source_map().lookup_char_pos(topmost
.lo());
402 let const_loc
= self.tcx
.const_caller_location((
403 rustc_span
::symbol
::Symbol
::intern(&caller
.file
.name
.to_string()),
405 caller
.col_display
as u32 + 1,
407 crate::constant
::codegen_const_value(self, const_loc
, self.tcx
.caller_location_ty())
410 pub(crate) fn triple(&self) -> &target_lexicon
::Triple
{
411 self.cx
.module
.isa().triple()
414 pub(crate) fn anonymous_str(&mut self, prefix
: &str, msg
: &str) -> Value
{
415 use std
::collections
::hash_map
::DefaultHasher
;
416 use std
::hash
::{Hash, Hasher}
;
418 let mut hasher
= DefaultHasher
::new();
419 msg
.hash(&mut hasher
);
420 let msg_hash
= hasher
.finish();
421 let mut data_ctx
= DataContext
::new();
422 data_ctx
.define(msg
.as_bytes().to_vec().into_boxed_slice());
427 &format
!("__{}_{:08x}", prefix
, msg_hash
),
434 // Ignore DuplicateDefinition error, as the data will be the same
435 let _
= self.cx
.module
.define_data(msg_id
, &data_ctx
);
437 let local_msg_id
= self.cx
.module
.declare_data_in_func(msg_id
, self.bcx
.func
);
438 #[cfg(debug_assertions)]
440 self.add_comment(local_msg_id
, msg
);
442 self.bcx
.ins().global_value(self.pointer_type
, local_msg_id
)