blob: 777f3f6b53fd48031e7f61dd2ca738a336f7d01d [file]
#![allow(non_camel_case_types)]
use rustc_hir::LangItem;
use rustc_hir::attrs::PeImportNameType;
use rustc_middle::mir::interpret::{GlobalAlloc, PointerArithmetic, Scalar};
use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::ty::{self, Instance, ScalarInt, TyCtxt};
use rustc_middle::{bug, span_bug};
use rustc_session::cstore::{DllCallingConvention, DllImport, DllImportSymbolType};
use rustc_span::Span;
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_mingw_gnu_toolchain(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
}