| #![allow(non_camel_case_types)] |
| |
| use rustc_hir::LangItem; |
| use rustc_middle::ty::layout::TyAndLayout; |
| use rustc_middle::ty::{self, Instance, TyCtxt}; |
| use rustc_middle::{bug, mir, span_bug}; |
| use rustc_session::cstore::{DllCallingConvention, DllImport, PeImportNameType}; |
| use rustc_span::Span; |
| use rustc_target::spec::Target; |
| |
| use crate::traits::*; |
| |
| #[derive(Copy, Clone, Debug)] |
| pub enum IntPredicate { |
| IntEQ, |
| IntNE, |
| IntUGT, |
| IntUGE, |
| IntULT, |
| IntULE, |
| IntSGT, |
| IntSGE, |
| IntSLT, |
| IntSLE, |
| } |
| |
| #[derive(Copy, Clone, Debug)] |
| pub enum RealPredicate { |
| RealPredicateFalse, |
| RealOEQ, |
| RealOGT, |
| RealOGE, |
| RealOLT, |
| RealOLE, |
| RealONE, |
| RealORD, |
| RealUNO, |
| RealUEQ, |
| RealUGT, |
| RealUGE, |
| RealULT, |
| RealULE, |
| RealUNE, |
| RealPredicateTrue, |
| } |
| |
| #[derive(Copy, Clone, PartialEq, Debug)] |
| pub enum AtomicRmwBinOp { |
| AtomicXchg, |
| AtomicAdd, |
| AtomicSub, |
| AtomicAnd, |
| AtomicNand, |
| AtomicOr, |
| AtomicXor, |
| AtomicMax, |
| AtomicMin, |
| AtomicUMax, |
| AtomicUMin, |
| } |
| |
| #[derive(Copy, Clone, Debug)] |
| pub enum SynchronizationScope { |
| SingleThread, |
| CrossThread, |
| } |
| |
| #[derive(Copy, Clone, PartialEq, Debug)] |
| pub enum TypeKind { |
| Void, |
| Half, |
| Float, |
| Double, |
| X86_FP80, |
| FP128, |
| PPC_FP128, |
| Label, |
| Integer, |
| Function, |
| Struct, |
| Array, |
| Pointer, |
| Vector, |
| Metadata, |
| Token, |
| ScalableVector, |
| BFloat, |
| X86_AMX, |
| } |
| |
| // FIXME(mw): Anything that is produced via DepGraph::with_task() must implement |
| // the HashStable trait. Normally DepGraph::with_task() calls are |
| // hidden behind queries, but CGU creation is a special case in two |
| // ways: (1) it's not a query and (2) CGU are output nodes, so their |
| // Fingerprints are not actually needed. It remains to be clarified |
| // how exactly this case will be handled in the red/green system but |
| // for now we content ourselves with providing a no-op HashStable |
| // implementation for CGUs. |
| mod temp_stable_hash_impls { |
| use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; |
| |
| use crate::ModuleCodegen; |
| |
| impl<HCX, M> HashStable<HCX> for ModuleCodegen<M> { |
| fn hash_stable(&self, _: &mut HCX, _: &mut StableHasher) { |
| // do nothing |
| } |
| } |
| } |
| |
| pub(crate) fn build_langcall<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( |
| bx: &Bx, |
| span: Span, |
| li: LangItem, |
| ) -> (Bx::FnAbiOfResult, Bx::Value, Instance<'tcx>) { |
| let tcx = bx.tcx(); |
| let def_id = tcx.require_lang_item(li, span); |
| let instance = ty::Instance::mono(tcx, def_id); |
| (bx.fn_abi_of_instance(instance, ty::List::empty()), bx.get_fn_addr(instance), instance) |
| } |
| |
| pub(crate) fn shift_mask_val<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( |
| bx: &mut Bx, |
| llty: Bx::Type, |
| mask_llty: Bx::Type, |
| invert: bool, |
| ) -> Bx::Value { |
| let kind = bx.type_kind(llty); |
| match kind { |
| TypeKind::Integer => { |
| // i8/u8 can shift by at most 7, i16/u16 by at most 15, etc. |
| let val = bx.int_width(llty) - 1; |
| if invert { |
| bx.const_int(mask_llty, !val as i64) |
| } else { |
| bx.const_uint(mask_llty, val) |
| } |
| } |
| TypeKind::Vector => { |
| let mask = |
| shift_mask_val(bx, bx.element_type(llty), bx.element_type(mask_llty), invert); |
| bx.vector_splat(bx.vector_length(mask_llty), mask) |
| } |
| _ => bug!("shift_mask_val: expected Integer or Vector, found {:?}", kind), |
| } |
| } |
| |
| pub fn asm_const_to_str<'tcx>( |
| tcx: TyCtxt<'tcx>, |
| sp: Span, |
| const_value: mir::ConstValue<'tcx>, |
| ty_and_layout: TyAndLayout<'tcx>, |
| ) -> String { |
| let mir::ConstValue::Scalar(scalar) = const_value else { |
| span_bug!(sp, "expected Scalar for promoted asm const, but got {:#?}", const_value) |
| }; |
| let value = scalar.assert_scalar_int().to_bits(ty_and_layout.size); |
| match ty_and_layout.ty.kind() { |
| ty::Uint(_) => value.to_string(), |
| ty::Int(int_ty) => match int_ty.normalize(tcx.sess.target.pointer_width) { |
| ty::IntTy::I8 => (value as i8).to_string(), |
| ty::IntTy::I16 => (value as i16).to_string(), |
| ty::IntTy::I32 => (value as i32).to_string(), |
| ty::IntTy::I64 => (value as i64).to_string(), |
| ty::IntTy::I128 => (value as i128).to_string(), |
| ty::IntTy::Isize => unreachable!(), |
| }, |
| _ => span_bug!(sp, "asm const has bad type {}", ty_and_layout.ty), |
| } |
| } |
| |
| pub fn is_mingw_gnu_toolchain(target: &Target) -> bool { |
| target.vendor == "pc" && target.os == "windows" && target.env == "gnu" && target.abi.is_empty() |
| } |
| |
| pub fn i686_decorated_name( |
| dll_import: &DllImport, |
| mingw: bool, |
| disable_name_mangling: bool, |
| force_fully_decorated: bool, |
| ) -> String { |
| let name = dll_import.name.as_str(); |
| |
| let (add_prefix, add_suffix) = match (force_fully_decorated, dll_import.import_name_type) { |
| // No prefix is a bit weird, in that LLVM/ar_archive_writer won't emit it, so we will |
| // ignore `force_fully_decorated` and always partially decorate it. |
| (_, Some(PeImportNameType::NoPrefix)) => (false, true), |
| (false, Some(PeImportNameType::Undecorated)) => (false, false), |
| _ => (true, true), |
| }; |
| |
| // Worst case: +1 for disable name mangling, +1 for prefix, +4 for suffix (@@__). |
| let mut decorated_name = String::with_capacity(name.len() + 6); |
| |
| if disable_name_mangling { |
| // LLVM uses a binary 1 ('\x01') prefix to a name to indicate that mangling needs to be |
| // disabled. |
| decorated_name.push('\x01'); |
| } |
| |
| let prefix = if add_prefix && dll_import.is_fn { |
| match dll_import.calling_convention { |
| DllCallingConvention::C | DllCallingConvention::Vectorcall(_) => None, |
| DllCallingConvention::Stdcall(_) => (!mingw |
| || dll_import.import_name_type == Some(PeImportNameType::Decorated)) |
| .then_some('_'), |
| DllCallingConvention::Fastcall(_) => Some('@'), |
| } |
| } else if !dll_import.is_fn && !mingw { |
| // For static variables, prefix with '_' on MSVC. |
| Some('_') |
| } else { |
| None |
| }; |
| if let Some(prefix) = prefix { |
| decorated_name.push(prefix); |
| } |
| |
| decorated_name.push_str(name); |
| |
| if add_suffix && dll_import.is_fn { |
| use std::fmt::Write; |
| |
| match dll_import.calling_convention { |
| DllCallingConvention::C => {} |
| DllCallingConvention::Stdcall(arg_list_size) |
| | DllCallingConvention::Fastcall(arg_list_size) => { |
| write!(&mut decorated_name, "@{arg_list_size}").unwrap(); |
| } |
| DllCallingConvention::Vectorcall(arg_list_size) => { |
| write!(&mut decorated_name, "@@{arg_list_size}").unwrap(); |
| } |
| } |
| } |
| |
| decorated_name |
| } |