trans: Provide the FnType for a direct call via Callee::direct_fn_type.

This commit is contained in:
Eduard Burtescu 2016-03-06 12:38:46 +02:00
parent 80d939fd22
commit 9e036c0ff0
2 changed files with 55 additions and 32 deletions

View File

@ -150,17 +150,18 @@ impl FnType {
abi: Abi,
sig: &ty::FnSig<'tcx>,
extra_args: &[Ty<'tcx>]) -> FnType {
let mut fn_ty = FnType::unadjusted(ccx, abi, sig, extra_args);
fn_ty.adjust_for_abi(ccx, abi, sig);
fn_ty
}
pub fn unadjusted<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
abi: Abi,
sig: &ty::FnSig<'tcx>,
extra_args: &[Ty<'tcx>]) -> FnType {
use self::Abi::*;
let cconv = match ccx.sess().target.target.adjust_abi(abi) {
RustIntrinsic => {
// Intrinsics are emitted at the call site
ccx.sess().bug("asked to compute FnType of intrinsic");
}
PlatformIntrinsic => {
// Intrinsics are emitted at the call site
ccx.sess().bug("asked to compute FnType of platform intrinsic");
}
RustIntrinsic | PlatformIntrinsic |
Rust | RustCall => llvm::CCallConv,
// It's the ABI's job to select this, not us.
@ -309,14 +310,20 @@ impl FnType {
}
}
let mut fty = FnType {
FnType {
args: args,
ret: ret,
variadic: sig.variadic,
cconv: cconv
};
}
}
if abi == Rust || abi == RustCall {
pub fn adjust_for_abi<'a, 'tcx>(&mut self,
ccx: &CrateContext<'a, 'tcx>,
abi: Abi,
sig: &ty::FnSig<'tcx>) {
if abi == Abi::Rust || abi == Abi::RustCall ||
abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic {
let fixup = |arg: &mut ArgType| {
if !arg.ty.is_aggregate() {
// Scalars and vectors, always immediate.
@ -332,49 +339,48 @@ impl FnType {
arg.cast = Some(Type::ix(ccx, size * 8));
}
};
if fty.ret.ty != Type::void(ccx) {
// Fat pointers are returned by-value.
// Fat pointers are returned by-value.
if !self.ret.is_ignore() {
if !type_is_fat_ptr(ccx.tcx(), sig.output.unwrap()) {
fixup(&mut fty.ret);
fixup(&mut self.ret);
}
}
for arg in &mut fty.args {
for arg in &mut self.args {
if arg.is_ignore() { continue; }
fixup(arg);
}
if fty.ret.is_indirect() {
fty.ret.attrs.set(llvm::Attribute::StructRet);
if self.ret.is_indirect() {
self.ret.attrs.set(llvm::Attribute::StructRet);
}
return fty;
return;
}
match &ccx.sess().target.target.arch[..] {
"x86" => cabi_x86::compute_abi_info(ccx, &mut fty),
"x86" => cabi_x86::compute_abi_info(ccx, self),
"x86_64" => if ccx.sess().target.target.options.is_like_windows {
cabi_x86_win64::compute_abi_info(ccx, &mut fty);
cabi_x86_win64::compute_abi_info(ccx, self);
} else {
cabi_x86_64::compute_abi_info(ccx, &mut fty);
cabi_x86_64::compute_abi_info(ccx, self);
},
"aarch64" => cabi_aarch64::compute_abi_info(ccx, &mut fty),
"aarch64" => cabi_aarch64::compute_abi_info(ccx, self),
"arm" => {
let flavor = if ccx.sess().target.target.target_os == "ios" {
cabi_arm::Flavor::Ios
} else {
cabi_arm::Flavor::General
};
cabi_arm::compute_abi_info(ccx, &mut fty, flavor);
cabi_arm::compute_abi_info(ccx, self, flavor);
},
"mips" => cabi_mips::compute_abi_info(ccx, &mut fty),
"powerpc" => cabi_powerpc::compute_abi_info(ccx, &mut fty),
"powerpc64" => cabi_powerpc64::compute_abi_info(ccx, &mut fty),
"asmjs" => cabi_asmjs::compute_abi_info(ccx, &mut fty),
"mips" => cabi_mips::compute_abi_info(ccx, self),
"powerpc" => cabi_powerpc::compute_abi_info(ccx, self),
"powerpc64" => cabi_powerpc64::compute_abi_info(ccx, self),
"asmjs" => cabi_asmjs::compute_abi_info(ccx, self),
a => ccx.sess().fatal(&format!("unrecognized arch \"{}\" in target specification", a))
}
if fty.ret.is_indirect() {
fty.ret.attrs.set(llvm::Attribute::StructRet);
if self.ret.is_indirect() {
self.ret.attrs.set(llvm::Attribute::StructRet);
}
fty
}
pub fn llvm_type(&self, ccx: &CrateContext) -> Type {

View File

@ -210,6 +210,23 @@ impl<'tcx> Callee<'tcx> {
}
}
/// Get the abi::FnType for a direct call. Mainly deals with the fact
/// that a Virtual call doesn't take the vtable, like its shim does.
/// The extra argument types are for variadic (extern "C") functions.
pub fn direct_fn_type<'a>(&self, ccx: &CrateContext<'a, 'tcx>,
extra_args: &[Ty<'tcx>]) -> FnType {
let abi = self.ty.fn_abi();
let sig = ccx.tcx().erase_late_bound_regions(self.ty.fn_sig());
let sig = infer::normalize_associated_type(ccx.tcx(), &sig);
let mut fn_ty = FnType::unadjusted(ccx, abi, &sig, extra_args);
if let Virtual(_) = self.data {
// Don't pass the vtable, it's not an argument of the virtual fn.
fn_ty.args[1].ignore();
}
fn_ty.adjust_for_abi(ccx, abi, &sig);
fn_ty
}
/// This behemoth of a function translates function calls. Unfortunately, in
/// order to generate more efficient LLVM output at -O0, it has quite a complex
/// signature (refactoring this into two functions seems like a good idea).