I've seen this thread:
About this interesting blog post:
http://blog.regehr.org/archives/1384
Is something like this in Rustc (or is Rustc going to have it)?
https://github.com/apple/swift/blob/master/lib/SILOptimizer/Transforms/RedundantOverflowCheckRemoval.cpp
This is my translation of the C code from the blog post (I've used get_unchecked as in C, and in foo2() I've added two extra casts as in C):
#[inline(never)]
fn foo(x: i32, y: i32) -> i32 {
x + y
}
#[inline(never)]
fn foo2(x: i32, y: i32) -> i32 {
(x as i16) as i32 + (y as i16) as i32
}
#[inline(never)]
fn foo3(x: i32, y: i32) -> i32 {
((x as i64) + (y as i64)) as i32
}
#[inline(never)]
fn foo4(x: i32, y: i32) -> i32 {
(x >> 1) + (y >> 1)
}
#[inline(never)]
fn foo5(x: i32, y: i32) -> i32 {
let mask: i32 = (!(3u32 << 30)) as i32;
(x & mask) + (y & mask)
}
#[inline(never)]
fn foo6(x: i32, y: i32) -> i32 {
let mask: i32 = (3u32 << 30) as i32;
(x | mask) + (y | mask)
}
#[inline(never)]
fn foo7(x: i32, y: i32) -> i32 {
let mask: i32 = (1u32 << 31) as i32;
(x | mask) + (y & !mask)
}
#[inline(never)]
fn foo8(x: i32) -> i32 {
use std::i32::MAX;
if x < MAX { x + 1 } else { MAX }
}
#[inline(never)]
fn foo9(x: i32, y: i32) -> i32 {
if x < 10 && x > -10 && y < 10 && y > -10 {
return x + y;
}
return 0;
}
#[inline(never)]
fn foo10(a: &mut [i8]) {
for i in 0i32 .. 10i32 {
unsafe {
*a.get_unchecked_mut(i as usize) = 0;
}
}
}
#[inline(never)]
fn foo11(a: &[u32], i: i32) -> u32 {
unsafe {
a.get_unchecked((i + 3) as usize) +
a.get_unchecked((i + 5) as usize) +
a.get_unchecked((i + 2) as usize)
}
}
fn main() {
let x: i32 = std::env::args().nth(1).unwrap().parse().unwrap();
let y: i32 = std::env::args().nth(0).unwrap().parse().unwrap();
println!("{}", foo(x, y));
println!("{}", foo2(x, y));
println!("{}", foo3(x, y));
println!("{}", foo4(x, y));
println!("{}", foo5(x, y));
println!("{}", foo6(x, y));
println!("{}", foo7(x, y));
println!("{}", foo8(x));
println!("{}", foo9(x, y));
let x8 = x as i8;
let y8 = y as i8;
let mut arr1 = [x8, y8, x8, y8, x8, y8, x8, y8, x8, y8];
foo10(&mut arr1);
println!("{:?}", arr1);
let ux = x as u32;
let uy = y as u32;
let arr2 = [ux, uy, ux, uy, ux, uy];
println!("{}", foo11(&arr2, x));
}
This is the asm, using "-Z force-overflow-checks=on -C opt-level=3 -C target-cpu=native --emit asm" (if I use just -O the asm is the same), using rustc 1.9.0-nightly 2016-04-02, on a 64 bit system. I have assumed int = i32, unsigned = u32, long = i64, char = i8:
_ZN4temp3foo17hcd7dc3780f71cf13E:
subq $40, %rsp
addl %edx, %ecx
jo .LBB0_2
movl %ecx, %eax
addq $40, %rsp
retq
.LBB0_2:
leaq panic_loc5965(%rip), %rcx
callq _ZN4core9panicking5panic17h188c6c6a0fe5463cE
ud2
_ZN4temp4foo217h36cd5306e44d9490E:
movswl %cx, %ecx
movswl %dx, %eax
addl %ecx, %eax
retq
_ZN4temp4foo317h2d6d816224352628E:
leal (%rcx,%rdx), %eax
retq
_ZN4temp4foo417h10e6771f01c6ce47E:
sarl %ecx
sarl %edx
leal (%rdx,%rcx), %eax
retq
_ZN4temp4foo517h16ae48d90b753b2aE:
andl $1073741823, %ecx
andl $1073741823, %edx
leal (%rdx,%rcx), %eax
retq
_ZN4temp4foo617hdc0b94050cc4ab8eE:
orl $-1073741824, %ecx
orl $-1073741824, %edx
leal (%rdx,%rcx), %eax
retq
_ZN4temp4foo717hc3e817990764820dE:
orl $-2147483648, %ecx
andl $2147483647, %edx
leal (%rdx,%rcx), %eax
retq
_ZN4temp4foo817hefdf0c9012716395E:
subq $40, %rsp
movl $2147483647, %eax
cmpl $2147483647, %ecx
je .LBB7_3
incl %ecx
jo .LBB7_4
movl %ecx, %eax
.LBB7_3:
addq $40, %rsp
retq
.LBB7_4:
leaq panic_loc5978(%rip), %rcx
callq _ZN4core9panicking5panic17h188c6c6a0fe5463cE
ud2
_ZN4temp4foo917h1b8e21683e5607dcE:
subq $40, %rsp
leal 9(%rcx), %r8d
xorl %eax, %eax
cmpl $18, %r8d
ja .LBB8_4
leal 9(%rdx), %r8d
cmpl $18, %r8d
ja .LBB8_4
addl %edx, %ecx
jo .LBB8_5
movl %ecx, %eax
.LBB8_4:
addq $40, %rsp
retq
.LBB8_5:
leaq panic_loc5981(%rip), %rcx
callq _ZN4core9panicking5panic17h188c6c6a0fe5463cE
ud2
_ZN4temp5foo1017h5bde45ebfe6d6fcdE:
subq $40, %rsp
xorl %eax, %eax
.align 16, 0x90
.LBB9_1:
movl %eax, %edx
incl %edx
jo .LBB9_4
cltq
movb $0, (%rcx,%rax)
movl %edx, %eax
cmpl $10, %edx
jl .LBB9_1
addq $40, %rsp
retq
.LBB9_4:
leaq panic_loc7761(%rip), %rcx
callq _ZN4core9panicking5panic17h188c6c6a0fe5463cE
ud2
_ZN4temp5foo1117hedfa86a790c1c8caE:
subq $40, %rsp
movl %edx, %r8d
addl $3, %r8d
jo .LBB10_7
movl %edx, %eax
addl $5, %eax
jo .LBB10_9
movslq %r8d, %r8
movslq %eax, %r9
movl (%rcx,%r8,4), %eax
addl (%rcx,%r9,4), %eax
jb .LBB10_8
addl $2, %edx
jo .LBB10_6
movslq %edx, %rdx
addl (%rcx,%rdx,4), %eax
jb .LBB10_8
addq $40, %rsp
retq
.LBB10_8:
leaq panic_loc7761(%rip), %rcx
callq _ZN4core9panicking5panic17h188c6c6a0fe5463cE
ud2
.LBB10_7:
leaq panic_loc7932(%rip), %rcx
callq _ZN4core9panicking5panic17h188c6c6a0fe5463cE
ud2
.LBB10_9:
leaq panic_loc7934(%rip), %rcx
callq _ZN4core9panicking5panic17h188c6c6a0fe5463cE
ud2
.LBB10_6:
leaq panic_loc7936(%rip), %rcx
callq _ZN4core9panicking5panic17h188c6c6a0fe5463cE
ud2
Compared to the blog post, the asm of foo() is longer. The asm of the C foo() is:
foo: # @foo
addl %esi, %edi
jo .LBB0_1
movl %edi, %eax
retq
.LBB0_1:
ud2
foo11() has five panics instead of three because the C code is compiled with -fsanitize=signed-integer-overflow -fsanitize-trap=signed-integer-overflow, so it ignores the unsigned overflows. If you add -fsanitize=unsigned-integer-overflow -fsanitize-trap=unsigned-integer-overflow to the C compilation flags, you get five traps in the C code too.