rustc_codegen_ssa/
common.rs

1#![allow(non_camel_case_types)]
2
3use rustc_hir::LangItem;
4use rustc_hir::attrs::PeImportNameType;
5use rustc_middle::ty::layout::TyAndLayout;
6use rustc_middle::ty::{self, Instance, TyCtxt};
7use rustc_middle::{bug, mir, span_bug};
8use rustc_session::cstore::{DllCallingConvention, DllImport};
9use rustc_span::Span;
10use rustc_target::spec::Target;
11
12use crate::traits::*;
13
14#[derive(Copy, Clone, 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(Copy, Clone, 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(Copy, Clone, PartialEq, 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(Copy, Clone, Debug)]
64pub enum SynchronizationScope {
65    SingleThread,
66    CrossThread,
67}
68
69#[derive(Copy, Clone, PartialEq, Debug)]
70pub enum TypeKind {
71    Void,
72    Half,
73    Float,
74    Double,
75    X86_FP80,
76    FP128,
77    PPC_FP128,
78    Label,
79    Integer,
80    Function,
81    Struct,
82    Array,
83    Pointer,
84    Vector,
85    Metadata,
86    Token,
87    ScalableVector,
88    BFloat,
89    X86_AMX,
90}
91
92// FIXME(mw): Anything that is produced via DepGraph::with_task() must implement
93//            the HashStable trait. Normally DepGraph::with_task() calls are
94//            hidden behind queries, but CGU creation is a special case in two
95//            ways: (1) it's not a query and (2) CGU are output nodes, so their
96//            Fingerprints are not actually needed. It remains to be clarified
97//            how exactly this case will be handled in the red/green system but
98//            for now we content ourselves with providing a no-op HashStable
99//            implementation for CGUs.
100mod temp_stable_hash_impls {
101    use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
102
103    use crate::ModuleCodegen;
104
105    impl<HCX, M> HashStable<HCX> for ModuleCodegen<M> {
106        fn hash_stable(&self, _: &mut HCX, _: &mut StableHasher) {
107            // do nothing
108        }
109    }
110}
111
112pub(crate) fn build_langcall<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
113    bx: &Bx,
114    span: Span,
115    li: LangItem,
116) -> (Bx::FnAbiOfResult, Bx::Value, Instance<'tcx>) {
117    let tcx = bx.tcx();
118    let def_id = tcx.require_lang_item(li, span);
119    let instance = ty::Instance::mono(tcx, def_id);
120    (bx.fn_abi_of_instance(instance, ty::List::empty()), bx.get_fn_addr(instance), instance)
121}
122
123pub(crate) fn shift_mask_val<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
124    bx: &mut Bx,
125    llty: Bx::Type,
126    mask_llty: Bx::Type,
127    invert: bool,
128) -> Bx::Value {
129    let kind = bx.type_kind(llty);
130    match kind {
131        TypeKind::Integer => {
132            // i8/u8 can shift by at most 7, i16/u16 by at most 15, etc.
133            let val = bx.int_width(llty) - 1;
134            if invert {
135                bx.const_int(mask_llty, !val as i64)
136            } else {
137                bx.const_uint(mask_llty, val)
138            }
139        }
140        TypeKind::Vector => {
141            let mask =
142                shift_mask_val(bx, bx.element_type(llty), bx.element_type(mask_llty), invert);
143            bx.vector_splat(bx.vector_length(mask_llty), mask)
144        }
145        _ => bug!("shift_mask_val: expected Integer or Vector, found {:?}", kind),
146    }
147}
148
149pub fn asm_const_to_str<'tcx>(
150    tcx: TyCtxt<'tcx>,
151    sp: Span,
152    const_value: mir::ConstValue,
153    ty_and_layout: TyAndLayout<'tcx>,
154) -> String {
155    let mir::ConstValue::Scalar(scalar) = const_value else {
156        span_bug!(sp, "expected Scalar for promoted asm const, but got {:#?}", const_value)
157    };
158    let value = scalar.assert_scalar_int().to_bits(ty_and_layout.size);
159    match ty_and_layout.ty.kind() {
160        ty::Uint(_) => value.to_string(),
161        ty::Int(int_ty) => match int_ty.normalize(tcx.sess.target.pointer_width) {
162            ty::IntTy::I8 => (value as i8).to_string(),
163            ty::IntTy::I16 => (value as i16).to_string(),
164            ty::IntTy::I32 => (value as i32).to_string(),
165            ty::IntTy::I64 => (value as i64).to_string(),
166            ty::IntTy::I128 => (value as i128).to_string(),
167            ty::IntTy::Isize => unreachable!(),
168        },
169        _ => span_bug!(sp, "asm const has bad type {}", ty_and_layout.ty),
170    }
171}
172
173pub fn is_mingw_gnu_toolchain(target: &Target) -> bool {
174    target.vendor == "pc" && target.os == "windows" && target.env == "gnu" && target.abi.is_empty()
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.is_fn {
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.is_fn && !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.is_fn {
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                write!(&mut decorated_name, "@{arg_list_size}").unwrap();
230            }
231            DllCallingConvention::Vectorcall(arg_list_size) => {
232                write!(&mut decorated_name, "@@{arg_list_size}").unwrap();
233            }
234        }
235    }
236
237    decorated_name
238}