Skip to main content

rustc_codegen_ssa/
common.rs

1#![allow(non_camel_case_types)]
2
3use rustc_attr_ir::PeImportNameType;
4use rustc_attr_ir::lang_items::LangItem;
5use rustc_crate_store::{DllCallingConvention, DllImport, DllImportSymbolType};
6use rustc_middle::mir::interpret::{GlobalAlloc, PointerArithmetic, Scalar};
7use rustc_middle::ty::layout::TyAndLayout;
8use rustc_middle::ty::{self, Instance, ScalarInt, TyCtxt};
9use rustc_span::{Span, bug, span_bug};
10use rustc_target::spec::{CfgAbi, Env, Os, Target};
11
12use crate::traits::*;
13
14#[derive(#[automatically_derived]impl ::core::marker::Copy for IntPredicate { }Copy, #[automatically_derived]#[doc(hidden)]unsafe impl ::core::clone::TrivialClone
    for IntPredicate {
}
#[automatically_derived]impl ::core::clone::Clone for IntPredicate {
    #[inline]
    fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]impl ::core::fmt::Debug for IntPredicate {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_c_like_enum_write_str(f,
            "IntEQ IntNE IntUGT IntUGE IntULT IntULE IntSGT IntSGE IntSLT IntSLE",
            match self {
                IntPredicate::IntEQ => 0usize,
                IntPredicate::IntNE => 6usize,
                IntPredicate::IntUGT => 12usize,
                IntPredicate::IntUGE => 19usize,
                IntPredicate::IntULT => 26usize,
                IntPredicate::IntULE => 33usize,
                IntPredicate::IntSGT => 40usize,
                IntPredicate::IntSGE => 47usize,
                IntPredicate::IntSLT => 54usize,
                IntPredicate::IntSLE => 61usize,
            })
    }
}Debug)]
15pub enum IntPredicate {
16    IntEQ,
17    IntNE,
18    IntUGT,
19    IntUGE,
20    IntULT,
21    IntULE,
22    IntSGT,
23    IntSGE,
24    IntSLT,
25    IntSLE,
26}
27
28#[derive(#[automatically_derived]impl ::core::marker::Copy for RealPredicate { }Copy, #[automatically_derived]#[doc(hidden)]unsafe impl ::core::clone::TrivialClone
    for RealPredicate {
}
#[automatically_derived]impl ::core::clone::Clone for RealPredicate {
    #[inline]
    fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]impl ::core::fmt::Debug for RealPredicate {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_c_like_enum_write_str(f,
            "RealPredicateFalse RealOEQ RealOGT RealOGE RealOLT RealOLE RealONE RealORD RealUNO RealUEQ RealUGT RealUGE RealULT RealULE RealUNE RealPredicateTrue",
            match self {
                RealPredicate::RealPredicateFalse => 0usize,
                RealPredicate::RealOEQ => 19usize,
                RealPredicate::RealOGT => 27usize,
                RealPredicate::RealOGE => 35usize,
                RealPredicate::RealOLT => 43usize,
                RealPredicate::RealOLE => 51usize,
                RealPredicate::RealONE => 59usize,
                RealPredicate::RealORD => 67usize,
                RealPredicate::RealUNO => 75usize,
                RealPredicate::RealUEQ => 83usize,
                RealPredicate::RealUGT => 91usize,
                RealPredicate::RealUGE => 99usize,
                RealPredicate::RealULT => 107usize,
                RealPredicate::RealULE => 115usize,
                RealPredicate::RealUNE => 123usize,
                RealPredicate::RealPredicateTrue => 131usize,
            })
    }
}Debug)]
29pub enum RealPredicate {
30    RealPredicateFalse,
31    RealOEQ,
32    RealOGT,
33    RealOGE,
34    RealOLT,
35    RealOLE,
36    RealONE,
37    RealORD,
38    RealUNO,
39    RealUEQ,
40    RealUGT,
41    RealUGE,
42    RealULT,
43    RealULE,
44    RealUNE,
45    RealPredicateTrue,
46}
47
48#[derive(#[automatically_derived]impl ::core::marker::Copy for AtomicRmwBinOp { }Copy, #[automatically_derived]#[doc(hidden)]unsafe impl ::core::clone::TrivialClone
    for AtomicRmwBinOp {
}
#[automatically_derived]impl ::core::clone::Clone for AtomicRmwBinOp {
    #[inline]
    fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]impl ::core::marker::StructuralPartialEq for
    AtomicRmwBinOp {
}
#[automatically_derived]impl ::core::cmp::PartialEq for AtomicRmwBinOp {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        ::core::intrinsics::discriminant_value(self) ==
            ::core::intrinsics::discriminant_value(other)
    }
}PartialEq, #[automatically_derived]impl ::core::fmt::Debug for AtomicRmwBinOp {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_c_like_enum_write_str(f,
            "AtomicXchg AtomicAdd AtomicSub AtomicAnd AtomicNand AtomicOr AtomicXor AtomicMax AtomicMin AtomicUMax AtomicUMin",
            match self {
                AtomicRmwBinOp::AtomicXchg => 0usize,
                AtomicRmwBinOp::AtomicAdd => 11usize,
                AtomicRmwBinOp::AtomicSub => 21usize,
                AtomicRmwBinOp::AtomicAnd => 31usize,
                AtomicRmwBinOp::AtomicNand => 41usize,
                AtomicRmwBinOp::AtomicOr => 52usize,
                AtomicRmwBinOp::AtomicXor => 61usize,
                AtomicRmwBinOp::AtomicMax => 71usize,
                AtomicRmwBinOp::AtomicMin => 81usize,
                AtomicRmwBinOp::AtomicUMax => 91usize,
                AtomicRmwBinOp::AtomicUMin => 102usize,
            })
    }
}Debug)]
49pub enum AtomicRmwBinOp {
50    AtomicXchg,
51    AtomicAdd,
52    AtomicSub,
53    AtomicAnd,
54    AtomicNand,
55    AtomicOr,
56    AtomicXor,
57    AtomicMax,
58    AtomicMin,
59    AtomicUMax,
60    AtomicUMin,
61}
62
63#[derive(#[automatically_derived]impl ::core::marker::Copy for SynchronizationScope { }Copy, #[automatically_derived]#[doc(hidden)]unsafe impl ::core::clone::TrivialClone
    for SynchronizationScope {
}
#[automatically_derived]impl ::core::clone::Clone for SynchronizationScope {
    #[inline]
    fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]impl ::core::fmt::Debug for SynchronizationScope {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f,
            match self {
                SynchronizationScope::SingleThread => "SingleThread",
                SynchronizationScope::CrossThread => "CrossThread",
            })
    }
}Debug)]
64pub enum SynchronizationScope {
65    SingleThread,
66    CrossThread,
67}
68
69// FIXME(mw): Anything that is produced via DepGraph::with_task() must implement
70//            the StableHash trait. Normally DepGraph::with_task() calls are
71//            hidden behind queries, but CGU creation is a special case in two
72//            ways: (1) it's not a query and (2) CGU are output nodes, so their
73//            Fingerprints are not actually needed. It remains to be clarified
74//            how exactly this case will be handled in the red/green system but
75//            for now we content ourselves with providing a no-op StableHash
76//            implementation for CGUs.
77mod temp_stable_hash_impls {
78    use rustc_data_structures::stable_hash::{StableHash, StableHashCtxt, StableHasher};
79
80    use crate::ModuleCodegen;
81
82    impl<M> StableHash for ModuleCodegen<M> {
83        fn stable_hash<Hcx: StableHashCtxt>(&self, _: &mut Hcx, _: &mut StableHasher) {
84            // do nothing
85        }
86    }
87}
88
89pub(crate) fn build_langcall<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
90    bx: &Bx,
91    span: Span,
92    li: LangItem,
93) -> (Bx::FnAbiOfResult, Bx::Value, Instance<'tcx>) {
94    let tcx = bx.tcx();
95    let def_id = tcx.require_lang_item(li, span);
96    let instance = ty::Instance::mono(tcx, def_id);
97    (
98        bx.fn_abi_of_instance(instance, ty::List::empty()),
99        bx.get_fn_addr(instance, tcx.sess.pointer_authentication_functions()),
100        instance,
101    )
102}
103
104pub(crate) fn shift_mask_val<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
105    bx: &mut Bx,
106    llty: Bx::Type,
107    mask_llty: Bx::Type,
108    invert: bool,
109) -> Bx::Value {
110    if let Some(val) = bx.int_width(llty) {
111        // i8/u8 can shift by at most 7, i16/u16 by at most 15, etc.
112        let val = val - 1;
113        if invert { bx.const_int(mask_llty, !val as i64) } else { bx.const_uint(mask_llty, val) }
114    } else if let Some(element) = bx.vector_element_type(llty) {
115        let (mask_elem, mask_len) =
116            bx.vector_element_type_and_length(llty).expect("mask was not a vector");
117        let mask = shift_mask_val(bx, element, mask_elem, invert);
118        bx.vector_splat(mask_len, mask)
119    } else {
120        ::rustc_span::macros::bug_impl(None,
    format_args!("shift_mask_val: expected Integer or Vector, found {0:?}",
        llty), Location::caller())bug!("shift_mask_val: expected Integer or Vector, found {llty:?}")
121    }
122}
123
124pub fn asm_const_to_str<'tcx>(
125    tcx: TyCtxt<'tcx>,
126    sp: Span,
127    scalar: ScalarInt,
128    ty_and_layout: TyAndLayout<'tcx>,
129) -> String {
130    let value = scalar.to_bits(ty_and_layout.size);
131    match ty_and_layout.ty.kind() {
132        ty::Uint(_) => value.to_string(),
133        ty::Int(int_ty) => match int_ty.normalize(tcx.sess.target.pointer_width) {
134            ty::IntTy::I8 => (value as i8).to_string(),
135            ty::IntTy::I16 => (value as i16).to_string(),
136            ty::IntTy::I32 => (value as i32).to_string(),
137            ty::IntTy::I64 => (value as i64).to_string(),
138            ty::IntTy::I128 => (value as i128).to_string(),
139            ty::IntTy::Isize => ::core::panicking::unreachable_default_msg()unreachable!(),
140        },
141        // For pointers without provenance, just print the unsigned value
142        ty::Ref(..) | ty::RawPtr(..) | ty::FnPtr(..) => value.to_string(),
143        _ => ::rustc_span::macros::bug_impl(Some(sp),
    format_args!("asm const has bad type {0}", ty_and_layout.ty),
    Location::caller())span_bug!(sp, "asm const has bad type {}", ty_and_layout.ty),
144    }
145}
146
147/// "Clean" a const pointer by removing values where the resulting ASM will not be
148/// `<symbol> + <offset>`.
149///
150/// These values are converted to `ScalarInt`.
151pub fn asm_const_ptr_clean<'tcx>(tcx: TyCtxt<'tcx>, scalar: Scalar) -> Scalar {
152    let Scalar::Ptr(ptr, _) = scalar else {
153        return scalar;
154    };
155    let (prov, offset) = ptr.prov_and_relative_offset();
156    let global_alloc = tcx.global_alloc(prov.alloc_id());
157    match global_alloc {
158        GlobalAlloc::TypeId { .. } => {
159            // `TypeId` provenances are not a thing in codegen. Just erase and replace with scalar offset.
160            Scalar::from_u64(offset.bytes())
161        }
162        GlobalAlloc::Memory(alloc) if alloc.inner().len() == 0 => {
163            // ZST const allocations don't actually get global defined when lowered.
164            // Turn them into integer without provenances now.
165            let val = alloc.inner().align.bytes().wrapping_add(offset.bytes());
166            Scalar::from_target_usize(tcx.truncate_to_target_usize(val), &tcx)
167        }
168        // Other types of `GlobalAlloc` are fine.
169        _ => scalar,
170    }
171}
172
173pub fn is_using_dlltool(target: &Target) -> bool {
174    target.os == Os::Windows && target.env == Env::Gnu && target.cfg_abi == CfgAbi::Unspecified
175}
176
177pub fn i686_decorated_name(
178    dll_import: &DllImport,
179    mingw: bool,
180    disable_name_mangling: bool,
181    force_fully_decorated: bool,
182) -> String {
183    let name = dll_import.name.as_str();
184
185    let (add_prefix, add_suffix) = match (force_fully_decorated, dll_import.import_name_type) {
186        // No prefix is a bit weird, in that LLVM/ar_archive_writer won't emit it, so we will
187        // ignore `force_fully_decorated` and always partially decorate it.
188        (_, Some(PeImportNameType::NoPrefix)) => (false, true),
189        (false, Some(PeImportNameType::Undecorated)) => (false, false),
190        _ => (true, true),
191    };
192
193    // Worst case: +1 for disable name mangling, +1 for prefix, +4 for suffix (@@__).
194    let mut decorated_name = String::with_capacity(name.len() + 6);
195
196    if disable_name_mangling {
197        // LLVM uses a binary 1 ('\x01') prefix to a name to indicate that mangling needs to be
198        // disabled.
199        decorated_name.push('\x01');
200    }
201
202    let prefix = if add_prefix && dll_import.symbol_type == DllImportSymbolType::Function {
203        match dll_import.calling_convention {
204            DllCallingConvention::C | DllCallingConvention::Vectorcall(_) => None,
205            DllCallingConvention::Stdcall(_) => (!mingw
206                || dll_import.import_name_type == Some(PeImportNameType::Decorated))
207            .then_some('_'),
208            DllCallingConvention::Fastcall(_) => Some('@'),
209        }
210    } else if dll_import.symbol_type != DllImportSymbolType::Function && !mingw {
211        // For static variables, prefix with '_' on MSVC.
212        Some('_')
213    } else {
214        None
215    };
216    if let Some(prefix) = prefix {
217        decorated_name.push(prefix);
218    }
219
220    decorated_name.push_str(name);
221
222    if add_suffix && dll_import.symbol_type == DllImportSymbolType::Function {
223        use std::fmt::Write;
224
225        match dll_import.calling_convention {
226            DllCallingConvention::C => {}
227            DllCallingConvention::Stdcall(arg_list_size)
228            | DllCallingConvention::Fastcall(arg_list_size) => {
229                (&mut decorated_name).write_fmt(format_args!("@{0}", arg_list_size))write!(&mut decorated_name, "@{arg_list_size}").unwrap();
230            }
231            DllCallingConvention::Vectorcall(arg_list_size) => {
232                (&mut decorated_name).write_fmt(format_args!("@@{0}", arg_list_size))write!(&mut decorated_name, "@@{arg_list_size}").unwrap();
233            }
234        }
235    }
236
237    decorated_name
238}