Skip to content

improve C ABI #9517

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 11, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 58 additions & 17 deletions src/librustc/middle/trans/cabi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,62 @@ use middle::trans::cabi_mips;
use middle::trans::type_::Type;
use syntax::abi::{X86, X86_64, Arm, Mips};

#[deriving(Clone, Eq)]
pub enum ArgKind {
/// Pass the argument directly using the normal converted
/// LLVM type or by coercing to another specified type
Direct,
/// Pass the argument indirectly via a hidden pointer
Indirect
}

/// Information about how a specific C type
/// should be passed to or returned from a function
///
/// This is borrowed from clang's ABIInfo.h
#[deriving(Clone)]
pub struct LLVMType {
cast: bool,
ty: Type
pub struct ArgType {
kind: ArgKind,
/// Original LLVM type
ty: Type,
/// Coerced LLVM Type
cast: option::Option<Type>,
/// Dummy argument, which is emitted before the real argument
pad: option::Option<Type>,
/// LLVM attribute of argument
attr: option::Option<Attribute>
}

impl ArgType {
pub fn direct(ty: Type, cast: option::Option<Type>,
pad: option::Option<Type>,
attr: option::Option<Attribute>) -> ArgType {
ArgType {
kind: Direct,
ty: ty,
cast: cast,
pad: pad,
attr: attr
}
}

pub fn indirect(ty: Type, attr: option::Option<Attribute>) -> ArgType {
ArgType {
kind: Indirect,
ty: ty,
cast: option::None,
pad: option::None,
attr: attr
}
}

pub fn is_direct(&self) -> bool {
return self.kind == Direct;
}

pub fn is_indirect(&self) -> bool {
return self.kind == Indirect;
}
}

/// Metadata describing how the arguments to a native function
Expand All @@ -30,22 +82,11 @@ pub struct LLVMType {
/// I will do my best to describe this structure, but these
/// comments are reverse-engineered and may be inaccurate. -NDM
pub struct FnType {
/// The LLVM types of each argument. If the cast flag is true,
/// then the argument should be cast, typically because the
/// official argument type will be an int and the rust type is i8
/// or something like that.
arg_tys: ~[LLVMType],

/// A list of attributes to be attached to each argument (parallel
/// the `arg_tys` array). If the attribute for a given is Some,
/// then the argument should be passed by reference.
attrs: ~[option::Option<Attribute>],
/// The LLVM types of each argument.
arg_tys: ~[ArgType],

/// LLVM return type.
ret_ty: LLVMType,

/// If true, then an implicit pointer should be added for the result.
sret: bool
ret_ty: ArgType,
}

pub fn compute_abi_info(ccx: &mut CrateContext,
Expand Down
39 changes: 13 additions & 26 deletions src/librustc/middle/trans/cabi_arm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@
#[allow(non_uppercase_pattern_statics)];

use lib::llvm::{llvm, Integer, Pointer, Float, Double, Struct, Array};
use lib::llvm::{Attribute, StructRetAttribute};
use middle::trans::cabi::{FnType, LLVMType};
use lib::llvm::StructRetAttribute;
use middle::trans::cabi::{FnType, ArgType};
use middle::trans::context::CrateContext;

use middle::trans::type_::Type;

use std::num;
use std::option::{Option, None, Some};
use std::option::{None, Some};

fn align_up_to(off: uint, a: uint) -> uint {
return (off + a - 1u) / a * a;
Expand Down Expand Up @@ -85,9 +85,9 @@ fn ty_size(ty: Type) -> uint {
}
}

fn classify_ret_ty(ty: Type) -> (LLVMType, Option<Attribute>) {
fn classify_ret_ty(ty: Type) -> ArgType {
if is_reg_ty(ty) {
return (LLVMType { cast: false, ty: ty }, None);
return ArgType::direct(ty, None, None, None);
}
let size = ty_size(ty);
if size <= 4 {
Expand All @@ -98,14 +98,14 @@ fn classify_ret_ty(ty: Type) -> (LLVMType, Option<Attribute>) {
} else {
Type::i32()
};
return (LLVMType { cast: true, ty: llty }, None);
return ArgType::direct(ty, Some(llty), None, None);
}
(LLVMType { cast: false, ty: ty.ptr_to() }, Some(StructRetAttribute))
ArgType::indirect(ty, Some(StructRetAttribute))
}

fn classify_arg_ty(ty: Type) -> (LLVMType, Option<Attribute>) {
fn classify_arg_ty(ty: Type) -> ArgType {
if is_reg_ty(ty) {
return (LLVMType { cast: false, ty: ty }, None);
return ArgType::direct(ty, None, None, None);
}
let align = ty_align(ty);
let size = ty_size(ty);
Expand All @@ -114,7 +114,7 @@ fn classify_arg_ty(ty: Type) -> (LLVMType, Option<Attribute>) {
} else {
Type::array(&Type::i64(), ((size + 7) / 8) as u64)
};
(LLVMType { cast: true, ty: llty }, None)
ArgType::direct(ty, Some(llty), None, None)
}

fn is_reg_ty(ty: Type) -> bool {
Expand All @@ -132,32 +132,19 @@ pub fn compute_abi_info(_ccx: &mut CrateContext,
rty: Type,
ret_def: bool) -> FnType {
let mut arg_tys = ~[];
let mut attrs = ~[];
for &aty in atys.iter() {
let (ty, attr) = classify_arg_ty(aty);
let ty = classify_arg_ty(aty);
arg_tys.push(ty);
attrs.push(attr);
}

let (ret_ty, ret_attr) = if ret_def {
let ret_ty = if ret_def {
classify_ret_ty(rty)
} else {
(LLVMType { cast: false, ty: Type::void() }, None)
ArgType::direct(Type::void(), None, None, None)
};

let mut ret_ty = ret_ty;

let sret = ret_attr.is_some();
if sret {
arg_tys.unshift(ret_ty);
attrs.unshift(ret_attr);
ret_ty = LLVMType { cast: false, ty: Type::void() };
}

return FnType {
arg_tys: arg_tys,
ret_ty: ret_ty,
attrs: attrs,
sret: sret
};
}
70 changes: 22 additions & 48 deletions src/librustc/middle/trans/cabi_mips.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,8 @@

use std::libc::c_uint;
use std::num;
use std::vec;
use lib::llvm::{llvm, Integer, Pointer, Float, Double, Struct, Array};
use lib::llvm::{Attribute, StructRetAttribute};
use lib::llvm::StructRetAttribute;
use middle::trans::context::CrateContext;
use middle::trans::context::task_llcx;
use middle::trans::cabi::*;
Expand Down Expand Up @@ -86,15 +85,15 @@ fn ty_size(ty: Type) -> uint {
}
}

fn classify_ret_ty(ty: Type) -> (LLVMType, Option<Attribute>) {
return if is_reg_ty(ty) {
(LLVMType { cast: false, ty: ty }, None)
fn classify_ret_ty(ty: Type) -> ArgType {
if is_reg_ty(ty) {
ArgType::direct(ty, None, None, None)
} else {
(LLVMType { cast: false, ty: ty.ptr_to() }, Some(StructRetAttribute))
};
ArgType::indirect(ty, Some(StructRetAttribute))
}
}

fn classify_arg_ty(ty: Type, offset: &mut uint) -> (LLVMType, Option<Attribute>) {
fn classify_arg_ty(ty: Type, offset: &mut uint) -> ArgType {
let orig_offset = *offset;
let size = ty_size(ty) * 8;
let mut align = ty_align(ty);
Expand All @@ -103,20 +102,16 @@ fn classify_arg_ty(ty: Type, offset: &mut uint) -> (LLVMType, Option<Attribute>)
*offset = align_up_to(*offset, align);
*offset += align_up_to(size, align * 8) / 8;

let padding = padding_ty(align, orig_offset);
return if !is_reg_ty(ty) {
(LLVMType {
cast: true,
ty: struct_ty(ty, padding, true)
}, None)
} else if padding.is_some() {
(LLVMType {
cast: true,
ty: struct_ty(ty, padding, false)
}, None)
if is_reg_ty(ty) {
ArgType::direct(ty, None, None, None)
} else {
(LLVMType { cast: false, ty: ty }, None)
};
ArgType::direct(
ty,
Some(struct_ty(ty)),
padding_ty(align, orig_offset),
None
)
}
}

fn is_reg_ty(ty: Type) -> bool {
Expand Down Expand Up @@ -157,54 +152,33 @@ fn coerce_to_int(size: uint) -> ~[Type] {
args
}

fn struct_ty(ty: Type,
padding: Option<Type>,
coerce: bool) -> Type {
fn struct_ty(ty: Type) -> Type {
let size = ty_size(ty) * 8;
let mut fields = padding.map_default(~[], |p| ~[p]);

if coerce {
fields = vec::append(fields, coerce_to_int(size));
} else {
fields.push(ty);
}

let fields = coerce_to_int(size);
return Type::struct_(fields, false);
}

pub fn compute_abi_info(_ccx: &mut CrateContext,
atys: &[Type],
rty: Type,
ret_def: bool) -> FnType {
let (ret_ty, ret_attr) = if ret_def {
let ret_ty = if ret_def {
classify_ret_ty(rty)
} else {
(LLVMType { cast: false, ty: Type::void() }, None)
ArgType::direct(Type::void(), None, None, None)
};

let mut ret_ty = ret_ty;

let sret = ret_attr.is_some();
let sret = ret_ty.is_indirect();
let mut arg_tys = ~[];
let mut attrs = ~[];
let mut offset = if sret { 4 } else { 0 };

for aty in atys.iter() {
let (ty, attr) = classify_arg_ty(*aty, &mut offset);
let ty = classify_arg_ty(*aty, &mut offset);
arg_tys.push(ty);
attrs.push(attr);
};

if sret {
arg_tys = vec::append(~[ret_ty], arg_tys);
attrs = vec::append(~[ret_attr], attrs);
ret_ty = LLVMType { cast: false, ty: Type::void() };
}

return FnType {
arg_tys: arg_tys,
ret_ty: ret_ty,
attrs: attrs,
sret: sret
};
}
37 changes: 5 additions & 32 deletions src/librustc/middle/trans/cabi_x86.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,10 @@ pub fn compute_abi_info(ccx: &mut CrateContext,
rty: Type,
ret_def: bool) -> FnType {
let mut arg_tys = ~[];
let mut attrs = ~[];

let ret_ty;
let sret;
if !ret_def {
ret_ty = LLVMType {
cast: false,
ty: Type::void(),
};
sret = false;
ret_ty = ArgType::direct(Type::void(), None, None, None);
} else if rty.kind() == Struct {
// Returning a structure. Most often, this will use
// a hidden first argument. On some platforms, though,
Expand Down Expand Up @@ -58,43 +52,22 @@ pub fn compute_abi_info(ccx: &mut CrateContext,

match strategy {
RetValue(t) => {
ret_ty = LLVMType {
cast: true,
ty: t
};
sret = false;
ret_ty = ArgType::direct(rty, Some(t), None, None);
}
RetPointer => {
arg_tys.push(LLVMType {
cast: false,
ty: rty.ptr_to()
});
attrs.push(Some(StructRetAttribute));

ret_ty = LLVMType {
cast: false,
ty: Type::void(),
};
sret = true;
ret_ty = ArgType::indirect(rty, Some(StructRetAttribute));
}
}
} else {
ret_ty = LLVMType {
cast: false,
ty: rty
};
sret = false;
ret_ty = ArgType::direct(rty, None, None, None);
}

for &a in atys.iter() {
arg_tys.push(LLVMType { cast: false, ty: a });
attrs.push(None);
arg_tys.push(ArgType::direct(a, None, None, None));
}

return FnType {
arg_tys: arg_tys,
ret_ty: ret_ty,
attrs: attrs,
sret: sret
};
}
Loading