pub use self::ArgKind::*;
-use llvm::{self, AttrHelper, ValueRef};
-use trans::attributes;
+use llvm;
use trans::common::{return_type_is_void, type_is_fat_ptr};
use trans::context::CrateContext;
use trans::cabi_x86;
use trans::cabi_powerpc64;
use trans::cabi_mips;
use trans::cabi_asmjs;
-use trans::machine::llsize_of_alloc;
+use trans::machine::{llsize_of_alloc, llsize_of_real};
use trans::type_::Type;
use trans::type_of;
cconv: cconv
};
+ // Add ZExt attributes to i1 arguments and returns.
+ for arg in Some(&mut fty.ret).into_iter().chain(&mut fty.args) {
+ if arg.ty == Type::i1(ccx) {
+ arg.attr = Some(llvm::Attribute::ZExt);
+ }
+ }
+
if abi == Rust || abi == RustCall {
let fixup = |arg: &mut ArgType| {
if !arg.ty.is_aggregate() {
fty
}
- pub fn to_llvm(&self, ccx: &CrateContext) -> Type {
+ pub fn llvm_type(&self, ccx: &CrateContext) -> Type {
let mut llargument_tys = Vec::new();
let llreturn_ty = if self.ret.is_indirect() {
}
}
- pub fn add_attributes(&self, llfn: ValueRef) {
- let mut i = if self.ret.is_indirect() {
- 1
- } else {
- 0
+ pub fn llvm_attrs(&self, ccx: &CrateContext) -> 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, llvm::Attribute::StructRet)
+ .arg(i, llvm::Attribute::NoAlias)
+ .arg(i, llvm::Attribute::NoCapture)
+ .arg(i, llvm::DereferenceableAttribute(llret_sz));
};
+ // Add attributes that depend on the concrete foreign ABI
if let Some(attr) = self.ret.attr {
- attr.apply_llfn(i, llfn);
+ attrs.arg(i, attr);
}
i += 1;
-
for arg in &self.args {
if arg.is_ignore() {
continue;
if arg.pad.is_some() { i += 1; }
if let Some(attr) = arg.attr {
- attr.apply_llfn(i, llfn);
+ attrs.arg(i, attr);
}
i += 1;
}
- attributes::unwind(llfn, false);
+ attrs
}
}
#![allow(non_upper_case_globals)]
-use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector, Attribute};
+use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector};
use trans::abi::{FnType, ArgType, Indirect};
use trans::context::CrateContext;
use trans::type_::Type;
fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
if is_reg_ty(ret.ty) {
- if ret.ty == Type::i1(ccx) {
- ret.attr = Some(Attribute::ZExt)
- }
return;
}
if let Some((base_ty, members)) = is_homogenous_aggregate_ty(ret.ty) {
return;
}
ret.kind = Indirect;
- ret.attr = Some(Attribute::StructRet);
}
fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) {
if is_reg_ty(arg.ty) {
- if arg.ty == Type::i1(ccx) {
- arg.attr = Some(Attribute::ZExt);
- }
return;
}
if let Some((base_ty, members)) = is_homogenous_aggregate_ty(arg.ty) {
#![allow(non_upper_case_globals)]
-use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector, Attribute};
+use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector};
use trans::abi::{FnType, ArgType, Indirect};
use trans::context::CrateContext;
use trans::type_::Type;
fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType, align_fn: TyAlignFn) {
if is_reg_ty(ret.ty) {
- if ret.ty == Type::i1(ccx) {
- ret.attr = Some(Attribute::ZExt);
- }
return;
}
let size = ty_size(ret.ty, align_fn);
return;
}
ret.kind = Indirect;
- ret.attr = Some(Attribute::StructRet);
}
fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, align_fn: TyAlignFn) {
if is_reg_ty(arg.ty) {
- if arg.ty == Type::i1(ccx) {
- arg.attr = Some(Attribute::ZExt);
- }
return;
}
let align = align_fn(arg.ty);
// 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(ccx: &CrateContext, ret: &mut ArgType) {
+fn classify_ret_ty(ret: &mut ArgType) {
match ret.ty.kind() {
Struct => {
let field_types = ret.ty.field_types();
ret.cast = Some(field_types[0]);
} else {
ret.kind = Indirect;
- ret.attr = Some(Attribute::StructRet);
}
- },
+ }
Array => {
ret.kind = Indirect;
- ret.attr = Some(Attribute::StructRet);
- },
- _ => {
- if ret.ty == Type::i1(ccx) {
- ret.attr = Some(Attribute::ZExt);
- }
}
+ _ => {}
}
}
-fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) {
+fn classify_arg_ty(arg: &mut ArgType) {
if arg.ty.is_aggregate() {
arg.kind = Indirect;
arg.attr = Some(Attribute::ByVal);
- } else {
- if arg.ty == Type::i1(ccx) {
- arg.attr = Some(Attribute::ZExt);
- }
}
}
pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
if fty.ret.ty != Type::void(ccx) {
- classify_ret_ty(ccx, &mut fty.ret);
+ classify_ret_ty(&mut fty.ret);
}
for arg in &mut fty.args {
- classify_arg_ty(ccx, arg);
+ classify_arg_ty(arg);
}
}
use libc::c_uint;
use std::cmp;
use llvm;
-use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector, Attribute};
+use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector};
use trans::abi::{ArgType, FnType, Indirect};
use trans::context::CrateContext;
use trans::type_::Type;
}
}
-fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
- if is_reg_ty(ret.ty) {
- if ret.ty == Type::i1(ccx) {
- ret.attr = Some(Attribute::ZExt);
- }
- } else {
- ret.kind = Indirect;
- ret.attr = Some(Attribute::StructRet);
- }
-}
-
fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut usize) {
let orig_offset = *offset;
let size = ty_size(arg.ty) * 8;
*offset = align_up_to(*offset, align);
*offset += align_up_to(size, align * 8) / 8;
- if is_reg_ty(arg.ty) {
- if arg.ty == Type::i1(ccx) {
- arg.attr = Some(Attribute::ZExt);
- }
- } else {
+ if !is_reg_ty(arg.ty) {
arg.cast = Some(struct_ty(ccx, arg.ty));
arg.pad = padding_ty(ccx, align, orig_offset);
}
pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
if fty.ret.ty != Type::void(ccx) {
- classify_ret_ty(ccx, &mut fty.ret);
+ if !is_reg_ty(fty.ret.ty) {
+ fty.ret.kind = Indirect;
+ }
}
let mut offset = if fty.ret.is_indirect() { 4 } else { 0 };
use libc::c_uint;
use llvm;
-use llvm::{Integer, Pointer, Float, Double, Struct, Array, Attribute};
+use llvm::{Integer, Pointer, Float, Double, Struct, Array};
use trans::abi::{FnType, ArgType, Indirect};
use trans::context::CrateContext;
use trans::type_::Type;
}
}
-fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
- if is_reg_ty(ret.ty) {
- if ret.ty == Type::i1(ccx) {
- ret.attr = Some(Attribute::ZExt);
- }
- } else {
- ret.kind = Indirect;
- ret.attr = Some(Attribute::StructRet);
- }
-}
-
fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut usize) {
let orig_offset = *offset;
let size = ty_size(arg.ty) * 8;
*offset = align_up_to(*offset, align);
*offset += align_up_to(size, align * 8) / 8;
- if is_reg_ty(arg.ty) {
- if arg.ty == Type::i1(ccx) {
- arg.attr = Some(Attribute::ZExt);
- }
- } else {
+ if !is_reg_ty(arg.ty) {
arg.cast = Some(struct_ty(ccx, arg.ty));
arg.pad = padding_ty(ccx, align, orig_offset);
}
pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
if fty.ret.ty != Type::void(ccx) {
- classify_ret_ty(ccx, &mut fty.ret);
+ if !is_reg_ty(fty.ret.ty) {
+ fty.ret.kind = Indirect;
+ }
}
let mut offset = if fty.ret.is_indirect() { 4 } else { 0 };
// Alignment of 128 bit types is not currently handled, this will
// need to be fixed when PowerPC vector support is added.
-use llvm::{Integer, Pointer, Float, Double, Struct, Array, Attribute};
+use llvm::{Integer, Pointer, Float, Double, Struct, Array};
use trans::abi::{FnType, ArgType, Indirect};
use trans::context::CrateContext;
use trans::type_::Type;
fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
if is_reg_ty(ret.ty) {
- if ret.ty == Type::i1(ccx) {
- ret.attr = Some(Attribute::ZExt);
- }
return;
}
// The PowerPC64 big endian ABI doesn't return aggregates in registers
if ccx.sess().target.target.target_endian == "big" {
ret.kind = Indirect;
- ret.attr = Some(Attribute::StructRet);
}
if let Some((base_ty, members)) = is_homogenous_aggregate_ty(ret.ty) {
}
ret.kind = Indirect;
- ret.attr = Some(Attribute::StructRet);
}
fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) {
if is_reg_ty(arg.ty) {
- if arg.ty == Type::i1(ccx) {
- arg.attr = Some(Attribute::ZExt);
- }
return;
}
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.attr = Some(Attribute::StructRet);
- }
+ _ => fty.ret.kind = Indirect
}
} else {
fty.ret.kind = Indirect;
- fty.ret.attr = Some(Attribute::StructRet);
}
- } else if fty.ret.ty == Type::i1(ccx) {
- fty.ret.attr = Some(Attribute::ZExt);
}
for arg in &mut fty.args {
arg.kind = Indirect;
arg.attr = Some(Attribute::ByVal);
}
- } else if arg.ty == Type::i1(ccx) {
- arg.attr = Some(Attribute::ZExt);
}
}
}
fn x86_64_ty<F>(ccx: &CrateContext,
arg: &mut ArgType,
is_mem_cls: F,
- ind_attr: Attribute)
+ ind_attr: Option<Attribute>)
where F: FnOnce(&[RegClass]) -> bool
{
if !arg.ty.is_reg_ty() {
let cls = classify_ty(arg.ty);
if is_mem_cls(&cls) {
arg.kind = Indirect;
- arg.attr = Some(ind_attr);
+ arg.attr = ind_attr;
} else {
arg.cast = Some(llreg_ty(ccx, &cls));
}
- } else {
- if arg.ty == Type::i1(ccx) {
- arg.attr = Some(Attribute::ZExt);
- }
}
}
} else {
false
}
- }, Attribute::StructRet);
+ }, None);
}
for arg in &mut fty.args {
sse_regs -= needed_sse;
}
in_mem
- }, Attribute::ByVal);
+ }, Some(Attribute::ByVal));
// An integer, pointer, double or float parameter
// thus the above closure passed to `x86_64_ty` won't
// Win64 ABI: http://msdn.microsoft.com/en-us/library/zthk2dkh.aspx
pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
- let fixup = |a: &mut ArgType, indirect_attr| {
+ let fixup = |a: &mut ArgType| {
if a.ty.kind() == Struct {
match llsize_of_alloc(ccx, a.ty) {
1 => a.cast = Some(Type::i8(ccx)),
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.attr = indirect_attr;
- }
+ _ => a.kind = Indirect
}
- } else if a.ty == Type::i1(ccx) {
- a.attr = Some(Attribute::ZExt);
}
};
if fty.ret.ty != Type::void(ccx) {
- fixup(&mut fty.ret, Some(Attribute::StructRet));
+ fixup(&mut fty.ret);
}
for arg in &mut fty.args {
- fixup(arg, None);
+ fixup(arg);
}
}
debug!("declare_rust_fn (after region erasure) sig={:?}", sig);
let fty = FnType::new(ccx, f.abi, &sig, &[]);
- let llfn = declare_raw_fn(ccx, name, fty.cconv, fty.to_llvm(ccx));
+ let llfn = declare_raw_fn(ccx, name, fty.cconv, fty.llvm_type(ccx));
if sig.output == ty::FnDiverging {
llvm::SetFunctionAttribute(llfn, llvm::Attribute::NoReturn);
}
- if f.abi == Abi::Rust || f.abi == Abi::RustCall {
- attributes::from_fn_type(ccx, fn_type).apply_llfn(llfn);
+ let attrs = if f.abi == Abi::Rust || f.abi == Abi::RustCall {
+ attributes::from_fn_type(ccx, fn_type)
} else {
- fty.add_attributes(llfn);
- }
+ attributes::unwind(llfn, false);
+ fty.llvm_attrs(ccx)
+ };
+
+ attrs.apply_llfn(llfn);
llfn
}
// A function pointer is called without the declaration available, so we have to apply
// any attributes with ABI implications directly to the call instruction.
- let mut attrs = llvm::AttrBuilder::new();
- // Add attributes that are always applicable, independent of the concrete foreign ABI
- if fn_type.ret.is_indirect() {
- let llret_sz = machine::llsize_of_real(ccx, fn_type.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(1, llvm::Attribute::NoAlias)
- .arg(1, llvm::Attribute::NoCapture)
- .arg(1, llvm::DereferenceableAttribute(llret_sz));
- };
-
- // Add attributes that depend on the concrete foreign ABI
- let mut arg_idx = if fn_type.ret.is_indirect() { 1 } else { 0 };
- match fn_type.ret.attr {
- Some(attr) => { attrs.arg(arg_idx, attr); },
- _ => ()
- }
-
- arg_idx += 1;
- for arg_ty in &fn_type.args {
- if arg_ty.is_ignore() {
- continue;
- }
- // skip padding
- if arg_ty.pad.is_some() { arg_idx += 1; }
-
- if let Some(attr) = arg_ty.attr {
- attrs.arg(arg_idx, attr);
- }
-
- arg_idx += 1;
- }
let llforeign_retval = CallWithConv(bcx,
llfn,
&llargs_foreign[..],
fn_type.cconv,
- Some(attrs),
+ Some(fn_type.llvm_attrs(ccx)),
call_debug_loc);
// If the function we just called does not use an outpointer,
ty::TyFnPtr(f) => {
let sig = cx.tcx().erase_late_bound_regions(&f.sig);
let sig = infer::normalize_associated_type(cx.tcx(), &sig);
- FnType::new(cx, f.abi, &sig, &[]).to_llvm(cx).ptr_to()
+ FnType::new(cx, f.abi, &sig, &[]).llvm_type(cx).ptr_to()
}
ty::TyTuple(ref tys) if tys.is_empty() => Type::nil(cx),
ty::TyTuple(..) => {