diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 10865df3a4d..b8377916efe 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -185,7 +185,7 @@ bitflags! { } } -#[derive(Copy, Clone, Default)] +#[derive(Copy, Clone, Default, Debug)] pub struct Attributes { regular: Attribute, dereferenceable_bytes: u64 diff --git a/src/librustc_trans/trans/abi.rs b/src/librustc_trans/trans/abi.rs index 7a639d5c89e..ccd276457ce 100644 --- a/src/librustc_trans/trans/abi.rs +++ b/src/librustc_trans/trans/abi.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub use self::ArgKind::*; - use llvm; use trans::common::{return_type_is_void, type_is_fat_ptr}; use trans::context::CrateContext; @@ -43,7 +41,7 @@ pub const FAT_PTR_ADDR: usize = 0; pub const FAT_PTR_EXTRA: usize = 1; #[derive(Clone, Copy, PartialEq, Debug)] -pub enum ArgKind { +enum ArgKind { /// Pass the argument directly using the normal converted /// LLVM type or by coercing to another specified type Direct, @@ -59,7 +57,7 @@ pub enum ArgKind { /// This is borrowed from clang's ABIInfo.h #[derive(Clone, Copy, Debug)] pub struct ArgType { - pub kind: ArgKind, + kind: ArgKind, /// Original LLVM type pub original_ty: Type, /// Sizing LLVM type (pointers are opaque). @@ -81,28 +79,48 @@ pub struct ArgType { pub cast: Option, /// Dummy argument, which is emitted before the real argument pub pad: Option, - /// LLVM attribute of argument - pub attr: Option + /// LLVM attributes of argument + pub attrs: llvm::Attributes } impl ArgType { fn new(original_ty: Type, ty: Type) -> ArgType { ArgType { - kind: Direct, + kind: ArgKind::Direct, original_ty: original_ty, ty: ty, cast: None, pad: None, - attr: None + attrs: llvm::Attributes::default() } } + pub fn make_indirect(&mut self, ccx: &CrateContext) { + // Wipe old attributes, likely not valid through indirection. + self.attrs = llvm::Attributes::default(); + + let llarg_sz = llsize_of_real(ccx, self.ty); + + // For non-immediate arguments the callee gets its own copy of + // the value on the stack, so there are no aliases. It's also + // program-invisible so can't possibly capture + self.attrs.set(llvm::Attribute::NoAlias) + .set(llvm::Attribute::NoCapture) + .set_dereferenceable(llarg_sz); + + self.kind = ArgKind::Indirect; + } + + pub fn ignore(&mut self) { + self.kind = ArgKind::Ignore; + } + pub fn is_indirect(&self) -> bool { - self.kind == Indirect + self.kind == ArgKind::Indirect } pub fn is_ignore(&self) -> bool { - self.kind == Ignore + self.kind == ArgKind::Ignore } } @@ -178,7 +196,7 @@ impl FnType { if ty.is_bool() { let llty = Type::i1(ccx); let mut arg = ArgType::new(llty, llty); - arg.attr = Some(llvm::Attribute::ZExt); + arg.attrs.set(llvm::Attribute::ZExt); arg } else { ArgType::new(type_of::type_of(ccx, ty), @@ -221,7 +239,7 @@ impl FnType { } let size = llsize_of_alloc(ccx, arg.ty); if size > llsize_of_alloc(ccx, ccx.int_type()) { - arg.kind = Indirect; + arg.make_indirect(ccx); } else if size > 0 { // We want to pass small aggregates as immediates, but using // a LLVM aggregate type for this leads to bad optimizations, @@ -238,6 +256,9 @@ impl FnType { for arg in &mut fty.args { fixup(arg); } + if fty.ret.is_indirect() { + fty.ret.attrs.set(llvm::Attribute::StructRet); + } return fty; } @@ -264,6 +285,10 @@ impl FnType { a => ccx.sess().fatal(&format!("unrecognized arch \"{}\" in target specification", a)) } + if fty.ret.is_indirect() { + fty.ret.attrs.set(llvm::Attribute::StructRet); + } + fty } @@ -302,43 +327,18 @@ impl FnType { } } - pub fn llvm_attrs(&self, ccx: &CrateContext) -> llvm::AttrBuilder { + pub fn llvm_attrs(&self) -> llvm::AttrBuilder { let mut attrs = llvm::AttrBuilder::new(); let mut i = if self.ret.is_indirect() { 1 } else { 0 }; - - // Add attributes that are always applicable, independent of the concrete foreign ABI - if self.ret.is_indirect() { - let llret_sz = llsize_of_real(ccx, self.ret.ty); - - // The outptr can be noalias and nocapture because it's entirely - // invisible to the program. We also know it's nonnull as well - // as how many bytes we can dereference - attrs.arg(i).set(llvm::Attribute::StructRet) - .set(llvm::Attribute::NoAlias) - .set(llvm::Attribute::NoCapture) - .set_dereferenceable(llret_sz); - }; - - // Add attributes that depend on the concrete foreign ABI - if let Some(attr) = self.ret.attr { - attrs.arg(i).set(attr); - } - + *attrs.arg(i) = self.ret.attrs; i += 1; for arg in &self.args { - if arg.is_ignore() { - continue; + if !arg.is_ignore() { + if arg.pad.is_some() { i += 1; } + *attrs.arg(i) = arg.attrs; + i += 1; } - // skip padding - if arg.pad.is_some() { i += 1; } - - if let Some(attr) = arg.attr { - attrs.arg(i).set(attr); - } - - i += 1; } - attrs } } diff --git a/src/librustc_trans/trans/cabi_aarch64.rs b/src/librustc_trans/trans/cabi_aarch64.rs index 65d2ad9c4fa..4398e14fdcc 100644 --- a/src/librustc_trans/trans/cabi_aarch64.rs +++ b/src/librustc_trans/trans/cabi_aarch64.rs @@ -11,7 +11,7 @@ #![allow(non_upper_case_globals)] use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector}; -use trans::abi::{FnType, ArgType, Indirect}; +use trans::abi::{FnType, ArgType}; use trans::context::CrateContext; use trans::type_::Type; @@ -185,7 +185,7 @@ fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) { ret.cast = Some(llty); return; } - ret.kind = Indirect; + ret.make_indirect(ccx); } fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) { @@ -214,7 +214,7 @@ fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) { arg.cast = Some(llty); return; } - arg.kind = Indirect; + arg.make_indirect(ccx); } fn is_reg_ty(ty: Type) -> bool { diff --git a/src/librustc_trans/trans/cabi_arm.rs b/src/librustc_trans/trans/cabi_arm.rs index 77941a853e6..2146a9c5e21 100644 --- a/src/librustc_trans/trans/cabi_arm.rs +++ b/src/librustc_trans/trans/cabi_arm.rs @@ -11,7 +11,7 @@ #![allow(non_upper_case_globals)] use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector}; -use trans::abi::{FnType, ArgType, Indirect}; +use trans::abi::{FnType, ArgType}; use trans::context::CrateContext; use trans::type_::Type; @@ -145,7 +145,7 @@ fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType, align_fn: TyAlignFn) { ret.cast = Some(llty); return; } - ret.kind = Indirect; + ret.make_indirect(ccx); } fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, align_fn: TyAlignFn) { diff --git a/src/librustc_trans/trans/cabi_asmjs.rs b/src/librustc_trans/trans/cabi_asmjs.rs index 5c9bf28e4e0..4ec547c3640 100644 --- a/src/librustc_trans/trans/cabi_asmjs.rs +++ b/src/librustc_trans/trans/cabi_asmjs.rs @@ -11,7 +11,7 @@ #![allow(non_upper_case_globals)] use llvm::{Struct, Array, Attribute}; -use trans::abi::{FnType, ArgType, Indirect}; +use trans::abi::{FnType, ArgType}; use trans::context::CrateContext; use trans::type_::Type; @@ -20,36 +20,36 @@ use trans::type_::Type; // See the https://github.com/kripken/emscripten-fastcomp-clang repository. // The class `EmscriptenABIInfo` in `/lib/CodeGen/TargetInfo.cpp` contains the ABI definitions. -fn classify_ret_ty(ret: &mut ArgType) { +fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) { match ret.ty.kind() { Struct => { let field_types = ret.ty.field_types(); if field_types.len() == 1 { ret.cast = Some(field_types[0]); } else { - ret.kind = Indirect; + ret.make_indirect(ccx); } } Array => { - ret.kind = Indirect; + ret.make_indirect(ccx); } _ => {} } } -fn classify_arg_ty(arg: &mut ArgType) { +fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) { if arg.ty.is_aggregate() { - arg.kind = Indirect; - arg.attr = Some(Attribute::ByVal); + arg.make_indirect(ccx); + arg.attrs.set(Attribute::ByVal); } } pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { if fty.ret.ty != Type::void(ccx) { - classify_ret_ty(&mut fty.ret); + classify_ret_ty(ccx, &mut fty.ret); } for arg in &mut fty.args { - classify_arg_ty(arg); + classify_arg_ty(ccx, arg); } } diff --git a/src/librustc_trans/trans/cabi_mips.rs b/src/librustc_trans/trans/cabi_mips.rs index 419c56072b4..b4fe00f8d69 100644 --- a/src/librustc_trans/trans/cabi_mips.rs +++ b/src/librustc_trans/trans/cabi_mips.rs @@ -14,7 +14,7 @@ use libc::c_uint; use std::cmp; use llvm; use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector}; -use trans::abi::{ArgType, FnType, Indirect}; +use trans::abi::{ArgType, FnType}; use trans::context::CrateContext; use trans::type_::Type; @@ -148,7 +148,7 @@ fn struct_ty(ccx: &CrateContext, ty: Type) -> Type { pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { if fty.ret.ty != Type::void(ccx) { if !is_reg_ty(fty.ret.ty) { - fty.ret.kind = Indirect; + fty.ret.make_indirect(ccx); } } diff --git a/src/librustc_trans/trans/cabi_powerpc.rs b/src/librustc_trans/trans/cabi_powerpc.rs index ecd5b71ada9..8d9c6e8e1f8 100644 --- a/src/librustc_trans/trans/cabi_powerpc.rs +++ b/src/librustc_trans/trans/cabi_powerpc.rs @@ -11,7 +11,7 @@ use libc::c_uint; use llvm; use llvm::{Integer, Pointer, Float, Double, Struct, Array}; -use trans::abi::{FnType, ArgType, Indirect}; +use trans::abi::{FnType, ArgType}; use trans::context::CrateContext; use trans::type_::Type; @@ -143,7 +143,7 @@ fn struct_ty(ccx: &CrateContext, ty: Type) -> Type { pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { if fty.ret.ty != Type::void(ccx) { if !is_reg_ty(fty.ret.ty) { - fty.ret.kind = Indirect; + fty.ret.make_indirect(ccx); } } diff --git a/src/librustc_trans/trans/cabi_powerpc64.rs b/src/librustc_trans/trans/cabi_powerpc64.rs index b28ec618650..77858398f37 100644 --- a/src/librustc_trans/trans/cabi_powerpc64.rs +++ b/src/librustc_trans/trans/cabi_powerpc64.rs @@ -16,7 +16,7 @@ // need to be fixed when PowerPC vector support is added. use llvm::{Integer, Pointer, Float, Double, Struct, Array}; -use trans::abi::{FnType, ArgType, Indirect}; +use trans::abi::{FnType, ArgType}; use trans::context::CrateContext; use trans::type_::Type; @@ -158,7 +158,7 @@ fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) { // The PowerPC64 big endian ABI doesn't return aggregates in registers if ccx.sess().target.target.target_endian == "big" { - ret.kind = Indirect; + ret.make_indirect(ccx); } if let Some((base_ty, members)) = is_homogenous_aggregate_ty(ret.ty) { @@ -182,7 +182,7 @@ fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) { return; } - ret.kind = Indirect; + ret.make_indirect(ccx); } fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) { diff --git a/src/librustc_trans/trans/cabi_x86.rs b/src/librustc_trans/trans/cabi_x86.rs index fd1b8b21401..af194e8e5d7 100644 --- a/src/librustc_trans/trans/cabi_x86.rs +++ b/src/librustc_trans/trans/cabi_x86.rs @@ -9,7 +9,7 @@ // except according to those terms. use llvm::*; -use trans::abi::{FnType, Indirect, Ignore}; +use trans::abi::FnType; use trans::type_::Type; use super::common::*; use super::machine::*; @@ -30,20 +30,20 @@ pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { 2 => fty.ret.cast = Some(Type::i16(ccx)), 4 => fty.ret.cast = Some(Type::i32(ccx)), 8 => fty.ret.cast = Some(Type::i64(ccx)), - _ => fty.ret.kind = Indirect + _ => fty.ret.make_indirect(ccx) } } else { - fty.ret.kind = Indirect; + fty.ret.make_indirect(ccx); } } for arg in &mut fty.args { if arg.ty.kind() == Struct { if llsize_of_alloc(ccx, arg.ty) == 0 { - arg.kind = Ignore; + arg.ignore(); } else { - arg.kind = Indirect; - arg.attr = Some(Attribute::ByVal); + arg.make_indirect(ccx); + arg.attrs.set(Attribute::ByVal); } } } diff --git a/src/librustc_trans/trans/cabi_x86_64.rs b/src/librustc_trans/trans/cabi_x86_64.rs index ab32ca206fc..c6f1dc9e671 100644 --- a/src/librustc_trans/trans/cabi_x86_64.rs +++ b/src/librustc_trans/trans/cabi_x86_64.rs @@ -16,7 +16,7 @@ use self::RegClass::*; use llvm::{Integer, Pointer, Float, Double}; use llvm::{Struct, Array, Attribute, Vector}; -use trans::abi::{ArgType, FnType, Indirect}; +use trans::abi::{ArgType, FnType}; use trans::context::CrateContext; use trans::type_::Type; @@ -393,8 +393,10 @@ pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { if !arg.ty.is_reg_ty() { let cls = classify_ty(arg.ty); if is_mem_cls(&cls) { - arg.kind = Indirect; - arg.attr = ind_attr; + arg.make_indirect(ccx); + if let Some(attr) = ind_attr { + arg.attrs.set(attr); + } } else { arg.cast = Some(llreg_ty(ccx, &cls)); } diff --git a/src/librustc_trans/trans/cabi_x86_win64.rs b/src/librustc_trans/trans/cabi_x86_win64.rs index e9a06fd8d6b..448789530a5 100644 --- a/src/librustc_trans/trans/cabi_x86_win64.rs +++ b/src/librustc_trans/trans/cabi_x86_win64.rs @@ -11,7 +11,7 @@ use llvm::*; use super::common::*; use super::machine::*; -use trans::abi::{ArgType, FnType, Indirect}; +use trans::abi::{ArgType, FnType}; use trans::type_::Type; // Win64 ABI: http://msdn.microsoft.com/en-us/library/zthk2dkh.aspx @@ -24,7 +24,7 @@ pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { 2 => a.cast = Some(Type::i16(ccx)), 4 => a.cast = Some(Type::i32(ccx)), 8 => a.cast = Some(Type::i64(ccx)), - _ => a.kind = Indirect + _ => a.make_indirect(ccx) } } }; diff --git a/src/librustc_trans/trans/declare.rs b/src/librustc_trans/trans/declare.rs index f7bc22a4482..6d21a90bb0d 100644 --- a/src/librustc_trans/trans/declare.rs +++ b/src/librustc_trans/trans/declare.rs @@ -113,7 +113,7 @@ pub fn declare_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str, attributes::from_fn_type(ccx, fn_type) } else { attributes::unwind(llfn, false); - fty.llvm_attrs(ccx) + fty.llvm_attrs() }; attrs.apply_llfn(llfn); diff --git a/src/librustc_trans/trans/foreign.rs b/src/librustc_trans/trans/foreign.rs index ed96871002a..ac316d18940 100644 --- a/src/librustc_trans/trans/foreign.rs +++ b/src/librustc_trans/trans/foreign.rs @@ -253,7 +253,7 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, llfn, &llargs_foreign[..], fn_type.cconv, - Some(fn_type.llvm_attrs(ccx)), + Some(fn_type.llvm_attrs()), call_debug_loc); // If the function we just called does not use an outpointer,