Skip to content

Commit

Permalink
rustc: Use an out pointer to return structs in x86 C ABI. rust-lang#5347
Browse files Browse the repository at this point in the history


This Adds a bunch of tests for passing and returning structs
of various sizes to C. It fixes the struct return rules on unix,
and on windows for structs of size > 8 bytes. Struct passing
on unix for structs under a certain size appears to still be broken.
  • Loading branch information
brson committed Apr 17, 2013
1 parent 7cd6816 commit a5ddc00
Show file tree
Hide file tree
Showing 19 changed files with 397 additions and 91 deletions.
2 changes: 0 additions & 2 deletions src/libcore/rt/uv/net.rs
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,6 @@ impl NativeHandle<*uvll::uv_write_t> for WriteRequest {


#[test]
#[ignore(reason = "ffi struct issues")]
fn connect_close() {
do run_in_bare_thread() {
let mut loop_ = Loop::new();
Expand Down Expand Up @@ -409,7 +408,6 @@ fn connect_read() {
}
#[test]
#[ignore(reason = "ffi struct issues")]
fn listen() {
do run_in_bare_thread() {
static MAX: int = 10;
Expand Down
41 changes: 20 additions & 21 deletions src/librustc/lib/llvm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,27 +125,25 @@ pub enum RealPredicate {
RealPredicateTrue = 15,
}

// enum for the LLVM TypeKind type - must stay in sync with the def of
// The LLVM TypeKind type - must stay in sync with the def of
// LLVMTypeKind in llvm/include/llvm-c/Core.h
#[deriving(Eq)]
pub enum TypeKind {
Void = 0,
Half = 1,
Float = 2,
Double = 3,
X86_FP80 = 4,
FP128 = 5,
PPC_FP128 = 6,
Label = 7,
Integer = 8,
Function = 9,
Struct = 10,
Array = 11,
Pointer = 12,
Vector = 13,
Metadata = 14,
X86_MMX = 15
}
pub type TypeKind = u32;
pub static Void: TypeKind = 0;
pub static Half: TypeKind = 1;
pub static Float: TypeKind = 2;
pub static Double: TypeKind = 3;
pub static X86_FP80: TypeKind = 4;
pub static FP128: TypeKind = 5;
pub static PPC_FP128: TypeKind = 6;
pub static Label: TypeKind = 7;
pub static Integer: TypeKind = 8;
pub static Function: TypeKind = 9;
pub static Struct: TypeKind = 10;
pub static Array: TypeKind = 11;
pub static Pointer: TypeKind = 12;
pub static Vector: TypeKind = 13;
pub static Metadata: TypeKind = 14;
pub static X86_MMX: TypeKind = 15;

pub enum AtomicBinOp {
Xchg = 0,
Expand Down Expand Up @@ -1582,7 +1580,8 @@ pub fn type_to_str_inner(names: @TypeNames, +outer0: &[TypeRef], ty: TypeRef)
}
Vector => return @"Vector",
Metadata => return @"Metadata",
X86_MMX => return @"X86_MMAX"
X86_MMX => return @"X86_MMAX",
_ => fail!()
}
}
}
Expand Down
34 changes: 0 additions & 34 deletions src/librustc/middle/trans/cabi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,37 +180,3 @@ pub impl FnType {
Ret(bcx, llretval);
}
}

enum LLVM_ABIInfo { LLVM_ABIInfo }

impl ABIInfo for LLVM_ABIInfo {
fn compute_info(&self,
atys: &[TypeRef],
rty: TypeRef,
_ret_def: bool) -> FnType {
let arg_tys = do atys.map |a| {
LLVMType { cast: false, ty: *a }
};
let ret_ty = LLVMType {
cast: false,
ty: rty
};
let attrs = do atys.map |_| {
option::None
};
let sret = false;

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

pub fn llvm_abi_info() -> @ABIInfo {
return @LLVM_ABIInfo as @ABIInfo;
}


2 changes: 1 addition & 1 deletion src/librustc/middle/trans/cabi_mips.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,6 @@ impl ABIInfo for MIPS_ABIInfo {
}
}

pub fn mips_abi_info() -> @ABIInfo {
pub fn abi_info() -> @ABIInfo {
return @MIPS_ABIInfo as @ABIInfo;
}
77 changes: 77 additions & 0 deletions src/librustc/middle/trans/cabi_x86.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use driver::session::os_win32;
use core::option::*;
use lib::llvm::*;
use lib::llvm::llvm::*;
use super::cabi::*;
use super::common::*;
use super::machine::*;

struct X86_ABIInfo {
ccx: @CrateContext
}

impl ABIInfo for X86_ABIInfo {
fn compute_info(&self,
atys: &[TypeRef],
rty: TypeRef,
ret_def: bool) -> FnType {
let mut arg_tys = do atys.map |a| {
LLVMType { cast: false, ty: *a }
};
let mut ret_ty = LLVMType {
cast: false,
ty: rty
};
let mut attrs = do atys.map |_| {
None
};

// Rules for returning structs taken from
// http://www.angelcode.com/dev/callconv/callconv.html
let sret = {
let returning_a_struct = unsafe { LLVMGetTypeKind(rty) == Struct && ret_def };
let big_struct = if self.ccx.sess.targ_cfg.os != os_win32 {
true
} else {
llsize_of_alloc(self.ccx, rty) > 8
};
returning_a_struct && big_struct
};

if sret {
let ret_ptr_ty = LLVMType {
cast: false,
ty: T_ptr(ret_ty.ty)
};
arg_tys = ~[ret_ptr_ty] + arg_tys;
attrs = ~[Some(StructRetAttribute)] + attrs;
ret_ty = LLVMType {
cast: false,
ty: T_void(),
};
}

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

pub fn abi_info(ccx: @CrateContext) -> @ABIInfo {
return @X86_ABIInfo {
ccx: ccx
} as @ABIInfo;
}
2 changes: 1 addition & 1 deletion src/librustc/middle/trans/cabi_x86_64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,6 @@ impl ABIInfo for X86_64_ABIInfo {
}
}

pub fn x86_64_abi_info() -> @ABIInfo {
pub fn abi_info() -> @ABIInfo {
return @X86_64_ABIInfo as @ABIInfo;
}
17 changes: 9 additions & 8 deletions src/librustc/middle/trans/foreign.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ use lib::llvm::{TypeRef, ValueRef};
use lib;
use middle::trans::base::*;
use middle::trans::cabi;
use middle::trans::cabi_x86_64::*;
use middle::trans::cabi_x86;
use middle::trans::cabi_x86_64;
use middle::trans::cabi_arm;
use middle::trans::cabi_mips::*;
use middle::trans::cabi_mips;
use middle::trans::build::*;
use middle::trans::callee::*;
use middle::trans::common::*;
Expand All @@ -42,12 +43,12 @@ use syntax::abi::{Architecture, X86, X86_64, Arm, Mips};
use syntax::abi::{RustIntrinsic, Rust, Stdcall, Fastcall,
Cdecl, Aapcs, C};

fn abi_info(arch: Architecture) -> @cabi::ABIInfo {
return match arch {
X86_64 => x86_64_abi_info(),
fn abi_info(ccx: @CrateContext) -> @cabi::ABIInfo {
return match ccx.sess.targ_cfg.arch {
X86 => cabi_x86::abi_info(ccx),
X86_64 => cabi_x86_64::abi_info(),
Arm => cabi_arm::abi_info(),
Mips => mips_abi_info(),
X86 => cabi::llvm_abi_info()
Mips => cabi_mips::abi_info(),
}
}

Expand Down Expand Up @@ -112,7 +113,7 @@ fn shim_types(ccx: @CrateContext, id: ast::node_id) -> ShimTypes {
!ty::type_is_bot(fn_sig.output) &&
!ty::type_is_nil(fn_sig.output);
let fn_ty =
abi_info(ccx.sess.targ_cfg.arch).compute_info(
abi_info(ccx).compute_info(
llsig.llarg_tys,
llsig.llret_ty,
ret_def);
Expand Down
1 change: 1 addition & 0 deletions src/librustc/rustc.rc
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ pub mod middle {
pub mod tvec;
pub mod meth;
pub mod cabi;
pub mod cabi_x86;
pub mod cabi_x86_64;
pub mod cabi_arm;
pub mod cabi_mips;
Expand Down
102 changes: 82 additions & 20 deletions src/rt/rust_test_helpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,26 +30,6 @@ rust_dbg_extern_identity_u64(uint64_t u) {
return u;
}

struct TwoU64s {
uint64_t one;
uint64_t two;
};

extern "C" CDECL TwoU64s
rust_dbg_extern_identity_TwoU64s(TwoU64s u) {
return u;
}

struct TwoDoubles {
double one;
double two;
};

extern "C" CDECL TwoDoubles
rust_dbg_extern_identity_TwoDoubles(TwoDoubles u) {
return u;
}

extern "C" CDECL double
rust_dbg_extern_identity_double(double u) {
return u;
Expand Down Expand Up @@ -103,3 +83,85 @@ rust_dbg_call(dbg_callback cb, void *data) {
}

extern "C" CDECL void rust_dbg_do_nothing() { }

struct TwoU8s {
uint8_t one;
uint8_t two;
};

extern "C" CDECL TwoU8s
rust_dbg_extern_return_TwoU8s() {
struct TwoU8s s;
s.one = 10;
s.two = 20;
return s;
}

extern "C" CDECL TwoU8s
rust_dbg_extern_identity_TwoU8s(TwoU8s u) {
return u;
}

struct TwoU16s {
uint16_t one;
uint16_t two;
};

extern "C" CDECL TwoU16s
rust_dbg_extern_return_TwoU16s() {
struct TwoU16s s;
s.one = 10;
s.two = 20;
return s;
}

extern "C" CDECL TwoU16s
rust_dbg_extern_identity_TwoU16s(TwoU16s u) {
return u;
}

struct TwoU32s {
uint32_t one;
uint32_t two;
};

extern "C" CDECL TwoU32s
rust_dbg_extern_return_TwoU32s() {
struct TwoU32s s;
s.one = 10;
s.two = 20;
return s;
}

extern "C" CDECL TwoU32s
rust_dbg_extern_identity_TwoU32s(TwoU32s u) {
return u;
}

struct TwoU64s {
uint64_t one;
uint64_t two;
};

extern "C" CDECL TwoU64s
rust_dbg_extern_return_TwoU64s() {
struct TwoU64s s;
s.one = 10;
s.two = 20;
return s;
}

extern "C" CDECL TwoU64s
rust_dbg_extern_identity_TwoU64s(TwoU64s u) {
return u;
}

struct TwoDoubles {
double one;
double two;
};

extern "C" CDECL TwoDoubles
rust_dbg_extern_identity_TwoDoubles(TwoDoubles u) {
return u;
}
8 changes: 7 additions & 1 deletion src/rt/rustrt.def.in
Original file line number Diff line number Diff line change
Expand Up @@ -198,8 +198,15 @@ rust_readdir
rust_opendir
rust_dbg_extern_identity_u32
rust_dbg_extern_identity_u64
rust_dbg_extern_identity_TwoU8s
rust_dbg_extern_identity_TwoU16s
rust_dbg_extern_identity_TwoU32s
rust_dbg_extern_identity_TwoU64s
rust_dbg_extern_identity_TwoDoubles
rust_dbg_extern_return_TwoU8s
rust_dbg_extern_return_TwoU16s
rust_dbg_extern_return_TwoU32s
rust_dbg_extern_return_TwoU64s
rust_dbg_extern_identity_double
rust_dbg_extern_identity_u8
rust_get_rt_env
Expand All @@ -214,4 +221,3 @@ rust_uv_free_ip6_addr
rust_call_nullary_fn
rust_initialize_global_state


Loading

1 comment on commit a5ddc00

@brson
Copy link
Owner Author

@brson brson commented on a5ddc00 Apr 17, 2013

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

r+

Please sign in to comment.