about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMichael Darakananda <pongad@gmail.com>2014-04-09 19:56:31 -0400
committerMichael Darakananda <pongad@gmail.com>2014-04-09 19:56:31 -0400
commita00be50e00bc244569cb8d660f96abdde10dc6ef (patch)
tree8be86006f28fb3c1c9634a575a58adb45e47d6ca /src
parent8801d891c4674f335fcdc67cb34237902d89a5ec (diff)
downloadrust-a00be50e00bc244569cb8d660f96abdde10dc6ef.tar.gz
rust-a00be50e00bc244569cb8d660f96abdde10dc6ef.zip
Emit intrinsic lazily
Diffstat (limited to 'src')
-rw-r--r--src/librustc/middle/trans/base.rs166
-rw-r--r--src/librustc/middle/trans/context.rs183
-rw-r--r--src/librustc/middle/trans/expr.rs2
-rw-r--r--src/librustc/middle/trans/intrinsic.rs14
4 files changed, 189 insertions, 176 deletions
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index d5646c611a0..69155f3df8e 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -977,7 +977,7 @@ pub fn call_memcpy(cx: &Block, dst: ValueRef, src: ValueRef, n_bytes: ValueRef,
         X86 | Arm | Mips => "llvm.memcpy.p0i8.p0i8.i32",
         X86_64 => "llvm.memcpy.p0i8.p0i8.i64"
     };
-    let memcpy = ccx.intrinsics.get_copy(&key);
+    let memcpy = ccx.get_intrinsic(&key);
     let src_ptr = PointerCast(cx, src, Type::i8p(ccx));
     let dst_ptr = PointerCast(cx, dst, Type::i8p(ccx));
     let size = IntCast(cx, n_bytes, ccx.int_type);
@@ -1022,7 +1022,7 @@ fn memzero(b: &Builder, llptr: ValueRef, ty: Type) {
         X86_64 => "llvm.memset.p0i8.i64"
     };
 
-    let llintrinsicfn = ccx.intrinsics.get_copy(&intrinsic_key);
+    let llintrinsicfn = ccx.get_intrinsic(&intrinsic_key);
     let llptr = b.pointercast(llptr, Type::i8(ccx).ptr_to());
     let llzeroval = C_u8(ccx, 0);
     let size = machine::llsize_of(ccx, ty);
@@ -2043,168 +2043,6 @@ pub fn p2i(ccx: &CrateContext, v: ValueRef) -> ValueRef {
     }
 }
 
-
-pub fn declare_intrinsics(ccx: &mut CrateContext) {
-    macro_rules! ifn (
-        ($name:expr fn() -> $ret:expr) => ({
-            let name = $name;
-            // HACK(eddyb) dummy output type, shouln't affect anything.
-            let f = decl_cdecl_fn(ccx.llmod, name, Type::func([], &$ret), ty::mk_nil());
-            ccx.intrinsics.insert(name, f);
-        });
-        ($name:expr fn($($arg:expr),*) -> $ret:expr) => ({
-            let name = $name;
-            // HACK(eddyb) dummy output type, shouln't affect anything.
-            let f = decl_cdecl_fn(ccx.llmod, name,
-                                  Type::func([$($arg),*], &$ret), ty::mk_nil());
-            ccx.intrinsics.insert(name, f);
-        })
-    )
-    macro_rules! mk_struct (
-        ($($field_ty:expr),*) => (Type::struct_(ccx, [$($field_ty),*], false))
-    )
-
-    let i8p = Type::i8p(ccx);
-    let void = Type::void(ccx);
-    let i1 = Type::i1(ccx);
-    let t_i8 = Type::i8(ccx);
-    let t_i16 = Type::i16(ccx);
-    let t_i32 = Type::i32(ccx);
-    let t_i64 = Type::i64(ccx);
-    let t_f32 = Type::f32(ccx);
-    let t_f64 = Type::f64(ccx);
-
-    ifn!("llvm.memcpy.p0i8.p0i8.i32" fn(i8p, i8p, t_i32, t_i32, i1) -> void);
-    ifn!("llvm.memcpy.p0i8.p0i8.i64" fn(i8p, i8p, t_i64, t_i32, i1) -> void);
-    ifn!("llvm.memmove.p0i8.p0i8.i32" fn(i8p, i8p, t_i32, t_i32, i1) -> void);
-    ifn!("llvm.memmove.p0i8.p0i8.i64" fn(i8p, i8p, t_i64, t_i32, i1) -> void);
-    ifn!("llvm.memset.p0i8.i32" fn(i8p, t_i8, t_i32, t_i32, i1) -> void);
-    ifn!("llvm.memset.p0i8.i64" fn(i8p, t_i8, t_i64, t_i32, i1) -> void);
-
-    ifn!("llvm.trap" fn() -> void);
-    ifn!("llvm.debugtrap" fn() -> void);
-    ifn!("llvm.frameaddress" fn(t_i32) -> i8p);
-
-    ifn!("llvm.powi.f32" fn(t_f32, t_i32) -> t_f32);
-    ifn!("llvm.powi.f64" fn(t_f64, t_i32) -> t_f64);
-    ifn!("llvm.pow.f32" fn(t_f32, t_f32) -> t_f32);
-    ifn!("llvm.pow.f64" fn(t_f64, t_f64) -> t_f64);
-
-    ifn!("llvm.sqrt.f32" fn(t_f32) -> t_f32);
-    ifn!("llvm.sqrt.f64" fn(t_f64) -> t_f64);
-    ifn!("llvm.sin.f32" fn(t_f32) -> t_f32);
-    ifn!("llvm.sin.f64" fn(t_f64) -> t_f64);
-    ifn!("llvm.cos.f32" fn(t_f32) -> t_f32);
-    ifn!("llvm.cos.f64" fn(t_f64) -> t_f64);
-    ifn!("llvm.exp.f32" fn(t_f32) -> t_f32);
-    ifn!("llvm.exp.f64" fn(t_f64) -> t_f64);
-    ifn!("llvm.exp2.f32" fn(t_f32) -> t_f32);
-    ifn!("llvm.exp2.f64" fn(t_f64) -> t_f64);
-    ifn!("llvm.log.f32" fn(t_f32) -> t_f32);
-    ifn!("llvm.log.f64" fn(t_f64) -> t_f64);
-    ifn!("llvm.log10.f32" fn(t_f32) -> t_f32);
-    ifn!("llvm.log10.f64" fn(t_f64) -> t_f64);
-    ifn!("llvm.log2.f32" fn(t_f32) -> t_f32);
-    ifn!("llvm.log2.f64" fn(t_f64) -> t_f64);
-
-    ifn!("llvm.fma.f32" fn(t_f32, t_f32, t_f32) -> t_f32);
-    ifn!("llvm.fma.f64" fn(t_f64, t_f64, t_f64) -> t_f64);
-
-    ifn!("llvm.fabs.f32" fn(t_f32) -> t_f32);
-    ifn!("llvm.fabs.f64" fn(t_f64) -> t_f64);
-
-    ifn!("llvm.floor.f32" fn(t_f32) -> t_f32);
-    ifn!("llvm.floor.f64" fn(t_f64) -> t_f64);
-    ifn!("llvm.ceil.f32" fn(t_f32) -> t_f32);
-    ifn!("llvm.ceil.f64" fn(t_f64) -> t_f64);
-    ifn!("llvm.trunc.f32" fn(t_f32) -> t_f32);
-    ifn!("llvm.trunc.f64" fn(t_f64) -> t_f64);
-
-    ifn!("llvm.rint.f32" fn(t_f32) -> t_f32);
-    ifn!("llvm.rint.f64" fn(t_f64) -> t_f64);
-    ifn!("llvm.nearbyint.f32" fn(t_f32) -> t_f32);
-    ifn!("llvm.nearbyint.f64" fn(t_f64) -> t_f64);
-
-    ifn!("llvm.ctpop.i8" fn(t_i8) -> t_i8);
-    ifn!("llvm.ctpop.i16" fn(t_i16) -> t_i16);
-    ifn!("llvm.ctpop.i32" fn(t_i32) -> t_i32);
-    ifn!("llvm.ctpop.i64" fn(t_i64) -> t_i64);
-
-    ifn!("llvm.ctlz.i8" fn(t_i8 , i1) -> t_i8);
-    ifn!("llvm.ctlz.i16" fn(t_i16, i1) -> t_i16);
-    ifn!("llvm.ctlz.i32" fn(t_i32, i1) -> t_i32);
-    ifn!("llvm.ctlz.i64" fn(t_i64, i1) -> t_i64);
-
-    ifn!("llvm.cttz.i8" fn(t_i8 , i1) -> t_i8);
-    ifn!("llvm.cttz.i16" fn(t_i16, i1) -> t_i16);
-    ifn!("llvm.cttz.i32" fn(t_i32, i1) -> t_i32);
-    ifn!("llvm.cttz.i64" fn(t_i64, i1) -> t_i64);
-
-    ifn!("llvm.bswap.i16" fn(t_i16) -> t_i16);
-    ifn!("llvm.bswap.i32" fn(t_i32) -> t_i32);
-    ifn!("llvm.bswap.i64" fn(t_i64) -> t_i64);
-
-    ifn!("llvm.sadd.with.overflow.i8" fn(t_i8, t_i8) -> mk_struct!{t_i8, i1});
-    ifn!("llvm.sadd.with.overflow.i16" fn(t_i16, t_i16) -> mk_struct!{t_i16, i1});
-    ifn!("llvm.sadd.with.overflow.i32" fn(t_i32, t_i32) -> mk_struct!{t_i32, i1});
-    ifn!("llvm.sadd.with.overflow.i64" fn(t_i64, t_i64) -> mk_struct!{t_i64, i1});
-
-    ifn!("llvm.uadd.with.overflow.i8" fn(t_i8, t_i8) -> mk_struct!{t_i8, i1});
-    ifn!("llvm.uadd.with.overflow.i16" fn(t_i16, t_i16) -> mk_struct!{t_i16, i1});
-    ifn!("llvm.uadd.with.overflow.i32" fn(t_i32, t_i32) -> mk_struct!{t_i32, i1});
-    ifn!("llvm.uadd.with.overflow.i64" fn(t_i64, t_i64) -> mk_struct!{t_i64, i1});
-
-    ifn!("llvm.ssub.with.overflow.i8" fn(t_i8, t_i8) -> mk_struct!{t_i8, i1});
-    ifn!("llvm.ssub.with.overflow.i16" fn(t_i16, t_i16) -> mk_struct!{t_i16, i1});
-    ifn!("llvm.ssub.with.overflow.i32" fn(t_i32, t_i32) -> mk_struct!{t_i32, i1});
-    ifn!("llvm.ssub.with.overflow.i64" fn(t_i64, t_i64) -> mk_struct!{t_i64, i1});
-
-    ifn!("llvm.usub.with.overflow.i8" fn(t_i8, t_i8) -> mk_struct!{t_i8, i1});
-    ifn!("llvm.usub.with.overflow.i16" fn(t_i16, t_i16) -> mk_struct!{t_i16, i1});
-    ifn!("llvm.usub.with.overflow.i32" fn(t_i32, t_i32) -> mk_struct!{t_i32, i1});
-    ifn!("llvm.usub.with.overflow.i64" fn(t_i64, t_i64) -> mk_struct!{t_i64, i1});
-
-    ifn!("llvm.smul.with.overflow.i8" fn(t_i8, t_i8) -> mk_struct!{t_i8, i1});
-    ifn!("llvm.smul.with.overflow.i16" fn(t_i16, t_i16) -> mk_struct!{t_i16, i1});
-    ifn!("llvm.smul.with.overflow.i32" fn(t_i32, t_i32) -> mk_struct!{t_i32, i1});
-    ifn!("llvm.smul.with.overflow.i64" fn(t_i64, t_i64) -> mk_struct!{t_i64, i1});
-
-    ifn!("llvm.umul.with.overflow.i8" fn(t_i8, t_i8) -> mk_struct!{t_i8, i1});
-    ifn!("llvm.umul.with.overflow.i16" fn(t_i16, t_i16) -> mk_struct!{t_i16, i1});
-    ifn!("llvm.umul.with.overflow.i32" fn(t_i32, t_i32) -> mk_struct!{t_i32, i1});
-    ifn!("llvm.umul.with.overflow.i64" fn(t_i64, t_i64) -> mk_struct!{t_i64, i1});
-
-    ifn!("llvm.expect.i1" fn(i1, i1) -> i1);
-
-    // Some intrinsics were introduced in later versions of LLVM, but they have
-    // fallbacks in libc or libm and such. Currently, all of these intrinsics
-    // were introduced in LLVM 3.4, so we case on that.
-    macro_rules! compatible_ifn (
-        ($name:expr, $cname:ident ($($arg:expr),*) -> $ret:expr) => ({
-            let name = $name;
-            if unsafe { llvm::LLVMVersionMinor() >= 4 } {
-                ifn!(name fn($($arg),*) -> $ret);
-            } else {
-                let f = decl_cdecl_fn(ccx.llmod, stringify!($cname),
-                                      Type::func([$($arg),*], &$ret),
-                                      ty::mk_nil());
-                ccx.intrinsics.insert(name, f);
-            }
-        })
-    )
-
-    compatible_ifn!("llvm.copysign.f32", copysignf(t_f32, t_f32) -> t_f32);
-    compatible_ifn!("llvm.copysign.f64", copysign(t_f64, t_f64) -> t_f64);
-    compatible_ifn!("llvm.round.f32", roundf(t_f32) -> t_f32);
-    compatible_ifn!("llvm.round.f64", round(t_f64) -> t_f64);
-
-
-    if ccx.sess().opts.debuginfo != NoDebugInfo {
-        ifn!("llvm.dbg.declare" fn(Type::metadata(ccx), Type::metadata(ccx)) -> void);
-        ifn!("llvm.dbg.value" fn(Type::metadata(ccx), t_i64, Type::metadata(ccx)) -> void);
-    }
-}
-
 pub fn crate_ctxt_to_encode_parms<'r>(cx: &'r CrateContext, ie: encoder::EncodeInlinedItem<'r>)
     -> encoder::EncodeParams<'r> {
 
diff --git a/src/librustc/middle/trans/context.rs b/src/librustc/middle/trans/context.rs
index f98a77eed65..4aad1cded1e 100644
--- a/src/librustc/middle/trans/context.rs
+++ b/src/librustc/middle/trans/context.rs
@@ -41,7 +41,6 @@ pub struct CrateContext {
     pub td: TargetData,
     pub tn: TypeNames,
     pub externs: RefCell<ExternMap>,
-    pub intrinsics: HashMap<&'static str, ValueRef>,
     pub item_vals: RefCell<NodeMap<ValueRef>>,
     pub exp_map2: resolve::ExportMap2,
     pub reachable: NodeSet,
@@ -107,6 +106,8 @@ pub struct CrateContext {
     /// is not emitted by LLVM's GC pass when no functions use GC.
     pub uses_gc: bool,
     pub dbg_cx: Option<debuginfo::CrateDebugContext>,
+
+    intrinsics: RefCell<HashMap<&'static str, ValueRef>>,
 }
 
 impl CrateContext {
@@ -150,7 +151,6 @@ impl CrateContext {
                 td: td,
                 tn: TypeNames::new(),
                 externs: RefCell::new(HashMap::new()),
-                intrinsics: HashMap::new(),
                 item_vals: RefCell::new(NodeMap::new()),
                 exp_map2: emap2,
                 reachable: reachable,
@@ -197,6 +197,7 @@ impl CrateContext {
                 builder: BuilderRef_res(llvm::LLVMCreateBuilderInContext(llcx)),
                 uses_gc: false,
                 dbg_cx: dbg_cx,
+                intrinsics: RefCell::new(HashMap::new()),
             };
 
             ccx.int_type = Type::int(&ccx);
@@ -208,8 +209,6 @@ impl CrateContext {
             str_slice_ty.set_struct_body([Type::i8p(&ccx), ccx.int_type], false);
             ccx.tn.associate_type("str_slice", &str_slice_ty);
 
-            base::declare_intrinsics(&mut ccx);
-
             if ccx.sess().count_llvm_insns() {
                 base::init_insn_ctxt()
             }
@@ -233,4 +232,180 @@ impl CrateContext {
     pub fn tydesc_type(&self) -> Type {
         self.tn.find_type("tydesc").unwrap()
     }
+
+    pub fn get_intrinsic(&self, key: & &'static str) -> ValueRef {
+        match self.intrinsics.borrow().find_copy(key) {
+            Some(v) => return v,
+            _ => {}
+        }
+        match declare_intrinsic(self, key) {
+            Some(v) => return v,
+            None => fail!()
+        }
+    }
+}
+
+fn declare_intrinsic(ccx: &CrateContext, key: & &'static str) -> Option<ValueRef> {
+    macro_rules! ifn (
+        ($name:expr fn() -> $ret:expr) => (
+            if *key == $name {
+                let f = base::decl_cdecl_fn(ccx.llmod, $name, Type::func([], &$ret), ty::mk_nil());
+                ccx.intrinsics.borrow_mut().insert($name, f.clone());
+                return Some(f);
+            }
+        );
+        ($name:expr fn($($arg:expr),*) -> $ret:expr) => (
+            if *key == $name {
+                let f = base::decl_cdecl_fn(ccx.llmod, $name,
+                                  Type::func([$($arg),*], &$ret), ty::mk_nil());
+                ccx.intrinsics.borrow_mut().insert($name, f.clone());
+                return Some(f);
+            }
+        )
+    )
+    macro_rules! mk_struct (
+        ($($field_ty:expr),*) => (Type::struct_(ccx, [$($field_ty),*], false))
+    )
+
+    let i8p = Type::i8p(ccx);
+    let void = Type::void(ccx);
+    let i1 = Type::i1(ccx);
+    let t_i8 = Type::i8(ccx);
+    let t_i16 = Type::i16(ccx);
+    let t_i32 = Type::i32(ccx);
+    let t_i64 = Type::i64(ccx);
+    let t_f32 = Type::f32(ccx);
+    let t_f64 = Type::f64(ccx);
+
+    ifn!("llvm.memcpy.p0i8.p0i8.i32" fn(i8p, i8p, t_i32, t_i32, i1) -> void);
+    ifn!("llvm.memcpy.p0i8.p0i8.i64" fn(i8p, i8p, t_i64, t_i32, i1) -> void);
+    ifn!("llvm.memmove.p0i8.p0i8.i32" fn(i8p, i8p, t_i32, t_i32, i1) -> void);
+    ifn!("llvm.memmove.p0i8.p0i8.i64" fn(i8p, i8p, t_i64, t_i32, i1) -> void);
+    ifn!("llvm.memset.p0i8.i32" fn(i8p, t_i8, t_i32, t_i32, i1) -> void);
+    ifn!("llvm.memset.p0i8.i64" fn(i8p, t_i8, t_i64, t_i32, i1) -> void);
+
+    ifn!("llvm.trap" fn() -> void);
+    ifn!("llvm.debugtrap" fn() -> void);
+    ifn!("llvm.frameaddress" fn(t_i32) -> i8p);
+
+    ifn!("llvm.powi.f32" fn(t_f32, t_i32) -> t_f32);
+    ifn!("llvm.powi.f64" fn(t_f64, t_i32) -> t_f64);
+    ifn!("llvm.pow.f32" fn(t_f32, t_f32) -> t_f32);
+    ifn!("llvm.pow.f64" fn(t_f64, t_f64) -> t_f64);
+
+    ifn!("llvm.sqrt.f32" fn(t_f32) -> t_f32);
+    ifn!("llvm.sqrt.f64" fn(t_f64) -> t_f64);
+    ifn!("llvm.sin.f32" fn(t_f32) -> t_f32);
+    ifn!("llvm.sin.f64" fn(t_f64) -> t_f64);
+    ifn!("llvm.cos.f32" fn(t_f32) -> t_f32);
+    ifn!("llvm.cos.f64" fn(t_f64) -> t_f64);
+    ifn!("llvm.exp.f32" fn(t_f32) -> t_f32);
+    ifn!("llvm.exp.f64" fn(t_f64) -> t_f64);
+    ifn!("llvm.exp2.f32" fn(t_f32) -> t_f32);
+    ifn!("llvm.exp2.f64" fn(t_f64) -> t_f64);
+    ifn!("llvm.log.f32" fn(t_f32) -> t_f32);
+    ifn!("llvm.log.f64" fn(t_f64) -> t_f64);
+    ifn!("llvm.log10.f32" fn(t_f32) -> t_f32);
+    ifn!("llvm.log10.f64" fn(t_f64) -> t_f64);
+    ifn!("llvm.log2.f32" fn(t_f32) -> t_f32);
+    ifn!("llvm.log2.f64" fn(t_f64) -> t_f64);
+
+    ifn!("llvm.fma.f32" fn(t_f32, t_f32, t_f32) -> t_f32);
+    ifn!("llvm.fma.f64" fn(t_f64, t_f64, t_f64) -> t_f64);
+
+    ifn!("llvm.fabs.f32" fn(t_f32) -> t_f32);
+    ifn!("llvm.fabs.f64" fn(t_f64) -> t_f64);
+
+    ifn!("llvm.floor.f32" fn(t_f32) -> t_f32);
+    ifn!("llvm.floor.f64" fn(t_f64) -> t_f64);
+    ifn!("llvm.ceil.f32" fn(t_f32) -> t_f32);
+    ifn!("llvm.ceil.f64" fn(t_f64) -> t_f64);
+    ifn!("llvm.trunc.f32" fn(t_f32) -> t_f32);
+    ifn!("llvm.trunc.f64" fn(t_f64) -> t_f64);
+
+    ifn!("llvm.rint.f32" fn(t_f32) -> t_f32);
+    ifn!("llvm.rint.f64" fn(t_f64) -> t_f64);
+    ifn!("llvm.nearbyint.f32" fn(t_f32) -> t_f32);
+    ifn!("llvm.nearbyint.f64" fn(t_f64) -> t_f64);
+
+    ifn!("llvm.ctpop.i8" fn(t_i8) -> t_i8);
+    ifn!("llvm.ctpop.i16" fn(t_i16) -> t_i16);
+    ifn!("llvm.ctpop.i32" fn(t_i32) -> t_i32);
+    ifn!("llvm.ctpop.i64" fn(t_i64) -> t_i64);
+
+    ifn!("llvm.ctlz.i8" fn(t_i8 , i1) -> t_i8);
+    ifn!("llvm.ctlz.i16" fn(t_i16, i1) -> t_i16);
+    ifn!("llvm.ctlz.i32" fn(t_i32, i1) -> t_i32);
+    ifn!("llvm.ctlz.i64" fn(t_i64, i1) -> t_i64);
+
+    ifn!("llvm.cttz.i8" fn(t_i8 , i1) -> t_i8);
+    ifn!("llvm.cttz.i16" fn(t_i16, i1) -> t_i16);
+    ifn!("llvm.cttz.i32" fn(t_i32, i1) -> t_i32);
+    ifn!("llvm.cttz.i64" fn(t_i64, i1) -> t_i64);
+
+    ifn!("llvm.bswap.i16" fn(t_i16) -> t_i16);
+    ifn!("llvm.bswap.i32" fn(t_i32) -> t_i32);
+    ifn!("llvm.bswap.i64" fn(t_i64) -> t_i64);
+
+    ifn!("llvm.sadd.with.overflow.i8" fn(t_i8, t_i8) -> mk_struct!{t_i8, i1});
+    ifn!("llvm.sadd.with.overflow.i16" fn(t_i16, t_i16) -> mk_struct!{t_i16, i1});
+    ifn!("llvm.sadd.with.overflow.i32" fn(t_i32, t_i32) -> mk_struct!{t_i32, i1});
+    ifn!("llvm.sadd.with.overflow.i64" fn(t_i64, t_i64) -> mk_struct!{t_i64, i1});
+
+    ifn!("llvm.uadd.with.overflow.i8" fn(t_i8, t_i8) -> mk_struct!{t_i8, i1});
+    ifn!("llvm.uadd.with.overflow.i16" fn(t_i16, t_i16) -> mk_struct!{t_i16, i1});
+    ifn!("llvm.uadd.with.overflow.i32" fn(t_i32, t_i32) -> mk_struct!{t_i32, i1});
+    ifn!("llvm.uadd.with.overflow.i64" fn(t_i64, t_i64) -> mk_struct!{t_i64, i1});
+
+    ifn!("llvm.ssub.with.overflow.i8" fn(t_i8, t_i8) -> mk_struct!{t_i8, i1});
+    ifn!("llvm.ssub.with.overflow.i16" fn(t_i16, t_i16) -> mk_struct!{t_i16, i1});
+    ifn!("llvm.ssub.with.overflow.i32" fn(t_i32, t_i32) -> mk_struct!{t_i32, i1});
+    ifn!("llvm.ssub.with.overflow.i64" fn(t_i64, t_i64) -> mk_struct!{t_i64, i1});
+
+    ifn!("llvm.usub.with.overflow.i8" fn(t_i8, t_i8) -> mk_struct!{t_i8, i1});
+    ifn!("llvm.usub.with.overflow.i16" fn(t_i16, t_i16) -> mk_struct!{t_i16, i1});
+    ifn!("llvm.usub.with.overflow.i32" fn(t_i32, t_i32) -> mk_struct!{t_i32, i1});
+    ifn!("llvm.usub.with.overflow.i64" fn(t_i64, t_i64) -> mk_struct!{t_i64, i1});
+
+    ifn!("llvm.smul.with.overflow.i8" fn(t_i8, t_i8) -> mk_struct!{t_i8, i1});
+    ifn!("llvm.smul.with.overflow.i16" fn(t_i16, t_i16) -> mk_struct!{t_i16, i1});
+    ifn!("llvm.smul.with.overflow.i32" fn(t_i32, t_i32) -> mk_struct!{t_i32, i1});
+    ifn!("llvm.smul.with.overflow.i64" fn(t_i64, t_i64) -> mk_struct!{t_i64, i1});
+
+    ifn!("llvm.umul.with.overflow.i8" fn(t_i8, t_i8) -> mk_struct!{t_i8, i1});
+    ifn!("llvm.umul.with.overflow.i16" fn(t_i16, t_i16) -> mk_struct!{t_i16, i1});
+    ifn!("llvm.umul.with.overflow.i32" fn(t_i32, t_i32) -> mk_struct!{t_i32, i1});
+    ifn!("llvm.umul.with.overflow.i64" fn(t_i64, t_i64) -> mk_struct!{t_i64, i1});
+
+    ifn!("llvm.expect.i1" fn(i1, i1) -> i1);
+
+    // Some intrinsics were introduced in later versions of LLVM, but they have
+    // fallbacks in libc or libm and such. Currently, all of these intrinsics
+    // were introduced in LLVM 3.4, so we case on that.
+    macro_rules! compatible_ifn (
+        ($name:expr, $cname:ident ($($arg:expr),*) -> $ret:expr) => (
+            if unsafe { llvm::LLVMVersionMinor() >= 4 } {
+                // The `if key == $name` is already in ifn!
+                ifn!($name fn($($arg),*) -> $ret);
+            } else if *key == $name {
+                let f = base::decl_cdecl_fn(ccx.llmod, stringify!($cname),
+                                      Type::func([$($arg),*], &$ret),
+                                      ty::mk_nil());
+                ccx.intrinsics.borrow_mut().insert($name, f.clone());
+                return Some(f);
+            }
+        )
+    )
+
+    compatible_ifn!("llvm.copysign.f32", copysignf(t_f32, t_f32) -> t_f32);
+    compatible_ifn!("llvm.copysign.f64", copysign(t_f64, t_f64) -> t_f64);
+    compatible_ifn!("llvm.round.f32", roundf(t_f32) -> t_f32);
+    compatible_ifn!("llvm.round.f64", round(t_f64) -> t_f64);
+
+
+    if ccx.sess().opts.debuginfo != NoDebugInfo {
+        ifn!("llvm.dbg.declare" fn(Type::metadata(ccx), Type::metadata(ccx)) -> void);
+        ifn!("llvm.dbg.value" fn(Type::metadata(ccx), t_i64, Type::metadata(ccx)) -> void);
+    }
+    return None;
 }
diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs
index e47362e8d9e..c12c8c106cb 100644
--- a/src/librustc/middle/trans/expr.rs
+++ b/src/librustc/middle/trans/expr.rs
@@ -513,7 +513,7 @@ fn trans_index<'a>(bcx: &'a Block<'a>,
     debug!("trans_index: len {}", bcx.val_to_str(len));
 
     let bounds_check = ICmp(bcx, lib::llvm::IntUGE, ix_val, len);
-    let expect = ccx.intrinsics.get_copy(&("llvm.expect.i1"));
+    let expect = ccx.get_intrinsic(&("llvm.expect.i1"));
     let expected = Call(bcx, expect, [bounds_check, C_i1(ccx, false)], []);
     let bcx = with_cond(bcx, expected, |bcx| {
             controlflow::trans_fail_bounds_check(bcx, index_expr.span, ix_val, len)
diff --git a/src/librustc/middle/trans/intrinsic.rs b/src/librustc/middle/trans/intrinsic.rs
index 28a39718e7f..6f4b115ad86 100644
--- a/src/librustc/middle/trans/intrinsic.rs
+++ b/src/librustc/middle/trans/intrinsic.rs
@@ -79,7 +79,7 @@ pub fn get_simple_intrinsic(ccx: &CrateContext, item: &ast::ForeignItem) -> Opti
         "bswap64" => "llvm.bswap.i64",
         _ => return None
     };
-    Some(ccx.intrinsics.get_copy(&name))
+    Some(ccx.get_intrinsic(&name))
 }
 
 pub fn trans_intrinsic(ccx: &CrateContext,
@@ -93,7 +93,7 @@ pub fn trans_intrinsic(ccx: &CrateContext,
         let first_real_arg = bcx.fcx.arg_pos(0u);
         let a = get_param(bcx.fcx.llfn, first_real_arg);
         let b = get_param(bcx.fcx.llfn, first_real_arg + 1);
-        let llfn = bcx.ccx().intrinsics.get_copy(&name);
+        let llfn = bcx.ccx().get_intrinsic(&name);
 
         // convert `i1` to a `bool`, and write to the out parameter
         let val = Call(bcx, llfn, [a, b], []);
@@ -155,7 +155,7 @@ pub fn trans_intrinsic(ccx: &CrateContext,
         let src_ptr = PointerCast(bcx, get_param(decl, first_real_arg + 1), Type::i8p(ccx));
         let count = get_param(decl, first_real_arg + 2);
         let volatile = C_i1(ccx, false);
-        let llfn = ccx.intrinsics.get_copy(&name);
+        let llfn = ccx.get_intrinsic(&name);
         Call(bcx, llfn, [dst_ptr, src_ptr, Mul(bcx, size, count), align, volatile], []);
         RetVoid(bcx);
     }
@@ -177,7 +177,7 @@ pub fn trans_intrinsic(ccx: &CrateContext,
         let val = get_param(decl, first_real_arg + 1);
         let count = get_param(decl, first_real_arg + 2);
         let volatile = C_i1(ccx, false);
-        let llfn = ccx.intrinsics.get_copy(&name);
+        let llfn = ccx.get_intrinsic(&name);
         Call(bcx, llfn, [dst_ptr, val, Mul(bcx, size, count), align, volatile], []);
         RetVoid(bcx);
     }
@@ -185,7 +185,7 @@ pub fn trans_intrinsic(ccx: &CrateContext,
     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(bcx.ccx(), false);
-        let llfn = bcx.ccx().intrinsics.get_copy(&name);
+        let llfn = bcx.ccx().get_intrinsic(&name);
         let llcall = Call(bcx, llfn, [x, y], []);
         Ret(bcx, llcall);
     }
@@ -274,12 +274,12 @@ pub fn trans_intrinsic(ccx: &CrateContext,
 
     match name.get() {
         "abort" => {
-            let llfn = bcx.ccx().intrinsics.get_copy(&("llvm.trap"));
+            let llfn = bcx.ccx().get_intrinsic(&("llvm.trap"));
             Call(bcx, llfn, [], []);
             Unreachable(bcx);
         }
         "breakpoint" => {
-            let llfn = bcx.ccx().intrinsics.get_copy(&("llvm.debugtrap"));
+            let llfn = bcx.ccx().get_intrinsic(&("llvm.debugtrap"));
             Call(bcx, llfn, [], []);
             RetVoid(bcx);
         }