5 ms·
Also Rust applications are increasingly going to be built with integer overflow checking enabled, e.g. Android's Rust components are going to ship with integer
by roca 5y ago
Also Rust applications are increasingly going to be built with integer overflow checking enabled, e.g. Android's Rust components are going to ship with integer overflow checking. And unlike say GMP, that poses a potential code density problem because we're not talking about inner loops that can be effectively cached, it's code bloat smeared across the entire binary.
- rstuart4133 5y ago> it's code bloat smeared across the entire binary. That's probably not true in the usual case. Most arch's are 64 bit nowadays. If you are working on something that isn't 64 it you are doing embedded stuff, and different rules and coding standards apply (like using embedded assembler rather than pure C or Rust). In 64 bit environments only pointers are 64 bits by default, almost all integers remain 32 bit. Checking for a 32 bit overflow on a 64 bit RISC-V machine takes the same amount of instructions as everywhere else. Also, in C integers are very common because they are used as iterators (ie, stepping along things in for loops). But in Rust, iterators replace integers for this sort thing. There still is an integer under the hood of course, and perhaps it will be bounds checked. But that is bounds checked - not overflow checked. 2^32 is far larger than most data structures in use. Which means while there may be some code bloat, the lack full 64 integers in your average Rust problem means it's going to be pretty rare. Since I'm here, I'll comment on the article. It's true the lack of carry will make adds a little more difficult for multi precision libraries. But - I've written a multi precision library, and the adds are the least of your problems. Adds just generate 1 bit of carry. Multiplies generate an entire word of carry, and they almost a common as adds. Divides are no so common fortunately, but the execution time of just one divide will make all the overhead caused by a lack of carry look like insignificant noise. I'm no CPU architect, but I gather the lack of carry and overflow bits makes life a little easier for just about every instruction other than adc and jo. If that's true, I'd be very surprised if the cumulative effect of those little gains didn't completely overwhelm the wins adc and jo gets from having them. Have a look at the code generated by a compiler some time. You will have a hard time spotting the adc's and jo's because there are bugger all of them.
- roca 5y agoIt's a good observation that checking for 32-bit overflow is not too bad, but... > In 64 bit ... almost all integers remain 32 bit. I don't believe this is true for Rust, even if we exclude index integers in iterators because we think those overflow checks can be optimized out. Certainly in my Rust project (Pernosco) there is a lot of manipulation of 64-bit integer data.
- Taniwha 5y agoYeah but the code required for an overflow check is just one extra instruction (3 rather than 2)
- masklinn 5y agoFor generalised signed addition, the overhead is 3 instructions per addition. It can be one in specific contexts where more is known about the operands (e.g. addition of immediates). It’s always 1 in x64/ARM64 as they have built-in support for overflow.
- Taniwha 5y agoyou have to include the branch instruction too in any comparison
- kccqzy 5y agoIn x86 it is still one instruction: jc or jo after an addition.
- brucehoult 5y agoAnd in RISC-V it's a "BLT sum,summand" after an unsigned addition, and a single branch instruction after a signed addition if you know the sign of one of them e.g. adding or subtracting a constant.
- rurban 5y agobuilt-in support for overflow is not really builtin. There's only adc, but the C library has no such function, and compilers only got them added a few years ago. Almost nobody uses them, as they introduce a dependency. Most workaround that in much slower ways, worse than RISC-V