+use crate::attributes;
use crate::builder::Builder;
use crate::context::CodegenCx;
-use crate::llvm::{self, AttributePlace};
+use crate::llvm::{self, Attribute, AttributePlace};
use crate::type_::Type;
use crate::type_of::LayoutLlvmExt;
use crate::value::Value;
use rustc_middle::ty::layout::LayoutOf;
pub use rustc_middle::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA};
use rustc_middle::ty::Ty;
+use rustc_session::config;
use rustc_target::abi::call::ArgAbi;
pub use rustc_target::abi::call::*;
use rustc_target::abi::{self, HasDataLayout, Int};
pub use rustc_target::spec::abi::Abi;
use libc::c_uint;
-
-macro_rules! for_each_kind {
- ($flags: ident, $f: ident, $($kind: ident),+) => ({
- $(if $flags.contains(ArgAttribute::$kind) { $f(llvm::Attribute::$kind) })+
- })
-}
-
-trait ArgAttributeExt {
- fn for_each_kind<F>(&self, f: F)
- where
- F: FnMut(llvm::Attribute);
-}
-
-impl ArgAttributeExt for ArgAttribute {
- fn for_each_kind<F>(&self, mut f: F)
- where
- F: FnMut(llvm::Attribute),
- {
- for_each_kind!(self, f, NoAlias, NoCapture, NonNull, ReadOnly, InReg, NoUndef)
- }
-}
+use smallvec::SmallVec;
pub trait ArgAttributesExt {
fn apply_attrs_to_llfn(&self, idx: AttributePlace, cx: &CodegenCx<'_, '_>, llfn: &Value);
cx.tcx.sess.opts.debugging_opts.mutable_noalias.unwrap_or(true)
}
-impl ArgAttributesExt for ArgAttributes {
- fn apply_attrs_to_llfn(&self, idx: AttributePlace, cx: &CodegenCx<'_, '_>, llfn: &Value) {
- let mut regular = self.regular;
- unsafe {
- let deref = self.pointee_size.bytes();
- if deref != 0 {
- if regular.contains(ArgAttribute::NonNull) {
- llvm::LLVMRustAddDereferenceableAttr(llfn, idx.as_uint(), deref);
- } else {
- llvm::LLVMRustAddDereferenceableOrNullAttr(llfn, idx.as_uint(), deref);
- }
- regular -= ArgAttribute::NonNull;
- }
- if let Some(align) = self.pointee_align {
- llvm::LLVMRustAddAlignmentAttr(llfn, idx.as_uint(), align.bytes() as u32);
- }
- regular.for_each_kind(|attr| attr.apply_llfn(idx, llfn));
- if regular.contains(ArgAttribute::NoAliasMutRef) && should_use_mutable_noalias(cx) {
- llvm::Attribute::NoAlias.apply_llfn(idx, llfn);
+const ABI_AFFECTING_ATTRIBUTES: [(ArgAttribute, llvm::AttributeKind); 1] =
+ [(ArgAttribute::InReg, llvm::AttributeKind::InReg)];
+
+const OPTIMIZATION_ATTRIBUTES: [(ArgAttribute, llvm::AttributeKind); 5] = [
+ (ArgAttribute::NoAlias, llvm::AttributeKind::NoAlias),
+ (ArgAttribute::NoCapture, llvm::AttributeKind::NoCapture),
+ (ArgAttribute::NonNull, llvm::AttributeKind::NonNull),
+ (ArgAttribute::ReadOnly, llvm::AttributeKind::ReadOnly),
+ (ArgAttribute::NoUndef, llvm::AttributeKind::NoUndef),
+];
+
+fn get_attrs<'ll>(this: &ArgAttributes, cx: &CodegenCx<'ll, '_>) -> SmallVec<[&'ll Attribute; 8]> {
+ let mut regular = this.regular;
+
+ let mut attrs = SmallVec::new();
+
+ // ABI-affecting attributes must always be applied
+ for (attr, llattr) in ABI_AFFECTING_ATTRIBUTES {
+ if regular.contains(attr) {
+ attrs.push(llattr.create_attr(cx.llcx));
+ }
+ }
+ if let Some(align) = this.pointee_align {
+ attrs.push(llvm::CreateAlignmentAttr(cx.llcx, align.bytes()));
+ }
+ match this.arg_ext {
+ ArgExtension::None => {}
+ ArgExtension::Zext => attrs.push(llvm::AttributeKind::ZExt.create_attr(cx.llcx)),
+ ArgExtension::Sext => attrs.push(llvm::AttributeKind::SExt.create_attr(cx.llcx)),
+ }
+
+ // Only apply remaining attributes when optimizing
+ if cx.sess().opts.optimize != config::OptLevel::No {
+ let deref = this.pointee_size.bytes();
+ if deref != 0 {
+ if regular.contains(ArgAttribute::NonNull) {
+ attrs.push(llvm::CreateDereferenceableAttr(cx.llcx, deref));
+ } else {
+ attrs.push(llvm::CreateDereferenceableOrNullAttr(cx.llcx, deref));
}
- match self.arg_ext {
- ArgExtension::None => {}
- ArgExtension::Zext => {
- llvm::Attribute::ZExt.apply_llfn(idx, llfn);
- }
- ArgExtension::Sext => {
- llvm::Attribute::SExt.apply_llfn(idx, llfn);
- }
+ regular -= ArgAttribute::NonNull;
+ }
+ for (attr, llattr) in OPTIMIZATION_ATTRIBUTES {
+ if regular.contains(attr) {
+ attrs.push(llattr.create_attr(cx.llcx));
}
}
+ if regular.contains(ArgAttribute::NoAliasMutRef) && should_use_mutable_noalias(cx) {
+ attrs.push(llvm::AttributeKind::NoAlias.create_attr(cx.llcx));
+ }
+ }
+
+ attrs
+}
+
+impl ArgAttributesExt for ArgAttributes {
+ fn apply_attrs_to_llfn(&self, idx: AttributePlace, cx: &CodegenCx<'_, '_>, llfn: &Value) {
+ let attrs = get_attrs(self, cx);
+ attributes::apply_to_llfn(llfn, idx, &attrs);
}
fn apply_attrs_to_callsite(
cx: &CodegenCx<'_, '_>,
callsite: &Value,
) {
- let mut regular = self.regular;
- unsafe {
- let deref = self.pointee_size.bytes();
- if deref != 0 {
- if regular.contains(ArgAttribute::NonNull) {
- llvm::LLVMRustAddDereferenceableCallSiteAttr(callsite, idx.as_uint(), deref);
- } else {
- llvm::LLVMRustAddDereferenceableOrNullCallSiteAttr(
- callsite,
- idx.as_uint(),
- deref,
- );
- }
- regular -= ArgAttribute::NonNull;
- }
- if let Some(align) = self.pointee_align {
- llvm::LLVMRustAddAlignmentCallSiteAttr(
- callsite,
- idx.as_uint(),
- align.bytes() as u32,
- );
- }
- regular.for_each_kind(|attr| attr.apply_callsite(idx, callsite));
- if regular.contains(ArgAttribute::NoAliasMutRef) && should_use_mutable_noalias(cx) {
- llvm::Attribute::NoAlias.apply_callsite(idx, callsite);
- }
- match self.arg_ext {
- ArgExtension::None => {}
- ArgExtension::Zext => {
- llvm::Attribute::ZExt.apply_callsite(idx, callsite);
- }
- ArgExtension::Sext => {
- llvm::Attribute::SExt.apply_callsite(idx, callsite);
- }
- }
- }
+ let attrs = get_attrs(self, cx);
+ attributes::apply_to_callsite(callsite, idx, &attrs);
}
}
}
fn apply_attrs_llfn(&self, cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value) {
- // FIXME(eddyb) can this also be applied to callsites?
+ let mut func_attrs = SmallVec::<[_; 2]>::new();
if self.ret.layout.abi.is_uninhabited() {
- llvm::Attribute::NoReturn.apply_llfn(llvm::AttributePlace::Function, llfn);
+ func_attrs.push(llvm::AttributeKind::NoReturn.create_attr(cx.llcx));
}
-
- // FIXME(eddyb, wesleywiser): apply this to callsites as well?
if !self.can_unwind {
- llvm::Attribute::NoUnwind.apply_llfn(llvm::AttributePlace::Function, llfn);
+ func_attrs.push(llvm::AttributeKind::NoUnwind.create_attr(cx.llcx));
}
+ attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &{ func_attrs });
let mut i = 0;
let mut apply = |attrs: &ArgAttributes| {
PassMode::Indirect { ref attrs, extra_attrs: _, on_stack } => {
assert!(!on_stack);
let i = apply(attrs);
- unsafe {
- llvm::LLVMRustAddStructRetAttr(
- llfn,
- llvm::AttributePlace::Argument(i).as_uint(),
- self.ret.layout.llvm_type(cx),
- );
- }
+ let sret = llvm::CreateStructRetAttr(cx.llcx, self.ret.layout.llvm_type(cx));
+ attributes::apply_to_llfn(llfn, llvm::AttributePlace::Argument(i), &[sret]);
}
PassMode::Cast(cast) => {
cast.attrs.apply_attrs_to_llfn(llvm::AttributePlace::ReturnValue, cx, llfn);
PassMode::Ignore => {}
PassMode::Indirect { ref attrs, extra_attrs: None, on_stack: true } => {
let i = apply(attrs);
- unsafe {
- llvm::LLVMRustAddByValAttr(
- llfn,
- llvm::AttributePlace::Argument(i).as_uint(),
- arg.layout.llvm_type(cx),
- );
- }
+ let byval = llvm::CreateByValAttr(cx.llcx, arg.layout.llvm_type(cx));
+ attributes::apply_to_llfn(llfn, llvm::AttributePlace::Argument(i), &[byval]);
}
PassMode::Direct(ref attrs)
| PassMode::Indirect { ref attrs, extra_attrs: None, on_stack: false } => {
}
fn apply_attrs_callsite(&self, bx: &mut Builder<'_, 'll, 'tcx>, callsite: &'ll Value) {
+ let mut func_attrs = SmallVec::<[_; 2]>::new();
if self.ret.layout.abi.is_uninhabited() {
- llvm::Attribute::NoReturn.apply_callsite(llvm::AttributePlace::Function, callsite);
+ func_attrs.push(llvm::AttributeKind::NoReturn.create_attr(bx.cx.llcx));
}
if !self.can_unwind {
- llvm::Attribute::NoUnwind.apply_callsite(llvm::AttributePlace::Function, callsite);
+ func_attrs.push(llvm::AttributeKind::NoUnwind.create_attr(bx.cx.llcx));
}
+ attributes::apply_to_callsite(callsite, llvm::AttributePlace::Function, &{ func_attrs });
let mut i = 0;
let mut apply = |cx: &CodegenCx<'_, '_>, attrs: &ArgAttributes| {
PassMode::Indirect { ref attrs, extra_attrs: _, on_stack } => {
assert!(!on_stack);
let i = apply(bx.cx, attrs);
- unsafe {
- llvm::LLVMRustAddStructRetCallSiteAttr(
- callsite,
- llvm::AttributePlace::Argument(i).as_uint(),
- self.ret.layout.llvm_type(bx),
- );
- }
+ let sret = llvm::CreateStructRetAttr(bx.cx.llcx, self.ret.layout.llvm_type(bx));
+ attributes::apply_to_callsite(callsite, llvm::AttributePlace::Argument(i), &[sret]);
}
PassMode::Cast(cast) => {
cast.attrs.apply_attrs_to_callsite(
PassMode::Ignore => {}
PassMode::Indirect { ref attrs, extra_attrs: None, on_stack: true } => {
let i = apply(bx.cx, attrs);
- unsafe {
- llvm::LLVMRustAddByValCallSiteAttr(
- callsite,
- llvm::AttributePlace::Argument(i).as_uint(),
- arg.layout.llvm_type(bx),
- );
- }
+ let byval = llvm::CreateByValAttr(bx.cx.llcx, arg.layout.llvm_type(bx));
+ attributes::apply_to_callsite(
+ callsite,
+ llvm::AttributePlace::Argument(i),
+ &[byval],
+ );
}
PassMode::Direct(ref attrs)
| PassMode::Indirect { ref attrs, extra_attrs: None, on_stack: false } => {
if self.conv == Conv::CCmseNonSecureCall {
// This will probably get ignored on all targets but those supporting the TrustZone-M
// extension (thumbv8m targets).
- unsafe {
- llvm::AddCallSiteAttrString(
- callsite,
- llvm::AttributePlace::Function,
- cstr::cstr!("cmse_nonsecure_call"),
- );
- }
+ let cmse_nonsecure_call = llvm::CreateAttrString(bx.cx.llcx, "cmse_nonsecure_call");
+ attributes::apply_to_callsite(
+ callsite,
+ llvm::AttributePlace::Function,
+ &[cmse_nonsecure_call],
+ );
}
}
}