diff --git a/src/librustc_codegen_llvm/context.rs b/src/librustc_codegen_llvm/context.rs index 673122095da29..80130411c2b99 100644 --- a/src/librustc_codegen_llvm/context.rs +++ b/src/librustc_codegen_llvm/context.rs @@ -470,8 +470,8 @@ impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> { } } -impl IntrinsicDeclarationMethods<'tcx> for CodegenCx<'b, 'tcx> { - fn get_intrinsic(&self, key: &str) -> &'b Value { +impl CodegenCx<'b, 'tcx> { + crate fn get_intrinsic(&self, key: &str) -> &'b Value { if let Some(v) = self.intrinsics.borrow().get(key).cloned() { return v; } diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index 3548ccfd5a537..c495a0d92d110 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -763,6 +763,95 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { } } } + + fn abort(&mut self) { + let fnname = self.cx().get_intrinsic(&("llvm.trap")); + self.call(fnname, &[], None); + } + + fn assume(&mut self, val: Self::Value) { + let assume_intrinsic = self.cx().get_intrinsic("llvm.assume"); + self.call(assume_intrinsic, &[val], None); + } + + fn expect(&mut self, cond: Self::Value, expected: bool) -> Self::Value { + let expect = self.cx().get_intrinsic(&"llvm.expect.i1"); + self.call(expect, &[cond, self.cx().const_bool(expected)], None) + } + + fn call_overflow_intrinsic( + &mut self, + oop: OverflowOp, + ty: Ty, + lhs: Self::Value, + rhs: Self::Value, + ) -> (Self::Value, Self::Value) { + use syntax::ast::IntTy::*; + use syntax::ast::UintTy::*; + use rustc::ty::{Int, Uint}; + + let new_sty = match ty.sty { + Int(Isize) => Int(self.tcx().sess.target.isize_ty), + Uint(Usize) => Uint(self.tcx().sess.target.usize_ty), + ref t @ Uint(_) | ref t @ Int(_) => t.clone(), + _ => panic!("tried to get overflow intrinsic for op applied to non-int type") + }; + + let name = match oop { + OverflowOp::Add => match new_sty { + Int(I8) => "llvm.sadd.with.overflow.i8", + Int(I16) => "llvm.sadd.with.overflow.i16", + Int(I32) => "llvm.sadd.with.overflow.i32", + Int(I64) => "llvm.sadd.with.overflow.i64", + Int(I128) => "llvm.sadd.with.overflow.i128", + + Uint(U8) => "llvm.uadd.with.overflow.i8", + Uint(U16) => "llvm.uadd.with.overflow.i16", + Uint(U32) => "llvm.uadd.with.overflow.i32", + Uint(U64) => "llvm.uadd.with.overflow.i64", + Uint(U128) => "llvm.uadd.with.overflow.i128", + + _ => unreachable!(), + }, + OverflowOp::Sub => match new_sty { + Int(I8) => "llvm.ssub.with.overflow.i8", + Int(I16) => "llvm.ssub.with.overflow.i16", + Int(I32) => "llvm.ssub.with.overflow.i32", + Int(I64) => "llvm.ssub.with.overflow.i64", + Int(I128) => "llvm.ssub.with.overflow.i128", + + Uint(U8) => "llvm.usub.with.overflow.i8", + Uint(U16) => "llvm.usub.with.overflow.i16", + Uint(U32) => "llvm.usub.with.overflow.i32", + Uint(U64) => "llvm.usub.with.overflow.i64", + Uint(U128) => "llvm.usub.with.overflow.i128", + + _ => unreachable!(), + }, + OverflowOp::Mul => match new_sty { + Int(I8) => "llvm.smul.with.overflow.i8", + Int(I16) => "llvm.smul.with.overflow.i16", + Int(I32) => "llvm.smul.with.overflow.i32", + Int(I64) => "llvm.smul.with.overflow.i64", + Int(I128) => "llvm.smul.with.overflow.i128", + + Uint(U8) => "llvm.umul.with.overflow.i8", + Uint(U16) => "llvm.umul.with.overflow.i16", + Uint(U32) => "llvm.umul.with.overflow.i32", + Uint(U64) => "llvm.umul.with.overflow.i64", + Uint(U128) => "llvm.umul.with.overflow.i128", + + _ => unreachable!(), + }, + }; + + let intrinsic = self.cx().get_intrinsic(&name); + let res = self.call(intrinsic, &[lhs, rhs], None); + ( + self.extract_value(res, 0), + self.extract_value(res, 1), + ) + } } fn copy_intrinsic( diff --git a/src/librustc_codegen_ssa/base.rs b/src/librustc_codegen_ssa/base.rs index 856bb9533c859..6425a19e4b61b 100644 --- a/src/librustc_codegen_ssa/base.rs +++ b/src/librustc_codegen_ssa/base.rs @@ -366,14 +366,6 @@ pub fn wants_msvc_seh(sess: &Session) -> bool { sess.target.target.options.is_like_msvc } -pub fn call_assume<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( - bx: &mut Bx, - val: Bx::Value -) { - let assume_intrinsic = bx.cx().get_intrinsic("llvm.assume"); - bx.call(assume_intrinsic, &[val], None); -} - pub fn from_immediate<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( bx: &mut Bx, val: Bx::Value diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index 75a6f07124ae7..992a44aa5bfc3 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -195,9 +195,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } mir::TerminatorKind::Abort => { - // Call core::intrinsics::abort() - let fnname = bx.cx().get_intrinsic(&("llvm.trap")); - bx.call(fnname, &[], None); + bx.abort(); bx.unreachable(); } @@ -364,8 +362,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } // Pass the condition through llvm.expect for branch hinting. - let expect = bx.cx().get_intrinsic(&"llvm.expect.i1"); - let cond = bx.call(expect, &[cond, bx.cx().const_bool(expected)], None); + let cond = bx.expect(cond, expected); // Create the failure block and the conditional branch to it. let lltarget = llblock(self, target); diff --git a/src/librustc_codegen_ssa/mir/operand.rs b/src/librustc_codegen_ssa/mir/operand.rs index fefbc14e4973c..a85e75936dedf 100644 --- a/src/librustc_codegen_ssa/mir/operand.rs +++ b/src/librustc_codegen_ssa/mir/operand.rs @@ -484,8 +484,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } // Allow RalfJ to sleep soundly knowing that even refactorings that remove // the above error (or silence it under some conditions) will not cause UB - let fnname = bx.cx().get_intrinsic(&("llvm.trap")); - bx.call(fnname, &[], None); + bx.abort(); // We've errored, so we don't have to produce working code. let layout = bx.cx().layout_of(ty); bx.load_operand(PlaceRef::new_sized( diff --git a/src/librustc_codegen_ssa/mir/place.rs b/src/librustc_codegen_ssa/mir/place.rs index e6fd6dfca736b..1406714f29366 100644 --- a/src/librustc_codegen_ssa/mir/place.rs +++ b/src/librustc_codegen_ssa/mir/place.rs @@ -413,8 +413,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // and compile-time agree on values // With floats that won't always be true // so we generate an abort - let fnname = bx.cx().get_intrinsic(&("llvm.trap")); - bx.call(fnname, &[], None); + bx.abort(); let llval = bx.cx().const_undef( bx.cx().type_ptr_to(bx.cx().backend_type(layout)) ); diff --git a/src/librustc_codegen_ssa/mir/rvalue.rs b/src/librustc_codegen_ssa/mir/rvalue.rs index 805c1a343d044..7c794c053ecd0 100644 --- a/src/librustc_codegen_ssa/mir/rvalue.rs +++ b/src/librustc_codegen_ssa/mir/rvalue.rs @@ -337,7 +337,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { llval, ll_t_in_const ); - base::call_assume(&mut bx, cmp); + bx.assume(cmp); } } } @@ -693,11 +693,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::BinOp::Mul => OverflowOp::Mul, _ => unreachable!() }; - let intrinsic = get_overflow_intrinsic(oop, bx, input_ty); - let res = bx.call(intrinsic, &[lhs, rhs], None); - - (bx.extract_value(res, 0), - bx.extract_value(res, 1)) + bx.call_overflow_intrinsic(oop, input_ty, lhs, rhs) } mir::BinOp::Shl | mir::BinOp::Shr => { let lhs_llty = bx.cx().val_ty(lhs); @@ -744,80 +740,6 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } -#[derive(Copy, Clone)] -enum OverflowOp { - Add, Sub, Mul -} - -fn get_overflow_intrinsic<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( - oop: OverflowOp, - bx: &mut Bx, - ty: Ty -) -> Bx::Value { - use syntax::ast::IntTy::*; - use syntax::ast::UintTy::*; - use rustc::ty::{Int, Uint}; - - let tcx = bx.tcx(); - - let new_sty = match ty.sty { - Int(Isize) => Int(tcx.sess.target.isize_ty), - Uint(Usize) => Uint(tcx.sess.target.usize_ty), - ref t @ Uint(_) | ref t @ Int(_) => t.clone(), - _ => panic!("tried to get overflow intrinsic for op applied to non-int type") - }; - - let name = match oop { - OverflowOp::Add => match new_sty { - Int(I8) => "llvm.sadd.with.overflow.i8", - Int(I16) => "llvm.sadd.with.overflow.i16", - Int(I32) => "llvm.sadd.with.overflow.i32", - Int(I64) => "llvm.sadd.with.overflow.i64", - Int(I128) => "llvm.sadd.with.overflow.i128", - - Uint(U8) => "llvm.uadd.with.overflow.i8", - Uint(U16) => "llvm.uadd.with.overflow.i16", - Uint(U32) => "llvm.uadd.with.overflow.i32", - Uint(U64) => "llvm.uadd.with.overflow.i64", - Uint(U128) => "llvm.uadd.with.overflow.i128", - - _ => unreachable!(), - }, - OverflowOp::Sub => match new_sty { - Int(I8) => "llvm.ssub.with.overflow.i8", - Int(I16) => "llvm.ssub.with.overflow.i16", - Int(I32) => "llvm.ssub.with.overflow.i32", - Int(I64) => "llvm.ssub.with.overflow.i64", - Int(I128) => "llvm.ssub.with.overflow.i128", - - Uint(U8) => "llvm.usub.with.overflow.i8", - Uint(U16) => "llvm.usub.with.overflow.i16", - Uint(U32) => "llvm.usub.with.overflow.i32", - Uint(U64) => "llvm.usub.with.overflow.i64", - Uint(U128) => "llvm.usub.with.overflow.i128", - - _ => unreachable!(), - }, - OverflowOp::Mul => match new_sty { - Int(I8) => "llvm.smul.with.overflow.i8", - Int(I16) => "llvm.smul.with.overflow.i16", - Int(I32) => "llvm.smul.with.overflow.i32", - Int(I64) => "llvm.smul.with.overflow.i64", - Int(I128) => "llvm.smul.with.overflow.i128", - - Uint(U8) => "llvm.umul.with.overflow.i8", - Uint(U16) => "llvm.umul.with.overflow.i16", - Uint(U32) => "llvm.umul.with.overflow.i32", - Uint(U64) => "llvm.umul.with.overflow.i64", - Uint(U128) => "llvm.umul.with.overflow.i128", - - _ => unreachable!(), - }, - }; - - bx.cx().get_intrinsic(&name) -} - fn cast_int_to_float<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( bx: &mut Bx, signed: bool, diff --git a/src/librustc_codegen_ssa/traits/intrinsic.rs b/src/librustc_codegen_ssa/traits/intrinsic.rs index 53a7878796b31..a17587d361974 100644 --- a/src/librustc_codegen_ssa/traits/intrinsic.rs +++ b/src/librustc_codegen_ssa/traits/intrinsic.rs @@ -8,13 +8,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use super::Backend; use super::HasCodegen; use mir::operand::OperandRef; use rustc::ty::Ty; use rustc_target::abi::call::FnType; use syntax_pos::Span; +#[derive(Copy, Clone)] +pub enum OverflowOp { + Add, Sub, Mul +} + pub trait IntrinsicCallMethods<'tcx>: HasCodegen<'tcx> { /// Remember to add all intrinsics here, in librustc_typeck/check/mod.rs, /// and in libcore/intrinsics.rs; if you need access to any llvm intrinsics, @@ -27,11 +31,16 @@ pub trait IntrinsicCallMethods<'tcx>: HasCodegen<'tcx> { llresult: Self::Value, span: Span, ); -} -pub trait IntrinsicDeclarationMethods<'tcx>: Backend<'tcx> { - fn get_intrinsic(&self, key: &str) -> Self::Value; + fn abort(&mut self); + fn assume(&mut self, val: Self::Value); + fn expect(&mut self, cond: Self::Value, expected: bool) -> Self::Value; - /// Declare any llvm intrinsics that you might need - fn declare_intrinsic(&self, key: &str) -> Option; + fn call_overflow_intrinsic( + &mut self, + oop: OverflowOp, + ty: Ty, + lhs: Self::Value, + rhs: Self::Value, + ) -> (Self::Value, Self::Value); } diff --git a/src/librustc_codegen_ssa/traits/mod.rs b/src/librustc_codegen_ssa/traits/mod.rs index b475d790140b1..61438195f38c6 100644 --- a/src/librustc_codegen_ssa/traits/mod.rs +++ b/src/librustc_codegen_ssa/traits/mod.rs @@ -44,7 +44,7 @@ pub use self::builder::BuilderMethods; pub use self::consts::ConstMethods; pub use self::debuginfo::{DebugInfoBuilderMethods, DebugInfoMethods}; pub use self::declare::{DeclareMethods, PreDefineMethods}; -pub use self::intrinsic::{IntrinsicCallMethods, IntrinsicDeclarationMethods}; +pub use self::intrinsic::{IntrinsicCallMethods, OverflowOp}; pub use self::misc::MiscMethods; pub use self::statics::StaticMethods; pub use self::type_::{ @@ -65,7 +65,6 @@ pub trait CodegenMethods<'tcx>: + StaticMethods + DebugInfoMethods<'tcx> + AbiMethods<'tcx> - + IntrinsicDeclarationMethods<'tcx> + DeclareMethods<'tcx> + AsmMethods<'tcx> + PreDefineMethods<'tcx> @@ -80,7 +79,6 @@ impl<'tcx, T> CodegenMethods<'tcx> for T where + StaticMethods + DebugInfoMethods<'tcx> + AbiMethods<'tcx> - + IntrinsicDeclarationMethods<'tcx> + DeclareMethods<'tcx> + AsmMethods<'tcx> + PreDefineMethods<'tcx>