1
Fork 0

Add support for NonNull function attribute

This commit is contained in:
Guillaume Gomez 2023-09-04 20:29:50 +02:00
parent 4dce75f2e7
commit 096f14d374
4 changed files with 43 additions and 22 deletions

View file

@ -1,4 +1,4 @@
use gccjit::{ToLValue, ToRValue, Type}; use gccjit::{FnAttribute, ToLValue, ToRValue, Type};
use rustc_codegen_ssa::traits::{AbiBuilderMethods, BaseTypeMethods}; use rustc_codegen_ssa::traits::{AbiBuilderMethods, BaseTypeMethods};
use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::fx::FxHashSet;
use rustc_middle::bug; use rustc_middle::bug;
@ -98,12 +98,12 @@ impl GccType for Reg {
pub trait FnAbiGccExt<'gcc, 'tcx> { pub trait FnAbiGccExt<'gcc, 'tcx> {
// TODO(antoyo): return a function pointer type instead? // TODO(antoyo): return a function pointer type instead?
fn gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> (Type<'gcc>, Vec<Type<'gcc>>, bool, FxHashSet<usize>); fn gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> (Type<'gcc>, Vec<Type<'gcc>>, bool, FxHashSet<usize>, Vec<FnAttribute<'gcc>>);
fn ptr_to_gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>; fn ptr_to_gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>;
} }
impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
fn gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> (Type<'gcc>, Vec<Type<'gcc>>, bool, FxHashSet<usize>) { fn gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> (Type<'gcc>, Vec<Type<'gcc>>, bool, FxHashSet<usize>, Vec<FnAttribute<'gcc>>) {
let mut on_stack_param_indices = FxHashSet::default(); let mut on_stack_param_indices = FxHashSet::default();
// This capacity calculation is approximate. // This capacity calculation is approximate.
@ -121,19 +121,23 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
cx.type_void() cx.type_void()
} }
}; };
let mut non_null_args = Vec::new();
#[cfg(feature = "master")] #[cfg(feature = "master")]
let apply_attrs = |ty: Type<'gcc>, attrs: &ArgAttributes| { let mut apply_attrs = |mut ty: Type<'gcc>, attrs: &ArgAttributes, arg_index: usize| {
if cx.sess().opts.optimize != config::OptLevel::No if cx.sess().opts.optimize == config::OptLevel::No {
&& attrs.regular.contains(rustc_target::abi::call::ArgAttribute::NoAlias) return ty;
{
ty.make_restrict()
} else {
ty
} }
if attrs.regular.contains(rustc_target::abi::call::ArgAttribute::NoAlias) {
ty = ty.make_restrict()
}
if attrs.regular.contains(rustc_target::abi::call::ArgAttribute::NonNull) {
non_null_args.push(arg_index as i32 + 1);
}
ty
}; };
#[cfg(not(feature = "master"))] #[cfg(not(feature = "master"))]
let apply_attrs = |ty: Type<'gcc>, _attrs: &ArgAttributes| { let apply_attrs = |ty: Type<'gcc>, _attrs: &ArgAttributes, _arg_index: usize| {
ty ty
}; };
@ -141,8 +145,9 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
let arg_ty = match arg.mode { let arg_ty = match arg.mode {
PassMode::Ignore => continue, PassMode::Ignore => continue,
PassMode::Pair(a, b) => { PassMode::Pair(a, b) => {
argument_tys.push(apply_attrs(arg.layout.scalar_pair_element_gcc_type(cx, 0), &a)); let arg_pos = argument_tys.len();
argument_tys.push(apply_attrs(arg.layout.scalar_pair_element_gcc_type(cx, 1), &b)); argument_tys.push(apply_attrs(arg.layout.scalar_pair_element_gcc_type(cx, 0), &a, arg_pos));
argument_tys.push(apply_attrs(arg.layout.scalar_pair_element_gcc_type(cx, 1), &b, arg_pos + 1));
continue; continue;
} }
PassMode::Cast { ref cast, pad_i32 } => { PassMode::Cast { ref cast, pad_i32 } => {
@ -151,30 +156,41 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
argument_tys.push(Reg::i32().gcc_type(cx)); argument_tys.push(Reg::i32().gcc_type(cx));
} }
let ty = cast.gcc_type(cx); let ty = cast.gcc_type(cx);
apply_attrs(ty, &cast.attrs) apply_attrs(ty, &cast.attrs, argument_tys.len())
} }
PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: true } => { PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: true } => {
// This is a "byval" argument, so we don't apply the `restrict` attribute on it. // This is a "byval" argument, so we don't apply the `restrict` attribute on it.
on_stack_param_indices.insert(argument_tys.len()); on_stack_param_indices.insert(argument_tys.len());
arg.memory_ty(cx) arg.memory_ty(cx)
}, },
PassMode::Direct(attrs) => apply_attrs(arg.layout.immediate_gcc_type(cx), &attrs), PassMode::Direct(attrs) => apply_attrs(arg.layout.immediate_gcc_type(cx), &attrs, argument_tys.len()),
PassMode::Indirect { attrs, meta_attrs: None, on_stack: false } => { PassMode::Indirect { attrs, meta_attrs: None, on_stack: false } => {
apply_attrs(cx.type_ptr_to(arg.memory_ty(cx)), &attrs) apply_attrs(cx.type_ptr_to(arg.memory_ty(cx)), &attrs, argument_tys.len())
} }
PassMode::Indirect { attrs, meta_attrs: Some(meta_attrs), on_stack } => { PassMode::Indirect { attrs, meta_attrs: Some(meta_attrs), on_stack } => {
assert!(!on_stack); assert!(!on_stack);
apply_attrs(apply_attrs(cx.type_ptr_to(arg.memory_ty(cx)), &attrs), &meta_attrs) let ty = apply_attrs(cx.type_ptr_to(arg.memory_ty(cx)), &attrs, argument_tys.len());
apply_attrs(ty, &meta_attrs, argument_tys.len())
} }
}; };
argument_tys.push(arg_ty); argument_tys.push(arg_ty);
} }
(return_ty, argument_tys, self.c_variadic, on_stack_param_indices) #[cfg(feature = "master")]
let fn_attrs = if non_null_args.is_empty() {
Vec::new()
} else {
vec![FnAttribute::NonNull(non_null_args)]
};
#[cfg(not(feature = "master"))]
let fn_attrs = Vec::new();
(return_ty, argument_tys, self.c_variadic, on_stack_param_indices, fn_attrs)
} }
fn ptr_to_gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> { fn ptr_to_gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> {
let (return_type, params, variadic, on_stack_param_indices) = self.gcc_type(cx); // FIXME: Should we do something with `fn_attrs`?
let (return_type, params, variadic, on_stack_param_indices, _fn_attrs) = self.gcc_type(cx);
let pointer_type = cx.context.new_function_pointer_type(None, return_type, &params, variadic); let pointer_type = cx.context.new_function_pointer_type(None, return_type, &params, variadic);
cx.on_stack_params.borrow_mut().insert(pointer_type.dyncast_function_ptr_type().expect("function ptr type"), on_stack_param_indices); cx.on_stack_params.borrow_mut().insert(pointer_type.dyncast_function_ptr_type().expect("function ptr type"), on_stack_param_indices);
pointer_type pointer_type

View file

@ -80,9 +80,13 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
} }
pub fn declare_fn(&self, name: &str, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Function<'gcc> { pub fn declare_fn(&self, name: &str, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Function<'gcc> {
let (return_type, params, variadic, on_stack_param_indices) = fn_abi.gcc_type(self); let (return_type, params, variadic, on_stack_param_indices, fn_attrs) = fn_abi.gcc_type(self);
let func = declare_raw_fn(self, name, () /*fn_abi.llvm_cconv()*/, return_type, &params, variadic); let func = declare_raw_fn(self, name, () /*fn_abi.llvm_cconv()*/, return_type, &params, variadic);
self.on_stack_function_params.borrow_mut().insert(func, on_stack_param_indices); self.on_stack_function_params.borrow_mut().insert(func, on_stack_param_indices);
// We need to handle `nonnull` here where we still have access to function args.
for fn_attr in fn_attrs {
func.add_attribute(fn_attr);
}
func func
} }

View file

@ -1197,7 +1197,7 @@ fn get_rust_try_fn<'a, 'gcc, 'tcx>(cx: &'a CodegenCx<'gcc, 'tcx>, codegen: &mut
#[cfg(feature="master")] #[cfg(feature="master")]
fn gen_fn<'a, 'gcc, 'tcx>(cx: &'a CodegenCx<'gcc, 'tcx>, name: &str, rust_fn_sig: ty::PolyFnSig<'tcx>, codegen: &mut dyn FnMut(Builder<'a, 'gcc, 'tcx>)) -> (Type<'gcc>, Function<'gcc>) { fn gen_fn<'a, 'gcc, 'tcx>(cx: &'a CodegenCx<'gcc, 'tcx>, name: &str, rust_fn_sig: ty::PolyFnSig<'tcx>, codegen: &mut dyn FnMut(Builder<'a, 'gcc, 'tcx>)) -> (Type<'gcc>, Function<'gcc>) {
let fn_abi = cx.fn_abi_of_fn_ptr(rust_fn_sig, ty::List::empty()); let fn_abi = cx.fn_abi_of_fn_ptr(rust_fn_sig, ty::List::empty());
let (typ, _, _, _) = fn_abi.gcc_type(cx); let (typ, _, _, _, _) = fn_abi.gcc_type(cx);
// FIXME(eddyb) find a nicer way to do this. // FIXME(eddyb) find a nicer way to do this.
cx.linkage.set(FunctionType::Internal); cx.linkage.set(FunctionType::Internal);
let func = cx.declare_fn(name, fn_abi); let func = cx.declare_fn(name, fn_abi);

View file

@ -372,7 +372,8 @@ impl<'gcc, 'tcx> LayoutTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
} }
fn fn_decl_backend_type(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Type<'gcc> { fn fn_decl_backend_type(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Type<'gcc> {
let (return_type, param_types, variadic, _) = fn_abi.gcc_type(self); // // FIXME: Should we do something with `fn_attrs`?
let (return_type, param_types, variadic, _, _fn_attrs) = fn_abi.gcc_type(self);
self.context.new_function_pointer_type(None, return_type, &param_types, variadic) self.context.new_function_pointer_type(None, return_type, &param_types, variadic)
} }
} }