From a00be50e00bc244569cb8d660f96abdde10dc6ef Mon Sep 17 00:00:00 2001 From: Michael Darakananda Date: Wed, 9 Apr 2014 19:56:31 -0400 Subject: [PATCH] Emit intrinsic lazily --- src/librustc/middle/trans/base.rs | 166 +--------------------- src/librustc/middle/trans/context.rs | 183 ++++++++++++++++++++++++- src/librustc/middle/trans/expr.rs | 2 +- src/librustc/middle/trans/intrinsic.rs | 14 +- 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, - pub intrinsics: HashMap<&'static str, ValueRef>, pub item_vals: RefCell>, 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, + + intrinsics: RefCell>, } 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 { + 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); }