Skip to main content

rustc_codegen_ssa/
common.rs

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