+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)
- }
-}
+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);
}
}
pub trait LlvmType {
- fn llvm_type(&self, cx: &CodegenCx<'ll, '_>) -> &'ll Type;
+ fn llvm_type<'ll>(&self, cx: &CodegenCx<'ll, '_>) -> &'ll Type;
}
impl LlvmType for Reg {
- fn llvm_type(&self, cx: &CodegenCx<'ll, '_>) -> &'ll Type {
+ fn llvm_type<'ll>(&self, cx: &CodegenCx<'ll, '_>) -> &'ll Type {
match self.kind {
RegKind::Integer => cx.type_ix(self.size.bits()),
RegKind::Float => match self.size.bits() {
}
impl LlvmType for CastTarget {
- fn llvm_type(&self, cx: &CodegenCx<'ll, '_>) -> &'ll Type {
+ fn llvm_type<'ll>(&self, cx: &CodegenCx<'ll, '_>) -> &'ll Type {
let rest_ll_unit = self.rest.unit.llvm_type(cx);
let (rest_count, rem_bytes) = if self.rest.unit.size.bytes() == 0 {
(0, 0)
let mut args: Vec<_> = self
.prefix
.iter()
- .flat_map(|option_kind| {
- option_kind.map(|kind| Reg { kind, size: self.prefix_chunk_size }.llvm_type(cx))
- })
+ .flat_map(|option_reg| option_reg.map(|reg| reg.llvm_type(cx)))
.chain((0..rest_count).map(|_| rest_ll_unit))
.collect();
);
}
-impl ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
+impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
/// Gets the LLVM type for a place of the original Rust type of
/// this argument/return, i.e., the result of `type_of::type_of`.
fn memory_ty(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type {
fn store_fn_arg(
&self,
- bx: &mut Builder<'a, 'll, 'tcx>,
+ bx: &mut Builder<'_, 'll, 'tcx>,
idx: &mut usize,
dst: PlaceRef<'tcx, &'ll Value>,
) {
}
}
-impl ArgAbiMethods<'tcx> for Builder<'a, 'll, 'tcx> {
+impl<'ll, 'tcx> ArgAbiMethods<'tcx> for Builder<'_, 'll, 'tcx> {
fn store_fn_arg(
&mut self,
arg_abi: &ArgAbi<'tcx, Ty<'tcx>>,
}
}
-pub trait FnAbiLlvmExt<'tcx> {
+pub trait FnAbiLlvmExt<'ll, 'tcx> {
fn llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type;
fn ptr_to_llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type;
fn llvm_cconv(&self) -> llvm::CallConv;
fn apply_attrs_llfn(&self, cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value);
- fn apply_attrs_callsite(&self, bx: &mut Builder<'a, 'll, 'tcx>, callsite: &'ll Value);
+ fn apply_attrs_callsite(&self, bx: &mut Builder<'_, 'll, 'tcx>, callsite: &'ll Value);
}
-impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> {
+impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
fn llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type {
// Ignore "extra" args from the call site for C variadic functions.
// Only the "fixed" args are part of the LLVM function signature.
}
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 } => {
apply(a);
apply(b);
}
- PassMode::Cast(_) => {
- apply(&ArgAttributes::new());
+ PassMode::Cast(cast) => {
+ apply(&cast.attrs);
}
}
}
}
- fn apply_attrs_callsite(&self, bx: &mut Builder<'a, 'll, 'tcx>, callsite: &'ll Value) {
+ 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(
+ llvm::AttributePlace::ReturnValue,
+ &bx.cx,
+ callsite,
+ );
}
_ => {}
}
// If the value is a boolean, the range is 0..2 and that ultimately
// become 0..0 when the type becomes i1, which would be rejected
// by the LLVM verifier.
- if let Int(..) = scalar.value {
+ if let Int(..) = scalar.primitive() {
if !scalar.is_bool() && !scalar.is_always_valid(bx) {
- bx.range_metadata(callsite, scalar.valid_range);
+ bx.range_metadata(callsite, scalar.valid_range(bx));
}
}
}
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 } => {
apply(bx.cx, a);
apply(bx.cx, b);
}
- PassMode::Cast(_) => {
- apply(bx.cx, &ArgAttributes::new());
+ PassMode::Cast(cast) => {
+ apply(bx.cx, &cast.attrs);
}
}
}
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],
+ );
}
}
}
-impl AbiBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
+impl<'tcx> AbiBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
fn apply_attrs_callsite(&mut self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, callsite: Self::Value) {
fn_abi.apply_attrs_callsite(self, callsite)
}