gcc/gcc/hwint.h
Richard Biener 261cdd2319 Handle overflow in dependence analysis lambda ops gracefully
The following tries to handle overflow in the integer computations
done by lambda ops of dependence analysis by failing instead of
silently continuing with overflowed values.

It also avoids treating large unsigned CHREC_RIGHT as negative
unless the chrec is of pointer type and avoids the most negative
integer value to avoid excessive overflow checking (with this
the fix for PR98758 can be partly simplified as seen).

I've added add_hwi and mul_hwi functions computing HOST_WIDE_INT
signed sum and product with indicating overflow, they hopefully
get matched to the appropriate internal functions.

I don't have any testcases triggering overflow in any of the
guarded computations.

2021-01-20  Richard Biener  <rguenther@suse.de>

	* hwint.h (add_hwi): New function.
	(mul_hwi): Likewise.
	* tree-data-ref.c (initialize_matrix_A): Properly translate
	tree constants and avoid HOST_WIDE_INT_MIN.
	(lambda_matrix_row_add): Avoid undefined integer overflow
	and return true on such overflow.
	(lambda_matrix_right_hermite): Handle overflow from
	lambda_matrix_row_add gracefully.  Simplify previous fix.
	(analyze_subscript_affine_affine): Likewise.
2021-01-20 16:32:11 +01:00

379 lines
11 KiB
C

/* HOST_WIDE_INT definitions for the GNU compiler.
Copyright (C) 1998-2021 Free Software Foundation, Inc.
This file is part of GCC.
Provide definitions for macros which depend on HOST_BITS_PER_INT
and HOST_BITS_PER_LONG. */
#ifndef GCC_HWINT_H
#define GCC_HWINT_H
/* This describes the machine the compiler is hosted on. */
#define HOST_BITS_PER_CHAR CHAR_BIT
#define HOST_BITS_PER_SHORT (CHAR_BIT * SIZEOF_SHORT)
#define HOST_BITS_PER_INT (CHAR_BIT * SIZEOF_INT)
#define HOST_BITS_PER_LONG (CHAR_BIT * SIZEOF_LONG)
#define HOST_BITS_PER_PTR (CHAR_BIT * SIZEOF_VOID_P)
/* The string that should be inserted into a printf style format to
indicate a "long" operand. */
#ifndef HOST_LONG_FORMAT
#define HOST_LONG_FORMAT "l"
#endif
/* The string that should be inserted into a printf style format to
indicate a "long long" operand. */
#ifndef HOST_LONG_LONG_FORMAT
#define HOST_LONG_LONG_FORMAT "ll"
#endif
/* If HAVE_LONG_LONG and SIZEOF_LONG_LONG aren't defined, but
GCC_VERSION >= 3000, assume this is the second or later stage of a
bootstrap, we do have long long, and it's 64 bits. (This is
required by C99; we do have some ports that violate that assumption
but they're all cross-compile-only.) Just in case, force a
constraint violation if that assumption is incorrect. */
#if !defined HAVE_LONG_LONG
# if GCC_VERSION >= 3000
# define HAVE_LONG_LONG 1
# define SIZEOF_LONG_LONG 8
extern char sizeof_long_long_must_be_8[sizeof (long long) == 8 ? 1 : -1];
# endif
#endif
#ifdef HAVE_LONG_LONG
# define HOST_BITS_PER_LONGLONG (CHAR_BIT * SIZEOF_LONG_LONG)
#endif
/* Set HOST_WIDE_INT, this should be always 64 bits.
The underlying type is matched to that of int64_t and assumed
to be either long or long long. */
#define HOST_BITS_PER_WIDE_INT 64
#if INT64_T_IS_LONG
# define HOST_WIDE_INT long
# define HOST_WIDE_INT_C(X) X ## L
#else
# if HOST_BITS_PER_LONGLONG == 64
# define HOST_WIDE_INT long long
# define HOST_WIDE_INT_C(X) X ## LL
# else
#error "Unable to find a suitable type for HOST_WIDE_INT"
# endif
#endif
#define HOST_WIDE_INT_UC(X) HOST_WIDE_INT_C (X ## U)
#define HOST_WIDE_INT_0 HOST_WIDE_INT_C (0)
#define HOST_WIDE_INT_0U HOST_WIDE_INT_UC (0)
#define HOST_WIDE_INT_1 HOST_WIDE_INT_C (1)
#define HOST_WIDE_INT_1U HOST_WIDE_INT_UC (1)
#define HOST_WIDE_INT_M1 HOST_WIDE_INT_C (-1)
#define HOST_WIDE_INT_M1U HOST_WIDE_INT_UC (-1)
/* This is a magic identifier which allows GCC to figure out the type
of HOST_WIDE_INT for %wd specifier checks. You must issue this
typedef before using the __asm_fprintf__ format attribute. */
typedef HOST_WIDE_INT __gcc_host_wide_int__;
/* Provide C99 <inttypes.h> style format definitions for 64bits. */
#ifndef HAVE_INTTYPES_H
#if INT64_T_IS_LONG
# define GCC_PRI64 HOST_LONG_FORMAT
#else
# define GCC_PRI64 HOST_LONG_LONG_FORMAT
#endif
#undef PRId64
#define PRId64 GCC_PRI64 "d"
#undef PRIi64
#define PRIi64 GCC_PRI64 "i"
#undef PRIo64
#define PRIo64 GCC_PRI64 "o"
#undef PRIu64
#define PRIu64 GCC_PRI64 "u"
#undef PRIx64
#define PRIx64 GCC_PRI64 "x"
#undef PRIX64
#define PRIX64 GCC_PRI64 "X"
#endif
/* Various printf format strings for HOST_WIDE_INT. */
#if INT64_T_IS_LONG
# define HOST_WIDE_INT_PRINT HOST_LONG_FORMAT
# define HOST_WIDE_INT_PRINT_C "L"
#else
# define HOST_WIDE_INT_PRINT HOST_LONG_LONG_FORMAT
# define HOST_WIDE_INT_PRINT_C "LL"
#endif
#define HOST_WIDE_INT_PRINT_DEC "%" PRId64
#define HOST_WIDE_INT_PRINT_DEC_C "%" PRId64 HOST_WIDE_INT_PRINT_C
#define HOST_WIDE_INT_PRINT_UNSIGNED "%" PRIu64
#define HOST_WIDE_INT_PRINT_HEX "%#" PRIx64
#define HOST_WIDE_INT_PRINT_HEX_PURE "%" PRIx64
#define HOST_WIDE_INT_PRINT_DOUBLE_HEX "0x%" PRIx64 "%016" PRIx64
#define HOST_WIDE_INT_PRINT_PADDED_HEX "%016" PRIx64
/* Define HOST_WIDEST_FAST_INT to the widest integer type supported
efficiently in hardware. (That is, the widest integer type that fits
in a hardware register.) Normally this is "long" but on some hosts it
should be "long long" or "__int64". This is no convenient way to
autodetect this, so such systems must set a flag in config.host; see there
for details. */
#ifdef USE_LONG_LONG_FOR_WIDEST_FAST_INT
# ifdef HAVE_LONG_LONG
# define HOST_WIDEST_FAST_INT long long
# define HOST_BITS_PER_WIDEST_FAST_INT HOST_BITS_PER_LONGLONG
# else
# error "Your host said it wanted to use long long but that does not exist"
# endif
#else
# define HOST_WIDEST_FAST_INT long
# define HOST_BITS_PER_WIDEST_FAST_INT HOST_BITS_PER_LONG
#endif
/* Inline functions operating on HOST_WIDE_INT. */
/* Return X with all but the lowest bit masked off. */
static inline unsigned HOST_WIDE_INT
least_bit_hwi (unsigned HOST_WIDE_INT x)
{
return (x & -x);
}
/* True if X is zero or a power of two. */
static inline bool
pow2_or_zerop (unsigned HOST_WIDE_INT x)
{
return least_bit_hwi (x) == x;
}
/* True if X is a power of two. */
static inline bool
pow2p_hwi (unsigned HOST_WIDE_INT x)
{
return x && pow2_or_zerop (x);
}
#if GCC_VERSION < 3004
extern int clz_hwi (unsigned HOST_WIDE_INT x);
extern int ctz_hwi (unsigned HOST_WIDE_INT x);
extern int ffs_hwi (unsigned HOST_WIDE_INT x);
/* Return the number of set bits in X. */
extern int popcount_hwi (unsigned HOST_WIDE_INT x);
/* Return log2, or -1 if not exact. */
extern int exact_log2 (unsigned HOST_WIDE_INT);
/* Return floor of log2, with -1 for zero. */
extern int floor_log2 (unsigned HOST_WIDE_INT);
/* Return the smallest n such that 2**n >= X. */
extern int ceil_log2 (unsigned HOST_WIDE_INT);
#else /* GCC_VERSION >= 3004 */
/* For convenience, define 0 -> word_size. */
static inline int
clz_hwi (unsigned HOST_WIDE_INT x)
{
if (x == 0)
return HOST_BITS_PER_WIDE_INT;
# if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG
return __builtin_clzl (x);
# elif HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONGLONG
return __builtin_clzll (x);
# else
return __builtin_clz (x);
# endif
}
static inline int
ctz_hwi (unsigned HOST_WIDE_INT x)
{
if (x == 0)
return HOST_BITS_PER_WIDE_INT;
# if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG
return __builtin_ctzl (x);
# elif HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONGLONG
return __builtin_ctzll (x);
# else
return __builtin_ctz (x);
# endif
}
static inline int
ffs_hwi (unsigned HOST_WIDE_INT x)
{
# if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG
return __builtin_ffsl (x);
# elif HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONGLONG
return __builtin_ffsll (x);
# else
return __builtin_ffs (x);
# endif
}
static inline int
popcount_hwi (unsigned HOST_WIDE_INT x)
{
# if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG
return __builtin_popcountl (x);
# elif HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONGLONG
return __builtin_popcountll (x);
# else
return __builtin_popcount (x);
# endif
}
static inline int
floor_log2 (unsigned HOST_WIDE_INT x)
{
return HOST_BITS_PER_WIDE_INT - 1 - clz_hwi (x);
}
static inline int
ceil_log2 (unsigned HOST_WIDE_INT x)
{
return x == 0 ? 0 : floor_log2 (x - 1) + 1;
}
static inline int
exact_log2 (unsigned HOST_WIDE_INT x)
{
return pow2p_hwi (x) ? ctz_hwi (x) : -1;
}
#endif /* GCC_VERSION >= 3004 */
#define HOST_WIDE_INT_MIN (HOST_WIDE_INT) \
(HOST_WIDE_INT_1U << (HOST_BITS_PER_WIDE_INT - 1))
#define HOST_WIDE_INT_MAX (~(HOST_WIDE_INT_MIN))
extern HOST_WIDE_INT abs_hwi (HOST_WIDE_INT);
extern unsigned HOST_WIDE_INT absu_hwi (HOST_WIDE_INT);
extern HOST_WIDE_INT gcd (HOST_WIDE_INT, HOST_WIDE_INT);
extern HOST_WIDE_INT pos_mul_hwi (HOST_WIDE_INT, HOST_WIDE_INT);
extern HOST_WIDE_INT mul_hwi (HOST_WIDE_INT, HOST_WIDE_INT);
extern HOST_WIDE_INT least_common_multiple (HOST_WIDE_INT, HOST_WIDE_INT);
/* Like ctz_hwi, except 0 when x == 0. */
static inline int
ctz_or_zero (unsigned HOST_WIDE_INT x)
{
return ffs_hwi (x) - 1;
}
/* Sign extend SRC starting from PREC. */
static inline HOST_WIDE_INT
sext_hwi (HOST_WIDE_INT src, unsigned int prec)
{
if (prec == HOST_BITS_PER_WIDE_INT)
return src;
else
#if defined (__GNUC__)
{
/* Take the faster path if the implementation-defined bits it's relying
on are implemented the way we expect them to be. Namely, conversion
from unsigned to signed preserves bit pattern, and right shift of
a signed value propagates the sign bit.
We have to convert from signed to unsigned and back, because when left
shifting signed values, any overflow is undefined behavior. */
gcc_checking_assert (prec < HOST_BITS_PER_WIDE_INT);
int shift = HOST_BITS_PER_WIDE_INT - prec;
return ((HOST_WIDE_INT) ((unsigned HOST_WIDE_INT) src << shift)) >> shift;
}
#else
{
/* Fall back to the slower, well defined path otherwise. */
gcc_checking_assert (prec < HOST_BITS_PER_WIDE_INT);
HOST_WIDE_INT sign_mask = HOST_WIDE_INT_1 << (prec - 1);
HOST_WIDE_INT value_mask = (HOST_WIDE_INT_1U << prec) - HOST_WIDE_INT_1U;
return (((src & value_mask) ^ sign_mask) - sign_mask);
}
#endif
}
/* Zero extend SRC starting from PREC. */
static inline unsigned HOST_WIDE_INT
zext_hwi (unsigned HOST_WIDE_INT src, unsigned int prec)
{
if (prec == HOST_BITS_PER_WIDE_INT)
return src;
else
{
gcc_checking_assert (prec < HOST_BITS_PER_WIDE_INT);
return src & ((HOST_WIDE_INT_1U << prec) - 1);
}
}
/* Compute the absolute value of X. */
inline HOST_WIDE_INT
abs_hwi (HOST_WIDE_INT x)
{
gcc_checking_assert (x != HOST_WIDE_INT_MIN);
return x >= 0 ? x : -x;
}
/* Compute the absolute value of X as an unsigned type. */
inline unsigned HOST_WIDE_INT
absu_hwi (HOST_WIDE_INT x)
{
return x >= 0 ? (unsigned HOST_WIDE_INT)x : -(unsigned HOST_WIDE_INT)x;
}
/* Compute the sum of signed A and B and indicate in *OVERFLOW whether
that operation overflowed. */
inline HOST_WIDE_INT
add_hwi (HOST_WIDE_INT a, HOST_WIDE_INT b, bool *overflow)
{
#if GCC_VERSION < 11000
unsigned HOST_WIDE_INT result = a + (unsigned HOST_WIDE_INT)b;
if ((((result ^ a) & (result ^ b))
>> (HOST_BITS_PER_WIDE_INT - 1)) & 1)
*overflow = true;
else
*overflow = false;
return result;
#else
HOST_WIDE_INT result;
*overflow = __builtin_add_overflow (a, b, &result);
return result;
#endif
}
/* Compute the product of signed A and B and indicate in *OVERFLOW whether
that operation overflowed. */
inline HOST_WIDE_INT
mul_hwi (HOST_WIDE_INT a, HOST_WIDE_INT b, bool *overflow)
{
#if GCC_VERSION < 11000
unsigned HOST_WIDE_INT result = a * (unsigned HOST_WIDE_INT)b;
if ((a == -1 && b == HOST_WIDE_INT_MIN)
|| (a != 0 && (HOST_WIDE_INT)result / a != b))
*overflow = true;
else
*overflow = false;
return result;
#else
HOST_WIDE_INT result;
*overflow = __builtin_mul_overflow (a, b, &result);
return result;
#endif
}
#endif /* ! GCC_HWINT_H */