rustc_codegen_ssa/
common.rs

1#![allow(non_camel_case_types)]
2
3use rustc_hir::LangItem;
4use rustc_middle::ty::layout::TyAndLayout;
5use rustc_middle::ty::{self, Instance, TyCtxt};
6use rustc_middle::{bug, mir, span_bug};
7use rustc_session::cstore::{DllCallingConvention, DllImport, PeImportNameType};
8use rustc_span::Span;
9use rustc_target::spec::Target;
10
11use crate::traits::*;
12
13#[derive(Copy, Clone, Debug)]
14pub enum IntPredicate {
15    IntEQ,
16    IntNE,
17    IntUGT,
18    IntUGE,
19    IntULT,
20    IntULE,
21    IntSGT,
22    IntSGE,
23    IntSLT,
24    IntSLE,
25}
26
27#[derive(Copy, Clone, Debug)]
28pub enum RealPredicate {
29    RealPredicateFalse,
30    RealOEQ,
31    RealOGT,
32    RealOGE,
33    RealOLT,
34    RealOLE,
35    RealONE,
36    RealORD,
37    RealUNO,
38    RealUEQ,
39    RealUGT,
40    RealUGE,
41    RealULT,
42    RealULE,
43    RealUNE,
44    RealPredicateTrue,
45}
46
47#[derive(Copy, Clone, PartialEq, Debug)]
48pub enum AtomicRmwBinOp {
49    AtomicXchg,
50    AtomicAdd,
51    AtomicSub,
52    AtomicAnd,
53    AtomicNand,
54    AtomicOr,
55    AtomicXor,
56    AtomicMax,
57    AtomicMin,
58    AtomicUMax,
59    AtomicUMin,
60}
61
62#[derive(Copy, Clone, Debug)]
63pub enum AtomicOrdering {
64    Unordered,
65    Relaxed,
66    Acquire,
67    Release,
68    AcquireRelease,
69    SequentiallyConsistent,
70}
71
72#[derive(Copy, Clone, Debug)]
73pub enum SynchronizationScope {
74    SingleThread,
75    CrossThread,
76}
77
78#[derive(Copy, Clone, PartialEq, Debug)]
79pub enum TypeKind {
80    Void,
81    Half,
82    Float,
83    Double,
84    X86_FP80,
85    FP128,
86    PPC_FP128,
87    Label,
88    Integer,
89    Function,
90    Struct,
91    Array,
92    Pointer,
93    Vector,
94    Metadata,
95    Token,
96    ScalableVector,
97    BFloat,
98    X86_AMX,
99}
100
101// FIXME(mw): Anything that is produced via DepGraph::with_task() must implement
102//            the HashStable trait. Normally DepGraph::with_task() calls are
103//            hidden behind queries, but CGU creation is a special case in two
104//            ways: (1) it's not a query and (2) CGU are output nodes, so their
105//            Fingerprints are not actually needed. It remains to be clarified
106//            how exactly this case will be handled in the red/green system but
107//            for now we content ourselves with providing a no-op HashStable
108//            implementation for CGUs.
109mod temp_stable_hash_impls {
110    use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
111
112    use crate::ModuleCodegen;
113
114    impl<HCX, M> HashStable<HCX> for ModuleCodegen<M> {
115        fn hash_stable(&self, _: &mut HCX, _: &mut StableHasher) {
116            // do nothing
117        }
118    }
119}
120
121pub(crate) fn build_langcall<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
122    bx: &Bx,
123    span: Option<Span>,
124    li: LangItem,
125) -> (Bx::FnAbiOfResult, Bx::Value, Instance<'tcx>) {
126    let tcx = bx.tcx();
127    let def_id = tcx.require_lang_item(li, span);
128    let instance = ty::Instance::mono(tcx, def_id);
129    (bx.fn_abi_of_instance(instance, ty::List::empty()), bx.get_fn_addr(instance), instance)
130}
131
132pub(crate) fn shift_mask_val<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
133    bx: &mut Bx,
134    llty: Bx::Type,
135    mask_llty: Bx::Type,
136    invert: bool,
137) -> Bx::Value {
138    let kind = bx.type_kind(llty);
139    match kind {
140        TypeKind::Integer => {
141            // i8/u8 can shift by at most 7, i16/u16 by at most 15, etc.
142            let val = bx.int_width(llty) - 1;
143            if invert {
144                bx.const_int(mask_llty, !val as i64)
145            } else {
146                bx.const_uint(mask_llty, val)
147            }
148        }
149        TypeKind::Vector => {
150            let mask =
151                shift_mask_val(bx, bx.element_type(llty), bx.element_type(mask_llty), invert);
152            bx.vector_splat(bx.vector_length(mask_llty), mask)
153        }
154        _ => bug!("shift_mask_val: expected Integer or Vector, found {:?}", kind),
155    }
156}
157
158pub fn asm_const_to_str<'tcx>(
159    tcx: TyCtxt<'tcx>,
160    sp: Span,
161    const_value: mir::ConstValue<'tcx>,
162    ty_and_layout: TyAndLayout<'tcx>,
163) -> String {
164    let mir::ConstValue::Scalar(scalar) = const_value else {
165        span_bug!(sp, "expected Scalar for promoted asm const, but got {:#?}", const_value)
166    };
167    let value = scalar.assert_scalar_int().to_bits(ty_and_layout.size);
168    match ty_and_layout.ty.kind() {
169        ty::Uint(_) => value.to_string(),
170        ty::Int(int_ty) => match int_ty.normalize(tcx.sess.target.pointer_width) {
171            ty::IntTy::I8 => (value as i8).to_string(),
172            ty::IntTy::I16 => (value as i16).to_string(),
173            ty::IntTy::I32 => (value as i32).to_string(),
174            ty::IntTy::I64 => (value as i64).to_string(),
175            ty::IntTy::I128 => (value as i128).to_string(),
176            ty::IntTy::Isize => unreachable!(),
177        },
178        _ => span_bug!(sp, "asm const has bad type {}", ty_and_layout.ty),
179    }
180}
181
182pub fn is_mingw_gnu_toolchain(target: &Target) -> bool {
183    target.vendor == "pc" && target.os == "windows" && target.env == "gnu" && target.abi.is_empty()
184}
185
186pub fn i686_decorated_name(
187    dll_import: &DllImport,
188    mingw: bool,
189    disable_name_mangling: bool,
190    force_fully_decorated: bool,
191) -> String {
192    let name = dll_import.name.as_str();
193
194    let (add_prefix, add_suffix) = match (force_fully_decorated, dll_import.import_name_type) {
195        // No prefix is a bit weird, in that LLVM/ar_archive_writer won't emit it, so we will
196        // ignore `force_fully_decorated` and always partially decorate it.
197        (_, Some(PeImportNameType::NoPrefix)) => (false, true),
198        (false, Some(PeImportNameType::Undecorated)) => (false, false),
199        _ => (true, true),
200    };
201
202    // Worst case: +1 for disable name mangling, +1 for prefix, +4 for suffix (@@__).
203    let mut decorated_name = String::with_capacity(name.len() + 6);
204
205    if disable_name_mangling {
206        // LLVM uses a binary 1 ('\x01') prefix to a name to indicate that mangling needs to be
207        // disabled.
208        decorated_name.push('\x01');
209    }
210
211    let prefix = if add_prefix && dll_import.is_fn {
212        match dll_import.calling_convention {
213            DllCallingConvention::C | DllCallingConvention::Vectorcall(_) => None,
214            DllCallingConvention::Stdcall(_) => (!mingw
215                || dll_import.import_name_type == Some(PeImportNameType::Decorated))
216            .then_some('_'),
217            DllCallingConvention::Fastcall(_) => Some('@'),
218        }
219    } else if !dll_import.is_fn && !mingw {
220        // For static variables, prefix with '_' on MSVC.
221        Some('_')
222    } else {
223        None
224    };
225    if let Some(prefix) = prefix {
226        decorated_name.push(prefix);
227    }
228
229    decorated_name.push_str(name);
230
231    if add_suffix && dll_import.is_fn {
232        use std::fmt::Write;
233
234        match dll_import.calling_convention {
235            DllCallingConvention::C => {}
236            DllCallingConvention::Stdcall(arg_list_size)
237            | DllCallingConvention::Fastcall(arg_list_size) => {
238                write!(&mut decorated_name, "@{arg_list_size}").unwrap();
239            }
240            DllCallingConvention::Vectorcall(arg_list_size) => {
241                write!(&mut decorated_name, "@@{arg_list_size}").unwrap();
242            }
243        }
244    }
245
246    decorated_name
247}