librustc: WIP patch for using the return value.

This commit is contained in:
Patrick Walton 2013-04-18 15:53:29 -07:00
parent 7720c15ae1
commit c995a62d44
26 changed files with 779 additions and 407 deletions

View File

@ -95,7 +95,7 @@ pub use str::{StrSlice};
pub use container::{Container, Mutable}; pub use container::{Container, Mutable};
pub use vec::{CopyableVector, ImmutableVector}; pub use vec::{CopyableVector, ImmutableVector};
pub use vec::{ImmutableEqVector, ImmutableCopyableVector}; pub use vec::{ImmutableEqVector, ImmutableCopyableVector};
pub use vec::{OwnedVector, OwnedCopyableVector}; pub use vec::{OwnedVector, OwnedCopyableVector, MutableVector};
pub use iter::{BaseIter, ExtendedIter, EqIter, CopyableIter}; pub use iter::{BaseIter, ExtendedIter, EqIter, CopyableIter};
pub use iter::{CopyableOrderedIter, CopyableNonstrictIter, Times}; pub use iter::{CopyableOrderedIter, CopyableNonstrictIter, Times};
pub use iter::{ExtendedMutableIter}; pub use iter::{ExtendedMutableIter};

View File

@ -16,7 +16,6 @@
use container::{Container, Mutable, Map, Set}; use container::{Container, Mutable, Map, Set};
use cmp::{Eq, Equiv}; use cmp::{Eq, Equiv};
use hash::Hash; use hash::Hash;
use to_bytes::IterBytes;
use iter::BaseIter; use iter::BaseIter;
use hash::Hash; use hash::Hash;
use iter; use iter;
@ -72,7 +71,7 @@ fn linear_map_with_capacity_and_keys<K:Eq + Hash,V>(
} }
} }
priv impl<K:Hash + IterBytes + Eq,V> HashMap<K, V> { priv impl<K:Hash + Eq,V> HashMap<K, V> {
#[inline(always)] #[inline(always)]
fn to_bucket(&self, h: uint) -> uint { fn to_bucket(&self, h: uint) -> uint {
// A good hash function with entropy spread over all of the // A good hash function with entropy spread over all of the
@ -111,9 +110,8 @@ priv impl<K:Hash + IterBytes + Eq,V> HashMap<K, V> {
} }
#[inline(always)] #[inline(always)]
fn bucket_for_key_equiv<Q:Hash + IterBytes + Equiv<K>>(&self, fn bucket_for_key_equiv<Q:Hash + Equiv<K>>(&self, k: &Q)
k: &Q) -> SearchResult {
-> SearchResult {
let hash = k.hash_keyed(self.k0, self.k1) as uint; let hash = k.hash_keyed(self.k0, self.k1) as uint;
self.bucket_for_key_with_hash_equiv(hash, k) self.bucket_for_key_with_hash_equiv(hash, k)
} }
@ -303,7 +301,7 @@ priv impl<K:Hash + IterBytes + Eq,V> HashMap<K, V> {
} }
} }
impl<K:Hash + IterBytes + Eq,V> Container for HashMap<K, V> { impl<K:Hash + Eq,V> Container for HashMap<K, V> {
/// Return the number of elements in the map /// Return the number of elements in the map
fn len(&const self) -> uint { self.size } fn len(&const self) -> uint { self.size }
@ -311,7 +309,7 @@ impl<K:Hash + IterBytes + Eq,V> Container for HashMap<K, V> {
fn is_empty(&const self) -> bool { self.len() == 0 } fn is_empty(&const self) -> bool { self.len() == 0 }
} }
impl<K:Hash + IterBytes + Eq,V> Mutable for HashMap<K, V> { impl<K:Hash + Eq,V> Mutable for HashMap<K, V> {
/// Clear the map, removing all key-value pairs. /// Clear the map, removing all key-value pairs.
fn clear(&mut self) { fn clear(&mut self) {
for uint::range(0, self.buckets.len()) |idx| { for uint::range(0, self.buckets.len()) |idx| {
@ -321,7 +319,7 @@ impl<K:Hash + IterBytes + Eq,V> Mutable for HashMap<K, V> {
} }
} }
impl<K:Hash + IterBytes + Eq,V> Map<K, V> for HashMap<K, V> { impl<K:Hash + Eq,V> Map<K, V> for HashMap<K, V> {
/// Return true if the map contains a value for the specified key /// Return true if the map contains a value for the specified key
fn contains_key(&self, k: &K) -> bool { fn contains_key(&self, k: &K) -> bool {
match self.bucket_for_key(k) { match self.bucket_for_key(k) {
@ -458,7 +456,7 @@ impl<K:Hash + IterBytes + Eq,V> Map<K, V> for HashMap<K, V> {
} }
} }
pub impl<K: Hash + IterBytes + Eq, V> HashMap<K, V> { pub impl<K: Hash + Eq, V> HashMap<K, V> {
/// Create an empty HashMap /// Create an empty HashMap
fn new() -> HashMap<K, V> { fn new() -> HashMap<K, V> {
HashMap::with_capacity(INITIAL_CAPACITY) HashMap::with_capacity(INITIAL_CAPACITY)
@ -669,8 +667,7 @@ pub impl<K: Hash + IterBytes + Eq, V> HashMap<K, V> {
/// Return true if the map contains a value for the specified key, /// Return true if the map contains a value for the specified key,
/// using equivalence /// using equivalence
fn contains_key_equiv<Q:Hash + IterBytes + Equiv<K>>(&self, key: &Q) fn contains_key_equiv<Q:Hash + Equiv<K>>(&self, key: &Q) -> bool {
-> bool {
match self.bucket_for_key_equiv(key) { match self.bucket_for_key_equiv(key) {
FoundEntry(_) => {true} FoundEntry(_) => {true}
TableFull | FoundHole(_) => {false} TableFull | FoundHole(_) => {false}
@ -680,8 +677,7 @@ pub impl<K: Hash + IterBytes + Eq, V> HashMap<K, V> {
/// Return the value corresponding to the key in the map, using /// Return the value corresponding to the key in the map, using
/// equivalence /// equivalence
#[cfg(stage0)] #[cfg(stage0)]
fn find_equiv<Q:Hash + IterBytes + Equiv<K>>(&self, k: &Q) fn find_equiv<Q:Hash + Equiv<K>>(&self, k: &Q) -> Option<&'self V> {
-> Option<&'self V> {
match self.bucket_for_key_equiv(k) { match self.bucket_for_key_equiv(k) {
FoundEntry(idx) => Some(self.value_for_bucket(idx)), FoundEntry(idx) => Some(self.value_for_bucket(idx)),
TableFull | FoundHole(_) => None, TableFull | FoundHole(_) => None,
@ -693,9 +689,7 @@ pub impl<K: Hash + IterBytes + Eq, V> HashMap<K, V> {
#[cfg(stage1)] #[cfg(stage1)]
#[cfg(stage2)] #[cfg(stage2)]
#[cfg(stage3)] #[cfg(stage3)]
fn find_equiv<'a, Q:Hash + IterBytes + Equiv<K>>( fn find_equiv<'a, Q:Hash + Equiv<K>>(&'a self, k: &Q) -> Option<&'a V> {
&'a self, k: &Q) -> Option<&'a V>
{
match self.bucket_for_key_equiv(k) { match self.bucket_for_key_equiv(k) {
FoundEntry(idx) => Some(self.value_for_bucket(idx)), FoundEntry(idx) => Some(self.value_for_bucket(idx)),
TableFull | FoundHole(_) => None, TableFull | FoundHole(_) => None,
@ -703,7 +697,7 @@ pub impl<K: Hash + IterBytes + Eq, V> HashMap<K, V> {
} }
} }
impl<K:Hash + IterBytes + Eq,V:Eq> Eq for HashMap<K, V> { impl<K:Hash + Eq,V:Eq> Eq for HashMap<K, V> {
fn eq(&self, other: &HashMap<K, V>) -> bool { fn eq(&self, other: &HashMap<K, V>) -> bool {
if self.len() != other.len() { return false; } if self.len() != other.len() { return false; }
@ -724,18 +718,18 @@ pub struct HashSet<T> {
priv map: HashMap<T, ()> priv map: HashMap<T, ()>
} }
impl<T:Hash + IterBytes + Eq> BaseIter<T> for HashSet<T> { impl<T:Hash + Eq> BaseIter<T> for HashSet<T> {
/// Visit all values in order /// Visit all values in order
fn each(&self, f: &fn(&T) -> bool) { self.map.each_key(f) } fn each(&self, f: &fn(&T) -> bool) { self.map.each_key(f) }
fn size_hint(&self) -> Option<uint> { Some(self.len()) } fn size_hint(&self) -> Option<uint> { Some(self.len()) }
} }
impl<T:Hash + IterBytes + Eq> Eq for HashSet<T> { impl<T:Hash + Eq> Eq for HashSet<T> {
fn eq(&self, other: &HashSet<T>) -> bool { self.map == other.map } fn eq(&self, other: &HashSet<T>) -> bool { self.map == other.map }
fn ne(&self, other: &HashSet<T>) -> bool { self.map != other.map } fn ne(&self, other: &HashSet<T>) -> bool { self.map != other.map }
} }
impl<T:Hash + IterBytes + Eq> Container for HashSet<T> { impl<T:Hash + Eq> Container for HashSet<T> {
/// Return the number of elements in the set /// Return the number of elements in the set
fn len(&const self) -> uint { self.map.len() } fn len(&const self) -> uint { self.map.len() }
@ -743,12 +737,12 @@ impl<T:Hash + IterBytes + Eq> Container for HashSet<T> {
fn is_empty(&const self) -> bool { self.map.is_empty() } fn is_empty(&const self) -> bool { self.map.is_empty() }
} }
impl<T:Hash + IterBytes + Eq> Mutable for HashSet<T> { impl<T:Hash + Eq> Mutable for HashSet<T> {
/// Clear the set, removing all values. /// Clear the set, removing all values.
fn clear(&mut self) { self.map.clear() } fn clear(&mut self) { self.map.clear() }
} }
impl<T:Hash + IterBytes + Eq> Set<T> for HashSet<T> { impl<T:Hash + Eq> Set<T> for HashSet<T> {
/// Return true if the set contains a value /// Return true if the set contains a value
fn contains(&self, value: &T) -> bool { self.map.contains_key(value) } fn contains(&self, value: &T) -> bool { self.map.contains_key(value) }
@ -816,7 +810,7 @@ impl<T:Hash + IterBytes + Eq> Set<T> for HashSet<T> {
} }
} }
pub impl <T:Hash + IterBytes + Eq> HashSet<T> { pub impl <T:Hash + Eq> HashSet<T> {
/// Create an empty HashSet /// Create an empty HashSet
fn new() -> HashSet<T> { fn new() -> HashSet<T> {
HashSet::with_capacity(INITIAL_CAPACITY) HashSet::with_capacity(INITIAL_CAPACITY)

View File

@ -1097,9 +1097,12 @@ pub mod funcs {
unsafe fn setbuf(stream: *FILE, buf: *c_char); unsafe fn setbuf(stream: *FILE, buf: *c_char);
// Omitted: printf and scanf variants. // Omitted: printf and scanf variants.
unsafe fn fgetc(stream: *FILE) -> c_int; unsafe fn fgetc(stream: *FILE) -> c_int;
#[fast_ffi]
unsafe fn fgets(buf: *mut c_char, n: c_int, unsafe fn fgets(buf: *mut c_char, n: c_int,
stream: *FILE) -> *c_char; stream: *FILE) -> *c_char;
#[fast_ffi]
unsafe fn fputc(c: c_int, stream: *FILE) -> c_int; unsafe fn fputc(c: c_int, stream: *FILE) -> c_int;
#[fast_ffi]
unsafe fn fputs(s: *c_char, stream: *FILE) -> *c_char; unsafe fn fputs(s: *c_char, stream: *FILE) -> *c_char;
// Omitted: getc, getchar (might be macros). // Omitted: getc, getchar (might be macros).
@ -1263,6 +1266,7 @@ pub mod funcs {
unsafe fn pclose(stream: *FILE) -> c_int; unsafe fn pclose(stream: *FILE) -> c_int;
#[link_name = "_fdopen"] #[link_name = "_fdopen"]
#[fast_ffi]
unsafe fn fdopen(fd: c_int, mode: *c_char) -> *FILE; unsafe fn fdopen(fd: c_int, mode: *c_char) -> *FILE;
#[link_name = "_fileno"] #[link_name = "_fileno"]

View File

@ -46,7 +46,7 @@ pub use to_str::ToStr;
pub use tuple::{CopyableTuple, ImmutableTuple, ExtendedTupleOps}; pub use tuple::{CopyableTuple, ImmutableTuple, ExtendedTupleOps};
pub use vec::{CopyableVector, ImmutableVector}; pub use vec::{CopyableVector, ImmutableVector};
pub use vec::{ImmutableEqVector, ImmutableCopyableVector}; pub use vec::{ImmutableEqVector, ImmutableCopyableVector};
pub use vec::{OwnedVector, OwnedCopyableVector}; pub use vec::{OwnedVector, OwnedCopyableVector, MutableVector};
pub use io::{Reader, ReaderUtil, Writer, WriterUtil}; pub use io::{Reader, ReaderUtil, Writer, WriterUtil};
/* Reexported runtime types */ /* Reexported runtime types */

View File

@ -430,6 +430,15 @@ pub fn byte_slice<T>(s: &str, f: &fn(v: &[u8]) -> T) -> T {
} }
} }
/// Work with the string as a byte slice, not including trailing null, without
/// a callback.
#[inline(always)]
pub fn byte_slice_no_callback<'a>(s: &'a str) -> &'a [u8] {
unsafe {
cast::transmute(s)
}
}
/// Convert a string to a unique vector of characters /// Convert a string to a unique vector of characters
pub fn to_chars(s: &str) -> ~[char] { pub fn to_chars(s: &str) -> ~[char] {
let mut buf = ~[]; let mut buf = ~[];

View File

@ -76,6 +76,7 @@ pub fn same_length<T, U>(xs: &const [T], ys: &const [U]) -> bool {
* * v - A vector * * v - A vector
* * n - The number of elements to reserve space for * * n - The number of elements to reserve space for
*/ */
#[inline]
pub fn reserve<T>(v: &mut ~[T], n: uint) { pub fn reserve<T>(v: &mut ~[T], n: uint) {
// Only make the (slow) call into the runtime if we have to // Only make the (slow) call into the runtime if we have to
use managed; use managed;
@ -1831,6 +1832,7 @@ pub trait ImmutableVector<T> {
fn alli(&self, f: &fn(uint, t: &T) -> bool) -> bool; fn alli(&self, f: &fn(uint, t: &T) -> bool) -> bool;
fn flat_map<U>(&self, f: &fn(t: &T) -> ~[U]) -> ~[U]; fn flat_map<U>(&self, f: &fn(t: &T) -> ~[U]) -> ~[U];
fn filter_mapped<U:Copy>(&self, f: &fn(t: &T) -> Option<U>) -> ~[U]; fn filter_mapped<U:Copy>(&self, f: &fn(t: &T) -> Option<U>) -> ~[U];
unsafe fn unsafe_ref(&self, index: uint) -> *T;
} }
/// Extension methods for vectors /// Extension methods for vectors
@ -1941,6 +1943,14 @@ impl<'self,T> ImmutableVector<T> for &'self [T] {
fn filter_mapped<U:Copy>(&self, f: &fn(t: &T) -> Option<U>) -> ~[U] { fn filter_mapped<U:Copy>(&self, f: &fn(t: &T) -> Option<U>) -> ~[U] {
filter_mapped(*self, f) filter_mapped(*self, f)
} }
/// Returns a pointer to the element at the given index, without doing
/// bounds checking.
#[inline(always)]
unsafe fn unsafe_ref(&self, index: uint) -> *T {
let (ptr, _): (*T, uint) = transmute(*self);
ptr.offset(index)
}
} }
#[cfg(stage1)] #[cfg(stage1)]
@ -2178,9 +2188,8 @@ impl<'self,T:Copy> ImmutableCopyableVector<T> for &'self [T] {
/// Returns the element at the given index, without doing bounds checking. /// Returns the element at the given index, without doing bounds checking.
#[inline(always)] #[inline(always)]
unsafe fn unsafe_get(&self, elem: uint) -> T { unsafe fn unsafe_get(&self, index: uint) -> T {
let (ptr, _): (*T, uint) = transmute(*self); *self.unsafe_ref(index)
*ptr.offset(elem)
} }
} }
@ -2323,15 +2332,21 @@ impl<T:Eq> OwnedEqVector<T> for ~[T] {
} }
pub trait MutableVector<T> { pub trait MutableVector<T> {
unsafe fn unsafe_set(&self, elem: uint, val: T); unsafe fn unsafe_mut_ref(&self, index: uint) -> *mut T;
unsafe fn unsafe_set(&self, index: uint, val: T);
} }
impl<'self,T> MutableVector<T> for &'self mut [T] { impl<'self,T> MutableVector<T> for &'self mut [T] {
#[inline(always)] #[inline(always)]
unsafe fn unsafe_set(&self, elem: uint, val: T) { unsafe fn unsafe_mut_ref(&self, index: uint) -> *mut T {
let pair_ptr: &(*mut T, uint) = transmute(self); let pair_ptr: &(*mut T, uint) = transmute(self);
let (ptr, _) = *pair_ptr; let (ptr, _) = *pair_ptr;
*ptr.offset(elem) = val; ptr.offset(index)
}
#[inline(always)]
unsafe fn unsafe_set(&self, index: uint, val: T) {
*self.unsafe_mut_ref(index) = val;
} }
} }

View File

@ -188,8 +188,10 @@ pub mod write {
return false; return false;
} }
pub fn run_passes(sess: Session, llmod: ModuleRef, pub fn run_passes(sess: Session,
output_type: output_type, output: &Path) { llmod: ModuleRef,
output_type: output_type,
output: &Path) {
unsafe { unsafe {
let opts = sess.opts; let opts = sess.opts;
if sess.time_llvm_passes() { llvm::LLVMRustEnableTimePasses(); } if sess.time_llvm_passes() { llvm::LLVMRustEnableTimePasses(); }

View File

@ -136,13 +136,17 @@ pub fn log_fn_time(ccx: @CrateContext, +name: ~str, start: time::Timespec,
ccx.stats.fn_times.push((name, elapsed)); ccx.stats.fn_times.push((name, elapsed));
} }
pub fn decl_fn(llmod: ModuleRef, name: &str, cc: lib::llvm::CallConv, pub fn decl_fn(llmod: ModuleRef,
llty: TypeRef) -> ValueRef { name: &str,
cc: lib::llvm::CallConv,
llty: TypeRef)
-> ValueRef {
let llfn: ValueRef = str::as_c_str(name, |buf| { let llfn: ValueRef = str::as_c_str(name, |buf| {
unsafe { unsafe {
llvm::LLVMGetOrInsertFunction(llmod, buf, llty) llvm::LLVMGetOrInsertFunction(llmod, buf, llty)
} }
}); });
lib::llvm::SetFunctionCallConv(llfn, cc); lib::llvm::SetFunctionCallConv(llfn, cc);
return llfn; return llfn;
} }
@ -478,17 +482,25 @@ pub fn note_unique_llvm_symbol(ccx: @CrateContext, sym: @~str) {
} }
pub fn get_res_dtor(ccx: @CrateContext, did: ast::def_id, pub fn get_res_dtor(ccx: @CrateContext,
parent_id: ast::def_id, substs: &[ty::t]) did: ast::def_id,
-> ValueRef { parent_id: ast::def_id,
substs: &[ty::t])
-> ValueRef {
let _icx = ccx.insn_ctxt("trans_res_dtor"); let _icx = ccx.insn_ctxt("trans_res_dtor");
if !substs.is_empty() { if !substs.is_empty() {
let did = if did.crate != ast::local_crate { let did = if did.crate != ast::local_crate {
inline::maybe_instantiate_inline(ccx, did, true) inline::maybe_instantiate_inline(ccx, did, true)
} else { did }; } else {
did
};
assert!(did.crate == ast::local_crate); assert!(did.crate == ast::local_crate);
let (val, _) = let (val, _) = monomorphize::monomorphic_fn(ccx,
monomorphize::monomorphic_fn(ccx, did, substs, None, None, None); did,
substs,
None,
None,
None);
val val
} else if did.crate == ast::local_crate { } else if did.crate == ast::local_crate {
@ -496,11 +508,16 @@ pub fn get_res_dtor(ccx: @CrateContext, did: ast::def_id,
} else { } else {
let tcx = ccx.tcx; let tcx = ccx.tcx;
let name = csearch::get_symbol(ccx.sess.cstore, did); let name = csearch::get_symbol(ccx.sess.cstore, did);
let class_ty = ty::subst_tps(tcx, substs, None, let class_ty = ty::subst_tps(tcx,
ty::lookup_item_type(tcx, parent_id).ty); substs,
None,
ty::lookup_item_type(tcx, parent_id).ty);
let llty = type_of_dtor(ccx, class_ty); let llty = type_of_dtor(ccx, class_ty);
let name = name.to_managed(); // :-( let name = name.to_managed(); // :-(
get_extern_fn(ccx.externs, ccx.llmod, name, lib::llvm::CCallConv, get_extern_fn(ccx.externs,
ccx.llmod,
name,
lib::llvm::CCallConv,
llty) llty)
} }
} }
@ -804,9 +821,12 @@ pub fn trans_external_path(ccx: @CrateContext, did: ast::def_id, t: ty::t)
}; };
} }
pub fn invoke(bcx: block, llfn: ValueRef, +llargs: ~[ValueRef]) -> block { pub fn invoke(bcx: block, llfn: ValueRef, +llargs: ~[ValueRef])
-> (ValueRef, block) {
let _icx = bcx.insn_ctxt("invoke_"); let _icx = bcx.insn_ctxt("invoke_");
if bcx.unreachable { return bcx; } if bcx.unreachable {
return (C_null(T_i8()), bcx);
}
match bcx.node_info { match bcx.node_info {
None => debug!("invoke at ???"), None => debug!("invoke at ???"),
@ -826,8 +846,12 @@ pub fn invoke(bcx: block, llfn: ValueRef, +llargs: ~[ValueRef]) -> block {
} }
} }
let normal_bcx = sub_block(bcx, ~"normal return"); let normal_bcx = sub_block(bcx, ~"normal return");
Invoke(bcx, llfn, llargs, normal_bcx.llbb, get_landing_pad(bcx)); let llresult = Invoke(bcx,
return normal_bcx; llfn,
llargs,
normal_bcx.llbb,
get_landing_pad(bcx));
return (llresult, normal_bcx);
} else { } else {
unsafe { unsafe {
debug!("calling %x at %x", debug!("calling %x at %x",
@ -837,8 +861,8 @@ pub fn invoke(bcx: block, llfn: ValueRef, +llargs: ~[ValueRef]) -> block {
debug!("arg: %x", ::core::cast::transmute(llarg)); debug!("arg: %x", ::core::cast::transmute(llarg));
} }
} }
Call(bcx, llfn, llargs); let llresult = Call(bcx, llfn, llargs);
return bcx; return (llresult, bcx);
} }
} }
@ -1568,6 +1592,18 @@ pub fn mk_standard_basic_blocks(llfn: ValueRef) -> BasicBlocks {
} }
} }
// Creates and returns space for, or returns the argument representing, the
// slot where the return value of the function must go.
pub fn make_return_pointer(fcx: fn_ctxt, output_type: ty::t) -> ValueRef {
unsafe {
if !ty::type_is_immediate(output_type) {
llvm::LLVMGetParam(fcx.llfn, 0)
} else {
let lloutputtype = type_of::type_of(*fcx.ccx, output_type);
alloca(raw_block(fcx, false, fcx.llstaticallocas), lloutputtype)
}
}
}
// NB: must keep 4 fns in sync: // NB: must keep 4 fns in sync:
// //
@ -1579,10 +1615,11 @@ pub fn new_fn_ctxt_w_id(ccx: @CrateContext,
+path: path, +path: path,
llfndecl: ValueRef, llfndecl: ValueRef,
id: ast::node_id, id: ast::node_id,
output_type: ty::t,
impl_id: Option<ast::def_id>, impl_id: Option<ast::def_id>,
param_substs: Option<@param_substs>, param_substs: Option<@param_substs>,
sp: Option<span>) -> fn_ctxt sp: Option<span>)
{ -> fn_ctxt {
for param_substs.each |p| { p.validate(); } for param_substs.each |p| { p.validate(); }
debug!("new_fn_ctxt_w_id(path=%s, id=%?, impl_id=%?, \ debug!("new_fn_ctxt_w_id(path=%s, id=%?, impl_id=%?, \
@ -1593,16 +1630,26 @@ pub fn new_fn_ctxt_w_id(ccx: @CrateContext,
param_substs.repr(ccx.tcx)); param_substs.repr(ccx.tcx));
let llbbs = mk_standard_basic_blocks(llfndecl); let llbbs = mk_standard_basic_blocks(llfndecl);
return @mut fn_ctxt_ {
let substd_output_type = match param_substs {
None => output_type,
Some(substs) => {
ty::subst_tps(ccx.tcx, substs.tys, substs.self_ty, output_type)
}
};
let is_immediate = ty::type_is_immediate(substd_output_type);
let fcx = @mut fn_ctxt_ {
llfn: llfndecl, llfn: llfndecl,
llenv: unsafe { llvm::LLVMGetParam(llfndecl, 1u as c_uint) }, llenv: unsafe { llvm::LLVMGetParam(llfndecl, 1u as c_uint) },
llretptr: unsafe { llvm::LLVMGetParam(llfndecl, 0u as c_uint) }, llretptr: None,
llstaticallocas: llbbs.sa, llstaticallocas: llbbs.sa,
llloadenv: None, llloadenv: None,
llreturn: llbbs.rt, llreturn: llbbs.rt,
llself: None, llself: None,
personality: None, personality: None,
loop_ret: None, loop_ret: None,
has_immediate_return_value: is_immediate,
llargs: @mut HashMap::new(), llargs: @mut HashMap::new(),
lllocals: @mut HashMap::new(), lllocals: @mut HashMap::new(),
llupvars: @mut HashMap::new(), llupvars: @mut HashMap::new(),
@ -1613,14 +1660,18 @@ pub fn new_fn_ctxt_w_id(ccx: @CrateContext,
path: path, path: path,
ccx: @ccx ccx: @ccx
}; };
fcx.llretptr = Some(make_return_pointer(fcx, substd_output_type));
fcx
} }
pub fn new_fn_ctxt(ccx: @CrateContext, pub fn new_fn_ctxt(ccx: @CrateContext,
+path: path, +path: path,
llfndecl: ValueRef, llfndecl: ValueRef,
output_type: ty::t,
sp: Option<span>) sp: Option<span>)
-> fn_ctxt { -> fn_ctxt {
return new_fn_ctxt_w_id(ccx, path, llfndecl, -1, None, None, sp); new_fn_ctxt_w_id(ccx, path, llfndecl, -1, output_type, None, None, sp)
} }
// NB: must keep 4 fns in sync: // NB: must keep 4 fns in sync:
@ -1639,7 +1690,8 @@ pub fn new_fn_ctxt(ccx: @CrateContext,
// field of the fn_ctxt with // field of the fn_ctxt with
pub fn create_llargs_for_fn_args(cx: fn_ctxt, pub fn create_llargs_for_fn_args(cx: fn_ctxt,
ty_self: self_arg, ty_self: self_arg,
args: &[ast::arg]) -> ~[ValueRef] { args: &[ast::arg])
-> ~[ValueRef] {
let _icx = cx.insn_ctxt("create_llargs_for_fn_args"); let _icx = cx.insn_ctxt("create_llargs_for_fn_args");
match ty_self { match ty_self {
@ -1745,8 +1797,19 @@ pub fn copy_args_to_allocas(fcx: fn_ctxt,
pub fn finish_fn(fcx: fn_ctxt, lltop: BasicBlockRef) { pub fn finish_fn(fcx: fn_ctxt, lltop: BasicBlockRef) {
let _icx = fcx.insn_ctxt("finish_fn"); let _icx = fcx.insn_ctxt("finish_fn");
tie_up_header_blocks(fcx, lltop); tie_up_header_blocks(fcx, lltop);
build_return_block(fcx);
}
// Builds the return block for a function.
pub fn build_return_block(fcx: fn_ctxt) {
let ret_cx = raw_block(fcx, false, fcx.llreturn); let ret_cx = raw_block(fcx, false, fcx.llreturn);
RetVoid(ret_cx);
// Return the value if this function immediate; otherwise, return void.
if fcx.has_immediate_return_value {
Ret(ret_cx, Load(ret_cx, fcx.llretptr.get()))
} else {
RetVoid(ret_cx)
}
} }
pub fn tie_up_header_blocks(fcx: fn_ctxt, lltop: BasicBlockRef) { pub fn tie_up_header_blocks(fcx: fn_ctxt, lltop: BasicBlockRef) {
@ -1777,6 +1840,7 @@ pub fn trans_closure(ccx: @CrateContext,
id: ast::node_id, id: ast::node_id,
impl_id: Option<ast::def_id>, impl_id: Option<ast::def_id>,
attributes: &[ast::attribute], attributes: &[ast::attribute],
output_type: ty::t,
maybe_load_env: &fn(fn_ctxt), maybe_load_env: &fn(fn_ctxt),
finish: &fn(block)) { finish: &fn(block)) {
ccx.stats.n_closures += 1; ccx.stats.n_closures += 1;
@ -1791,6 +1855,7 @@ pub fn trans_closure(ccx: @CrateContext,
path, path,
llfndecl, llfndecl,
id, id,
output_type,
impl_id, impl_id,
param_substs, param_substs,
Some(body.span)); Some(body.span));
@ -1833,7 +1898,8 @@ pub fn trans_closure(ccx: @CrateContext,
{ {
bcx = controlflow::trans_block(bcx, body, expr::Ignore); bcx = controlflow::trans_block(bcx, body, expr::Ignore);
} else { } else {
bcx = controlflow::trans_block(bcx, body, expr::SaveIn(fcx.llretptr)); let dest = expr::SaveIn(fcx.llretptr.get());
bcx = controlflow::trans_block(bcx, body, dest);
} }
finish(bcx); finish(bcx);
@ -1864,6 +1930,7 @@ pub fn trans_fn(ccx: @CrateContext,
let _icx = ccx.insn_ctxt("trans_fn"); let _icx = ccx.insn_ctxt("trans_fn");
ccx.stats.n_fns += 1; ccx.stats.n_fns += 1;
let the_path_str = path_str(ccx.sess, path); let the_path_str = path_str(ccx.sess, path);
let output_type = ty::ty_fn_ret(ty::node_id_to_type(ccx.tcx, id));
trans_closure(ccx, trans_closure(ccx,
path, path,
decl, decl,
@ -1874,6 +1941,7 @@ pub fn trans_fn(ccx: @CrateContext,
id, id,
impl_id, impl_id,
attrs, attrs,
output_type,
|fcx| { |fcx| {
if ccx.sess.opts.extra_debuginfo { if ccx.sess.opts.extra_debuginfo {
debuginfo::create_function(fcx); debuginfo::create_function(fcx);
@ -1907,26 +1975,39 @@ pub fn trans_enum_variant(ccx: @CrateContext,
id: varg.id, id: varg.id,
} }
}; };
let fcx = new_fn_ctxt_w_id(ccx, ~[], llfndecl, variant.node.id, None,
param_substs, None);
let raw_llargs = create_llargs_for_fn_args(fcx, no_self, fn_args);
let ty_param_substs = match param_substs { let ty_param_substs = match param_substs {
Some(ref substs) => { copy substs.tys } Some(ref substs) => { copy substs.tys }
None => ~[] None => ~[]
}; };
let enum_ty = ty::subst_tps(ccx.tcx,
ty_param_substs,
None,
ty::node_id_to_type(ccx.tcx, enum_id));
let fcx = new_fn_ctxt_w_id(ccx,
~[],
llfndecl,
variant.node.id,
enum_ty,
None,
param_substs,
None);
let raw_llargs = create_llargs_for_fn_args(fcx, no_self, fn_args);
let bcx = top_scope_block(fcx, None), lltop = bcx.llbb; let bcx = top_scope_block(fcx, None), lltop = bcx.llbb;
let arg_tys = ty::ty_fn_args(node_id_type(bcx, variant.node.id)); let arg_tys = ty::ty_fn_args(node_id_type(bcx, variant.node.id));
let bcx = copy_args_to_allocas(fcx, bcx, fn_args, raw_llargs, arg_tys); let bcx = copy_args_to_allocas(fcx, bcx, fn_args, raw_llargs, arg_tys);
// XXX is there a better way to reconstruct the ty::t? // XXX is there a better way to reconstruct the ty::t?
let enum_ty = ty::subst_tps(ccx.tcx, ty_param_substs, None,
ty::node_id_to_type(ccx.tcx, enum_id));
let repr = adt::represent_type(ccx, enum_ty); let repr = adt::represent_type(ccx, enum_ty);
adt::trans_start_init(bcx, repr, fcx.llretptr, disr); adt::trans_start_init(bcx, repr, fcx.llretptr.get(), disr);
for vec::eachi(args) |i, va| { for vec::eachi(args) |i, va| {
let lldestptr = adt::trans_field_ptr(bcx, repr, fcx.llretptr, let lldestptr = adt::trans_field_ptr(bcx,
disr, i); repr,
fcx.llretptr.get(),
disr,
i);
// If this argument to this function is a enum, it'll have come in to // If this argument to this function is a enum, it'll have come in to
// this function as an opaque blob due to the way that type_of() // this function as an opaque blob due to the way that type_of()
@ -1964,21 +2045,6 @@ pub fn trans_tuple_struct(ccx: @CrateContext,
} }
}; };
let fcx = new_fn_ctxt_w_id(ccx,
~[],
llfndecl,
ctor_id,
None,
param_substs,
None);
let raw_llargs = create_llargs_for_fn_args(fcx, no_self, fn_args);
let bcx = top_scope_block(fcx, None);
let lltop = bcx.llbb;
let arg_tys = ty::ty_fn_args(node_id_type(bcx, ctor_id));
let bcx = copy_args_to_allocas(fcx, bcx, fn_args, raw_llargs, arg_tys);
// XXX is there a better way to reconstruct the ty::t? // XXX is there a better way to reconstruct the ty::t?
let ty_param_substs = match param_substs { let ty_param_substs = match param_substs {
Some(ref substs) => { copy substs.tys } Some(ref substs) => { copy substs.tys }
@ -1992,10 +2058,31 @@ pub fn trans_tuple_struct(ccx: @CrateContext,
return type %s", return type %s",
ty_to_str(ccx.tcx, ctor_ty))) ty_to_str(ccx.tcx, ctor_ty)))
}; };
let fcx = new_fn_ctxt_w_id(ccx,
~[],
llfndecl,
ctor_id,
tup_ty,
None,
param_substs,
None);
let raw_llargs = create_llargs_for_fn_args(fcx, no_self, fn_args);
let bcx = top_scope_block(fcx, None);
let lltop = bcx.llbb;
let arg_tys = ty::ty_fn_args(node_id_type(bcx, ctor_id));
let bcx = copy_args_to_allocas(fcx, bcx, fn_args, raw_llargs, arg_tys);
let repr = adt::represent_type(ccx, tup_ty); let repr = adt::represent_type(ccx, tup_ty);
for fields.eachi |i, field| { for fields.eachi |i, field| {
let lldestptr = adt::trans_field_ptr(bcx, repr, fcx.llretptr, 0, i); let lldestptr = adt::trans_field_ptr(bcx,
repr,
fcx.llretptr.get(),
0,
i);
let llarg = match *fcx.llargs.get(&field.node.id) { let llarg = match *fcx.llargs.get(&field.node.id) {
local_mem(x) => x, local_mem(x) => x,
_ => { _ => {
@ -2095,10 +2182,12 @@ pub fn trans_item(ccx: @CrateContext, item: ast::item) {
if purity == ast::extern_fn { if purity == ast::extern_fn {
let llfndecl = get_item_val(ccx, item.id); let llfndecl = get_item_val(ccx, item.id);
foreign::trans_foreign_fn(ccx, foreign::trans_foreign_fn(ccx,
vec::append( vec::append(/*bad*/copy *path,
/*bad*/copy *path, ~[path_name(item.ident)]),
~[path_name(item.ident)]), decl,
decl, body, llfndecl, item.id); body,
llfndecl,
item.id);
} else if !generics.is_type_parameterized() { } else if !generics.is_type_parameterized() {
let llfndecl = get_item_val(ccx, item.id); let llfndecl = get_item_val(ccx, item.id);
trans_fn(ccx, trans_fn(ccx,
@ -2215,7 +2304,7 @@ pub fn register_fn_fuller(ccx: @CrateContext,
node_type: ty::t, node_type: ty::t,
cc: lib::llvm::CallConv, cc: lib::llvm::CallConv,
llfty: TypeRef) llfty: TypeRef)
-> ValueRef { -> ValueRef {
debug!("register_fn_fuller creating fn for item %d with path %s", debug!("register_fn_fuller creating fn for item %d with path %s",
node_id, node_id,
ast_map::path_to_str(path, ccx.sess.parse_sess.interner)); ast_map::path_to_str(path, ccx.sess.parse_sess.interner));
@ -2235,7 +2324,9 @@ pub fn register_fn_fuller(ccx: @CrateContext,
(!*ccx.sess.building_library || (!*ccx.sess.building_library ||
(*ccx.sess.building_library && (*ccx.sess.building_library &&
ccx.sess.targ_cfg.os == session::os_android)); ccx.sess.targ_cfg.os == session::os_android));
if is_entry { create_entry_wrapper(ccx, sp, llfn); } if is_entry {
create_entry_wrapper(ccx, sp, llfn);
}
llfn llfn
} }
@ -2264,23 +2355,26 @@ pub fn create_entry_wrapper(ccx: @CrateContext,
let llfdecl = decl_fn(ccx.llmod, ~"_rust_main", let llfdecl = decl_fn(ccx.llmod, ~"_rust_main",
lib::llvm::CCallConv, llfty); lib::llvm::CCallConv, llfty);
let fcx = new_fn_ctxt(ccx, ~[], llfdecl, None); let fcx = new_fn_ctxt(ccx, ~[], llfdecl, nt, None);
let bcx = top_scope_block(fcx, None); let bcx = top_scope_block(fcx, None);
let lltop = bcx.llbb; let lltop = bcx.llbb;
// Call main. // Call main.
let lloutputarg = unsafe { llvm::LLVMGetParam(llfdecl, 0 as c_uint) }; let lloutputarg = C_null(T_ptr(T_i8()));
let llenvarg = unsafe { llvm::LLVMGetParam(llfdecl, 1 as c_uint) }; let llenvarg = unsafe { llvm::LLVMGetParam(llfdecl, 1 as c_uint) };
let mut args = ~[lloutputarg, llenvarg]; let mut args = ~[lloutputarg, llenvarg];
Call(bcx, main_llfn, args); let llresult = Call(bcx, main_llfn, args);
Store(bcx, llresult, fcx.llretptr.get());
build_return(bcx); build_return(bcx);
finish_fn(fcx, lltop); finish_fn(fcx, lltop);
return llfdecl; return llfdecl;
} }
fn create_entry_fn(ccx: @CrateContext, rust_main: ValueRef, use_start_lang_item:bool) { fn create_entry_fn(ccx: @CrateContext,
rust_main: ValueRef,
use_start_lang_item: bool) {
let llfty = T_fn(~[ccx.int_type, T_ptr(T_ptr(T_i8()))], ccx.int_type); let llfty = T_fn(~[ccx.int_type, T_ptr(T_ptr(T_i8()))], ccx.int_type);
// FIXME #4404 android JNI hacks // FIXME #4404 android JNI hacks
@ -2301,58 +2395,70 @@ pub fn create_entry_wrapper(ccx: @CrateContext,
let bld = ccx.builder.B; let bld = ccx.builder.B;
unsafe { unsafe {
llvm::LLVMPositionBuilderAtEnd(bld, llbb); llvm::LLVMPositionBuilderAtEnd(bld, llbb);
}
let retptr = unsafe { let crate_map = ccx.crate_map;
llvm::LLVMBuildAlloca(bld, ccx.int_type, noname())
};
let crate_map = ccx.crate_map;
let opaque_crate_map = unsafe {llvm::LLVMBuildPointerCast(
bld, crate_map, T_ptr(T_i8()), noname())};
let (start_fn, args) = if use_start_lang_item {
let start_def_id = ccx.tcx.lang_items.start_fn(); let start_def_id = ccx.tcx.lang_items.start_fn();
let start_fn = if start_def_id.crate == ast::local_crate { let start_fn = if start_def_id.crate == ast::local_crate {
ccx.sess.bug(~"start lang item is never in the local crate") ccx.sess.bug(~"start lang item is never in the local crate")
} else { } else {
let start_fn_type = csearch::get_type(ccx.tcx, let start_fn_type = csearch::get_type(ccx.tcx,
start_def_id).ty; start_def_id).ty;
trans_external_path(ccx, start_def_id, start_fn_type) trans_external_path(ccx, start_def_id, start_fn_type)
}; };
let args = unsafe { let retptr = llvm::LLVMBuildAlloca(bld, T_i8(), noname());
let opaque_rust_main = llvm::LLVMBuildPointerCast(
bld, rust_main, T_ptr(T_i8()), noname());
~[ let crate_map = ccx.crate_map;
retptr, let opaque_crate_map = llvm::LLVMBuildPointerCast(bld,
C_null(T_opaque_box_ptr(ccx)), crate_map,
opaque_rust_main, T_ptr(T_i8()),
llvm::LLVMGetParam(llfn, 0 as c_uint), noname());
llvm::LLVMGetParam(llfn, 1 as c_uint),
opaque_crate_map let (start_fn, args) = if use_start_lang_item {
] let start_def_id = ccx.tcx.lang_items.start_fn();
}; let start_fn = if start_def_id.crate == ast::local_crate {
(start_fn, args) ccx.sess.bug(~"start lang item is never in the local \
} else { crate")
debug!("using user-defined start fn"); } else {
let args = unsafe { let start_fn_type = csearch::get_type(ccx.tcx,
~[ retptr, start_def_id).ty;
C_null(T_opaque_box_ptr(ccx)), trans_external_path(ccx, start_def_id, start_fn_type)
llvm::LLVMGetParam(llfn, 0 as c_uint), };
llvm::LLVMGetParam(llfn, 1 as c_uint),
opaque_crate_map let args = {
] let opaque_rust_main = llvm::LLVMBuildPointerCast(
bld, rust_main, T_ptr(T_i8()), noname());
~[
retptr,
C_null(T_opaque_box_ptr(ccx)),
opaque_rust_main,
llvm::LLVMGetParam(llfn, 0),
llvm::LLVMGetParam(llfn, 1),
opaque_crate_map
]
};
(start_fn, args)
} else {
debug!("using user-defined start fn");
let args = {
~[
retptr,
C_null(T_opaque_box_ptr(ccx)),
llvm::LLVMGetParam(llfn, 0 as c_uint),
llvm::LLVMGetParam(llfn, 1 as c_uint),
opaque_crate_map
]
};
(rust_main, args)
}; };
(rust_main, args) let result = llvm::LLVMBuildCall(bld,
}; start_fn,
&args[0],
unsafe { args.len() as c_uint,
llvm::LLVMBuildCall(bld, start_fn, vec::raw::to_ptr(args), noname());
args.len() as c_uint, noname());
let result = llvm::LLVMBuildLoad(bld, retptr, noname());
llvm::LLVMBuildRet(bld, result); llvm::LLVMBuildRet(bld, result);
} }
} }
@ -2423,7 +2529,6 @@ pub fn get_item_val(ccx: @CrateContext, id: ast::node_id) -> ValueRef {
match ccx.item_vals.find(&id) { match ccx.item_vals.find(&id) {
Some(&v) => v, Some(&v) => v,
None => { None => {
let mut exprt = false; let mut exprt = false;
let val = match *ccx.tcx.items.get(&id) { let val = match *ccx.tcx.items.get(&id) {
ast_map::node_item(i, pth) => { ast_map::node_item(i, pth) => {
@ -2515,10 +2620,10 @@ pub fn get_item_val(ccx: @CrateContext, id: ast::node_id) -> ValueRef {
assert!(!ty::type_has_params(class_ty)); assert!(!ty::type_has_params(class_ty));
let lldty = unsafe { let lldty = unsafe {
T_fn(~[ T_fn(~[
T_ptr(type_of(ccx, ty::mk_nil(tcx))), T_ptr(T_i8()),
T_ptr(type_of(ccx, class_ty)) T_ptr(type_of(ccx, class_ty))
], ],
llvm::LLVMVoidType()) T_nil())
}; };
let s = get_dtor_symbol(ccx, /*bad*/copy *pt, dt.node.id, None); let s = get_dtor_symbol(ccx, /*bad*/copy *pt, dt.node.id, None);

View File

@ -181,9 +181,15 @@ pub fn noname() -> *libc::c_char {
} }
} }
pub fn Invoke(cx: block, Fn: ValueRef, Args: &[ValueRef], pub fn Invoke(cx: block,
Then: BasicBlockRef, Catch: BasicBlockRef) { Fn: ValueRef,
if cx.unreachable { return; } Args: &[ValueRef],
Then: BasicBlockRef,
Catch: BasicBlockRef)
-> ValueRef {
if cx.unreachable {
return C_null(T_i8());
}
check_not_terminated(cx); check_not_terminated(cx);
terminate(cx, "Invoke"); terminate(cx, "Invoke");
debug!("Invoke(%s with arguments (%s))", debug!("Invoke(%s with arguments (%s))",
@ -193,9 +199,13 @@ pub fn Invoke(cx: block, Fn: ValueRef, Args: &[ValueRef],
~", ")); ~", "));
unsafe { unsafe {
count_insn(cx, "invoke"); count_insn(cx, "invoke");
llvm::LLVMBuildInvoke(B(cx), Fn, vec::raw::to_ptr(Args), llvm::LLVMBuildInvoke(B(cx),
Args.len() as c_uint, Then, Catch, Fn,
noname()); vec::raw::to_ptr(Args),
Args.len() as c_uint,
Then,
Catch,
noname())
} }
} }

View File

@ -13,6 +13,7 @@ use middle::trans::base::*;
use middle::trans::build::*; use middle::trans::build::*;
use middle::trans::common::*; use middle::trans::common::*;
use core::io::println;
use core::libc::c_uint; use core::libc::c_uint;
use core::option; use core::option;
use core::vec; use core::vec;
@ -92,16 +93,19 @@ pub impl FnType {
return llargvals; return llargvals;
} }
fn build_shim_ret(&self, bcx: block, fn build_shim_ret(&self,
arg_tys: &[TypeRef], ret_def: bool, bcx: block,
llargbundle: ValueRef, llretval: ValueRef) { arg_tys: &[TypeRef],
ret_def: bool,
llargbundle: ValueRef,
llretval: ValueRef) {
for vec::eachi(self.attrs) |i, a| { for vec::eachi(self.attrs) |i, a| {
match *a { match *a {
option::Some(attr) => { option::Some(attr) => {
unsafe { unsafe {
llvm::LLVMAddInstrAttribute( llvm::LLVMAddInstrAttribute(llretval,
llretval, (i + 1u) as c_uint, (i + 1u) as c_uint,
attr as c_uint); attr as c_uint);
} }
} }
_ => () _ => ()
@ -125,8 +129,11 @@ pub impl FnType {
}; };
} }
fn build_wrap_args(&self, bcx: block, ret_ty: TypeRef, fn build_wrap_args(&self,
llwrapfn: ValueRef, llargbundle: ValueRef) { bcx: block,
ret_ty: TypeRef,
llwrapfn: ValueRef,
llargbundle: ValueRef) {
let mut atys = /*bad*/copy self.arg_tys; let mut atys = /*bad*/copy self.arg_tys;
let mut attrs = /*bad*/copy self.attrs; let mut attrs = /*bad*/copy self.attrs;
let mut j = 0u; let mut j = 0u;
@ -161,22 +168,27 @@ pub impl FnType {
store_inbounds(bcx, llretptr, llargbundle, [0u, n]); store_inbounds(bcx, llretptr, llargbundle, [0u, n]);
} }
fn build_wrap_ret(&self, bcx: block, fn build_wrap_ret(&self,
arg_tys: &[TypeRef], llargbundle: ValueRef) { bcx: block,
arg_tys: &[TypeRef],
llargbundle: ValueRef) {
unsafe { unsafe {
if llvm::LLVMGetTypeKind(self.ret_ty.ty) == Void { if llvm::LLVMGetTypeKind(self.ret_ty.ty) == Void {
RetVoid(bcx);
return; return;
} }
} }
let n = vec::len(arg_tys);
let llretval = load_inbounds(bcx, llargbundle, ~[0u, n]); let llretval = load_inbounds(bcx, llargbundle, ~[ 0, arg_tys.len() ]);
let llretval = if self.ret_ty.cast { let llretval = if self.ret_ty.cast {
let retptr = BitCast(bcx, llretval, T_ptr(self.ret_ty.ty)); let retptr = BitCast(bcx, llretval, T_ptr(self.ret_ty.ty));
Load(bcx, retptr) Load(bcx, retptr)
} else { } else {
Load(bcx, llretval) Load(bcx, llretval)
}; };
Ret(bcx, llretval); let llretptr = BitCast(bcx,
bcx.fcx.llretptr.get(),
T_ptr(self.ret_ty.ty));
Store(bcx, llretval, llretptr);
} }
} }

View File

@ -314,11 +314,16 @@ pub fn trans_call(in_cx: block,
args: CallArgs, args: CallArgs,
id: ast::node_id, id: ast::node_id,
dest: expr::Dest) dest: expr::Dest)
-> block { -> block {
let _icx = in_cx.insn_ctxt("trans_call"); let _icx = in_cx.insn_ctxt("trans_call");
trans_call_inner( trans_call_inner(in_cx,
in_cx, call_ex.info(), expr_ty(in_cx, f), node_id_type(in_cx, id), call_ex.info(),
|cx| trans(cx, f), args, dest, DontAutorefArg) expr_ty(in_cx, f),
node_id_type(in_cx, id),
|cx| trans(cx, f),
args,
dest,
DontAutorefArg)
} }
pub fn trans_method_call(in_cx: block, pub fn trans_method_call(in_cx: block,
@ -326,7 +331,7 @@ pub fn trans_method_call(in_cx: block,
rcvr: @ast::expr, rcvr: @ast::expr,
args: CallArgs, args: CallArgs,
dest: expr::Dest) dest: expr::Dest)
-> block { -> block {
let _icx = in_cx.insn_ctxt("trans_method_call"); let _icx = in_cx.insn_ctxt("trans_method_call");
debug!("trans_method_call(call_ex=%s, rcvr=%s)", debug!("trans_method_call(call_ex=%s, rcvr=%s)",
call_ex.repr(in_cx.tcx()), call_ex.repr(in_cx.tcx()),
@ -439,15 +444,15 @@ pub fn body_contains_ret(body: &ast::blk) -> bool {
} }
// See [Note-arg-mode] // See [Note-arg-mode]
pub fn trans_call_inner( pub fn trans_call_inner(++in_cx: block,
++in_cx: block, call_info: Option<NodeInfo>,
call_info: Option<NodeInfo>, fn_expr_ty: ty::t,
fn_expr_ty: ty::t, ret_ty: ty::t,
ret_ty: ty::t, get_callee: &fn(block) -> Callee,
get_callee: &fn(block) -> Callee, args: CallArgs,
args: CallArgs, dest: expr::Dest,
dest: expr::Dest, autoref_arg: AutorefArg)
autoref_arg: AutorefArg) -> block { -> block {
do base::with_scope(in_cx, call_info, ~"call") |cx| { do base::with_scope(in_cx, call_info, ~"call") |cx| {
let ret_in_loop = match args { let ret_in_loop = match args {
ArgExprs(args) => { ArgExprs(args) => {
@ -500,7 +505,15 @@ pub fn trans_call_inner(
let llretslot = trans_ret_slot(bcx, fn_expr_ty, dest); let llretslot = trans_ret_slot(bcx, fn_expr_ty, dest);
let mut llargs = ~[]; let mut llargs = ~[];
llargs.push(llretslot);
if ty::type_is_immediate(ret_ty) {
unsafe {
llargs.push(llvm::LLVMGetUndef(T_ptr(T_i8())));
}
} else {
llargs.push(llretslot);
}
llargs.push(llenv); llargs.push(llenv);
bcx = trans_args(bcx, args, fn_expr_ty, bcx = trans_args(bcx, args, fn_expr_ty,
ret_flag, autoref_arg, &mut llargs); ret_flag, autoref_arg, &mut llargs);
@ -527,17 +540,34 @@ pub fn trans_call_inner(
// If the block is terminated, then one or more of the args // If the block is terminated, then one or more of the args
// has type _|_. Since that means it diverges, the code for // has type _|_. Since that means it diverges, the code for
// the call itself is unreachable. // the call itself is unreachable.
bcx = base::invoke(bcx, llfn, llargs); let (llresult, new_bcx) = base::invoke(bcx, llfn, llargs);
match dest { // drop the value if it is not being saved. bcx = new_bcx;
match dest {
expr::Ignore => { expr::Ignore => {
// drop the value if it is not being saved.
unsafe { unsafe {
if llvm::LLVMIsUndef(llretslot) != lib::llvm::True { if llvm::LLVMIsUndef(llretslot) != lib::llvm::True {
bcx = glue::drop_ty(bcx, llretslot, ret_ty); if ty::type_is_immediate(ret_ty) {
let llscratchptr = alloc_ty(bcx, ret_ty);
Store(bcx, llresult, llscratchptr);
bcx = glue::drop_ty(bcx, llscratchptr, ret_ty);
} else {
bcx = glue::drop_ty(bcx, llretslot, ret_ty);
}
} }
} }
} }
expr::SaveIn(_) => { } expr::SaveIn(lldest) => {
// If this is an immediate, store into the result location.
// (If this was not an immediate, the result will already be
// directly written into the output slot.)
if ty::type_is_immediate(ret_ty) {
Store(bcx, llresult, lldest);
}
}
} }
if ty::type_is_bot(ret_ty) { if ty::type_is_bot(ret_ty) {
Unreachable(bcx); Unreachable(bcx);
} else if ret_in_loop { } else if ret_in_loop {
@ -545,7 +575,7 @@ pub fn trans_call_inner(
bcx = do with_cond(bcx, ret_flag_result) |bcx| { bcx = do with_cond(bcx, ret_flag_result) |bcx| {
for (copy bcx.fcx.loop_ret).each |&(flagptr, _)| { for (copy bcx.fcx.loop_ret).each |&(flagptr, _)| {
Store(bcx, C_bool(true), flagptr); Store(bcx, C_bool(true), flagptr);
Store(bcx, C_bool(false), bcx.fcx.llretptr); Store(bcx, C_bool(false), bcx.fcx.llretptr.get());
} }
base::cleanup_and_leave(bcx, None, Some(bcx.fcx.llreturn)); base::cleanup_and_leave(bcx, None, Some(bcx.fcx.llreturn));
Unreachable(bcx); Unreachable(bcx);
@ -562,11 +592,10 @@ pub enum CallArgs<'self> {
ArgVals(&'self [ValueRef]) ArgVals(&'self [ValueRef])
} }
pub fn trans_ret_slot(+bcx: block, pub fn trans_ret_slot(+bcx: block, +fn_ty: ty::t, +dest: expr::Dest)
+fn_ty: ty::t, -> ValueRef {
+dest: expr::Dest) -> ValueRef
{
let retty = ty::ty_fn_ret(fn_ty); let retty = ty::ty_fn_ret(fn_ty);
match dest { match dest {
expr::SaveIn(dst) => dst, expr::SaveIn(dst) => dst,
expr::Ignore => { expr::Ignore => {

View File

@ -299,7 +299,7 @@ pub fn build_closure(bcx0: block,
// the right thing): // the right thing):
let ret_true = match bcx.fcx.loop_ret { let ret_true = match bcx.fcx.loop_ret {
Some((_, retptr)) => retptr, Some((_, retptr)) => retptr,
None => bcx.fcx.llretptr None => bcx.fcx.llretptr.get()
}; };
let ret_casted = PointerCast(bcx, ret_true, T_ptr(T_nil())); let ret_casted = PointerCast(bcx, ret_true, T_ptr(T_nil()));
let ret_datum = Datum {val: ret_casted, ty: ty::mk_nil(tcx), let ret_datum = Datum {val: ret_casted, ty: ty::mk_nil(tcx),
@ -367,8 +367,7 @@ pub fn trans_expr_fn(bcx: block,
outer_id: ast::node_id, outer_id: ast::node_id,
user_id: ast::node_id, user_id: ast::node_id,
is_loop_body: Option<Option<ValueRef>>, is_loop_body: Option<Option<ValueRef>>,
dest: expr::Dest) -> block dest: expr::Dest) -> block {
{
/*! /*!
* *
* Translates the body of a closure expression. * Translates the body of a closure expression.
@ -400,7 +399,9 @@ pub fn trans_expr_fn(bcx: block,
let ccx = bcx.ccx(); let ccx = bcx.ccx();
let fty = node_id_type(bcx, outer_id); let fty = node_id_type(bcx, outer_id);
let llfnty = type_of_fn_from_ty(ccx, fty); let llfnty = type_of_fn_from_ty(ccx, fty);
let sub_path = vec::append_one(/*bad*/copy bcx.fcx.path, let sub_path = vec::append_one(/*bad*/copy bcx.fcx.path,
path_name(special_idents::anon)); path_name(special_idents::anon));
// XXX: Bad copy. // XXX: Bad copy.
@ -418,6 +419,12 @@ pub fn trans_expr_fn(bcx: block,
set_inline_hint(llfn); set_inline_hint(llfn);
} }
let real_return_type = if is_loop_body.is_some() {
ty::mk_bool(bcx.tcx())
} else {
ty::ty_fn_ret(fty)
};
let Result {bcx: bcx, val: closure} = match sigil { let Result {bcx: bcx, val: closure} = match sigil {
ast::BorrowedSigil | ast::ManagedSigil | ast::OwnedSigil => { ast::BorrowedSigil | ast::ManagedSigil | ast::OwnedSigil => {
let cap_vars = *ccx.maps.capture_map.get(&user_id); let cap_vars = *ccx.maps.capture_map.get(&user_id);
@ -435,11 +442,14 @@ pub fn trans_expr_fn(bcx: block,
user_id, user_id,
None, None,
[], [],
real_return_type,
|fcx| load_environment(fcx, cdata_ty, cap_vars, |fcx| load_environment(fcx, cdata_ty, cap_vars,
ret_handle.is_some(), sigil), ret_handle.is_some(), sigil),
|bcx| { |bcx| {
if is_loop_body.is_some() { if is_loop_body.is_some() {
Store(bcx, C_bool(true), bcx.fcx.llretptr); Store(bcx,
C_bool(true),
bcx.fcx.llretptr.get());
} }
}); });
rslt(bcx, llbox) rslt(bcx, llbox)

View File

@ -291,10 +291,15 @@ pub struct fn_ctxt_ {
// section of the executable we're generating. // section of the executable we're generating.
llfn: ValueRef, llfn: ValueRef,
// The two implicit arguments that arrive in the function we're creating. // The implicit environment argument that arrives in the function we're
// For instance, foo(int, int) is really foo(ret*, env*, int, int). // creating.
llenv: ValueRef, llenv: ValueRef,
llretptr: ValueRef,
// The place to store the return value. If the return type is immediate,
// this is an alloca in the function. Otherwise, it's the hidden first
// parameter to the function. After function construction, this should
// always be Some.
llretptr: Option<ValueRef>,
// These elements: "hoisted basic blocks" containing // These elements: "hoisted basic blocks" containing
// administrative activities that have to happen in only one place in // administrative activities that have to happen in only one place in
@ -322,6 +327,11 @@ pub struct fn_ctxt_ {
// for that (flagptr, retptr) // for that (flagptr, retptr)
loop_ret: Option<(ValueRef, ValueRef)>, loop_ret: Option<(ValueRef, ValueRef)>,
// True if this function has an immediate return value, false otherwise.
// If this is false, the llretptr will alias the first argument of the
// function.
has_immediate_return_value: bool,
// Maps arguments to allocas created for them in llallocas. // Maps arguments to allocas created for them in llallocas.
llargs: @mut HashMap<ast::node_id, local_val>, llargs: @mut HashMap<ast::node_id, local_val>,
// Maps the def_ids for local variables to the allocas created for // Maps the def_ids for local variables to the allocas created for

View File

@ -274,7 +274,7 @@ pub fn trans_break_cont(bcx: block,
Some(bcx) => bcx, Some(bcx) => bcx,
// This is a return from a loop body block // This is a return from a loop body block
None => { None => {
Store(bcx, C_bool(!to_end), bcx.fcx.llretptr); Store(bcx, C_bool(!to_end), bcx.fcx.llretptr.get());
cleanup_and_leave(bcx, None, Some(bcx.fcx.llreturn)); cleanup_and_leave(bcx, None, Some(bcx.fcx.llreturn));
Unreachable(bcx); Unreachable(bcx);
return bcx; return bcx;
@ -303,14 +303,14 @@ pub fn trans_ret(bcx: block, e: Option<@ast::expr>) -> block {
// to false, return flag to true, and then store the value in the // to false, return flag to true, and then store the value in the
// parent's retptr. // parent's retptr.
Store(bcx, C_bool(true), flagptr); Store(bcx, C_bool(true), flagptr);
Store(bcx, C_bool(false), bcx.fcx.llretptr); Store(bcx, C_bool(false), bcx.fcx.llretptr.get());
match e { match e {
Some(x) => PointerCast(bcx, retptr, Some(x) => PointerCast(bcx, retptr,
T_ptr(type_of(bcx.ccx(), expr_ty(bcx, x)))), T_ptr(type_of(bcx.ccx(), expr_ty(bcx, x)))),
None => retptr None => retptr
} }
} }
None => bcx.fcx.llretptr None => bcx.fcx.llretptr.get()
}; };
match e { match e {
Some(x) => { Some(x) => {

View File

@ -31,7 +31,7 @@
* value stored in the datum is indicated in the field `ty`. * value stored in the datum is indicated in the field `ty`.
* *
* Generally speaking, you probably do not want to access the `val` field * Generally speaking, you probably do not want to access the `val` field
* unless you know what mode the value is in. Intead you should use one * unless you know what mode the value is in. Instead you should use one
* of the following accessors: * of the following accessors:
* *
* - `to_value_llval()` converts to by-value * - `to_value_llval()` converts to by-value

View File

@ -624,10 +624,14 @@ fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr,
let sigil = ty::ty_closure_sigil(expr_ty); let sigil = ty::ty_closure_sigil(expr_ty);
match blk.node { match blk.node {
ast::expr_fn_block(ref decl, ref body) => { ast::expr_fn_block(ref decl, ref body) => {
return closure::trans_expr_fn(bcx, sigil, return closure::trans_expr_fn(bcx,
decl, body, sigil,
expr.id, blk.id, decl,
Some(None), dest); body,
expr.id,
blk.id,
Some(None),
dest);
} }
_ => { _ => {
bcx.sess().impossible_case( bcx.sess().impossible_case(
@ -655,15 +659,30 @@ fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr,
} }
ast::expr_binary(_, lhs, rhs) => { ast::expr_binary(_, lhs, rhs) => {
// if not overloaded, would be RvalueDatumExpr // if not overloaded, would be RvalueDatumExpr
return trans_overloaded_op(bcx, expr, lhs, ~[rhs], dest); return trans_overloaded_op(bcx,
expr,
lhs,
~[rhs],
expr_ty(bcx, expr),
dest);
} }
ast::expr_unary(_, subexpr) => { ast::expr_unary(_, subexpr) => {
// if not overloaded, would be RvalueDatumExpr // if not overloaded, would be RvalueDatumExpr
return trans_overloaded_op(bcx, expr, subexpr, ~[], dest); return trans_overloaded_op(bcx,
expr,
subexpr,
~[],
expr_ty(bcx, expr),
dest);
} }
ast::expr_index(base, idx) => { ast::expr_index(base, idx) => {
// if not overloaded, would be RvalueDatumExpr // if not overloaded, would be RvalueDatumExpr
return trans_overloaded_op(bcx, expr, base, ~[idx], dest); return trans_overloaded_op(bcx,
expr,
base,
~[idx],
expr_ty(bcx, expr),
dest);
} }
ast::expr_cast(val, _) => { ast::expr_cast(val, _) => {
match ty::get(node_id_type(bcx, expr.id)).sty { match ty::get(node_id_type(bcx, expr.id)).sty {
@ -1554,15 +1573,24 @@ fn trans_overloaded_op(bcx: block,
expr: @ast::expr, expr: @ast::expr,
rcvr: @ast::expr, rcvr: @ast::expr,
+args: ~[@ast::expr], +args: ~[@ast::expr],
dest: Dest) -> block ret_ty: ty::t,
{ dest: Dest)
-> block {
let origin = *bcx.ccx().maps.method_map.get(&expr.id); let origin = *bcx.ccx().maps.method_map.get(&expr.id);
let fty = node_id_type(bcx, expr.callee_id); let fty = node_id_type(bcx, expr.callee_id);
return callee::trans_call_inner( callee::trans_call_inner(bcx,
bcx, expr.info(), fty, expr.info(),
expr_ty(bcx, expr), fty,
|bcx| meth::trans_method_callee(bcx, expr.callee_id, rcvr, origin), ret_ty,
callee::ArgExprs(args), dest, DoAutorefArg); |bcx| {
meth::trans_method_callee(bcx,
expr.callee_id,
rcvr,
origin)
},
callee::ArgExprs(args),
dest,
DoAutorefArg)
} }
fn int_cast(bcx: block, lldsttype: TypeRef, llsrctype: TypeRef, fn int_cast(bcx: block, lldsttype: TypeRef, llsrctype: TypeRef,
@ -1697,7 +1725,11 @@ fn trans_assign_op(bcx: block,
if bcx.ccx().maps.method_map.find(&expr.id).is_some() { if bcx.ccx().maps.method_map.find(&expr.id).is_some() {
// FIXME(#2528) evaluates the receiver twice!! // FIXME(#2528) evaluates the receiver twice!!
let scratch = scratch_datum(bcx, dst_datum.ty, false); let scratch = scratch_datum(bcx, dst_datum.ty, false);
let bcx = trans_overloaded_op(bcx, expr, dst, ~[src], let bcx = trans_overloaded_op(bcx,
expr,
dst,
~[src],
dst_datum.ty,
SaveIn(scratch.val)); SaveIn(scratch.val));
return scratch.move_to_datum(bcx, DROP_EXISTING, dst_datum); return scratch.move_to_datum(bcx, DROP_EXISTING, dst_datum);
} }

View File

@ -83,10 +83,11 @@ struct ShimTypes {
struct LlvmSignature { struct LlvmSignature {
llarg_tys: ~[TypeRef], llarg_tys: ~[TypeRef],
llret_ty: TypeRef, llret_ty: TypeRef,
sret: bool,
} }
fn foreign_signature(ccx: @CrateContext, fn foreign_signature(ccx: @CrateContext, fn_sig: &ty::FnSig)
fn_sig: &ty::FnSig) -> LlvmSignature { -> LlvmSignature {
/*! /*!
* The ForeignSignature is the LLVM types of the arguments/return type * The ForeignSignature is the LLVM types of the arguments/return type
* of a function. Note that these LLVM types are not quite the same * of a function. Note that these LLVM types are not quite the same
@ -97,7 +98,11 @@ fn foreign_signature(ccx: @CrateContext,
let llarg_tys = fn_sig.inputs.map(|arg| type_of(ccx, arg.ty)); let llarg_tys = fn_sig.inputs.map(|arg| type_of(ccx, arg.ty));
let llret_ty = type_of::type_of(ccx, fn_sig.output); let llret_ty = type_of::type_of(ccx, fn_sig.output);
LlvmSignature {llarg_tys: llarg_tys, llret_ty: llret_ty} LlvmSignature {
llarg_tys: llarg_tys,
llret_ty: llret_ty,
sret: !ty::type_is_immediate(fn_sig.output),
}
} }
fn shim_types(ccx: @CrateContext, id: ast::node_id) -> ShimTypes { fn shim_types(ccx: @CrateContext, id: ast::node_id) -> ShimTypes {
@ -109,20 +114,17 @@ fn shim_types(ccx: @CrateContext, id: ast::node_id) -> ShimTypes {
let bundle_ty = T_struct(vec::append_one(copy llsig.llarg_tys, let bundle_ty = T_struct(vec::append_one(copy llsig.llarg_tys,
T_ptr(llsig.llret_ty)), T_ptr(llsig.llret_ty)),
false); false);
let ret_def = let ret_def = !ty::type_is_bot(fn_sig.output) &&
!ty::type_is_bot(fn_sig.output) && !ty::type_is_nil(fn_sig.output);
!ty::type_is_nil(fn_sig.output); let fn_ty = abi_info(ccx).compute_info(llsig.llarg_tys,
let fn_ty = llsig.llret_ty,
abi_info(ccx).compute_info( ret_def);
llsig.llarg_tys,
llsig.llret_ty,
ret_def);
ShimTypes { ShimTypes {
fn_sig: fn_sig, fn_sig: fn_sig,
llsig: llsig, llsig: llsig,
ret_def: ret_def, ret_def: ret_def,
bundle_ty: bundle_ty, bundle_ty: bundle_ty,
shim_fn_ty: T_fn(~[T_ptr(bundle_ty)], T_void()), shim_fn_ty: T_fn(~[T_ptr(bundle_ty)], T_nil()),
fn_ty: fn_ty fn_ty: fn_ty
} }
} }
@ -142,13 +144,13 @@ fn build_shim_fn_(ccx: @CrateContext,
tys: &ShimTypes, tys: &ShimTypes,
cc: lib::llvm::CallConv, cc: lib::llvm::CallConv,
arg_builder: shim_arg_builder, arg_builder: shim_arg_builder,
ret_builder: shim_ret_builder) -> ValueRef ret_builder: shim_ret_builder)
{ -> ValueRef {
let llshimfn = decl_internal_cdecl_fn( let llshimfn = decl_internal_cdecl_fn(
ccx.llmod, shim_name, tys.shim_fn_ty); ccx.llmod, shim_name, tys.shim_fn_ty);
// Declare the body of the shim function: // Declare the body of the shim function:
let fcx = new_fn_ctxt(ccx, ~[], llshimfn, None); let fcx = new_fn_ctxt(ccx, ~[], llshimfn, tys.fn_sig.output, None);
let bcx = top_scope_block(fcx, None); let bcx = top_scope_block(fcx, None);
let lltop = bcx.llbb; let lltop = bcx.llbb;
let llargbundle = get_param(llshimfn, 0u); let llargbundle = get_param(llshimfn, 0u);
@ -159,19 +161,24 @@ fn build_shim_fn_(ccx: @CrateContext,
ret_builder(bcx, tys, llargbundle, llretval); ret_builder(bcx, tys, llargbundle, llretval);
build_return(bcx); // Don't finish up the function in the usual way, because this doesn't
finish_fn(fcx, lltop); // follow the normal Rust calling conventions.
tie_up_header_blocks(fcx, lltop);
let ret_cx = raw_block(fcx, false, fcx.llreturn);
Ret(ret_cx, C_null(T_nil()));
return llshimfn; return llshimfn;
} }
type wrap_arg_builder<'self> = type wrap_arg_builder<'self> = &'self fn(bcx: block,
&'self fn(bcx: block, tys: &ShimTypes, tys: &ShimTypes,
llwrapfn: ValueRef, llargbundle: ValueRef); llwrapfn: ValueRef,
llargbundle: ValueRef);
type wrap_ret_builder<'self> = type wrap_ret_builder<'self> = &'self fn(bcx: block,
&'self fn(bcx: block, tys: &ShimTypes, tys: &ShimTypes,
llargbundle: ValueRef); llargbundle: ValueRef);
fn build_wrap_fn_(ccx: @CrateContext, fn build_wrap_fn_(ccx: @CrateContext,
tys: &ShimTypes, tys: &ShimTypes,
@ -179,10 +186,17 @@ fn build_wrap_fn_(ccx: @CrateContext,
llwrapfn: ValueRef, llwrapfn: ValueRef,
shim_upcall: ValueRef, shim_upcall: ValueRef,
arg_builder: wrap_arg_builder, arg_builder: wrap_arg_builder,
ret_builder: wrap_ret_builder) ret_builder: wrap_ret_builder) {
{
let _icx = ccx.insn_ctxt("foreign::build_wrap_fn_"); let _icx = ccx.insn_ctxt("foreign::build_wrap_fn_");
let fcx = new_fn_ctxt(ccx, ~[], llwrapfn, None); let fcx = new_fn_ctxt(ccx, ~[], llwrapfn, tys.fn_sig.output, None);
// Patch up the return type if it's not immediate.
/*if !ty::type_is_immediate(tys.fn_sig.output) {
let lloutputtype = type_of::type_of(*fcx.ccx, tys.fn_sig.output);
fcx.llretptr = Some(alloca(raw_block(fcx, false, fcx.llstaticallocas),
lloutputtype));
}*/
let bcx = top_scope_block(fcx, None); let bcx = top_scope_block(fcx, None);
let lltop = bcx.llbb; let lltop = bcx.llbb;
@ -196,11 +210,34 @@ fn build_wrap_fn_(ccx: @CrateContext,
Call(bcx, shim_upcall, ~[llrawargbundle, llshimfnptr]); Call(bcx, shim_upcall, ~[llrawargbundle, llshimfnptr]);
ret_builder(bcx, tys, llargbundle); ret_builder(bcx, tys, llargbundle);
// Perform a custom version of `finish_fn`. First, tie up the header
// blocks.
tie_up_header_blocks(fcx, lltop); tie_up_header_blocks(fcx, lltop);
// Make sure our standard return block (that we didn't use) is terminated // Then return according to the C ABI.
let ret_cx = raw_block(fcx, false, fcx.llreturn); unsafe {
Unreachable(ret_cx); let return_context = raw_block(fcx, false, fcx.llreturn);
let llfunctiontype = val_ty(llwrapfn);
let llfunctiontype =
::lib::llvm::llvm::LLVMGetElementType(llfunctiontype);
let llfunctionreturntype =
::lib::llvm::llvm::LLVMGetReturnType(llfunctiontype);
if ::lib::llvm::llvm::LLVMGetTypeKind(llfunctionreturntype) ==
::lib::llvm::Void {
// XXX: This might be wrong if there are any functions for which
// the C ABI specifies a void output pointer and the Rust ABI
// does not.
RetVoid(return_context);
} else {
// Cast if we have to...
// XXX: This is ugly.
let llretptr = BitCast(return_context,
fcx.llretptr.get(),
T_ptr(llfunctionreturntype));
Ret(return_context, Load(return_context, llretptr));
}
}
} }
// For each foreign function F, we generate a wrapper function W and a shim // For each foreign function F, we generate a wrapper function W and a shim
@ -241,8 +278,7 @@ fn build_wrap_fn_(ccx: @CrateContext,
// in the future. // in the future.
pub fn trans_foreign_mod(ccx: @CrateContext, pub fn trans_foreign_mod(ccx: @CrateContext,
path: &ast_map::path, path: &ast_map::path,
foreign_mod: &ast::foreign_mod) foreign_mod: &ast::foreign_mod) {
{
let _icx = ccx.insn_ctxt("foreign::trans_foreign_mod"); let _icx = ccx.insn_ctxt("foreign::trans_foreign_mod");
let arch = ccx.sess.targ_cfg.arch; let arch = ccx.sess.targ_cfg.arch;
@ -312,8 +348,7 @@ pub fn trans_foreign_mod(ccx: @CrateContext,
fn build_foreign_fn(ccx: @CrateContext, fn build_foreign_fn(ccx: @CrateContext,
id: ast::node_id, id: ast::node_id,
foreign_item: @ast::foreign_item, foreign_item: @ast::foreign_item,
cc: lib::llvm::CallConv) cc: lib::llvm::CallConv) {
{
let llwrapfn = get_item_val(ccx, id); let llwrapfn = get_item_val(ccx, id);
let tys = shim_types(ccx, id); let tys = shim_types(ccx, id);
if attr::attrs_contains_name(foreign_item.attrs, "rust_stack") { if attr::attrs_contains_name(foreign_item.attrs, "rust_stack") {
@ -322,8 +357,7 @@ pub fn trans_foreign_mod(ccx: @CrateContext,
} else if attr::attrs_contains_name(foreign_item.attrs, "fast_ffi") { } else if attr::attrs_contains_name(foreign_item.attrs, "fast_ffi") {
build_fast_ffi_fn(ccx, llwrapfn, foreign_item, &tys, cc); build_fast_ffi_fn(ccx, llwrapfn, foreign_item, &tys, cc);
} else { } else {
let llshimfn = build_shim_fn(ccx, foreign_item, let llshimfn = build_shim_fn(ccx, foreign_item, &tys, cc);
&tys, cc);
build_wrap_fn(ccx, &tys, llshimfn, llwrapfn); build_wrap_fn(ccx, &tys, llshimfn, llwrapfn);
} }
} }
@ -331,8 +365,8 @@ pub fn trans_foreign_mod(ccx: @CrateContext,
fn build_shim_fn(ccx: @CrateContext, fn build_shim_fn(ccx: @CrateContext,
foreign_item: @ast::foreign_item, foreign_item: @ast::foreign_item,
tys: &ShimTypes, tys: &ShimTypes,
cc: lib::llvm::CallConv) -> ValueRef cc: lib::llvm::CallConv)
{ -> ValueRef {
/*! /*!
* *
* Build S, from comment above: * Build S, from comment above:
@ -344,31 +378,43 @@ pub fn trans_foreign_mod(ccx: @CrateContext,
let _icx = ccx.insn_ctxt("foreign::build_shim_fn"); let _icx = ccx.insn_ctxt("foreign::build_shim_fn");
fn build_args(bcx: block, tys: &ShimTypes, fn build_args(bcx: block, tys: &ShimTypes, llargbundle: ValueRef)
llargbundle: ValueRef) -> ~[ValueRef] { -> ~[ValueRef] {
let _icx = bcx.insn_ctxt("foreign::shim::build_args"); let _icx = bcx.insn_ctxt("foreign::shim::build_args");
tys.fn_ty.build_shim_args( tys.fn_ty.build_shim_args(bcx, tys.llsig.llarg_tys, llargbundle)
bcx, tys.llsig.llarg_tys, llargbundle)
} }
fn build_ret(bcx: block, tys: &ShimTypes, fn build_ret(bcx: block,
llargbundle: ValueRef, llretval: ValueRef) { tys: &ShimTypes,
llargbundle: ValueRef,
llretval: ValueRef) {
let _icx = bcx.insn_ctxt("foreign::shim::build_ret"); let _icx = bcx.insn_ctxt("foreign::shim::build_ret");
tys.fn_ty.build_shim_ret( tys.fn_ty.build_shim_ret(bcx,
bcx, tys.llsig.llarg_tys, tys.llsig.llarg_tys,
tys.ret_def, llargbundle, llretval); tys.ret_def,
llargbundle,
llretval);
build_return(bcx);
} }
let lname = link_name(ccx, foreign_item); let lname = link_name(ccx, foreign_item);
let llbasefn = base_fn(ccx, *lname, tys, cc); let llbasefn = base_fn(ccx, *lname, tys, cc);
// Name the shim function // Name the shim function
let shim_name = *lname + ~"__c_stack_shim"; let shim_name = *lname + ~"__c_stack_shim";
return build_shim_fn_(ccx, shim_name, llbasefn, tys, cc, build_shim_fn_(ccx,
build_args, build_ret); shim_name,
llbasefn,
tys,
cc,
build_args,
build_ret)
} }
fn base_fn(ccx: @CrateContext, lname: &str, tys: &ShimTypes, fn base_fn(ccx: @CrateContext,
cc: lib::llvm::CallConv) -> ValueRef { lname: &str,
tys: &ShimTypes,
cc: lib::llvm::CallConv)
-> ValueRef {
// Declare the "prototype" for the base function F: // Declare the "prototype" for the base function F:
do tys.fn_ty.decl_fn |fnty| { do tys.fn_ty.decl_fn |fnty| {
decl_fn(ccx.llmod, lname, cc, fnty) decl_fn(ccx.llmod, lname, cc, fnty)
@ -377,12 +423,14 @@ pub fn trans_foreign_mod(ccx: @CrateContext,
// FIXME (#2535): this is very shaky and probably gets ABIs wrong all // FIXME (#2535): this is very shaky and probably gets ABIs wrong all
// over the place // over the place
fn build_direct_fn(ccx: @CrateContext, decl: ValueRef, fn build_direct_fn(ccx: @CrateContext,
item: @ast::foreign_item, tys: &ShimTypes, decl: ValueRef,
item: @ast::foreign_item,
tys: &ShimTypes,
cc: lib::llvm::CallConv) { cc: lib::llvm::CallConv) {
debug!("build_direct_fn(%s)", *link_name(ccx, item)); debug!("build_direct_fn(%s)", *link_name(ccx, item));
let fcx = new_fn_ctxt(ccx, ~[], decl, None); let fcx = new_fn_ctxt(ccx, ~[], decl, tys.fn_sig.output, None);
let bcx = top_scope_block(fcx, None), lltop = bcx.llbb; let bcx = top_scope_block(fcx, None), lltop = bcx.llbb;
let llbasefn = base_fn(ccx, *link_name(ccx, item), tys, cc); let llbasefn = base_fn(ccx, *link_name(ccx, item), tys, cc);
let ty = ty::lookup_item_type(ccx.tcx, let ty = ty::lookup_item_type(ccx.tcx,
@ -393,7 +441,7 @@ pub fn trans_foreign_mod(ccx: @CrateContext,
let retval = Call(bcx, llbasefn, args); let retval = Call(bcx, llbasefn, args);
let ret_ty = ty::ty_fn_ret(ty); let ret_ty = ty::ty_fn_ret(ty);
if !ty::type_is_nil(ret_ty) && !ty::type_is_bot(ret_ty) { if !ty::type_is_nil(ret_ty) && !ty::type_is_bot(ret_ty) {
Store(bcx, retval, fcx.llretptr); Store(bcx, retval, fcx.llretptr.get());
} }
build_return(bcx); build_return(bcx);
finish_fn(fcx, lltop); finish_fn(fcx, lltop);
@ -408,7 +456,7 @@ pub fn trans_foreign_mod(ccx: @CrateContext,
cc: lib::llvm::CallConv) { cc: lib::llvm::CallConv) {
debug!("build_fast_ffi_fn(%s)", *link_name(ccx, item)); debug!("build_fast_ffi_fn(%s)", *link_name(ccx, item));
let fcx = new_fn_ctxt(ccx, ~[], decl, None); let fcx = new_fn_ctxt(ccx, ~[], decl, tys.fn_sig.output, None);
let bcx = top_scope_block(fcx, None), lltop = bcx.llbb; let bcx = top_scope_block(fcx, None), lltop = bcx.llbb;
let llbasefn = base_fn(ccx, *link_name(ccx, item), tys, cc); let llbasefn = base_fn(ccx, *link_name(ccx, item), tys, cc);
set_no_inline(fcx.llfn); set_no_inline(fcx.llfn);
@ -421,7 +469,7 @@ pub fn trans_foreign_mod(ccx: @CrateContext,
let retval = Call(bcx, llbasefn, args); let retval = Call(bcx, llbasefn, args);
let ret_ty = ty::ty_fn_ret(ty); let ret_ty = ty::ty_fn_ret(ty);
if !ty::type_is_nil(ret_ty) && !ty::type_is_bot(ret_ty) { if !ty::type_is_nil(ret_ty) && !ty::type_is_bot(ret_ty) {
Store(bcx, retval, fcx.llretptr); Store(bcx, retval, fcx.llretptr.get());
} }
build_return(bcx); build_return(bcx);
finish_fn(fcx, lltop); finish_fn(fcx, lltop);
@ -446,12 +494,18 @@ pub fn trans_foreign_mod(ccx: @CrateContext,
let _icx = ccx.insn_ctxt("foreign::build_wrap_fn"); let _icx = ccx.insn_ctxt("foreign::build_wrap_fn");
build_wrap_fn_(ccx, tys, llshimfn, llwrapfn, build_wrap_fn_(ccx,
tys,
llshimfn,
llwrapfn,
ccx.upcalls.call_shim_on_c_stack, ccx.upcalls.call_shim_on_c_stack,
build_args, build_ret); build_args,
build_ret);
fn build_args(bcx: block, tys: &ShimTypes, fn build_args(bcx: block,
llwrapfn: ValueRef, llargbundle: ValueRef) { tys: &ShimTypes,
llwrapfn: ValueRef,
llargbundle: ValueRef) {
let _icx = bcx.insn_ctxt("foreign::wrap::build_args"); let _icx = bcx.insn_ctxt("foreign::wrap::build_args");
let ccx = bcx.ccx(); let ccx = bcx.ccx();
let n = vec::len(tys.llsig.llarg_tys); let n = vec::len(tys.llsig.llarg_tys);
@ -468,14 +522,18 @@ pub fn trans_foreign_mod(ccx: @CrateContext,
store_inbounds(bcx, llargval, llargbundle, ~[0u, i]); store_inbounds(bcx, llargval, llargbundle, ~[0u, i]);
} }
let llretptr = get_param(llwrapfn, 0u); let llretptr = bcx.fcx.llretptr.get();
store_inbounds(bcx, llretptr, llargbundle, ~[0u, n]); store_inbounds(bcx, llretptr, llargbundle, ~[0u, n]);
} }
fn build_ret(bcx: block, _tys: &ShimTypes, fn build_ret(bcx: block,
_llargbundle: ValueRef) { shim_types: &ShimTypes,
llargbundle: ValueRef) {
let _icx = bcx.insn_ctxt("foreign::wrap::build_ret"); let _icx = bcx.insn_ctxt("foreign::wrap::build_ret");
RetVoid(bcx); let arg_count = shim_types.fn_sig.inputs.len();
let llretptr = load_inbounds(bcx, llargbundle, ~[0, arg_count]);
Store(bcx, Load(bcx, llretptr), bcx.fcx.llretptr.get());
build_return(bcx);
} }
} }
} }
@ -488,9 +546,18 @@ pub fn trans_intrinsic(ccx: @CrateContext,
ref_id: Option<ast::node_id>) { ref_id: Option<ast::node_id>) {
debug!("trans_intrinsic(item.ident=%s)", *ccx.sess.str_of(item.ident)); debug!("trans_intrinsic(item.ident=%s)", *ccx.sess.str_of(item.ident));
let output_type = ty::ty_fn_ret(ty::node_id_to_type(ccx.tcx, item.id));
// XXX: Bad copy. // XXX: Bad copy.
let fcx = new_fn_ctxt_w_id(ccx, path, decl, item.id, None, let fcx = new_fn_ctxt_w_id(ccx,
Some(copy substs), Some(item.span)); path,
decl,
item.id,
output_type,
None,
Some(copy substs),
Some(item.span));
let mut bcx = top_scope_block(fcx, None), lltop = bcx.llbb; let mut bcx = top_scope_block(fcx, None), lltop = bcx.llbb;
match *ccx.sess.str_of(item.ident) { match *ccx.sess.str_of(item.ident) {
~"atomic_cxchg" => { ~"atomic_cxchg" => {
@ -499,7 +566,7 @@ pub fn trans_intrinsic(ccx: @CrateContext,
get_param(decl, first_real_arg + 1u), get_param(decl, first_real_arg + 1u),
get_param(decl, first_real_arg + 2u), get_param(decl, first_real_arg + 2u),
SequentiallyConsistent); SequentiallyConsistent);
Store(bcx, old, fcx.llretptr); Store(bcx, old, fcx.llretptr.get());
} }
~"atomic_cxchg_acq" => { ~"atomic_cxchg_acq" => {
let old = AtomicCmpXchg(bcx, let old = AtomicCmpXchg(bcx,
@ -507,7 +574,7 @@ pub fn trans_intrinsic(ccx: @CrateContext,
get_param(decl, first_real_arg + 1u), get_param(decl, first_real_arg + 1u),
get_param(decl, first_real_arg + 2u), get_param(decl, first_real_arg + 2u),
Acquire); Acquire);
Store(bcx, old, fcx.llretptr); Store(bcx, old, fcx.llretptr.get());
} }
~"atomic_cxchg_rel" => { ~"atomic_cxchg_rel" => {
let old = AtomicCmpXchg(bcx, let old = AtomicCmpXchg(bcx,
@ -515,76 +582,76 @@ pub fn trans_intrinsic(ccx: @CrateContext,
get_param(decl, first_real_arg + 1u), get_param(decl, first_real_arg + 1u),
get_param(decl, first_real_arg + 2u), get_param(decl, first_real_arg + 2u),
Release); Release);
Store(bcx, old, fcx.llretptr); Store(bcx, old, fcx.llretptr.get());
} }
~"atomic_xchg" => { ~"atomic_xchg" => {
let old = AtomicRMW(bcx, Xchg, let old = AtomicRMW(bcx, Xchg,
get_param(decl, first_real_arg), get_param(decl, first_real_arg),
get_param(decl, first_real_arg + 1u), get_param(decl, first_real_arg + 1u),
SequentiallyConsistent); SequentiallyConsistent);
Store(bcx, old, fcx.llretptr); Store(bcx, old, fcx.llretptr.get());
} }
~"atomic_xchg_acq" => { ~"atomic_xchg_acq" => {
let old = AtomicRMW(bcx, Xchg, let old = AtomicRMW(bcx, Xchg,
get_param(decl, first_real_arg), get_param(decl, first_real_arg),
get_param(decl, first_real_arg + 1u), get_param(decl, first_real_arg + 1u),
Acquire); Acquire);
Store(bcx, old, fcx.llretptr); Store(bcx, old, fcx.llretptr.get());
} }
~"atomic_xchg_rel" => { ~"atomic_xchg_rel" => {
let old = AtomicRMW(bcx, Xchg, let old = AtomicRMW(bcx, Xchg,
get_param(decl, first_real_arg), get_param(decl, first_real_arg),
get_param(decl, first_real_arg + 1u), get_param(decl, first_real_arg + 1u),
Release); Release);
Store(bcx, old, fcx.llretptr); Store(bcx, old, fcx.llretptr.get());
} }
~"atomic_xadd" => { ~"atomic_xadd" => {
let old = AtomicRMW(bcx, lib::llvm::Add, let old = AtomicRMW(bcx, lib::llvm::Add,
get_param(decl, first_real_arg), get_param(decl, first_real_arg),
get_param(decl, first_real_arg + 1u), get_param(decl, first_real_arg + 1u),
SequentiallyConsistent); SequentiallyConsistent);
Store(bcx, old, fcx.llretptr); Store(bcx, old, fcx.llretptr.get());
} }
~"atomic_xadd_acq" => { ~"atomic_xadd_acq" => {
let old = AtomicRMW(bcx, lib::llvm::Add, let old = AtomicRMW(bcx, lib::llvm::Add,
get_param(decl, first_real_arg), get_param(decl, first_real_arg),
get_param(decl, first_real_arg + 1u), get_param(decl, first_real_arg + 1u),
Acquire); Acquire);
Store(bcx, old, fcx.llretptr); Store(bcx, old, fcx.llretptr.get());
} }
~"atomic_xadd_rel" => { ~"atomic_xadd_rel" => {
let old = AtomicRMW(bcx, lib::llvm::Add, let old = AtomicRMW(bcx, lib::llvm::Add,
get_param(decl, first_real_arg), get_param(decl, first_real_arg),
get_param(decl, first_real_arg + 1u), get_param(decl, first_real_arg + 1u),
Release); Release);
Store(bcx, old, fcx.llretptr); Store(bcx, old, fcx.llretptr.get());
} }
~"atomic_xsub" => { ~"atomic_xsub" => {
let old = AtomicRMW(bcx, lib::llvm::Sub, let old = AtomicRMW(bcx, lib::llvm::Sub,
get_param(decl, first_real_arg), get_param(decl, first_real_arg),
get_param(decl, first_real_arg + 1u), get_param(decl, first_real_arg + 1u),
SequentiallyConsistent); SequentiallyConsistent);
Store(bcx, old, fcx.llretptr); Store(bcx, old, fcx.llretptr.get());
} }
~"atomic_xsub_acq" => { ~"atomic_xsub_acq" => {
let old = AtomicRMW(bcx, lib::llvm::Sub, let old = AtomicRMW(bcx, lib::llvm::Sub,
get_param(decl, first_real_arg), get_param(decl, first_real_arg),
get_param(decl, first_real_arg + 1u), get_param(decl, first_real_arg + 1u),
Acquire); Acquire);
Store(bcx, old, fcx.llretptr); Store(bcx, old, fcx.llretptr.get());
} }
~"atomic_xsub_rel" => { ~"atomic_xsub_rel" => {
let old = AtomicRMW(bcx, lib::llvm::Sub, let old = AtomicRMW(bcx, lib::llvm::Sub,
get_param(decl, first_real_arg), get_param(decl, first_real_arg),
get_param(decl, first_real_arg + 1u), get_param(decl, first_real_arg + 1u),
Release); Release);
Store(bcx, old, fcx.llretptr); Store(bcx, old, fcx.llretptr.get());
} }
~"size_of" => { ~"size_of" => {
let tp_ty = substs.tys[0]; let tp_ty = substs.tys[0];
let lltp_ty = type_of::type_of(ccx, tp_ty); let lltp_ty = type_of::type_of(ccx, tp_ty);
Store(bcx, C_uint(ccx, machine::llsize_of_real(ccx, lltp_ty)), Store(bcx, C_uint(ccx, machine::llsize_of_real(ccx, lltp_ty)),
fcx.llretptr); fcx.llretptr.get());
} }
~"move_val" => { ~"move_val" => {
// Create a datum reflecting the value being moved: // Create a datum reflecting the value being moved:
@ -615,13 +682,13 @@ pub fn trans_intrinsic(ccx: @CrateContext,
let tp_ty = substs.tys[0]; let tp_ty = substs.tys[0];
let lltp_ty = type_of::type_of(ccx, tp_ty); let lltp_ty = type_of::type_of(ccx, tp_ty);
Store(bcx, C_uint(ccx, machine::llalign_of_min(ccx, lltp_ty)), Store(bcx, C_uint(ccx, machine::llalign_of_min(ccx, lltp_ty)),
fcx.llretptr); fcx.llretptr.get());
} }
~"pref_align_of"=> { ~"pref_align_of"=> {
let tp_ty = substs.tys[0]; let tp_ty = substs.tys[0];
let lltp_ty = type_of::type_of(ccx, tp_ty); let lltp_ty = type_of::type_of(ccx, tp_ty);
Store(bcx, C_uint(ccx, machine::llalign_of_pref(ccx, lltp_ty)), Store(bcx, C_uint(ccx, machine::llalign_of_pref(ccx, lltp_ty)),
fcx.llretptr); fcx.llretptr.get());
} }
~"get_tydesc" => { ~"get_tydesc" => {
let tp_ty = substs.tys[0]; let tp_ty = substs.tys[0];
@ -631,13 +698,13 @@ pub fn trans_intrinsic(ccx: @CrateContext,
// FIXME (#3727): change this to T_ptr(ccx.tydesc_ty) when the // FIXME (#3727): change this to T_ptr(ccx.tydesc_ty) when the
// core::sys copy of the get_tydesc interface dies off. // core::sys copy of the get_tydesc interface dies off.
let td = PointerCast(bcx, static_ti.tydesc, T_ptr(T_nil())); let td = PointerCast(bcx, static_ti.tydesc, T_ptr(T_nil()));
Store(bcx, td, fcx.llretptr); Store(bcx, td, fcx.llretptr.get());
} }
~"init" => { ~"init" => {
let tp_ty = substs.tys[0]; let tp_ty = substs.tys[0];
let lltp_ty = type_of::type_of(ccx, tp_ty); let lltp_ty = type_of::type_of(ccx, tp_ty);
if !ty::type_is_nil(tp_ty) { if !ty::type_is_nil(tp_ty) {
Store(bcx, C_null(lltp_ty), fcx.llretptr); Store(bcx, C_null(lltp_ty), fcx.llretptr.get());
} }
} }
~"forget" => {} ~"forget" => {}
@ -663,20 +730,21 @@ pub fn trans_intrinsic(ccx: @CrateContext,
// NB: Do not use a Load and Store here. This causes // NB: Do not use a Load and Store here. This causes
// massive code bloat when reinterpret_cast is used on // massive code bloat when reinterpret_cast is used on
// large structural types. // large structural types.
let llretptr = PointerCast(bcx, fcx.llretptr, T_ptr(T_i8())); let llretptr = fcx.llretptr.get();
let llretptr = PointerCast(bcx, llretptr, T_ptr(T_i8()));
let llcast = get_param(decl, first_real_arg); let llcast = get_param(decl, first_real_arg);
let llcast = PointerCast(bcx, llcast, T_ptr(T_i8())); let llcast = PointerCast(bcx, llcast, T_ptr(T_i8()));
call_memcpy(bcx, llretptr, llcast, llsize_of(ccx, lltp_ty)); call_memcpy(bcx, llretptr, llcast, llsize_of(ccx, lltp_ty));
} }
} }
~"addr_of" => { ~"addr_of" => {
Store(bcx, get_param(decl, first_real_arg), fcx.llretptr); Store(bcx, get_param(decl, first_real_arg), fcx.llretptr.get());
} }
~"needs_drop" => { ~"needs_drop" => {
let tp_ty = substs.tys[0]; let tp_ty = substs.tys[0];
Store(bcx, Store(bcx,
C_bool(ty::type_needs_drop(ccx.tcx, tp_ty)), C_bool(ty::type_needs_drop(ccx.tcx, tp_ty)),
fcx.llretptr); fcx.llretptr.get());
} }
~"visit_tydesc" => { ~"visit_tydesc" => {
let td = get_param(decl, first_real_arg); let td = get_param(decl, first_real_arg);
@ -718,7 +786,7 @@ pub fn trans_intrinsic(ccx: @CrateContext,
bcx.ccx().llmod, ~"__morestack", llfty); bcx.ccx().llmod, ~"__morestack", llfty);
let morestack_addr = PointerCast(bcx, morestack_addr, let morestack_addr = PointerCast(bcx, morestack_addr,
T_ptr(T_nil())); T_ptr(T_nil()));
Store(bcx, morestack_addr, fcx.llretptr); Store(bcx, morestack_addr, fcx.llretptr.get());
} }
~"memmove32" => { ~"memmove32" => {
let dst_ptr = get_param(decl, first_real_arg); let dst_ptr = get_param(decl, first_real_arg);
@ -743,243 +811,243 @@ pub fn trans_intrinsic(ccx: @CrateContext,
~"sqrtf32" => { ~"sqrtf32" => {
let x = get_param(decl, first_real_arg); let x = get_param(decl, first_real_arg);
let sqrtf = *ccx.intrinsics.get(&~"llvm.sqrt.f32"); let sqrtf = *ccx.intrinsics.get(&~"llvm.sqrt.f32");
Store(bcx, Call(bcx, sqrtf, ~[x]), fcx.llretptr); Store(bcx, Call(bcx, sqrtf, ~[x]), fcx.llretptr.get());
} }
~"sqrtf64" => { ~"sqrtf64" => {
let x = get_param(decl, first_real_arg); let x = get_param(decl, first_real_arg);
let sqrtf = *ccx.intrinsics.get(&~"llvm.sqrt.f64"); let sqrtf = *ccx.intrinsics.get(&~"llvm.sqrt.f64");
Store(bcx, Call(bcx, sqrtf, ~[x]), fcx.llretptr); Store(bcx, Call(bcx, sqrtf, ~[x]), fcx.llretptr.get());
} }
~"powif32" => { ~"powif32" => {
let a = get_param(decl, first_real_arg); let a = get_param(decl, first_real_arg);
let x = get_param(decl, first_real_arg + 1u); let x = get_param(decl, first_real_arg + 1u);
let powif = *ccx.intrinsics.get(&~"llvm.powi.f32"); let powif = *ccx.intrinsics.get(&~"llvm.powi.f32");
Store(bcx, Call(bcx, powif, ~[a, x]), fcx.llretptr); Store(bcx, Call(bcx, powif, ~[a, x]), fcx.llretptr.get());
} }
~"powif64" => { ~"powif64" => {
let a = get_param(decl, first_real_arg); let a = get_param(decl, first_real_arg);
let x = get_param(decl, first_real_arg + 1u); let x = get_param(decl, first_real_arg + 1u);
let powif = *ccx.intrinsics.get(&~"llvm.powi.f64"); let powif = *ccx.intrinsics.get(&~"llvm.powi.f64");
Store(bcx, Call(bcx, powif, ~[a, x]), fcx.llretptr); Store(bcx, Call(bcx, powif, ~[a, x]), fcx.llretptr.get());
} }
~"sinf32" => { ~"sinf32" => {
let x = get_param(decl, first_real_arg); let x = get_param(decl, first_real_arg);
let sinf = *ccx.intrinsics.get(&~"llvm.sin.f32"); let sinf = *ccx.intrinsics.get(&~"llvm.sin.f32");
Store(bcx, Call(bcx, sinf, ~[x]), fcx.llretptr); Store(bcx, Call(bcx, sinf, ~[x]), fcx.llretptr.get());
} }
~"sinf64" => { ~"sinf64" => {
let x = get_param(decl, first_real_arg); let x = get_param(decl, first_real_arg);
let sinf = *ccx.intrinsics.get(&~"llvm.sin.f64"); let sinf = *ccx.intrinsics.get(&~"llvm.sin.f64");
Store(bcx, Call(bcx, sinf, ~[x]), fcx.llretptr); Store(bcx, Call(bcx, sinf, ~[x]), fcx.llretptr.get());
} }
~"cosf32" => { ~"cosf32" => {
let x = get_param(decl, first_real_arg); let x = get_param(decl, first_real_arg);
let cosf = *ccx.intrinsics.get(&~"llvm.cos.f32"); let cosf = *ccx.intrinsics.get(&~"llvm.cos.f32");
Store(bcx, Call(bcx, cosf, ~[x]), fcx.llretptr); Store(bcx, Call(bcx, cosf, ~[x]), fcx.llretptr.get());
} }
~"cosf64" => { ~"cosf64" => {
let x = get_param(decl, first_real_arg); let x = get_param(decl, first_real_arg);
let cosf = *ccx.intrinsics.get(&~"llvm.cos.f64"); let cosf = *ccx.intrinsics.get(&~"llvm.cos.f64");
Store(bcx, Call(bcx, cosf, ~[x]), fcx.llretptr); Store(bcx, Call(bcx, cosf, ~[x]), fcx.llretptr.get());
} }
~"powf32" => { ~"powf32" => {
let a = get_param(decl, first_real_arg); let a = get_param(decl, first_real_arg);
let x = get_param(decl, first_real_arg + 1u); let x = get_param(decl, first_real_arg + 1u);
let powf = *ccx.intrinsics.get(&~"llvm.pow.f32"); let powf = *ccx.intrinsics.get(&~"llvm.pow.f32");
Store(bcx, Call(bcx, powf, ~[a, x]), fcx.llretptr); Store(bcx, Call(bcx, powf, ~[a, x]), fcx.llretptr.get());
} }
~"powf64" => { ~"powf64" => {
let a = get_param(decl, first_real_arg); let a = get_param(decl, first_real_arg);
let x = get_param(decl, first_real_arg + 1u); let x = get_param(decl, first_real_arg + 1u);
let powf = *ccx.intrinsics.get(&~"llvm.pow.f64"); let powf = *ccx.intrinsics.get(&~"llvm.pow.f64");
Store(bcx, Call(bcx, powf, ~[a, x]), fcx.llretptr); Store(bcx, Call(bcx, powf, ~[a, x]), fcx.llretptr.get());
} }
~"expf32" => { ~"expf32" => {
let x = get_param(decl, first_real_arg); let x = get_param(decl, first_real_arg);
let expf = *ccx.intrinsics.get(&~"llvm.exp.f32"); let expf = *ccx.intrinsics.get(&~"llvm.exp.f32");
Store(bcx, Call(bcx, expf, ~[x]), fcx.llretptr); Store(bcx, Call(bcx, expf, ~[x]), fcx.llretptr.get());
} }
~"expf64" => { ~"expf64" => {
let x = get_param(decl, first_real_arg); let x = get_param(decl, first_real_arg);
let expf = *ccx.intrinsics.get(&~"llvm.exp.f64"); let expf = *ccx.intrinsics.get(&~"llvm.exp.f64");
Store(bcx, Call(bcx, expf, ~[x]), fcx.llretptr); Store(bcx, Call(bcx, expf, ~[x]), fcx.llretptr.get());
} }
~"exp2f32" => { ~"exp2f32" => {
let x = get_param(decl, first_real_arg); let x = get_param(decl, first_real_arg);
let exp2f = *ccx.intrinsics.get(&~"llvm.exp2.f32"); let exp2f = *ccx.intrinsics.get(&~"llvm.exp2.f32");
Store(bcx, Call(bcx, exp2f, ~[x]), fcx.llretptr); Store(bcx, Call(bcx, exp2f, ~[x]), fcx.llretptr.get());
} }
~"exp2f64" => { ~"exp2f64" => {
let x = get_param(decl, first_real_arg); let x = get_param(decl, first_real_arg);
let exp2f = *ccx.intrinsics.get(&~"llvm.exp2.f64"); let exp2f = *ccx.intrinsics.get(&~"llvm.exp2.f64");
Store(bcx, Call(bcx, exp2f, ~[x]), fcx.llretptr); Store(bcx, Call(bcx, exp2f, ~[x]), fcx.llretptr.get());
} }
~"logf32" => { ~"logf32" => {
let x = get_param(decl, first_real_arg); let x = get_param(decl, first_real_arg);
let logf = *ccx.intrinsics.get(&~"llvm.log.f32"); let logf = *ccx.intrinsics.get(&~"llvm.log.f32");
Store(bcx, Call(bcx, logf, ~[x]), fcx.llretptr); Store(bcx, Call(bcx, logf, ~[x]), fcx.llretptr.get());
} }
~"logf64" => { ~"logf64" => {
let x = get_param(decl, first_real_arg); let x = get_param(decl, first_real_arg);
let logf = *ccx.intrinsics.get(&~"llvm.log.f64"); let logf = *ccx.intrinsics.get(&~"llvm.log.f64");
Store(bcx, Call(bcx, logf, ~[x]), fcx.llretptr); Store(bcx, Call(bcx, logf, ~[x]), fcx.llretptr.get());
} }
~"log10f32" => { ~"log10f32" => {
let x = get_param(decl, first_real_arg); let x = get_param(decl, first_real_arg);
let log10f = *ccx.intrinsics.get(&~"llvm.log10.f32"); let log10f = *ccx.intrinsics.get(&~"llvm.log10.f32");
Store(bcx, Call(bcx, log10f, ~[x]), fcx.llretptr); Store(bcx, Call(bcx, log10f, ~[x]), fcx.llretptr.get());
} }
~"log10f64" => { ~"log10f64" => {
let x = get_param(decl, first_real_arg); let x = get_param(decl, first_real_arg);
let log10f = *ccx.intrinsics.get(&~"llvm.log10.f64"); let log10f = *ccx.intrinsics.get(&~"llvm.log10.f64");
Store(bcx, Call(bcx, log10f, ~[x]), fcx.llretptr); Store(bcx, Call(bcx, log10f, ~[x]), fcx.llretptr.get());
} }
~"log2f32" => { ~"log2f32" => {
let x = get_param(decl, first_real_arg); let x = get_param(decl, first_real_arg);
let log2f = *ccx.intrinsics.get(&~"llvm.log2.f32"); let log2f = *ccx.intrinsics.get(&~"llvm.log2.f32");
Store(bcx, Call(bcx, log2f, ~[x]), fcx.llretptr); Store(bcx, Call(bcx, log2f, ~[x]), fcx.llretptr.get());
} }
~"log2f64" => { ~"log2f64" => {
let x = get_param(decl, first_real_arg); let x = get_param(decl, first_real_arg);
let log2f = *ccx.intrinsics.get(&~"llvm.log2.f64"); let log2f = *ccx.intrinsics.get(&~"llvm.log2.f64");
Store(bcx, Call(bcx, log2f, ~[x]), fcx.llretptr); Store(bcx, Call(bcx, log2f, ~[x]), fcx.llretptr.get());
} }
~"fmaf32" => { ~"fmaf32" => {
let a = get_param(decl, first_real_arg); let a = get_param(decl, first_real_arg);
let b = get_param(decl, first_real_arg + 1u); let b = get_param(decl, first_real_arg + 1u);
let c = get_param(decl, first_real_arg + 2u); let c = get_param(decl, first_real_arg + 2u);
let fmaf = *ccx.intrinsics.get(&~"llvm.fma.f32"); let fmaf = *ccx.intrinsics.get(&~"llvm.fma.f32");
Store(bcx, Call(bcx, fmaf, ~[a, b, c]), fcx.llretptr); Store(bcx, Call(bcx, fmaf, ~[a, b, c]), fcx.llretptr.get());
} }
~"fmaf64" => { ~"fmaf64" => {
let a = get_param(decl, first_real_arg); let a = get_param(decl, first_real_arg);
let b = get_param(decl, first_real_arg + 1u); let b = get_param(decl, first_real_arg + 1u);
let c = get_param(decl, first_real_arg + 2u); let c = get_param(decl, first_real_arg + 2u);
let fmaf = *ccx.intrinsics.get(&~"llvm.fma.f64"); let fmaf = *ccx.intrinsics.get(&~"llvm.fma.f64");
Store(bcx, Call(bcx, fmaf, ~[a, b, c]), fcx.llretptr); Store(bcx, Call(bcx, fmaf, ~[a, b, c]), fcx.llretptr.get());
} }
~"fabsf32" => { ~"fabsf32" => {
let x = get_param(decl, first_real_arg); let x = get_param(decl, first_real_arg);
let fabsf = *ccx.intrinsics.get(&~"llvm.fabs.f32"); let fabsf = *ccx.intrinsics.get(&~"llvm.fabs.f32");
Store(bcx, Call(bcx, fabsf, ~[x]), fcx.llretptr); Store(bcx, Call(bcx, fabsf, ~[x]), fcx.llretptr.get());
} }
~"fabsf64" => { ~"fabsf64" => {
let x = get_param(decl, first_real_arg); let x = get_param(decl, first_real_arg);
let fabsf = *ccx.intrinsics.get(&~"llvm.fabs.f64"); let fabsf = *ccx.intrinsics.get(&~"llvm.fabs.f64");
Store(bcx, Call(bcx, fabsf, ~[x]), fcx.llretptr); Store(bcx, Call(bcx, fabsf, ~[x]), fcx.llretptr.get());
} }
~"floorf32" => { ~"floorf32" => {
let x = get_param(decl, first_real_arg); let x = get_param(decl, first_real_arg);
let floorf = *ccx.intrinsics.get(&~"llvm.floor.f32"); let floorf = *ccx.intrinsics.get(&~"llvm.floor.f32");
Store(bcx, Call(bcx, floorf, ~[x]), fcx.llretptr); Store(bcx, Call(bcx, floorf, ~[x]), fcx.llretptr.get());
} }
~"floorf64" => { ~"floorf64" => {
let x = get_param(decl, first_real_arg); let x = get_param(decl, first_real_arg);
let floorf = *ccx.intrinsics.get(&~"llvm.floor.f64"); let floorf = *ccx.intrinsics.get(&~"llvm.floor.f64");
Store(bcx, Call(bcx, floorf, ~[x]), fcx.llretptr); Store(bcx, Call(bcx, floorf, ~[x]), fcx.llretptr.get());
} }
~"ceilf32" => { ~"ceilf32" => {
let x = get_param(decl, first_real_arg); let x = get_param(decl, first_real_arg);
let ceilf = *ccx.intrinsics.get(&~"llvm.ceil.f32"); let ceilf = *ccx.intrinsics.get(&~"llvm.ceil.f32");
Store(bcx, Call(bcx, ceilf, ~[x]), fcx.llretptr); Store(bcx, Call(bcx, ceilf, ~[x]), fcx.llretptr.get());
} }
~"ceilf64" => { ~"ceilf64" => {
let x = get_param(decl, first_real_arg); let x = get_param(decl, first_real_arg);
let ceilf = *ccx.intrinsics.get(&~"llvm.ceil.f64"); let ceilf = *ccx.intrinsics.get(&~"llvm.ceil.f64");
Store(bcx, Call(bcx, ceilf, ~[x]), fcx.llretptr); Store(bcx, Call(bcx, ceilf, ~[x]), fcx.llretptr.get());
} }
~"truncf32" => { ~"truncf32" => {
let x = get_param(decl, first_real_arg); let x = get_param(decl, first_real_arg);
let truncf = *ccx.intrinsics.get(&~"llvm.trunc.f32"); let truncf = *ccx.intrinsics.get(&~"llvm.trunc.f32");
Store(bcx, Call(bcx, truncf, ~[x]), fcx.llretptr); Store(bcx, Call(bcx, truncf, ~[x]), fcx.llretptr.get());
} }
~"truncf64" => { ~"truncf64" => {
let x = get_param(decl, first_real_arg); let x = get_param(decl, first_real_arg);
let truncf = *ccx.intrinsics.get(&~"llvm.trunc.f64"); let truncf = *ccx.intrinsics.get(&~"llvm.trunc.f64");
Store(bcx, Call(bcx, truncf, ~[x]), fcx.llretptr); Store(bcx, Call(bcx, truncf, ~[x]), fcx.llretptr.get());
} }
~"ctpop8" => { ~"ctpop8" => {
let x = get_param(decl, first_real_arg); let x = get_param(decl, first_real_arg);
let ctpop = *ccx.intrinsics.get(&~"llvm.ctpop.i8"); let ctpop = *ccx.intrinsics.get(&~"llvm.ctpop.i8");
Store(bcx, Call(bcx, ctpop, ~[x]), fcx.llretptr) Store(bcx, Call(bcx, ctpop, ~[x]), fcx.llretptr.get())
} }
~"ctpop16" => { ~"ctpop16" => {
let x = get_param(decl, first_real_arg); let x = get_param(decl, first_real_arg);
let ctpop = *ccx.intrinsics.get(&~"llvm.ctpop.i16"); let ctpop = *ccx.intrinsics.get(&~"llvm.ctpop.i16");
Store(bcx, Call(bcx, ctpop, ~[x]), fcx.llretptr) Store(bcx, Call(bcx, ctpop, ~[x]), fcx.llretptr.get())
} }
~"ctpop32" => { ~"ctpop32" => {
let x = get_param(decl, first_real_arg); let x = get_param(decl, first_real_arg);
let ctpop = *ccx.intrinsics.get(&~"llvm.ctpop.i32"); let ctpop = *ccx.intrinsics.get(&~"llvm.ctpop.i32");
Store(bcx, Call(bcx, ctpop, ~[x]), fcx.llretptr) Store(bcx, Call(bcx, ctpop, ~[x]), fcx.llretptr.get())
} }
~"ctpop64" => { ~"ctpop64" => {
let x = get_param(decl, first_real_arg); let x = get_param(decl, first_real_arg);
let ctpop = *ccx.intrinsics.get(&~"llvm.ctpop.i64"); let ctpop = *ccx.intrinsics.get(&~"llvm.ctpop.i64");
Store(bcx, Call(bcx, ctpop, ~[x]), fcx.llretptr) Store(bcx, Call(bcx, ctpop, ~[x]), fcx.llretptr.get())
} }
~"ctlz8" => { ~"ctlz8" => {
let x = get_param(decl, first_real_arg); let x = get_param(decl, first_real_arg);
let y = C_i1(false); let y = C_i1(false);
let ctlz = *ccx.intrinsics.get(&~"llvm.ctlz.i8"); let ctlz = *ccx.intrinsics.get(&~"llvm.ctlz.i8");
Store(bcx, Call(bcx, ctlz, ~[x, y]), fcx.llretptr) Store(bcx, Call(bcx, ctlz, ~[x, y]), fcx.llretptr.get())
} }
~"ctlz16" => { ~"ctlz16" => {
let x = get_param(decl, first_real_arg); let x = get_param(decl, first_real_arg);
let y = C_i1(false); let y = C_i1(false);
let ctlz = *ccx.intrinsics.get(&~"llvm.ctlz.i16"); let ctlz = *ccx.intrinsics.get(&~"llvm.ctlz.i16");
Store(bcx, Call(bcx, ctlz, ~[x, y]), fcx.llretptr) Store(bcx, Call(bcx, ctlz, ~[x, y]), fcx.llretptr.get())
} }
~"ctlz32" => { ~"ctlz32" => {
let x = get_param(decl, first_real_arg); let x = get_param(decl, first_real_arg);
let y = C_i1(false); let y = C_i1(false);
let ctlz = *ccx.intrinsics.get(&~"llvm.ctlz.i32"); let ctlz = *ccx.intrinsics.get(&~"llvm.ctlz.i32");
Store(bcx, Call(bcx, ctlz, ~[x, y]), fcx.llretptr) Store(bcx, Call(bcx, ctlz, ~[x, y]), fcx.llretptr.get())
} }
~"ctlz64" => { ~"ctlz64" => {
let x = get_param(decl, first_real_arg); let x = get_param(decl, first_real_arg);
let y = C_i1(false); let y = C_i1(false);
let ctlz = *ccx.intrinsics.get(&~"llvm.ctlz.i64"); let ctlz = *ccx.intrinsics.get(&~"llvm.ctlz.i64");
Store(bcx, Call(bcx, ctlz, ~[x, y]), fcx.llretptr) Store(bcx, Call(bcx, ctlz, ~[x, y]), fcx.llretptr.get())
} }
~"cttz8" => { ~"cttz8" => {
let x = get_param(decl, first_real_arg); let x = get_param(decl, first_real_arg);
let y = C_i1(false); let y = C_i1(false);
let cttz = *ccx.intrinsics.get(&~"llvm.cttz.i8"); let cttz = *ccx.intrinsics.get(&~"llvm.cttz.i8");
Store(bcx, Call(bcx, cttz, ~[x, y]), fcx.llretptr) Store(bcx, Call(bcx, cttz, ~[x, y]), fcx.llretptr.get())
} }
~"cttz16" => { ~"cttz16" => {
let x = get_param(decl, first_real_arg); let x = get_param(decl, first_real_arg);
let y = C_i1(false); let y = C_i1(false);
let cttz = *ccx.intrinsics.get(&~"llvm.cttz.i16"); let cttz = *ccx.intrinsics.get(&~"llvm.cttz.i16");
Store(bcx, Call(bcx, cttz, ~[x, y]), fcx.llretptr) Store(bcx, Call(bcx, cttz, ~[x, y]), fcx.llretptr.get())
} }
~"cttz32" => { ~"cttz32" => {
let x = get_param(decl, first_real_arg); let x = get_param(decl, first_real_arg);
let y = C_i1(false); let y = C_i1(false);
let cttz = *ccx.intrinsics.get(&~"llvm.cttz.i32"); let cttz = *ccx.intrinsics.get(&~"llvm.cttz.i32");
Store(bcx, Call(bcx, cttz, ~[x, y]), fcx.llretptr) Store(bcx, Call(bcx, cttz, ~[x, y]), fcx.llretptr.get())
} }
~"cttz64" => { ~"cttz64" => {
let x = get_param(decl, first_real_arg); let x = get_param(decl, first_real_arg);
let y = C_i1(false); let y = C_i1(false);
let cttz = *ccx.intrinsics.get(&~"llvm.cttz.i64"); let cttz = *ccx.intrinsics.get(&~"llvm.cttz.i64");
Store(bcx, Call(bcx, cttz, ~[x, y]), fcx.llretptr) Store(bcx, Call(bcx, cttz, ~[x, y]), fcx.llretptr.get())
} }
~"bswap16" => { ~"bswap16" => {
let x = get_param(decl, first_real_arg); let x = get_param(decl, first_real_arg);
let cttz = *ccx.intrinsics.get(&~"llvm.bswap.i16"); let cttz = *ccx.intrinsics.get(&~"llvm.bswap.i16");
Store(bcx, Call(bcx, cttz, ~[x]), fcx.llretptr) Store(bcx, Call(bcx, cttz, ~[x]), fcx.llretptr.get())
} }
~"bswap32" => { ~"bswap32" => {
let x = get_param(decl, first_real_arg); let x = get_param(decl, first_real_arg);
let cttz = *ccx.intrinsics.get(&~"llvm.bswap.i32"); let cttz = *ccx.intrinsics.get(&~"llvm.bswap.i32");
Store(bcx, Call(bcx, cttz, ~[x]), fcx.llretptr) Store(bcx, Call(bcx, cttz, ~[x]), fcx.llretptr.get())
} }
~"bswap64" => { ~"bswap64" => {
let x = get_param(decl, first_real_arg); let x = get_param(decl, first_real_arg);
let cttz = *ccx.intrinsics.get(&~"llvm.bswap.i64"); let cttz = *ccx.intrinsics.get(&~"llvm.bswap.i64");
Store(bcx, Call(bcx, cttz, ~[x]), fcx.llretptr) Store(bcx, Call(bcx, cttz, ~[x]), fcx.llretptr.get())
} }
_ => { _ => {
// Could we make this an enum rather than a string? does it get // Could we make this an enum rather than a string? does it get
@ -1025,9 +1093,12 @@ pub fn trans_foreign_fn(ccx: @CrateContext,
id: ast::node_id) { id: ast::node_id) {
let _icx = ccx.insn_ctxt("foreign::build_foreign_fn"); let _icx = ccx.insn_ctxt("foreign::build_foreign_fn");
fn build_rust_fn(ccx: @CrateContext, +path: ast_map::path, fn build_rust_fn(ccx: @CrateContext,
decl: &ast::fn_decl, body: &ast::blk, +path: ast_map::path,
id: ast::node_id) -> ValueRef { decl: &ast::fn_decl,
body: &ast::blk,
id: ast::node_id)
-> ValueRef {
let _icx = ccx.insn_ctxt("foreign::foreign::build_rust_fn"); let _icx = ccx.insn_ctxt("foreign::foreign::build_rust_fn");
let t = ty::node_id_to_type(ccx.tcx, id); let t = ty::node_id_to_type(ccx.tcx, id);
// XXX: Bad copy. // XXX: Bad copy.
@ -1050,8 +1121,11 @@ pub fn trans_foreign_fn(ccx: @CrateContext,
return llfndecl; return llfndecl;
} }
fn build_shim_fn(ccx: @CrateContext, +path: ast_map::path, fn build_shim_fn(ccx: @CrateContext,
llrustfn: ValueRef, tys: &ShimTypes) -> ValueRef { +path: ast_map::path,
llrustfn: ValueRef,
tys: &ShimTypes)
-> ValueRef {
/*! /*!
* *
* Generate the shim S: * Generate the shim S:
@ -1069,15 +1143,21 @@ pub fn trans_foreign_fn(ccx: @CrateContext,
let _icx = ccx.insn_ctxt("foreign::foreign::build_shim_fn"); let _icx = ccx.insn_ctxt("foreign::foreign::build_shim_fn");
fn build_args(bcx: block, tys: &ShimTypes, fn build_args(bcx: block, tys: &ShimTypes, llargbundle: ValueRef)
llargbundle: ValueRef) -> ~[ValueRef] { -> ~[ValueRef] {
let _icx = bcx.insn_ctxt("foreign::extern::shim::build_args"); let _icx = bcx.insn_ctxt("foreign::extern::shim::build_args");
let ccx = bcx.ccx(); let ccx = bcx.ccx();
let mut llargvals = ~[]; let mut llargvals = ~[];
let mut i = 0u; let mut i = 0u;
let n = tys.fn_sig.inputs.len(); let n = tys.fn_sig.inputs.len();
let llretptr = load_inbounds(bcx, llargbundle, ~[0u, n]);
llargvals.push(llretptr); if !ty::type_is_immediate(tys.fn_sig.output) {
let llretptr = load_inbounds(bcx, llargbundle, ~[0u, n]);
llargvals.push(llretptr);
} else {
llargvals.push(C_null(T_ptr(T_i8())));
}
let llenvptr = C_null(T_opaque_box_ptr(bcx.ccx())); let llenvptr = C_null(T_opaque_box_ptr(bcx.ccx()));
llargvals.push(llenvptr); llargvals.push(llenvptr);
while i < n { while i < n {
@ -1095,24 +1175,43 @@ pub fn trans_foreign_fn(ccx: @CrateContext,
return llargvals; return llargvals;
} }
fn build_ret(_bcx: block, _tys: &ShimTypes, fn build_ret(bcx: block,
_llargbundle: ValueRef, _llretval: ValueRef) { shim_types: &ShimTypes,
// Nop. The return pointer in the Rust ABI function llargbundle: ValueRef,
// is wired directly into the return slot in the shim struct llretval: ValueRef) {
if ty::type_is_immediate(shim_types.fn_sig.output) {
// Write the value into the argument bundle.
let arg_count = shim_types.fn_sig.inputs.len();
let llretptr = load_inbounds(bcx,
llargbundle,
~[0, arg_count]);
Store(bcx, llretval, llretptr);
} else {
// NB: The return pointer in the Rust ABI function is wired
// directly into the return slot in the shim struct.
}
build_return(bcx);
} }
let shim_name = link::mangle_internal_name_by_path( let shim_name = link::mangle_internal_name_by_path(
ccx, vec::append_one(path, ast_map::path_name( ccx,
vec::append_one(path, ast_map::path_name(
special_idents::clownshoe_stack_shim special_idents::clownshoe_stack_shim
))); )));
return build_shim_fn_(ccx, shim_name, llrustfn, tys, build_shim_fn_(ccx,
lib::llvm::CCallConv, shim_name,
build_args, build_ret); llrustfn,
tys,
lib::llvm::CCallConv,
build_args,
build_ret)
} }
fn build_wrap_fn(ccx: @CrateContext, llshimfn: ValueRef, fn build_wrap_fn(ccx: @CrateContext,
llwrapfn: ValueRef, tys: &ShimTypes) llshimfn: ValueRef,
{ llwrapfn: ValueRef,
tys: &ShimTypes) {
/*! /*!
* *
* Generate the wrapper W: * Generate the wrapper W:
@ -1125,23 +1224,29 @@ pub fn trans_foreign_fn(ccx: @CrateContext,
let _icx = ccx.insn_ctxt("foreign::foreign::build_wrap_fn"); let _icx = ccx.insn_ctxt("foreign::foreign::build_wrap_fn");
build_wrap_fn_(ccx, tys, llshimfn, llwrapfn, build_wrap_fn_(ccx,
tys,
llshimfn,
llwrapfn,
ccx.upcalls.call_shim_on_rust_stack, ccx.upcalls.call_shim_on_rust_stack,
build_args, build_ret); build_args,
build_ret);
fn build_args(bcx: block, tys: &ShimTypes, fn build_args(bcx: block,
llwrapfn: ValueRef, llargbundle: ValueRef) { tys: &ShimTypes,
llwrapfn: ValueRef,
llargbundle: ValueRef) {
let _icx = bcx.insn_ctxt("foreign::foreign::wrap::build_args"); let _icx = bcx.insn_ctxt("foreign::foreign::wrap::build_args");
tys.fn_ty.build_wrap_args( tys.fn_ty.build_wrap_args(bcx,
bcx, tys.llsig.llret_ty, tys.llsig.llret_ty,
llwrapfn, llargbundle); llwrapfn,
llargbundle);
} }
fn build_ret(bcx: block, tys: &ShimTypes, fn build_ret(bcx: block, tys: &ShimTypes, llargbundle: ValueRef) {
llargbundle: ValueRef) {
let _icx = bcx.insn_ctxt("foreign::foreign::wrap::build_ret"); let _icx = bcx.insn_ctxt("foreign::foreign::wrap::build_ret");
tys.fn_ty.build_wrap_ret( tys.fn_ty.build_wrap_ret(bcx, tys.llsig.llarg_tys, llargbundle);
bcx, tys.llsig.llarg_tys, llargbundle); build_return(bcx);
} }
} }
@ -1160,12 +1265,20 @@ pub fn register_foreign_fn(ccx: @CrateContext,
+path: ast_map::path, +path: ast_map::path,
node_id: ast::node_id, node_id: ast::node_id,
attrs: &[ast::attribute]) attrs: &[ast::attribute])
-> ValueRef { -> ValueRef {
let _icx = ccx.insn_ctxt("foreign::register_foreign_fn"); let _icx = ccx.insn_ctxt("foreign::register_foreign_fn");
let t = ty::node_id_to_type(ccx.tcx, node_id); let t = ty::node_id_to_type(ccx.tcx, node_id);
let tys = shim_types(ccx, node_id); let tys = shim_types(ccx, node_id);
do tys.fn_ty.decl_fn |fnty| { do tys.fn_ty.decl_fn |fnty| {
register_fn_fuller(ccx, sp, /*bad*/copy path, node_id, attrs, register_fn_fuller(ccx,
t, lib::llvm::CCallConv, fnty) sp,
/*bad*/copy path,
node_id,
attrs,
t,
lib::llvm::CCallConv,
fnty)
} }
} }

View File

@ -499,7 +499,8 @@ pub fn trans_struct_drop(bcx: block,
} }
let self_arg = PointerCast(bcx, llval, params[1]); let self_arg = PointerCast(bcx, llval, params[1]);
let args = ~[bcx.fcx.llretptr, self_arg]; let args = ~[C_null(T_ptr(T_i8())), self_arg];
Call(bcx, dtor_addr, args); Call(bcx, dtor_addr, args);
// Drop the fields // Drop the fields
@ -575,9 +576,7 @@ pub fn make_drop_glue(bcx: block, v0: ValueRef, t: ty::t) {
build_return(bcx); build_return(bcx);
} }
pub fn decr_refcnt_maybe_free(bcx: block, pub fn decr_refcnt_maybe_free(bcx: block, box_ptr: ValueRef, t: ty::t)
box_ptr: ValueRef,
t: ty::t)
-> block { -> block {
let _icx = bcx.insn_ctxt("decr_refcnt_maybe_free"); let _icx = bcx.insn_ctxt("decr_refcnt_maybe_free");
let ccx = bcx.ccx(); let ccx = bcx.ccx();
@ -737,7 +736,7 @@ pub fn make_generic_glue_inner(ccx: @CrateContext,
helper: glue_helper) helper: glue_helper)
-> ValueRef { -> ValueRef {
let _icx = ccx.insn_ctxt("make_generic_glue_inner"); let _icx = ccx.insn_ctxt("make_generic_glue_inner");
let fcx = new_fn_ctxt(ccx, ~[], llfn, None); let fcx = new_fn_ctxt(ccx, ~[], llfn, ty::mk_nil(ccx.tcx), None);
lib::llvm::SetLinkage(llfn, lib::llvm::InternalLinkage); lib::llvm::SetLinkage(llfn, lib::llvm::InternalLinkage);
ccx.stats.n_glues_created += 1u; ccx.stats.n_glues_created += 1u;
// All glue functions take values passed *by alias*; this is a // All glue functions take values passed *by alias*; this is a
@ -756,8 +755,11 @@ pub fn make_generic_glue_inner(ccx: @CrateContext,
return llfn; return llfn;
} }
pub fn make_generic_glue(ccx: @CrateContext, t: ty::t, llfn: ValueRef, pub fn make_generic_glue(ccx: @CrateContext,
helper: glue_helper, name: &str) t: ty::t,
llfn: ValueRef,
helper: glue_helper,
name: &str)
-> ValueRef { -> ValueRef {
let _icx = ccx.insn_ctxt("make_generic_glue"); let _icx = ccx.insn_ctxt("make_generic_glue");
if !ccx.sess.trans_stats() { if !ccx.sess.trans_stats() {
@ -767,8 +769,10 @@ pub fn make_generic_glue(ccx: @CrateContext, t: ty::t, llfn: ValueRef,
let start = time::get_time(); let start = time::get_time();
let llval = make_generic_glue_inner(ccx, t, llfn, helper); let llval = make_generic_glue_inner(ccx, t, llfn, helper);
let end = time::get_time(); let end = time::get_time();
log_fn_time(ccx, fmt!("glue %s %s", name, ty_to_short_str(ccx.tcx, t)), log_fn_time(ccx,
start, end); fmt!("glue %s %s", name, ty_to_short_str(ccx.tcx, t)),
start,
end);
return llval; return llval;
} }

View File

@ -39,20 +39,34 @@ pub fn type_of_explicit_args(ccx: @CrateContext,
inputs.map(|arg| type_of_explicit_arg(ccx, arg)) inputs.map(|arg| type_of_explicit_arg(ccx, arg))
} }
pub fn type_of_fn(cx: @CrateContext, inputs: &[ty::arg], pub fn type_of_fn(cx: @CrateContext, inputs: &[ty::arg], output: ty::t)
output: ty::t) -> TypeRef { -> TypeRef {
unsafe { unsafe {
let mut atys: ~[TypeRef] = ~[]; let mut atys: ~[TypeRef] = ~[];
// Arg 0: Output pointer. // Arg 0: Output pointer.
atys.push(T_ptr(type_of(cx, output))); // (if the output type is non-immediate)
let output_is_immediate = ty::type_is_immediate(output);
let lloutputtype = type_of(cx, output);
if !output_is_immediate {
atys.push(T_ptr(lloutputtype));
} else {
// XXX: Eliminate this.
atys.push(T_ptr(T_i8()));
}
// Arg 1: Environment // Arg 1: Environment
atys.push(T_opaque_box_ptr(cx)); atys.push(T_opaque_box_ptr(cx));
// ... then explicit args. // ... then explicit args.
atys.push_all(type_of_explicit_args(cx, inputs)); atys.push_all(type_of_explicit_args(cx, inputs));
return T_fn(atys, llvm::LLVMVoidType());
// Use the output as the actual return value if it's immediate.
if output_is_immediate {
T_fn(atys, lloutputtype)
} else {
T_fn(atys, llvm::LLVMVoidType())
}
} }
} }
@ -318,11 +332,9 @@ pub fn llvm_type_name(cx: @CrateContext,
} }
pub fn type_of_dtor(ccx: @CrateContext, self_ty: ty::t) -> TypeRef { pub fn type_of_dtor(ccx: @CrateContext, self_ty: ty::t) -> TypeRef {
unsafe { T_fn(~[T_ptr(T_i8()), // output pointer
T_fn(~[T_ptr(type_of(ccx, ty::mk_nil(ccx.tcx))), // output pointer T_ptr(type_of(ccx, self_ty))], // self arg
T_ptr(type_of(ccx, self_ty))], // self arg T_nil())
llvm::LLVMVoidType())
}
} }
pub fn type_of_rooted(ccx: @CrateContext, t: ty::t) -> TypeRef { pub fn type_of_rooted(ccx: @CrateContext, t: ty::t) -> TypeRef {
@ -336,5 +348,5 @@ pub fn type_of_glue_fn(ccx: @CrateContext, t: ty::t) -> TypeRef {
let tydescpp = T_ptr(T_ptr(ccx.tydesc_type)); let tydescpp = T_ptr(T_ptr(ccx.tydesc_type));
let llty = T_ptr(type_of(ccx, t)); let llty = T_ptr(type_of(ccx, t));
return T_fn(~[T_ptr(T_nil()), T_ptr(T_nil()), tydescpp, llty], return T_fn(~[T_ptr(T_nil()), T_ptr(T_nil()), tydescpp, llty],
T_void()); T_nil());
} }

View File

@ -222,7 +222,11 @@ pub fn connect(input_ip: ip::IpAddr, port: uint,
}; };
match connect_result { match connect_result {
0i32 => { 0i32 => {
debug!("tcp_connect successful"); debug!("tcp_connect successful: \
stream %x,
socket data %x",
stream_handle_ptr as uint,
socket_data_ptr as uint);
// reusable data that we'll have for the // reusable data that we'll have for the
// duration.. // duration..
uv::ll::set_data_for_uv_handle( uv::ll::set_data_for_uv_handle(
@ -556,13 +560,21 @@ pub fn accept(new_conn: TcpNewConnection)
server_handle_ptr as *libc::c_void, server_handle_ptr as *libc::c_void,
client_stream_handle_ptr as *libc::c_void) { client_stream_handle_ptr as *libc::c_void) {
0i32 => { 0i32 => {
debug!( debug!("successfully accepted client \
"successfully accepted client \ connection: \
connection"); stream %x, \
socket data %x",
client_stream_handle_ptr as uint,
client_socket_data_ptr as uint);
uv::ll::set_data_for_uv_handle( uv::ll::set_data_for_uv_handle(
client_stream_handle_ptr, client_stream_handle_ptr,
client_socket_data_ptr client_socket_data_ptr
as *libc::c_void); as *libc::c_void);
let ptr = uv::ll::get_data_for_uv_handle(
client_stream_handle_ptr);
debug!("ptrs: %x %x",
client_socket_data_ptr as uint,
ptr as uint);
result_ch.send(None); result_ch.send(None);
} }
_ => { _ => {
@ -1268,14 +1280,15 @@ impl ToTcpErr for uv::ll::uv_err_data {
} }
extern fn on_tcp_read_cb(stream: *uv::ll::uv_stream_t, extern fn on_tcp_read_cb(stream: *uv::ll::uv_stream_t,
nread: libc::ssize_t, nread: libc::ssize_t,
buf: uv::ll::uv_buf_t) { buf: uv::ll::uv_buf_t) {
unsafe { unsafe {
debug!("entering on_tcp_read_cb stream: %? nread: %?", debug!("entering on_tcp_read_cb stream: %x nread: %?",
stream, nread); stream as uint, nread);
let loop_ptr = uv::ll::get_loop_for_uv_handle(stream); let loop_ptr = uv::ll::get_loop_for_uv_handle(stream);
let socket_data_ptr = uv::ll::get_data_for_uv_handle(stream) let socket_data_ptr = uv::ll::get_data_for_uv_handle(stream)
as *TcpSocketData; as *TcpSocketData;
debug!("socket data is %x", socket_data_ptr as uint);
match nread as int { match nread as int {
// incoming err.. probably eof // incoming err.. probably eof
-1 => { -1 => {

View File

@ -1156,8 +1156,7 @@ pub unsafe fn set_data_for_uv_loop(loop_ptr: *libc::c_void,
pub unsafe fn get_data_for_uv_handle<T>(handle: *T) -> *libc::c_void { pub unsafe fn get_data_for_uv_handle<T>(handle: *T) -> *libc::c_void {
return rustrt::rust_uv_get_data_for_uv_handle(handle as *libc::c_void); return rustrt::rust_uv_get_data_for_uv_handle(handle as *libc::c_void);
} }
pub unsafe fn set_data_for_uv_handle<T, U>(handle: *T, pub unsafe fn set_data_for_uv_handle<T, U>(handle: *T, data: *U) {
data: *U) {
rustrt::rust_uv_set_data_for_uv_handle(handle as *libc::c_void, rustrt::rust_uv_set_data_for_uv_handle(handle as *libc::c_void,
data as *libc::c_void); data as *libc::c_void);
} }

View File

@ -401,8 +401,7 @@ rust_uv_get_data_for_uv_handle(uv_handle_t* handle) {
} }
extern "C" void extern "C" void
rust_uv_set_data_for_uv_handle(uv_handle_t* handle, rust_uv_set_data_for_uv_handle(uv_handle_t* handle, void* data) {
void* data) {
handle->data = data; handle->data = data;
} }

View File

@ -17,11 +17,11 @@ fn foo<T:Copy + Const>(x: T) -> T { x }
struct F { field: int } struct F { field: int }
pub fn main() { pub fn main() {
foo(1); /*foo(1);
foo(~"hi"); foo(~"hi");
foo(~[1, 2, 3]); foo(~[1, 2, 3]);
foo(F{field: 42}); foo(F{field: 42});
foo((1, 2u)); foo((1, 2u));
foo(@1); foo(@1);*/
foo(~1); foo(~1);
} }

View File

@ -11,7 +11,7 @@
mod rustrt { mod rustrt {
pub extern { pub extern {
pub fn rust_dbg_call(cb: *u8, data: libc::uintptr_t) pub fn rust_dbg_call(cb: *u8, data: libc::uintptr_t)
-> libc::uintptr_t; -> libc::uintptr_t;
} }
} }