| #![allow(non_camel_case_types)] | |
| use rustc_attr_ir::PeImportNameType; | |
| use rustc_attr_ir::lang_items::LangItem; | |
| use rustc_crate_store::{DllCallingConvention, DllImport, DllImportSymbolType}; | |
| use rustc_middle::mir::interpret::{GlobalAlloc, PointerArithmetic, Scalar}; | |
| use rustc_middle::ty::layout::TyAndLayout; | |
| use rustc_middle::ty::{self, Instance, ScalarInt, TyCtxt}; | |
| use rustc_span::{Span, bug, span_bug}; | |
| use rustc_target::spec::{CfgAbi, 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 StableHash 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 StableHash | |
| // implementation for CGUs. | |
| mod temp_stable_hash_impls { | |
| use rustc_data_structures::stable_hash::{StableHash, StableHashCtxt, StableHasher}; | |
| use crate::ModuleCodegen; | |
| impl<M> StableHash for ModuleCodegen<M> { | |
| fn stable_hash<Hcx: StableHashCtxt>(&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, tcx.sess.pointer_authentication_functions()), | |
| 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, | |
| scalar: ScalarInt, | |
| ty_and_layout: TyAndLayout<'tcx>, | |
| ) -> String { | |
| let value = scalar.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!(), | |
| }, | |
| // For pointers without provenance, just print the unsigned value | |
| ty::Ref(..) | ty::RawPtr(..) | ty::FnPtr(..) => value.to_string(), | |
| _ => span_bug!(sp, "asm const has bad type {}", ty_and_layout.ty), | |
| } | |
| } | |
| /// "Clean" a const pointer by removing values where the resulting ASM will not be | |
| /// `<symbol> + <offset>`. | |
| /// | |
| /// These values are converted to `ScalarInt`. | |
| pub fn asm_const_ptr_clean<'tcx>(tcx: TyCtxt<'tcx>, scalar: Scalar) -> Scalar { | |
| let Scalar::Ptr(ptr, _) = scalar else { | |
| return scalar; | |
| }; | |
| let (prov, offset) = ptr.prov_and_relative_offset(); | |
| let global_alloc = tcx.global_alloc(prov.alloc_id()); | |
| match global_alloc { | |
| GlobalAlloc::TypeId { .. } => { | |
| // `TypeId` provenances are not a thing in codegen. Just erase and replace with scalar offset. | |
| Scalar::from_u64(offset.bytes()) | |
| } | |
| GlobalAlloc::Memory(alloc) if alloc.inner().len() == 0 => { | |
| // ZST const allocations don't actually get global defined when lowered. | |
| // Turn them into integer without provenances now. | |
| let val = alloc.inner().align.bytes().wrapping_add(offset.bytes()); | |
| Scalar::from_target_usize(tcx.truncate_to_target_usize(val), &tcx) | |
| } | |
| // Other types of `GlobalAlloc` are fine. | |
| _ => scalar, | |
| } | |
| } | |
| pub fn is_using_dlltool(target: &Target) -> bool { | |
| target.os == Os::Windows && target.env == Env::Gnu && target.cfg_abi == CfgAbi::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.symbol_type == DllImportSymbolType::Function { | |
| 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.symbol_type != DllImportSymbolType::Function && !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.symbol_type == DllImportSymbolType::Function { | |
| 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 | |
| } |