@@ -82,6 +82,7 @@ use trans::machine::{llsize_of, llsize_of_alloc};
8282use trans:: type_:: Type ;
8383
8484use syntax:: { ast, ast_util, codemap} ;
85+ use syntax:: parse:: token:: InternedString ;
8586use syntax:: ptr:: P ;
8687use syntax:: parse:: token;
8788use std:: iter:: repeat;
@@ -1709,8 +1710,8 @@ fn trans_eager_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
17091710 } ;
17101711 let is_float = ty:: type_is_fp ( intype) ;
17111712 let is_signed = ty:: type_is_signed ( intype) ;
1712-
17131713 let rhs = base:: cast_shift_expr_rhs ( bcx, op, lhs, rhs) ;
1714+ let info = expr_info ( binop_expr) ;
17141715
17151716 let binop_debug_loc = binop_expr. debug_loc ( ) ;
17161717
@@ -1720,21 +1721,30 @@ fn trans_eager_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
17201721 if is_float {
17211722 FAdd ( bcx, lhs, rhs, binop_debug_loc)
17221723 } else {
1723- Add ( bcx, lhs, rhs, binop_debug_loc)
1724+ let ( newbcx, res) = with_overflow_check (
1725+ bcx, OverflowOp :: Add , info, lhs_t, lhs, rhs, binop_debug_loc) ;
1726+ bcx = newbcx;
1727+ res
17241728 }
17251729 }
17261730 ast:: BiSub => {
17271731 if is_float {
17281732 FSub ( bcx, lhs, rhs, binop_debug_loc)
17291733 } else {
1730- Sub ( bcx, lhs, rhs, binop_debug_loc)
1734+ let ( newbcx, res) = with_overflow_check (
1735+ bcx, OverflowOp :: Sub , info, lhs_t, lhs, rhs, binop_debug_loc) ;
1736+ bcx = newbcx;
1737+ res
17311738 }
17321739 }
17331740 ast:: BiMul => {
17341741 if is_float {
17351742 FMul ( bcx, lhs, rhs, binop_debug_loc)
17361743 } else {
1737- Mul ( bcx, lhs, rhs, binop_debug_loc)
1744+ let ( newbcx, res) = with_overflow_check (
1745+ bcx, OverflowOp :: Mul , info, lhs_t, lhs, rhs, binop_debug_loc) ;
1746+ bcx = newbcx;
1747+ res
17381748 }
17391749 }
17401750 ast:: BiDiv => {
@@ -2314,3 +2324,110 @@ fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
23142324 DatumBlock { bcx : bcx, datum : datum }
23152325 }
23162326}
2327+
2328+ enum OverflowOp {
2329+ Add ,
2330+ Sub ,
2331+ Mul ,
2332+ }
2333+
2334+ impl OverflowOp {
2335+ fn to_intrinsic_name ( & self , tcx : & ty:: ctxt , ty : Ty ) -> & ' static str {
2336+ use syntax:: ast:: IntTy :: * ;
2337+ use syntax:: ast:: UintTy :: * ;
2338+ use middle:: ty:: { ty_int, ty_uint} ;
2339+
2340+ let new_sty = match ty. sty {
2341+ ty_int( TyIs ( _) ) => match & tcx. sess . target . target . target_pointer_width [ ..] {
2342+ "32" => ty_int ( TyI32 ) ,
2343+ "64" => ty_int ( TyI64 ) ,
2344+ _ => panic ! ( "unsupported target word size" )
2345+ } ,
2346+ ty_uint( TyUs ( _) ) => match & tcx. sess . target . target . target_pointer_width [ ..] {
2347+ "32" => ty_uint ( TyU32 ) ,
2348+ "64" => ty_uint ( TyU64 ) ,
2349+ _ => panic ! ( "unsupported target word size" )
2350+ } ,
2351+ ref t @ ty_uint( _) | ref t @ ty_int( _) => t. clone ( ) ,
2352+ _ => panic ! ( "tried to get overflow intrinsic for non-int type" )
2353+ } ;
2354+
2355+ match * self {
2356+ OverflowOp :: Add => match new_sty {
2357+ ty_int( TyI8 ) => "llvm.sadd.with.overflow.i8" ,
2358+ ty_int( TyI16 ) => "llvm.sadd.with.overflow.i16" ,
2359+ ty_int( TyI32 ) => "llvm.sadd.with.overflow.i32" ,
2360+ ty_int( TyI64 ) => "llvm.sadd.with.overflow.i64" ,
2361+
2362+ ty_uint( TyU8 ) => "llvm.uadd.with.overflow.i8" ,
2363+ ty_uint( TyU16 ) => "llvm.uadd.with.overflow.i16" ,
2364+ ty_uint( TyU32 ) => "llvm.uadd.with.overflow.i32" ,
2365+ ty_uint( TyU64 ) => "llvm.uadd.with.overflow.i64" ,
2366+
2367+ _ => unreachable ! ( ) ,
2368+ } ,
2369+ OverflowOp :: Sub => match new_sty {
2370+ ty_int( TyI8 ) => "llvm.ssub.with.overflow.i8" ,
2371+ ty_int( TyI16 ) => "llvm.ssub.with.overflow.i16" ,
2372+ ty_int( TyI32 ) => "llvm.ssub.with.overflow.i32" ,
2373+ ty_int( TyI64 ) => "llvm.ssub.with.overflow.i64" ,
2374+
2375+ ty_uint( TyU8 ) => "llvm.usub.with.overflow.i8" ,
2376+ ty_uint( TyU16 ) => "llvm.usub.with.overflow.i16" ,
2377+ ty_uint( TyU32 ) => "llvm.usub.with.overflow.i32" ,
2378+ ty_uint( TyU64 ) => "llvm.usub.with.overflow.i64" ,
2379+
2380+ _ => unreachable ! ( ) ,
2381+ } ,
2382+ OverflowOp :: Mul => match new_sty {
2383+ ty_int( TyI8 ) => "llvm.smul.with.overflow.i8" ,
2384+ ty_int( TyI16 ) => "llvm.smul.with.overflow.i16" ,
2385+ ty_int( TyI32 ) => "llvm.smul.with.overflow.i32" ,
2386+ ty_int( TyI64 ) => "llvm.smul.with.overflow.i64" ,
2387+
2388+ ty_uint( TyU8 ) => "llvm.umul.with.overflow.i8" ,
2389+ ty_uint( TyU16 ) => "llvm.umul.with.overflow.i16" ,
2390+ ty_uint( TyU32 ) => "llvm.umul.with.overflow.i32" ,
2391+ ty_uint( TyU64 ) => "llvm.umul.with.overflow.i64" ,
2392+
2393+ _ => unreachable ! ( ) ,
2394+ } ,
2395+ }
2396+ }
2397+ }
2398+
2399+
2400+ fn with_overflow_check < ' a , ' b > ( bcx : Block < ' a , ' b > , oop : OverflowOp , info : NodeIdAndSpan ,
2401+ lhs_t : Ty , lhs : ValueRef , rhs : ValueRef , binop_debug_loc : DebugLoc )
2402+ -> ( Block < ' a , ' b > , ValueRef ) {
2403+ if bcx. unreachable . get ( ) { return ( bcx, _Undef ( lhs) ) ; }
2404+ if bcx. ccx ( ) . check_overflow ( ) {
2405+ let name = oop. to_intrinsic_name ( bcx. tcx ( ) , lhs_t) ;
2406+ let llfn = bcx. ccx ( ) . get_intrinsic ( & name) ;
2407+
2408+ let val = Call ( bcx, llfn, & [ lhs, rhs] , None , binop_debug_loc) ;
2409+ let result = ExtractValue ( bcx, val, 0 ) ; // iN operation result
2410+ let overflow = ExtractValue ( bcx, val, 1 ) ; // i1 "did it overflow?"
2411+
2412+ let cond = ICmp ( bcx, llvm:: IntEQ , overflow, C_integral ( Type :: i1 ( bcx. ccx ( ) ) , 1 , false ) ,
2413+ binop_debug_loc) ;
2414+
2415+ let expect = bcx. ccx ( ) . get_intrinsic ( & "llvm.expect.i1" ) ;
2416+ Call ( bcx, expect, & [ cond, C_integral ( Type :: i1 ( bcx. ccx ( ) ) , 0 , false ) ] ,
2417+ None , binop_debug_loc) ;
2418+
2419+ let bcx =
2420+ base:: with_cond ( bcx, cond, |bcx|
2421+ controlflow:: trans_fail ( bcx, info,
2422+ InternedString :: new ( "arithmetic operation overflowed" ) ) ) ;
2423+
2424+ ( bcx, result)
2425+ } else {
2426+ let res = match oop {
2427+ OverflowOp :: Add => Add ( bcx, lhs, rhs, binop_debug_loc) ,
2428+ OverflowOp :: Sub => Sub ( bcx, lhs, rhs, binop_debug_loc) ,
2429+ OverflowOp :: Mul => Mul ( bcx, lhs, rhs, binop_debug_loc) ,
2430+ } ;
2431+ ( bcx, res)
2432+ }
2433+ }
0 commit comments