Skip to content

Commit f9b4228

Browse files
committed
add intrinsics for checked overflow add/sub/mul
1 parent cdba212 commit f9b4228

File tree

10 files changed

+663
-8
lines changed

10 files changed

+663
-8
lines changed

src/librustc/middle/trans/base.rs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2721,6 +2721,60 @@ pub fn declare_intrinsics(llmod: ModuleRef) -> HashMap<&'static str, ValueRef> {
27212721
ifn!("llvm.bswap.i32",[Type::i32()], Type::i32());
27222722
ifn!("llvm.bswap.i64",[Type::i64()], Type::i64());
27232723

2724+
ifn!("llvm.sadd.with.overflow.i8",
2725+
[Type::i8(), Type::i8()], Type::struct_([Type::i8(), Type::i1()], false));
2726+
ifn!("llvm.sadd.with.overflow.i16",
2727+
[Type::i16(), Type::i16()], Type::struct_([Type::i16(), Type::i1()], false));
2728+
ifn!("llvm.sadd.with.overflow.i32",
2729+
[Type::i32(), Type::i32()], Type::struct_([Type::i32(), Type::i1()], false));
2730+
ifn!("llvm.sadd.with.overflow.i64",
2731+
[Type::i64(), Type::i64()], Type::struct_([Type::i64(), Type::i1()], false));
2732+
2733+
ifn!("llvm.uadd.with.overflow.i8",
2734+
[Type::i8(), Type::i8()], Type::struct_([Type::i8(), Type::i1()], false));
2735+
ifn!("llvm.uadd.with.overflow.i16",
2736+
[Type::i16(), Type::i16()], Type::struct_([Type::i16(), Type::i1()], false));
2737+
ifn!("llvm.uadd.with.overflow.i32",
2738+
[Type::i32(), Type::i32()], Type::struct_([Type::i32(), Type::i1()], false));
2739+
ifn!("llvm.uadd.with.overflow.i64",
2740+
[Type::i64(), Type::i64()], Type::struct_([Type::i64(), Type::i1()], false));
2741+
2742+
ifn!("llvm.ssub.with.overflow.i8",
2743+
[Type::i8(), Type::i8()], Type::struct_([Type::i8(), Type::i1()], false));
2744+
ifn!("llvm.ssub.with.overflow.i16",
2745+
[Type::i16(), Type::i16()], Type::struct_([Type::i16(), Type::i1()], false));
2746+
ifn!("llvm.ssub.with.overflow.i32",
2747+
[Type::i32(), Type::i32()], Type::struct_([Type::i32(), Type::i1()], false));
2748+
ifn!("llvm.ssub.with.overflow.i64",
2749+
[Type::i64(), Type::i64()], Type::struct_([Type::i64(), Type::i1()], false));
2750+
2751+
ifn!("llvm.usub.with.overflow.i8",
2752+
[Type::i8(), Type::i8()], Type::struct_([Type::i8(), Type::i1()], false));
2753+
ifn!("llvm.usub.with.overflow.i16",
2754+
[Type::i16(), Type::i16()], Type::struct_([Type::i16(), Type::i1()], false));
2755+
ifn!("llvm.usub.with.overflow.i32",
2756+
[Type::i32(), Type::i32()], Type::struct_([Type::i32(), Type::i1()], false));
2757+
ifn!("llvm.usub.with.overflow.i64",
2758+
[Type::i64(), Type::i64()], Type::struct_([Type::i64(), Type::i1()], false));
2759+
2760+
ifn!("llvm.smul.with.overflow.i8",
2761+
[Type::i8(), Type::i8()], Type::struct_([Type::i8(), Type::i1()], false));
2762+
ifn!("llvm.smul.with.overflow.i16",
2763+
[Type::i16(), Type::i16()], Type::struct_([Type::i16(), Type::i1()], false));
2764+
ifn!("llvm.smul.with.overflow.i32",
2765+
[Type::i32(), Type::i32()], Type::struct_([Type::i32(), Type::i1()], false));
2766+
ifn!("llvm.smul.with.overflow.i64",
2767+
[Type::i64(), Type::i64()], Type::struct_([Type::i64(), Type::i1()], false));
2768+
2769+
ifn!("llvm.umul.with.overflow.i8",
2770+
[Type::i8(), Type::i8()], Type::struct_([Type::i8(), Type::i1()], false));
2771+
ifn!("llvm.umul.with.overflow.i16",
2772+
[Type::i16(), Type::i16()], Type::struct_([Type::i16(), Type::i1()], false));
2773+
ifn!("llvm.umul.with.overflow.i32",
2774+
[Type::i32(), Type::i32()], Type::struct_([Type::i32(), Type::i1()], false));
2775+
ifn!("llvm.umul.with.overflow.i64",
2776+
[Type::i64(), Type::i64()], Type::struct_([Type::i64(), Type::i1()], false));
2777+
27242778
return intrinsics;
27252779
}
27262780

src/librustc/middle/trans/build.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -714,9 +714,11 @@ pub fn ExtractValue(cx: @mut Block, AggVal: ValueRef, Index: uint) -> ValueRef {
714714
}
715715
}
716716

717-
pub fn InsertValue(cx: @mut Block, AggVal: ValueRef, EltVal: ValueRef, Index: uint) {
718-
if cx.unreachable { return; }
719-
B(cx).insert_value(AggVal, EltVal, Index)
717+
pub fn InsertValue(cx: @mut Block, AggVal: ValueRef, EltVal: ValueRef, Index: uint) -> ValueRef {
718+
unsafe {
719+
if cx.unreachable { return llvm::LLVMGetUndef(Type::nil().to_ref()); }
720+
B(cx).insert_value(AggVal, EltVal, Index)
721+
}
720722
}
721723

722724
pub fn IsNull(cx: @mut Block, Val: ValueRef) -> ValueRef {

src/librustc/middle/trans/builder.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -861,11 +861,11 @@ impl Builder {
861861
}
862862

863863
pub fn insert_value(&self, agg_val: ValueRef, elt: ValueRef,
864-
idx: uint) {
864+
idx: uint) -> ValueRef {
865865
self.count_insn("insertvalue");
866866
unsafe {
867867
llvm::LLVMBuildInsertValue(self.llbuilder, agg_val, elt, idx as c_uint,
868-
noname());
868+
noname())
869869
}
870870
}
871871

src/librustc/middle/trans/common.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ impl FunctionContext {
237237
}
238238

239239
pub fn out_arg_pos(&self) -> uint {
240-
assert!(self.has_immediate_return_value);
240+
assert!(!self.has_immediate_return_value);
241241
0u
242242
}
243243

src/librustc/middle/trans/foreign.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,24 @@ pub fn trans_intrinsic(ccx: @mut CrateContext,
550550
Ret(bcx, Call(bcx, llfn, args.slice(0, num_args)));
551551
}
552552

553+
fn with_overflow_instrinsic(bcx: @mut Block, name: &'static str) {
554+
let first_real_arg = bcx.fcx.arg_pos(0u);
555+
let a = get_param(bcx.fcx.llfn, first_real_arg);
556+
let b = get_param(bcx.fcx.llfn, first_real_arg + 1);
557+
let llfn = bcx.ccx().intrinsics.get_copy(&name);
558+
559+
// convert `i1` to a `bool`, and write to the out parameter
560+
let val = Call(bcx, llfn, [a, b]);
561+
let result = ExtractValue(bcx, val, 0);
562+
let overflow = ZExt(bcx, ExtractValue(bcx, val, 1), Type::bool());
563+
let retptr = get_param(bcx.fcx.llfn, bcx.fcx.out_arg_pos());
564+
let ret = Load(bcx, retptr);
565+
let ret = InsertValue(bcx, ret, result, 0);
566+
let ret = InsertValue(bcx, ret, overflow, 1);
567+
Store(bcx, ret, retptr);
568+
RetVoid(bcx)
569+
}
570+
553571
fn memcpy_intrinsic(bcx: @mut Block, name: &'static str, tp_ty: ty::t, sizebits: u8) {
554572
let ccx = bcx.ccx();
555573
let lltp_ty = type_of::type_of(ccx, tp_ty);
@@ -944,6 +962,37 @@ pub fn trans_intrinsic(ccx: @mut CrateContext,
944962
"bswap16" => simple_llvm_intrinsic(bcx, "llvm.bswap.i16", 1),
945963
"bswap32" => simple_llvm_intrinsic(bcx, "llvm.bswap.i32", 1),
946964
"bswap64" => simple_llvm_intrinsic(bcx, "llvm.bswap.i64", 1),
965+
966+
"i8_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.sadd.with.overflow.i8"),
967+
"i16_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.sadd.with.overflow.i16"),
968+
"i32_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.sadd.with.overflow.i32"),
969+
"i64_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.sadd.with.overflow.i64"),
970+
971+
"u8_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.uadd.with.overflow.i8"),
972+
"u16_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.uadd.with.overflow.i16"),
973+
"u32_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.uadd.with.overflow.i32"),
974+
"u64_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.uadd.with.overflow.i64"),
975+
976+
"i8_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.ssub.with.overflow.i8"),
977+
"i16_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.ssub.with.overflow.i16"),
978+
"i32_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.ssub.with.overflow.i32"),
979+
"i64_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.ssub.with.overflow.i64"),
980+
981+
"u8_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.usub.with.overflow.i8"),
982+
"u16_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.usub.with.overflow.i16"),
983+
"u32_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.usub.with.overflow.i32"),
984+
"u64_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.usub.with.overflow.i64"),
985+
986+
"i8_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.smul.with.overflow.i8"),
987+
"i16_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.smul.with.overflow.i16"),
988+
"i32_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.smul.with.overflow.i32"),
989+
"i64_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.smul.with.overflow.i64"),
990+
991+
"u8_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.umul.with.overflow.i8"),
992+
"u16_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.umul.with.overflow.i16"),
993+
"u32_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.umul.with.overflow.i32"),
994+
"u64_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.umul.with.overflow.i64"),
995+
947996
_ => {
948997
// Could we make this an enum rather than a string? does it get
949998
// checked earlier?

src/librustc/middle/trans/type_use.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,22 @@ pub fn type_uses_for(ccx: @mut CrateContext, fn_id: def_id, n_tps: uint)
168168

169169
"bswap16" | "bswap32" | "bswap64" => 0,
170170

171+
172+
"i8_add_with_overflow" | "u8_add_with_overflow" |
173+
"i16_add_with_overflow" | "u16_add_with_overflow" |
174+
"i32_add_with_overflow" | "u32_add_with_overflow" |
175+
"i64_add_with_overflow" | "u64_add_with_overflow" => 0,
176+
177+
"i8_sub_with_overflow" | "u8_sub_with_overflow" |
178+
"i16_sub_with_overflow" | "u16_sub_with_overflow" |
179+
"i32_sub_with_overflow" | "u32_sub_with_overflow" |
180+
"i64_sub_with_overflow" | "u64_sub_with_overflow" => 0,
181+
182+
"i8_mul_with_overflow" | "u8_mul_with_overflow" |
183+
"i16_mul_with_overflow" | "u16_mul_with_overflow" |
184+
"i32_mul_with_overflow" | "u32_mul_with_overflow" |
185+
"i64_mul_with_overflow" | "u64_mul_with_overflow" => 0,
186+
171187
// would be cool to make these an enum instead of
172188
// strings!
173189
_ => fail!("unknown intrinsic in type_use")

src/librustc/middle/typeck/check/mod.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3648,6 +3648,39 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) {
36483648
"bswap16" => (0, ~[ ty::mk_i16() ], ty::mk_i16()),
36493649
"bswap32" => (0, ~[ ty::mk_i32() ], ty::mk_i32()),
36503650
"bswap64" => (0, ~[ ty::mk_i64() ], ty::mk_i64()),
3651+
3652+
"i8_add_with_overflow" | "i8_sub_with_overflow" | "i8_mul_with_overflow" =>
3653+
(0, ~[ty::mk_i8(), ty::mk_i8()],
3654+
ty::mk_tup(tcx, ~[ty::mk_i8(), ty::mk_bool()])),
3655+
3656+
"i16_add_with_overflow" | "i16_sub_with_overflow" | "i16_mul_with_overflow" =>
3657+
(0, ~[ty::mk_i16(), ty::mk_i16()],
3658+
ty::mk_tup(tcx, ~[ty::mk_i16(), ty::mk_bool()])),
3659+
3660+
"i32_add_with_overflow" | "i32_sub_with_overflow" | "i32_mul_with_overflow" =>
3661+
(0, ~[ty::mk_i32(), ty::mk_i32()],
3662+
ty::mk_tup(tcx, ~[ty::mk_i32(), ty::mk_bool()])),
3663+
3664+
"i64_add_with_overflow" | "i64_sub_with_overflow" | "i64_mul_with_overflow" =>
3665+
(0, ~[ty::mk_i64(), ty::mk_i64()],
3666+
ty::mk_tup(tcx, ~[ty::mk_i64(), ty::mk_bool()])),
3667+
3668+
"u8_add_with_overflow" | "u8_sub_with_overflow" | "u8_mul_with_overflow" =>
3669+
(0, ~[ty::mk_u8(), ty::mk_u8()],
3670+
ty::mk_tup(tcx, ~[ty::mk_u8(), ty::mk_bool()])),
3671+
3672+
"u16_add_with_overflow" | "u16_sub_with_overflow" | "u16_mul_with_overflow" =>
3673+
(0, ~[ty::mk_u16(), ty::mk_u16()],
3674+
ty::mk_tup(tcx, ~[ty::mk_u16(), ty::mk_bool()])),
3675+
3676+
"u32_add_with_overflow" | "u32_sub_with_overflow" | "u32_mul_with_overflow"=>
3677+
(0, ~[ty::mk_u32(), ty::mk_u32()],
3678+
ty::mk_tup(tcx, ~[ty::mk_u32(), ty::mk_bool()])),
3679+
3680+
"u64_add_with_overflow" | "u64_sub_with_overflow" | "u64_mul_with_overflow" =>
3681+
(0, ~[ty::mk_u64(), ty::mk_u64()],
3682+
ty::mk_tup(tcx, ~[ty::mk_u64(), ty::mk_bool()])),
3683+
36513684
ref other => {
36523685
tcx.sess.span_err(it.span,
36533686
fmt!("unrecognized intrinsic function: `%s`",

0 commit comments

Comments
 (0)