4 ms·
> It allows the programmer to express intent. Can the programmer express the intent that this will not overflow? i.e. is it possible to coerce the Rust compile
by millstone 8y ago
> It allows the programmer to express intent.
Can the programmer express the intent that this will not overflow? i.e. is it possible to coerce the Rust compiler to optimize (x*2)/2 to x? "Cheap hardware traps" cannot substitute for such a compile-time optimization.
> C seems pretty hopeless since there is no way to know whether or not the coder intended on overflow or not.
Well this doesn't matter: if signed arithmetic overflows the code is undefined, regardless of intent.
In practice comments can express intent, and unsigned arithmetic can with some finessing produce most codegen. Explicit operators would be a big improvement though.
- lyinsteve 8y agoI don’t know much about rust specifically, but the overflow traps happen in debug (i.e. -O0) builds, and are not emitted when optimizations are enabled. LLVM’s constant folding and canonicalization passes will convert (x * 2) / 2 from %0 = mul i64 %x, i64 2 %1 = div i64 %0, i64 2 to %0 = shl i64 %x, i64 1 %1 = shr i64 %0, i64 1 Which constant folding will reduce to just %x.
- millstone 8y agoWell ok but (x*3)/3 will be a lot worse :)
- Franciscouzo 8y agoNot by a lot, the divide by constant can be optimized to a multiplication, if you're doing it in a loop (why would you care if you do it only once), you can reach a throughput of one multiplication per cycle, so (x*3)/3 would take 2 cycles on average.
- millstone 8y agoThis is a silly line of argument; optimizing (x*3)/3 to x unlocks further CSE, inlining, etc. so the benefit may be arbitrarily large. Rust made the right tradeoff here but it is a tradeoff!
- BeeOnRope 8y agoHow do the two shifts reduce to x? The top bit is zeroed as a result of those shifts.
- CryZe 8y agoThe point is rather that Rust has a bunch of methods on integer for dealing with overflows in a variety of ways, like saturating, wrapping or returning an Option with a None value on overflow (there's also one that returns a tuple with the carry).
- millstone 8y agoThat's all good but it misses my point: the one redeeming quality of C's integer overflow non-semantics is that it unlocks further compiler optimizations, and that's the mode which AFAICT Rust doesn't support. For example, a for loop from 0-through-N (N:i32) will execute N times in C, but N-or-infinity times in Rust. That small difference of infinity controls how the loop condition is tested, whether it can be turned into a simple counter or not.
- jcranmer 8y ago> For example, a for loop from 0-through-N (N:i32) will execute N times in C, but N-or-infinity times in Rust. Eh, not quite true. If N is a 64-bit or an unsigned integer but your loop index is a signed 32-bit integer, then you will have this behavior. In Rust, the idiomatic for loop will have the index variable always be the same size as the condition variable, which prevents the infinity case from happening. In C, if you have a 64-bit condition but a 32-bit unsigned loop index variable, you get the N-or-infinity case as well. In other words, if your language is subtly redesigned to make you jump through hoops to do things like have mismatched integer types in for loops, then the need to rely on undefined behavior to reclaim that performance is lessened.