about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-07-17 23:52:40 -0700
committerbors <bors@rust-lang.org>2013-07-17 23:52:40 -0700
commit30ef79ca6d069e3cc100e3d1332a286cbbc1eab3 (patch)
tree181e00e2df0b8430a72e168828f3bd7e34be93f9
parentd300a64520294eac39a649c276b0b41a62a0fb99 (diff)
parent15ea4a8dd8242a0ee01169872bc538c974e748c9 (diff)
downloadrust-30ef79ca6d069e3cc100e3d1332a286cbbc1eab3.tar.gz
rust-30ef79ca6d069e3cc100e3d1332a286cbbc1eab3.zip
auto merge of #7851 : dotdash/rust/intrinsics, r=pcwalton
-rw-r--r--src/librustc/middle/trans/base.rs7
-rw-r--r--src/librustc/middle/trans/foreign.rs512
2 files changed, 169 insertions, 350 deletions
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index 9d8bac6467e..588b0b5c75f 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -1612,6 +1612,7 @@ pub fn new_fn_ctxt_w_id(ccx: @mut CrateContext,
                         llfndecl: ValueRef,
                         id: ast::node_id,
                         output_type: ty::t,
+                        skip_retptr: bool,
                         param_substs: Option<@param_substs>,
                         sp: Option<span>)
                      -> fn_ctxt {
@@ -1655,7 +1656,7 @@ pub fn new_fn_ctxt_w_id(ccx: @mut CrateContext,
     fcx.llenv = unsafe {
           llvm::LLVMGetParam(llfndecl, fcx.env_arg_pos() as c_uint)
     };
-    if !ty::type_is_nil(substd_output_type) {
+    if !ty::type_is_nil(substd_output_type) && !(is_immediate && skip_retptr) {
         fcx.llretptr = Some(make_return_pointer(fcx, substd_output_type));
     }
     fcx
@@ -1667,7 +1668,7 @@ pub fn new_fn_ctxt(ccx: @mut CrateContext,
                    output_type: ty::t,
                    sp: Option<span>)
                 -> fn_ctxt {
-    new_fn_ctxt_w_id(ccx, path, llfndecl, -1, output_type, None, sp)
+    new_fn_ctxt_w_id(ccx, path, llfndecl, -1, output_type, false, None, sp)
 }
 
 // NB: must keep 4 fns in sync:
@@ -1861,6 +1862,7 @@ pub fn trans_closure(ccx: @mut CrateContext,
                                llfndecl,
                                id,
                                output_type,
+                               false,
                                param_substs,
                                Some(body.span));
     let raw_llargs = create_llargs_for_fn_args(fcx, self_arg, decl.inputs);
@@ -2079,6 +2081,7 @@ pub fn trans_enum_variant_or_tuple_like_struct<A:IdAndTy>(
                                llfndecl,
                                ctor_id,
                                result_ty,
+                               false,
                                param_substs,
                                None);
 
diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs
index bebed1c3d0d..f7d0e71387b 100644
--- a/src/librustc/middle/trans/foreign.rs
+++ b/src/librustc/middle/trans/foreign.rs
@@ -10,7 +10,7 @@
 
 
 use back::{link, abi};
-use lib::llvm::{ValueRef};
+use lib::llvm::{Pointer, ValueRef};
 use lib;
 use middle::trans::base::*;
 use middle::trans::cabi;
@@ -550,6 +550,66 @@ pub fn trans_intrinsic(ccx: @mut CrateContext,
                        ref_id: Option<ast::node_id>) {
     debug!("trans_intrinsic(item.ident=%s)", ccx.sess.str_of(item.ident));
 
+    fn simple_llvm_intrinsic(bcx: block, name: &'static str, num_args: uint) {
+        assert!(num_args <= 4);
+        let mut args = [0 as ValueRef, ..4];
+        let first_real_arg = bcx.fcx.arg_pos(0u);
+        for uint::range(0, num_args) |i| {
+            args[i] = get_param(bcx.fcx.llfn, first_real_arg + i);
+        }
+        let llfn = bcx.ccx().intrinsics.get_copy(&name);
+        Ret(bcx, Call(bcx, llfn, args.slice(0, num_args)));
+    }
+
+    fn memcpy_intrinsic(bcx: block, name: &'static str, tp_ty: ty::t, sizebits: u8) {
+        let ccx = bcx.ccx();
+        let lltp_ty = type_of::type_of(ccx, tp_ty);
+        let align = C_i32(machine::llalign_of_min(ccx, lltp_ty) as i32);
+        let size = match sizebits {
+            32 => C_i32(machine::llsize_of_real(ccx, lltp_ty) as i32),
+            64 => C_i64(machine::llsize_of_real(ccx, lltp_ty) as i64),
+            _ => ccx.sess.fatal("Invalid value for sizebits")
+        };
+
+        let decl = bcx.fcx.llfn;
+        let first_real_arg = bcx.fcx.arg_pos(0u);
+        let dst_ptr = PointerCast(bcx, get_param(decl, first_real_arg), Type::i8p());
+        let src_ptr = PointerCast(bcx, get_param(decl, first_real_arg + 1), Type::i8p());
+        let count = get_param(decl, first_real_arg + 2);
+        let volatile = C_i1(false);
+        let llfn = bcx.ccx().intrinsics.get_copy(&name);
+        Call(bcx, llfn, [dst_ptr, src_ptr, Mul(bcx, size, count), align, volatile]);
+        RetVoid(bcx);
+    }
+
+    fn memset_intrinsic(bcx: block, name: &'static str, tp_ty: ty::t, sizebits: u8) {
+        let ccx = bcx.ccx();
+        let lltp_ty = type_of::type_of(ccx, tp_ty);
+        let align = C_i32(machine::llalign_of_min(ccx, lltp_ty) as i32);
+        let size = match sizebits {
+            32 => C_i32(machine::llsize_of_real(ccx, lltp_ty) as i32),
+            64 => C_i64(machine::llsize_of_real(ccx, lltp_ty) as i64),
+            _ => ccx.sess.fatal("Invalid value for sizebits")
+        };
+
+        let decl = bcx.fcx.llfn;
+        let first_real_arg = bcx.fcx.arg_pos(0u);
+        let dst_ptr = PointerCast(bcx, get_param(decl, first_real_arg), Type::i8p());
+        let val = get_param(decl, first_real_arg + 1);
+        let count = get_param(decl, first_real_arg + 2);
+        let volatile = C_i1(false);
+        let llfn = bcx.ccx().intrinsics.get_copy(&name);
+        Call(bcx, llfn, [dst_ptr, val, Mul(bcx, size, count), align, volatile]);
+        RetVoid(bcx);
+    }
+
+    fn count_zeros_intrinsic(bcx: block, name: &'static str) {
+        let x = get_param(bcx.fcx.llfn, bcx.fcx.arg_pos(0u));
+        let y = C_i1(false);
+        let llfn = bcx.ccx().intrinsics.get_copy(&name);
+        Ret(bcx, Call(bcx, llfn, [x, y]));
+    }
+
     let output_type = ty::ty_fn_ret(ty::node_id_to_type(ccx.tcx, item.id));
 
     let fcx = new_fn_ctxt_w_id(ccx,
@@ -557,16 +617,18 @@ pub fn trans_intrinsic(ccx: @mut CrateContext,
                                decl,
                                item.id,
                                output_type,
+                               true,
                                Some(substs),
                                Some(item.span));
 
+    set_always_inline(fcx.llfn);
+
     // Set the fixed stack segment flag if necessary.
     if attr::attrs_contains_name(attributes, "fixed_stack_segment") {
         set_fixed_stack_segment(fcx.llfn);
     }
 
     let mut bcx = top_scope_block(fcx, None);
-    let lltop = bcx.llbb;
     let first_real_arg = fcx.arg_pos(0u);
 
     let nm = ccx.sess.str_of(item.ident);
@@ -595,17 +657,18 @@ pub fn trans_intrinsic(ccx: @mut CrateContext,
                                         get_param(decl, first_real_arg + 1u),
                                         get_param(decl, first_real_arg + 2u),
                                         order);
-                Store(bcx, old, fcx.llretptr.get());
+                Ret(bcx, old);
             }
             "load" => {
                 let old = AtomicLoad(bcx, get_param(decl, first_real_arg),
                                      order);
-                Store(bcx, old, fcx.llretptr.get());
+                Ret(bcx, old);
             }
             "store" => {
                 AtomicStore(bcx, get_param(decl, first_real_arg + 1u),
                             get_param(decl, first_real_arg),
                             order);
+                RetVoid(bcx);
             }
             op => {
                 // These are all AtomicRMW ops
@@ -627,12 +690,10 @@ pub fn trans_intrinsic(ccx: @mut CrateContext,
                 let old = AtomicRMW(bcx, atom_op, get_param(decl, first_real_arg),
                                     get_param(decl, first_real_arg + 1u),
                                     order);
-                Store(bcx, old, fcx.llretptr.get());
+                Ret(bcx, old);
             }
         }
 
-        finish_fn(fcx, lltop, bcx);
-
         return;
     }
 
@@ -640,8 +701,7 @@ pub fn trans_intrinsic(ccx: @mut CrateContext,
         "size_of" => {
             let tp_ty = substs.tys[0];
             let lltp_ty = type_of::type_of(ccx, tp_ty);
-            Store(bcx, C_uint(ccx, machine::llsize_of_real(ccx, lltp_ty)),
-                  fcx.llretptr.get());
+            Ret(bcx, C_uint(ccx, machine::llsize_of_real(ccx, lltp_ty)));
         }
         "move_val" => {
             // Create a datum reflecting the value being moved.
@@ -655,6 +715,7 @@ pub fn trans_intrinsic(ccx: @mut CrateContext,
                              ty: tp_ty, mode: mode};
             bcx = src.move_to(bcx, DROP_EXISTING,
                               get_param(decl, first_real_arg));
+            RetVoid(bcx);
         }
         "move_val_init" => {
             // See comments for `"move_val"`.
@@ -663,18 +724,17 @@ pub fn trans_intrinsic(ccx: @mut CrateContext,
             let src = Datum {val: get_param(decl, first_real_arg + 1u),
                              ty: tp_ty, mode: mode};
             bcx = src.move_to(bcx, INIT, get_param(decl, first_real_arg));
+            RetVoid(bcx);
         }
         "min_align_of" => {
             let tp_ty = substs.tys[0];
             let lltp_ty = type_of::type_of(ccx, tp_ty);
-            Store(bcx, C_uint(ccx, machine::llalign_of_min(ccx, lltp_ty)),
-                  fcx.llretptr.get());
+            Ret(bcx, C_uint(ccx, machine::llalign_of_min(ccx, lltp_ty)));
         }
         "pref_align_of"=> {
             let tp_ty = substs.tys[0];
             let lltp_ty = type_of::type_of(ccx, tp_ty);
-            Store(bcx, C_uint(ccx, machine::llalign_of_pref(ccx, lltp_ty)),
-                  fcx.llretptr.get());
+            Ret(bcx, C_uint(ccx, machine::llalign_of_pref(ccx, lltp_ty)));
         }
         "get_tydesc" => {
             let tp_ty = substs.tys[0];
@@ -687,19 +747,31 @@ pub fn trans_intrinsic(ccx: @mut CrateContext,
             // the llvm type of intrinsic::TyDesc struct.
             let userland_tydesc_ty = type_of::type_of(ccx, output_type);
             let td = PointerCast(bcx, static_ti.tydesc, userland_tydesc_ty);
-            Store(bcx, td, fcx.llretptr.get());
+            Ret(bcx, td);
         }
         "init" => {
             let tp_ty = substs.tys[0];
             let lltp_ty = type_of::type_of(ccx, tp_ty);
-            if !ty::type_is_nil(tp_ty) {
-                Store(bcx, C_null(lltp_ty), fcx.llretptr.get());
+            match bcx.fcx.llretptr {
+                Some(ptr) => { Store(bcx, C_null(lltp_ty), ptr); RetVoid(bcx); }
+                None if ty::type_is_nil(tp_ty) => RetVoid(bcx),
+                None => Ret(bcx, C_null(lltp_ty)),
             }
         }
         "uninit" => {
             // Do nothing, this is effectively a no-op
+            let retty = substs.tys[0];
+            if ty::type_is_immediate(ccx.tcx, retty) && !ty::type_is_nil(retty) {
+                unsafe {
+                    Ret(bcx, lib::llvm::llvm::LLVMGetUndef(type_of(ccx, retty).to_ref()));
+                }
+            } else {
+                RetVoid(bcx)
+            }
+        }
+        "forget" => {
+            RetVoid(bcx);
         }
-        "forget" => {}
         "transmute" => {
             let (in_type, out_type) = (substs.tys[0], substs.tys[1]);
             let llintype = type_of::type_of(ccx, in_type);
@@ -726,34 +798,45 @@ pub fn trans_intrinsic(ccx: @mut CrateContext,
             }
 
             if !ty::type_is_nil(out_type) {
-                let lldestptr = fcx.llretptr.get();
                 let llsrcval = get_param(decl, first_real_arg);
                 if ty::type_is_immediate(ccx.tcx, in_type) {
-                    let lldestptr = PointerCast(bcx, lldestptr, llintype.ptr_to());
-                    Store(bcx, llsrcval, lldestptr);
+                    match fcx.llretptr {
+                        Some(llretptr) => {
+                            Store(bcx, llsrcval, PointerCast(bcx, llretptr, llintype.ptr_to()));
+                            RetVoid(bcx);
+                        }
+                        None => match (llintype.kind(), llouttype.kind()) {
+                            (Pointer, other) | (other, Pointer) if other != Pointer => {
+                                let tmp = Alloca(bcx, llouttype, "");
+                                Store(bcx, llsrcval, PointerCast(bcx, tmp, llintype.ptr_to()));
+                                Ret(bcx, Load(bcx, tmp));
+                            }
+                            _ => Ret(bcx, BitCast(bcx, llsrcval, llouttype))
+                        }
+                    }
                 } else {
                     // NB: Do not use a Load and Store here. This causes massive
                     // code bloat when `transmute` is used on large structural
                     // types.
+                    let lldestptr = fcx.llretptr.get();
                     let lldestptr = PointerCast(bcx, lldestptr, Type::i8p());
                     let llsrcptr = PointerCast(bcx, llsrcval, Type::i8p());
 
                     let llsize = llsize_of(ccx, llintype);
                     call_memcpy(bcx, lldestptr, llsrcptr, llsize, 1);
+                    RetVoid(bcx);
                 };
+            } else {
+                RetVoid(bcx);
             }
         }
         "needs_drop" => {
             let tp_ty = substs.tys[0];
-            Store(bcx,
-                  C_bool(ty::type_needs_drop(ccx.tcx, tp_ty)),
-                  fcx.llretptr.get());
+            Ret(bcx, C_bool(ty::type_needs_drop(ccx.tcx, tp_ty)));
         }
         "contains_managed" => {
             let tp_ty = substs.tys[0];
-            Store(bcx,
-                  C_bool(ty::type_contents(ccx.tcx, tp_ty).contains_managed()),
-                  fcx.llretptr.get());
+            Ret(bcx, C_bool(ty::type_contents(ccx.tcx, tp_ty).contains_managed()));
         }
         "visit_tydesc" => {
             let td = get_param(decl, first_real_arg);
@@ -763,6 +846,7 @@ pub fn trans_intrinsic(ccx: @mut CrateContext,
             let td = PointerCast(bcx, td, ccx.tydesc_type.ptr_to());
             glue::call_tydesc_glue_full(bcx, visitor, td,
                                         abi::tydesc_field_visit_glue, None);
+            RetVoid(bcx);
         }
         "frame_address" => {
             let frameaddress = ccx.intrinsics.get_copy(& &"llvm.frameaddress");
@@ -789,6 +873,7 @@ pub fn trans_intrinsic(ccx: @mut CrateContext,
                 bcx, None, fty, ty::mk_nil(),
                 |bcx| Callee {bcx: bcx, data: Closure(datum)},
                 ArgVals(arg_vals), Some(Ignore), DontAutorefArg).bcx;
+            RetVoid(bcx);
         }
         "morestack_addr" => {
             // XXX This is a hack to grab the address of this particular
@@ -798,334 +883,65 @@ pub fn trans_intrinsic(ccx: @mut CrateContext,
             let morestack_addr = decl_cdecl_fn(
                 bcx.ccx().llmod, "__morestack", llfty);
             let morestack_addr = PointerCast(bcx, morestack_addr, Type::nil().ptr_to());
-            Store(bcx, morestack_addr, fcx.llretptr.get());
-        }
-        "memcpy32" => {
-            let tp_ty = substs.tys[0];
-            let lltp_ty = type_of::type_of(ccx, tp_ty);
-            let align = C_i32(machine::llalign_of_min(ccx, lltp_ty) as i32);
-            let size = C_i32(machine::llsize_of_real(ccx, lltp_ty) as i32);
-
-            let dst_ptr = PointerCast(bcx, get_param(decl, first_real_arg), Type::i8p());
-            let src_ptr = PointerCast(bcx, get_param(decl, first_real_arg + 1), Type::i8p());
-            let count = get_param(decl, first_real_arg + 2);
-            let volatile = C_i1(false);
-            let llfn = bcx.ccx().intrinsics.get_copy(& &"llvm.memcpy.p0i8.p0i8.i32");
-            Call(bcx, llfn, [dst_ptr, src_ptr, Mul(bcx, size, count), align, volatile]);
-        }
-        "memcpy64" => {
-            let tp_ty = substs.tys[0];
-            let lltp_ty = type_of::type_of(ccx, tp_ty);
-            let align = C_i32(machine::llalign_of_min(ccx, lltp_ty) as i32);
-            let size = C_i64(machine::llsize_of_real(ccx, lltp_ty) as i64);
-
-            let dst_ptr = PointerCast(bcx, get_param(decl, first_real_arg), Type::i8p());
-            let src_ptr = PointerCast(bcx, get_param(decl, first_real_arg + 1), Type::i8p());
-            let count = get_param(decl, first_real_arg + 2);
-            let volatile = C_i1(false);
-            let llfn = bcx.ccx().intrinsics.get_copy(& &"llvm.memcpy.p0i8.p0i8.i64");
-            Call(bcx, llfn, [dst_ptr, src_ptr, Mul(bcx, size, count), align, volatile]);
-        }
-        "memmove32" => {
-            let tp_ty = substs.tys[0];
-            let lltp_ty = type_of::type_of(ccx, tp_ty);
-            let align = C_i32(machine::llalign_of_min(ccx, lltp_ty) as i32);
-            let size = C_i32(machine::llsize_of_real(ccx, lltp_ty) as i32);
-
-            let dst_ptr = PointerCast(bcx, get_param(decl, first_real_arg), Type::i8p());
-            let src_ptr = PointerCast(bcx, get_param(decl, first_real_arg + 1), Type::i8p());
-            let count = get_param(decl, first_real_arg + 2);
-            let volatile = C_i1(false);
-            let llfn = bcx.ccx().intrinsics.get_copy(& &"llvm.memmove.p0i8.p0i8.i32");
-            Call(bcx, llfn, [dst_ptr, src_ptr, Mul(bcx, size, count), align, volatile]);
-        }
-        "memmove64" => {
-            let tp_ty = substs.tys[0];
-            let lltp_ty = type_of::type_of(ccx, tp_ty);
-            let align = C_i32(machine::llalign_of_min(ccx, lltp_ty) as i32);
-            let size = C_i64(machine::llsize_of_real(ccx, lltp_ty) as i64);
-
-            let dst_ptr = PointerCast(bcx, get_param(decl, first_real_arg), Type::i8p());
-            let src_ptr = PointerCast(bcx, get_param(decl, first_real_arg + 1), Type::i8p());
-            let count = get_param(decl, first_real_arg + 2);
-            let volatile = C_i1(false);
-            let llfn = bcx.ccx().intrinsics.get_copy(& &"llvm.memmove.p0i8.p0i8.i64");
-            Call(bcx, llfn, [dst_ptr, src_ptr, Mul(bcx, size, count), align, volatile]);
-        }
-        "memset32" => {
-            let tp_ty = substs.tys[0];
-            let lltp_ty = type_of::type_of(ccx, tp_ty);
-            let align = C_i32(machine::llalign_of_min(ccx, lltp_ty) as i32);
-            let size = C_i32(machine::llsize_of_real(ccx, lltp_ty) as i32);
-
-            let dst_ptr = PointerCast(bcx, get_param(decl, first_real_arg), Type::i8p());
-            let val = get_param(decl, first_real_arg + 1);
-            let count = get_param(decl, first_real_arg + 2);
-            let volatile = C_i1(false);
-            let llfn = bcx.ccx().intrinsics.get_copy(& &"llvm.memset.p0i8.i32");
-            Call(bcx, llfn, [dst_ptr, val, Mul(bcx, size, count), align, volatile]);
-        }
-        "memset64" => {
-            let tp_ty = substs.tys[0];
-            let lltp_ty = type_of::type_of(ccx, tp_ty);
-            let align = C_i32(machine::llalign_of_min(ccx, lltp_ty) as i32);
-            let size = C_i64(machine::llsize_of_real(ccx, lltp_ty) as i64);
-
-            let dst_ptr = PointerCast(bcx, get_param(decl, first_real_arg), Type::i8p());
-            let val = get_param(decl, first_real_arg + 1);
-            let count = get_param(decl, first_real_arg + 2);
-            let volatile = C_i1(false);
-            let llfn = bcx.ccx().intrinsics.get_copy(& &"llvm.memset.p0i8.i64");
-            Call(bcx, llfn, [dst_ptr, val, Mul(bcx, size, count), align, volatile]);
-        }
-        "sqrtf32" => {
-            let x = get_param(decl, first_real_arg);
-            let sqrtf = ccx.intrinsics.get_copy(& &"llvm.sqrt.f32");
-            Store(bcx, Call(bcx, sqrtf, [x]), fcx.llretptr.get());
-        }
-        "sqrtf64" => {
-            let x = get_param(decl, first_real_arg);
-            let sqrtf = ccx.intrinsics.get_copy(& &"llvm.sqrt.f64");
-            Store(bcx, Call(bcx, sqrtf, [x]), fcx.llretptr.get());
-        }
-        "powif32" => {
-            let a = get_param(decl, first_real_arg);
-            let x = get_param(decl, first_real_arg + 1u);
-            let powif = ccx.intrinsics.get_copy(& &"llvm.powi.f32");
-            Store(bcx, Call(bcx, powif, [a, x]), fcx.llretptr.get());
-        }
-        "powif64" => {
-            let a = get_param(decl, first_real_arg);
-            let x = get_param(decl, first_real_arg + 1u);
-            let powif = ccx.intrinsics.get_copy(& &"llvm.powi.f64");
-            Store(bcx, Call(bcx, powif, [a, x]), fcx.llretptr.get());
-        }
-        "sinf32" => {
-            let x = get_param(decl, first_real_arg);
-            let sinf = ccx.intrinsics.get_copy(& &"llvm.sin.f32");
-            Store(bcx, Call(bcx, sinf, [x]), fcx.llretptr.get());
-        }
-        "sinf64" => {
-            let x = get_param(decl, first_real_arg);
-            let sinf = ccx.intrinsics.get_copy(& &"llvm.sin.f64");
-            Store(bcx, Call(bcx, sinf, [x]), fcx.llretptr.get());
-        }
-        "cosf32" => {
-            let x = get_param(decl, first_real_arg);
-            let cosf = ccx.intrinsics.get_copy(& &"llvm.cos.f32");
-            Store(bcx, Call(bcx, cosf, [x]), fcx.llretptr.get());
-        }
-        "cosf64" => {
-            let x = get_param(decl, first_real_arg);
-            let cosf = ccx.intrinsics.get_copy(& &"llvm.cos.f64");
-            Store(bcx, Call(bcx, cosf, [x]), fcx.llretptr.get());
-        }
-        "powf32" => {
-            let a = get_param(decl, first_real_arg);
-            let x = get_param(decl, first_real_arg + 1u);
-            let powf = ccx.intrinsics.get_copy(& &"llvm.pow.f32");
-            Store(bcx, Call(bcx, powf, [a, x]), fcx.llretptr.get());
-        }
-        "powf64" => {
-            let a = get_param(decl, first_real_arg);
-            let x = get_param(decl, first_real_arg + 1u);
-            let powf = ccx.intrinsics.get_copy(& &"llvm.pow.f64");
-            Store(bcx, Call(bcx, powf, [a, x]), fcx.llretptr.get());
-        }
-        "expf32" => {
-            let x = get_param(decl, first_real_arg);
-            let expf = ccx.intrinsics.get_copy(& &"llvm.exp.f32");
-            Store(bcx, Call(bcx, expf, [x]), fcx.llretptr.get());
-        }
-        "expf64" => {
-            let x = get_param(decl, first_real_arg);
-            let expf = ccx.intrinsics.get_copy(& &"llvm.exp.f64");
-            Store(bcx, Call(bcx, expf, [x]), fcx.llretptr.get());
-        }
-        "exp2f32" => {
-            let x = get_param(decl, first_real_arg);
-            let exp2f = ccx.intrinsics.get_copy(& &"llvm.exp2.f32");
-            Store(bcx, Call(bcx, exp2f, [x]), fcx.llretptr.get());
-        }
-        "exp2f64" => {
-            let x = get_param(decl, first_real_arg);
-            let exp2f = ccx.intrinsics.get_copy(& &"llvm.exp2.f64");
-            Store(bcx, Call(bcx, exp2f, [x]), fcx.llretptr.get());
-        }
-        "logf32" => {
-            let x = get_param(decl, first_real_arg);
-            let logf = ccx.intrinsics.get_copy(& &"llvm.log.f32");
-            Store(bcx, Call(bcx, logf, [x]), fcx.llretptr.get());
-        }
-        "logf64" => {
-            let x = get_param(decl, first_real_arg);
-            let logf = ccx.intrinsics.get_copy(& &"llvm.log.f64");
-            Store(bcx, Call(bcx, logf, [x]), fcx.llretptr.get());
-        }
-        "log10f32" => {
-            let x = get_param(decl, first_real_arg);
-            let log10f = ccx.intrinsics.get_copy(& &"llvm.log10.f32");
-            Store(bcx, Call(bcx, log10f, [x]), fcx.llretptr.get());
-        }
-        "log10f64" => {
-            let x = get_param(decl, first_real_arg);
-            let log10f = ccx.intrinsics.get_copy(& &"llvm.log10.f64");
-            Store(bcx, Call(bcx, log10f, [x]), fcx.llretptr.get());
-        }
-        "log2f32" => {
-            let x = get_param(decl, first_real_arg);
-            let log2f = ccx.intrinsics.get_copy(& &"llvm.log2.f32");
-            Store(bcx, Call(bcx, log2f, [x]), fcx.llretptr.get());
-        }
-        "log2f64" => {
-            let x = get_param(decl, first_real_arg);
-            let log2f = ccx.intrinsics.get_copy(& &"llvm.log2.f64");
-            Store(bcx, Call(bcx, log2f, [x]), fcx.llretptr.get());
-        }
-        "fmaf32" => {
-            let a = get_param(decl, first_real_arg);
-            let b = get_param(decl, first_real_arg + 1u);
-            let c = get_param(decl, first_real_arg + 2u);
-            let fmaf = ccx.intrinsics.get_copy(& &"llvm.fma.f32");
-            Store(bcx, Call(bcx, fmaf, [a, b, c]), fcx.llretptr.get());
-        }
-        "fmaf64" => {
-            let a = get_param(decl, first_real_arg);
-            let b = get_param(decl, first_real_arg + 1u);
-            let c = get_param(decl, first_real_arg + 2u);
-            let fmaf = ccx.intrinsics.get_copy(& &"llvm.fma.f64");
-            Store(bcx, Call(bcx, fmaf, [a, b, c]), fcx.llretptr.get());
-        }
-        "fabsf32" => {
-            let x = get_param(decl, first_real_arg);
-            let fabsf = ccx.intrinsics.get_copy(& &"llvm.fabs.f32");
-            Store(bcx, Call(bcx, fabsf, [x]), fcx.llretptr.get());
-        }
-        "fabsf64" => {
-            let x = get_param(decl, first_real_arg);
-            let fabsf = ccx.intrinsics.get_copy(& &"llvm.fabs.f64");
-            Store(bcx, Call(bcx, fabsf, [x]), fcx.llretptr.get());
-        }
-        "floorf32" => {
-            let x = get_param(decl, first_real_arg);
-            let floorf = ccx.intrinsics.get_copy(& &"llvm.floor.f32");
-            Store(bcx, Call(bcx, floorf, [x]), fcx.llretptr.get());
-        }
-        "floorf64" => {
-            let x = get_param(decl, first_real_arg);
-            let floorf = ccx.intrinsics.get_copy(& &"llvm.floor.f64");
-            Store(bcx, Call(bcx, floorf, [x]), fcx.llretptr.get());
-        }
-        "ceilf32" => {
-            let x = get_param(decl, first_real_arg);
-            let ceilf = ccx.intrinsics.get_copy(& &"llvm.ceil.f32");
-            Store(bcx, Call(bcx, ceilf, [x]), fcx.llretptr.get());
-        }
-        "ceilf64" => {
-            let x = get_param(decl, first_real_arg);
-            let ceilf = ccx.intrinsics.get_copy(& &"llvm.ceil.f64");
-            Store(bcx, Call(bcx, ceilf, [x]), fcx.llretptr.get());
-        }
-        "truncf32" => {
-            let x = get_param(decl, first_real_arg);
-            let truncf = ccx.intrinsics.get_copy(& &"llvm.trunc.f32");
-            Store(bcx, Call(bcx, truncf, [x]), fcx.llretptr.get());
-        }
-        "truncf64" => {
-            let x = get_param(decl, first_real_arg);
-            let truncf = ccx.intrinsics.get_copy(& &"llvm.trunc.f64");
-            Store(bcx, Call(bcx, truncf, [x]), fcx.llretptr.get());
-        }
-        "ctpop8" => {
-            let x = get_param(decl, first_real_arg);
-            let ctpop = ccx.intrinsics.get_copy(& &"llvm.ctpop.i8");
-            Store(bcx, Call(bcx, ctpop, [x]), fcx.llretptr.get())
-        }
-        "ctpop16" => {
-            let x = get_param(decl, first_real_arg);
-            let ctpop = ccx.intrinsics.get_copy(& &"llvm.ctpop.i16");
-            Store(bcx, Call(bcx, ctpop, [x]), fcx.llretptr.get())
-        }
-        "ctpop32" => {
-            let x = get_param(decl, first_real_arg);
-            let ctpop = ccx.intrinsics.get_copy(& &"llvm.ctpop.i32");
-            Store(bcx, Call(bcx, ctpop, [x]), fcx.llretptr.get())
-        }
-        "ctpop64" => {
-            let x = get_param(decl, first_real_arg);
-            let ctpop = ccx.intrinsics.get_copy(& &"llvm.ctpop.i64");
-            Store(bcx, Call(bcx, ctpop, [x]), fcx.llretptr.get())
-        }
-        "ctlz8" => {
-            let x = get_param(decl, first_real_arg);
-            let y = C_i1(false);
-            let ctlz = ccx.intrinsics.get_copy(& &"llvm.ctlz.i8");
-            Store(bcx, Call(bcx, ctlz, [x, y]), fcx.llretptr.get())
-        }
-        "ctlz16" => {
-            let x = get_param(decl, first_real_arg);
-            let y = C_i1(false);
-            let ctlz = ccx.intrinsics.get_copy(& &"llvm.ctlz.i16");
-            Store(bcx, Call(bcx, ctlz, [x, y]), fcx.llretptr.get())
-        }
-        "ctlz32" => {
-            let x = get_param(decl, first_real_arg);
-            let y = C_i1(false);
-            let ctlz = ccx.intrinsics.get_copy(& &"llvm.ctlz.i32");
-            Store(bcx, Call(bcx, ctlz, [x, y]), fcx.llretptr.get())
-        }
-        "ctlz64" => {
-            let x = get_param(decl, first_real_arg);
-            let y = C_i1(false);
-            let ctlz = ccx.intrinsics.get_copy(& &"llvm.ctlz.i64");
-            Store(bcx, Call(bcx, ctlz, [x, y]), fcx.llretptr.get())
-        }
-        "cttz8" => {
-            let x = get_param(decl, first_real_arg);
-            let y = C_i1(false);
-            let cttz = ccx.intrinsics.get_copy(& &"llvm.cttz.i8");
-            Store(bcx, Call(bcx, cttz, [x, y]), fcx.llretptr.get())
-        }
-        "cttz16" => {
-            let x = get_param(decl, first_real_arg);
-            let y = C_i1(false);
-            let cttz = ccx.intrinsics.get_copy(& &"llvm.cttz.i16");
-            Store(bcx, Call(bcx, cttz, [x, y]), fcx.llretptr.get())
-        }
-        "cttz32" => {
-            let x = get_param(decl, first_real_arg);
-            let y = C_i1(false);
-            let cttz = ccx.intrinsics.get_copy(& &"llvm.cttz.i32");
-            Store(bcx, Call(bcx, cttz, [x, y]), fcx.llretptr.get())
-        }
-        "cttz64" => {
-            let x = get_param(decl, first_real_arg);
-            let y = C_i1(false);
-            let cttz = ccx.intrinsics.get_copy(& &"llvm.cttz.i64");
-            Store(bcx, Call(bcx, cttz, [x, y]), fcx.llretptr.get())
-        }
-        "bswap16" => {
-            let x = get_param(decl, first_real_arg);
-            let cttz = ccx.intrinsics.get_copy(& &"llvm.bswap.i16");
-            Store(bcx, Call(bcx, cttz, [x]), fcx.llretptr.get())
-        }
-        "bswap32" => {
-            let x = get_param(decl, first_real_arg);
-            let cttz = ccx.intrinsics.get_copy(& &"llvm.bswap.i32");
-            Store(bcx, Call(bcx, cttz, [x]), fcx.llretptr.get())
-        }
-        "bswap64" => {
-            let x = get_param(decl, first_real_arg);
-            let cttz = ccx.intrinsics.get_copy(& &"llvm.bswap.i64");
-            Store(bcx, Call(bcx, cttz, [x]), fcx.llretptr.get())
-        }
+            Ret(bcx, morestack_addr);
+        }
+        "memcpy32" => memcpy_intrinsic(bcx, "llvm.memcpy.p0i8.p0i8.i32", substs.tys[0], 32),
+        "memcpy64" => memcpy_intrinsic(bcx, "llvm.memcpy.p0i8.p0i8.i64", substs.tys[0], 64),
+        "memmove32" => memcpy_intrinsic(bcx, "llvm.memmove.p0i8.p0i8.i32", substs.tys[0], 32),
+        "memmove64" => memcpy_intrinsic(bcx, "llvm.memmove.p0i8.p0i8.i64", substs.tys[0], 64),
+        "memset32" => memset_intrinsic(bcx, "llvm.memset.p0i8.i32", substs.tys[0], 32),
+        "memset64" => memset_intrinsic(bcx, "llvm.memset.p0i8.i64", substs.tys[0], 64),
+        "sqrtf32" => simple_llvm_intrinsic(bcx, "llvm.sqrt.f32", 1),
+        "sqrtf64" => simple_llvm_intrinsic(bcx, "llvm.sqrt.f64", 1),
+        "powif32" => simple_llvm_intrinsic(bcx, "llvm.powi.f32", 2),
+        "powif64" => simple_llvm_intrinsic(bcx, "llvm.powi.f64", 2),
+        "sinf32" => simple_llvm_intrinsic(bcx, "llvm.sin.f32", 1),
+        "sinf64" => simple_llvm_intrinsic(bcx, "llvm.sin.f64", 1),
+        "cosf32" => simple_llvm_intrinsic(bcx, "llvm.cos.f32", 1),
+        "cosf64" => simple_llvm_intrinsic(bcx, "llvm.cos.f64", 1),
+        "powf32" => simple_llvm_intrinsic(bcx, "llvm.pow.f32", 2),
+        "powf64" => simple_llvm_intrinsic(bcx, "llvm.pow.f64", 2),
+        "expf32" => simple_llvm_intrinsic(bcx, "llvm.exp.f32", 1),
+        "expf64" => simple_llvm_intrinsic(bcx, "llvm.exp.f64", 1),
+        "exp2f32" => simple_llvm_intrinsic(bcx, "llvm.exp2.f32", 1),
+        "exp2f64" => simple_llvm_intrinsic(bcx, "llvm.exp2.f64", 1),
+        "logf32" => simple_llvm_intrinsic(bcx, "llvm.log.f32", 1),
+        "logf64" => simple_llvm_intrinsic(bcx, "llvm.log.f64", 1),
+        "log10f32" => simple_llvm_intrinsic(bcx, "llvm.log10.f32", 1),
+        "log10f64" => simple_llvm_intrinsic(bcx, "llvm.log10.f64", 1),
+        "log2f32" => simple_llvm_intrinsic(bcx, "llvm.log2.f32", 1),
+        "log2f64" => simple_llvm_intrinsic(bcx, "llvm.log2.f64", 1),
+        "fmaf32" => simple_llvm_intrinsic(bcx, "llvm.fma.f32", 3),
+        "fmaf64" => simple_llvm_intrinsic(bcx, "llvm.fma.f64", 3),
+        "fabsf32" => simple_llvm_intrinsic(bcx, "llvm.fabs.f32", 1),
+        "fabsf64" => simple_llvm_intrinsic(bcx, "llvm.fabs.f64", 1),
+        "floorf32" => simple_llvm_intrinsic(bcx, "llvm.floor.f32", 1),
+        "floorf64" => simple_llvm_intrinsic(bcx, "llvm.floor.f64", 1),
+        "ceilf32" => simple_llvm_intrinsic(bcx, "llvm.ceil.f32", 1),
+        "ceilf64" => simple_llvm_intrinsic(bcx, "llvm.ceil.f64", 1),
+        "truncf32" => simple_llvm_intrinsic(bcx, "llvm.trunc.f32", 1),
+        "truncf64" => simple_llvm_intrinsic(bcx, "llvm.trunc.f64", 1),
+        "ctpop8" => simple_llvm_intrinsic(bcx, "llvm.ctpop.i8", 1),
+        "ctpop16" => simple_llvm_intrinsic(bcx, "llvm.ctpop.i16", 1),
+        "ctpop32" => simple_llvm_intrinsic(bcx, "llvm.ctpop.i32", 1),
+        "ctpop64" => simple_llvm_intrinsic(bcx, "llvm.ctpop.i64", 1),
+        "ctlz8" => count_zeros_intrinsic(bcx, "llvm.ctlz.i8"),
+        "ctlz16" => count_zeros_intrinsic(bcx, "llvm.ctlz.i16"),
+        "ctlz32" => count_zeros_intrinsic(bcx, "llvm.ctlz.i32"),
+        "ctlz64" => count_zeros_intrinsic(bcx, "llvm.ctlz.i64"),
+        "cttz8" => count_zeros_intrinsic(bcx, "llvm.cttz.i8"),
+        "cttz16" => count_zeros_intrinsic(bcx, "llvm.cttz.i16"),
+        "cttz32" => count_zeros_intrinsic(bcx, "llvm.cttz.i32"),
+        "cttz64" => count_zeros_intrinsic(bcx, "llvm.cttz.i64"),
+        "bswap16" => simple_llvm_intrinsic(bcx, "llvm.bswap.i16", 1),
+        "bswap32" => simple_llvm_intrinsic(bcx, "llvm.bswap.i32", 1),
+        "bswap64" => simple_llvm_intrinsic(bcx, "llvm.bswap.i64", 1),
         _ => {
             // Could we make this an enum rather than a string? does it get
             // checked earlier?
             ccx.sess.span_bug(item.span, "unknown intrinsic");
         }
     }
-    finish_fn(fcx, lltop, bcx);
 }
 
 /**