[Bug middle-end/48580] missed optimization: integer overflow checks
joseph at codesourcery dot com
gcc-bugzilla@gcc.gnu.org
Wed Apr 13 12:46:00 GMT 2011
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=48580
--- Comment #9 from joseph at codesourcery dot com <joseph at codesourcery dot com> 2011-04-13 12:45:35 UTC ---
On Wed, 13 Apr 2011, rguenth at gcc dot gnu.org wrote:
> For the latter reasons I think the builtins should be sth like
> __builtin_smul_ovfl_p (multiplication-result, op0, op1), thus pass
> in the multiplication result and keep the multiplication itself
> in the IL to also allow for regular optimizations to work on them.
> If the multiplication is just used as the builtin call argument
> expansion can get rid of it.
My inclination is that we probably want to separate the API for users from
the built-in functions or other operations used internally - possibly
providing a header gccarith.h with a supported API and saying the built-in
functions are subject to change and should not be used directly in source
code. Maybe (inspired by the style used on C1X stdatomic.h) one could
have operations like
arith_mul_signed (a, b, 32, ARITH_SAT)
that multiplies a and b (integers to infinite precision, producing an
infinite precision result), saturates the result to 32-bit signed and
returns an implementation-defined type (signed, two's complement, at least
32 bits), or
arith_mul_signed_check (a, b, 32, ARITH_WRAP, &overflow_p)
that stores an overflow flag in the provided _Bool *. Or the overflow
handling (wrap, saturate, undefined, unspecified-value, trap) could be
part of the macro/function name (putting it as a separate operand is
inspired by the memory_order parameters in stdatomic.h).
The _check versions with explicit overflow flags could be used with any
overflow handling other than "undefined behavior". (So if you don't care
about what the value is when the overflow flag is set - if you'll just
call some error handler - then you'd use "unspecified-value" as the
overflow handling.) On divide by zero, both division and modulo
operations would have undefined behavior except for the "trap" case - but
modulo -1 would always be defined, unlike for C INT_MIN % -1 (I'm thinking
of these operations as all being defined on their own by producing an
infinite precision result first, but there might also be operations such
as divmod producing multiple results). It may also make sense to expose
different variations of division/modulo (rounding to 0, -infinity or
+infinity; a true modulo operation, rounding to -infinity, is one of those
things C doesn't make easy; GCC has these as TRUNC_DIV_EXPR,
FLOOR_DIV_EXPR, CEIL_DIV_EXPR and corresponding *_MOD_EXPR). Starting
with addition then increasing the set of operations gradually probably
makes sense.
Along with all the arithmetic operations you get range check operations -
take a value (in any integer type), and check whether it is in the
signed/unsigned range with a given number of bits, wrapping/saturating
etc. and setting overflow flags as needed. These are just like the above
but with one fewer operands.
The explicit number of bits (required to be an integer constant
expression) is deliberate because it is sometimes useful e.g. to saturate
to 16 bits, but integer promotions in C make it rather fragile to rely on
16-bit operands remaining 16-bit rather than getting implicitly promoted
to 32 bits. A consequence is that operations with strange numbers of bits
can be written without involving bit-field types (since the result is
allowed to have more than the given number of bits). I don't expect those
to be very efficient in general, but note that ARM for example has SSAT
and USAT instructions to saturate a value to a given number of bits (up to
32) and set a flag if it was out of range.
More information about the Gcc-bugs
mailing list