| #![allow(non_camel_case_types)] | |
| use rustc_hir::LangItem; | |
| use rustc_hir::attrs::PeImportNameType; | |
| 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}; | |
| use rustc_span::Span; | |
| use rustc_target::spec::{Abi, Env, Os, 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, | |
| 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.os == Os::Windows && target.env == Env::Gnu && target.abi == Abi::Unspecified | |
| } | |
| 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 | |
| } |