While overflow-trapped arithmetic may impose only a moderate cost to a non-optimizing compiler, most languages that support overflow trapping treat any signals, traps, exceptions, etc. as strongly sequenced behaviors. This means that a compiler given something like:
extern int f1(void);
extern void f2(int, int, int);
void test(int x, int y)
{
int temp = x*y;
if (f1())
f2(temp, x, y);
}
would be required to perform the multiplication before calling f1()
, and would not be able to skip the useless multiplication in cases where f1()
would return zero.
In order for a language to allow compilers to perform an optimizing transform to yield:
extern int f1(void);
extern void f2(int, int, int);
void test(int x, int y)
{
if (f1())
f2(x*y, x, y);
}
it would be necessary to either:
Specify that the multiplication will never have side effects,
Characterize as Undefined Behavior all situations where the multiplication could have observable side effects, or
Have a recognized category of "loosely sequenced" side effects which compilers would be allowed to reorder relative to other operations, and sometimes skip altogether, provided they didn't cross special ordering barriers.
IMHO, #3 would be the best approach, but I've not seen language designers use it. Of those two choices, #1 is vastly superior to #2, but #3 would be vastly better yet.