1
Fork 0

Make allocator shim creation mostly use safe code

This commit is contained in:
Oli Scherer 2025-02-24 11:14:21 +00:00
parent 840e31b29f
commit 396baa750e
5 changed files with 91 additions and 93 deletions

View file

@ -3,33 +3,31 @@ use rustc_ast::expand::allocator::{
ALLOCATOR_METHODS, AllocatorKind, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE, ALLOCATOR_METHODS, AllocatorKind, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE,
alloc_error_handler_name, default_fn_name, global_fn_name, alloc_error_handler_name, default_fn_name, global_fn_name,
}; };
use rustc_codegen_ssa::traits::BaseTypeCodegenMethods as _;
use rustc_middle::bug; use rustc_middle::bug;
use rustc_middle::ty::TyCtxt; use rustc_middle::ty::TyCtxt;
use rustc_session::config::{DebugInfo, OomStrategy}; use rustc_session::config::{DebugInfo, OomStrategy};
use crate::common::AsCCharPtr; use crate::builder::SBuilder;
use crate::llvm::{self, Context, False, Module, True, Type}; use crate::declare::declare_simple_fn;
use crate::{ModuleLlvm, attributes, debuginfo}; use crate::llvm::{self, False, True, Type};
use crate::{SimpleCx, attributes, debuginfo};
pub(crate) unsafe fn codegen( pub(crate) unsafe fn codegen(
tcx: TyCtxt<'_>, tcx: TyCtxt<'_>,
module_llvm: &mut ModuleLlvm, cx: SimpleCx<'_>,
module_name: &str, module_name: &str,
kind: AllocatorKind, kind: AllocatorKind,
alloc_error_handler_kind: AllocatorKind, alloc_error_handler_kind: AllocatorKind,
) { ) {
let llcx = &*module_llvm.llcx; let usize = match tcx.sess.target.pointer_width {
let llmod = module_llvm.llmod(); 16 => cx.type_i16(),
let usize = unsafe { 32 => cx.type_i32(),
match tcx.sess.target.pointer_width { 64 => cx.type_i64(),
16 => llvm::LLVMInt16TypeInContext(llcx), tws => bug!("Unsupported target word size for int: {}", tws),
32 => llvm::LLVMInt32TypeInContext(llcx),
64 => llvm::LLVMInt64TypeInContext(llcx),
tws => bug!("Unsupported target word size for int: {}", tws),
}
}; };
let i8 = unsafe { llvm::LLVMInt8TypeInContext(llcx) }; let i8 = cx.type_i8();
let i8p = unsafe { llvm::LLVMPointerTypeInContext(llcx, 0) }; let i8p = cx.type_ptr();
if kind == AllocatorKind::Default { if kind == AllocatorKind::Default {
for method in ALLOCATOR_METHODS { for method in ALLOCATOR_METHODS {
@ -58,15 +56,14 @@ pub(crate) unsafe fn codegen(
let from_name = global_fn_name(method.name); let from_name = global_fn_name(method.name);
let to_name = default_fn_name(method.name); let to_name = default_fn_name(method.name);
create_wrapper_function(tcx, llcx, llmod, &from_name, &to_name, &args, output, false); create_wrapper_function(tcx, &cx, &from_name, &to_name, &args, output, false);
} }
} }
// rust alloc error handler // rust alloc error handler
create_wrapper_function( create_wrapper_function(
tcx, tcx,
llcx, &cx,
llmod,
"__rust_alloc_error_handler", "__rust_alloc_error_handler",
alloc_error_handler_name(alloc_error_handler_kind), alloc_error_handler_name(alloc_error_handler_kind),
&[usize, usize], // size, align &[usize, usize], // size, align
@ -77,21 +74,21 @@ pub(crate) unsafe fn codegen(
unsafe { unsafe {
// __rust_alloc_error_handler_should_panic // __rust_alloc_error_handler_should_panic
let name = OomStrategy::SYMBOL; let name = OomStrategy::SYMBOL;
let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_c_char_ptr(), name.len(), i8); let ll_g = cx.declare_global(name, i8);
llvm::set_visibility(ll_g, llvm::Visibility::from_generic(tcx.sess.default_visibility())); llvm::set_visibility(ll_g, llvm::Visibility::from_generic(tcx.sess.default_visibility()));
let val = tcx.sess.opts.unstable_opts.oom.should_panic(); let val = tcx.sess.opts.unstable_opts.oom.should_panic();
let llval = llvm::LLVMConstInt(i8, val as u64, False); let llval = llvm::LLVMConstInt(i8, val as u64, False);
llvm::set_initializer(ll_g, llval); llvm::set_initializer(ll_g, llval);
let name = NO_ALLOC_SHIM_IS_UNSTABLE; let name = NO_ALLOC_SHIM_IS_UNSTABLE;
let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_c_char_ptr(), name.len(), i8); let ll_g = cx.declare_global(name, i8);
llvm::set_visibility(ll_g, llvm::Visibility::from_generic(tcx.sess.default_visibility())); llvm::set_visibility(ll_g, llvm::Visibility::from_generic(tcx.sess.default_visibility()));
let llval = llvm::LLVMConstInt(i8, 0, False); let llval = llvm::LLVMConstInt(i8, 0, False);
llvm::set_initializer(ll_g, llval); llvm::set_initializer(ll_g, llval);
} }
if tcx.sess.opts.debuginfo != DebugInfo::None { if tcx.sess.opts.debuginfo != DebugInfo::None {
let dbg_cx = debuginfo::CodegenUnitDebugContext::new(llmod); let dbg_cx = debuginfo::CodegenUnitDebugContext::new(cx.llmod);
debuginfo::metadata::build_compile_unit_di_node(tcx, module_name, &dbg_cx); debuginfo::metadata::build_compile_unit_di_node(tcx, module_name, &dbg_cx);
dbg_cx.finalize(tcx.sess); dbg_cx.finalize(tcx.sess);
} }
@ -99,77 +96,64 @@ pub(crate) unsafe fn codegen(
fn create_wrapper_function( fn create_wrapper_function(
tcx: TyCtxt<'_>, tcx: TyCtxt<'_>,
llcx: &Context, cx: &SimpleCx<'_>,
llmod: &Module,
from_name: &str, from_name: &str,
to_name: &str, to_name: &str,
args: &[&Type], args: &[&Type],
output: Option<&Type>, output: Option<&Type>,
no_return: bool, no_return: bool,
) { ) {
unsafe { let ty = cx.type_func(args, output.unwrap_or_else(|| cx.type_void()));
let ty = llvm::LLVMFunctionType( let llfn = declare_simple_fn(
output.unwrap_or_else(|| llvm::LLVMVoidTypeInContext(llcx)), &cx,
args.as_ptr(), from_name,
args.len() as c_uint, llvm::CallConv::CCallConv,
False, llvm::UnnamedAddr::Global,
); llvm::Visibility::from_generic(tcx.sess.default_visibility()),
let llfn = llvm::LLVMRustGetOrInsertFunction( ty,
llmod, );
from_name.as_c_char_ptr(), let no_return = if no_return {
from_name.len(), // -> ! DIFlagNoReturn
ty, let no_return = llvm::AttributeKind::NoReturn.create_attr(cx.llcx);
); attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[no_return]);
let no_return = if no_return { Some(no_return)
// -> ! DIFlagNoReturn } else {
let no_return = llvm::AttributeKind::NoReturn.create_attr(llcx); None
attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[no_return]); };
Some(no_return)
} else {
None
};
llvm::set_visibility(llfn, llvm::Visibility::from_generic(tcx.sess.default_visibility())); if tcx.sess.must_emit_unwind_tables() {
let uwtable =
attributes::uwtable_attr(cx.llcx, tcx.sess.opts.unstable_opts.use_sync_unwind);
attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[uwtable]);
}
if tcx.sess.must_emit_unwind_tables() { let callee = declare_simple_fn(
let uwtable = &cx,
attributes::uwtable_attr(llcx, tcx.sess.opts.unstable_opts.use_sync_unwind); to_name,
attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[uwtable]); llvm::CallConv::CCallConv,
} llvm::UnnamedAddr::Global,
llvm::Visibility::Hidden,
ty,
);
if let Some(no_return) = no_return {
// -> ! DIFlagNoReturn
attributes::apply_to_llfn(callee, llvm::AttributePlace::Function, &[no_return]);
}
llvm::set_visibility(callee, llvm::Visibility::Hidden);
let callee = let llbb = unsafe { llvm::LLVMAppendBasicBlockInContext(cx.llcx, llfn, c"entry".as_ptr()) };
llvm::LLVMRustGetOrInsertFunction(llmod, to_name.as_c_char_ptr(), to_name.len(), ty);
if let Some(no_return) = no_return {
// -> ! DIFlagNoReturn
attributes::apply_to_llfn(callee, llvm::AttributePlace::Function, &[no_return]);
}
llvm::set_visibility(callee, llvm::Visibility::Hidden);
let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, c"entry".as_ptr()); let mut bx = SBuilder::build(&cx, llbb);
let args = args
let llbuilder = llvm::LLVMCreateBuilderInContext(llcx); .iter()
llvm::LLVMPositionBuilderAtEnd(llbuilder, llbb); .enumerate()
let args = args .map(|(i, _)| llvm::get_param(llfn, i as c_uint))
.iter() .collect::<Vec<_>>();
.enumerate() let ret = bx.call(ty, callee, &args, None);
.map(|(i, _)| llvm::LLVMGetParam(llfn, i as c_uint)) llvm::LLVMSetTailCall(ret, True);
.collect::<Vec<_>>(); if output.is_some() {
let ret = llvm::LLVMBuildCallWithOperandBundles( bx.ret(ret);
llbuilder, } else {
ty, bx.ret_void()
callee,
args.as_ptr(),
args.len() as c_uint,
[].as_ptr(),
0 as c_uint,
c"".as_ptr(),
);
llvm::LLVMSetTailCall(ret, True);
if output.is_some() {
llvm::LLVMBuildRet(llbuilder, ret);
} else {
llvm::LLVMBuildRetVoid(llbuilder);
}
llvm::LLVMDisposeBuilder(llbuilder);
} }
} }

View file

@ -57,7 +57,7 @@ impl<'a, 'll, CX: Borrow<SCx<'ll>>> Drop for GenericBuilder<'a, 'll, CX> {
} }
impl<'a, 'll> SBuilder<'a, 'll> { impl<'a, 'll> SBuilder<'a, 'll> {
fn call( pub(crate) fn call(
&mut self, &mut self,
llty: &'ll Type, llty: &'ll Type,
llfn: &'ll Value, llfn: &'ll Value,
@ -100,17 +100,17 @@ impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> {
unsafe { llvm::LLVMBuildBitCast(self.llbuilder, val, dest_ty, UNNAMED) } unsafe { llvm::LLVMBuildBitCast(self.llbuilder, val, dest_ty, UNNAMED) }
} }
fn ret_void(&mut self) { pub(crate) fn ret_void(&mut self) {
llvm::LLVMBuildRetVoid(self.llbuilder); llvm::LLVMBuildRetVoid(self.llbuilder);
} }
fn ret(&mut self, v: &'ll Value) { pub(crate) fn ret(&mut self, v: &'ll Value) {
unsafe { unsafe {
llvm::LLVMBuildRet(self.llbuilder, v); llvm::LLVMBuildRet(self.llbuilder, v);
} }
} }
fn build(cx: &'a GenericCx<'ll, CX>, llbb: &'ll BasicBlock) -> Self { pub(crate) fn build(cx: &'a GenericCx<'ll, CX>, llbb: &'ll BasicBlock) -> Self {
let bx = Self::with_cx(cx); let bx = Self::with_cx(cx);
unsafe { unsafe {
llvm::LLVMPositionBuilderAtEnd(bx.llbuilder, llbb); llvm::LLVMPositionBuilderAtEnd(bx.llbuilder, llbb);

View file

@ -11,6 +11,8 @@
//! * Use define_* family of methods when you might be defining the Value. //! * Use define_* family of methods when you might be defining the Value.
//! * When in doubt, define. //! * When in doubt, define.
use std::borrow::Borrow;
use itertools::Itertools; use itertools::Itertools;
use rustc_codegen_ssa::traits::TypeMembershipCodegenMethods; use rustc_codegen_ssa::traits::TypeMembershipCodegenMethods;
use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::fx::FxIndexSet;
@ -22,7 +24,7 @@ use tracing::debug;
use crate::abi::FnAbiLlvmExt; use crate::abi::FnAbiLlvmExt;
use crate::common::AsCCharPtr; use crate::common::AsCCharPtr;
use crate::context::{CodegenCx, SimpleCx}; use crate::context::{CodegenCx, GenericCx, SCx, SimpleCx};
use crate::llvm::AttributePlace::Function; use crate::llvm::AttributePlace::Function;
use crate::llvm::Visibility; use crate::llvm::Visibility;
use crate::type_::Type; use crate::type_::Type;
@ -81,16 +83,25 @@ pub(crate) fn declare_raw_fn<'ll, 'tcx>(
llfn llfn
} }
impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
/// Declare a global value. /// Declare a global value.
/// ///
/// If theres a value with the same name already declared, the function will /// If theres a value with the same name already declared, the function will
/// return its Value instead. /// return its Value instead.
pub(crate) fn declare_global(&self, name: &str, ty: &'ll Type) -> &'ll Value { pub(crate) fn declare_global(&self, name: &str, ty: &'ll Type) -> &'ll Value {
debug!("declare_global(name={:?})", name); debug!("declare_global(name={:?})", name);
unsafe { llvm::LLVMRustGetOrInsertGlobal(self.llmod, name.as_c_char_ptr(), name.len(), ty) } unsafe {
llvm::LLVMRustGetOrInsertGlobal(
(**self).borrow().llmod,
name.as_c_char_ptr(),
name.len(),
ty,
)
}
} }
}
impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
/// Declare a C ABI function. /// Declare a C ABI function.
/// ///
/// Only use this for foreign function ABIs and glue. For Rust functions use /// Only use this for foreign function ABIs and glue. For Rust functions use

View file

@ -29,6 +29,7 @@ use std::mem::ManuallyDrop;
use back::owned_target_machine::OwnedTargetMachine; use back::owned_target_machine::OwnedTargetMachine;
use back::write::{create_informational_target_machine, create_target_machine}; use back::write::{create_informational_target_machine, create_target_machine};
use context::SimpleCx;
use errors::{AutoDiffWithoutLTO, ParseTargetMachineConfig}; use errors::{AutoDiffWithoutLTO, ParseTargetMachineConfig};
pub(crate) use llvm_util::target_features_cfg; pub(crate) use llvm_util::target_features_cfg;
use rustc_ast::expand::allocator::AllocatorKind; use rustc_ast::expand::allocator::AllocatorKind;
@ -116,9 +117,11 @@ impl ExtraBackendMethods for LlvmCodegenBackend {
kind: AllocatorKind, kind: AllocatorKind,
alloc_error_handler_kind: AllocatorKind, alloc_error_handler_kind: AllocatorKind,
) -> ModuleLlvm { ) -> ModuleLlvm {
let mut module_llvm = ModuleLlvm::new_metadata(tcx, module_name); let module_llvm = ModuleLlvm::new_metadata(tcx, module_name);
let cx =
SimpleCx::new(module_llvm.llmod(), &module_llvm.llcx, tcx.data_layout.pointer_size);
unsafe { unsafe {
allocator::codegen(tcx, &mut module_llvm, module_name, kind, alloc_error_handler_kind); allocator::codegen(tcx, cx, module_name, kind, alloc_error_handler_kind);
} }
module_llvm module_llvm
} }

View file

@ -1147,7 +1147,7 @@ unsafe extern "C" {
pub(crate) fn LLVMSetThreadLocalMode(GlobalVar: &Value, Mode: ThreadLocalMode); pub(crate) fn LLVMSetThreadLocalMode(GlobalVar: &Value, Mode: ThreadLocalMode);
pub(crate) fn LLVMIsGlobalConstant(GlobalVar: &Value) -> Bool; pub(crate) fn LLVMIsGlobalConstant(GlobalVar: &Value) -> Bool;
pub(crate) fn LLVMSetGlobalConstant(GlobalVar: &Value, IsConstant: Bool); pub(crate) fn LLVMSetGlobalConstant(GlobalVar: &Value, IsConstant: Bool);
pub(crate) fn LLVMSetTailCall(CallInst: &Value, IsTailCall: Bool); pub(crate) safe fn LLVMSetTailCall(CallInst: &Value, IsTailCall: Bool);
// Operations on attributes // Operations on attributes
pub(crate) fn LLVMCreateStringAttribute( pub(crate) fn LLVMCreateStringAttribute(