re PR tree-optimization/56064 (Optimize VIEW_CONVERT_EXPR with FIXED_CST)
gcc/ PR tree-optimization/56064 * fixed-value.c (fixed_from_double_int): New function. * fixed-value.h (fixed_from_double_int): New prototype. (const_fixed_from_double_int): New static inline function. * fold-const.c (native_interpret_fixed): New static function. (native_interpret_expr) <FIXED_POINT_TYPE>: Use it. (can_native_interpret_type_p) <FIXED_POINT_TYPE>: Return true. (native_encode_fixed): New static function. (native_encode_expr) <FIXED_CST>: Use it. (native_interpret_int): Move double_int worker code to... * double-int.c (double_int::from_buffer): ...this new static method. * double-int.h (double_int::from_buffer): Prototype it. gcc/testsuite/ PR tree-optimization/56064 * gcc.dg/fixed-point/view-convert.c: New test. From-SVN: r195574
This commit is contained in:
parent
d394a308e3
commit
cc06c01d0a
|
@ -1,3 +1,18 @@
|
|||
2013-01-30 Georg-Johann Lay <avr@gjlay.de>
|
||||
|
||||
PR tree-optimization/56064
|
||||
* fixed-value.c (fixed_from_double_int): New function.
|
||||
* fixed-value.h (fixed_from_double_int): New prototype.
|
||||
(const_fixed_from_double_int): New static inline function.
|
||||
* fold-const.c (native_interpret_fixed): New static function.
|
||||
(native_interpret_expr) <FIXED_POINT_TYPE>: Use it.
|
||||
(can_native_interpret_type_p) <FIXED_POINT_TYPE>: Return true.
|
||||
(native_encode_fixed): New static function.
|
||||
(native_encode_expr) <FIXED_CST>: Use it.
|
||||
(native_interpret_int): Move double_int worker code to...
|
||||
* double-int.c (double_int::from_buffer): ...this new static method.
|
||||
* double-int.h (double_int::from_buffer): Prototype it.
|
||||
|
||||
2013-01-30 Richard Biener <rguenther@suse.de>
|
||||
|
||||
* tree-ssa-structalias.c (final_solutions, final_solutions_obstack):
|
||||
|
|
|
@ -641,6 +641,54 @@ div_and_round_double (unsigned code, int uns,
|
|||
return overflow;
|
||||
}
|
||||
|
||||
|
||||
/* Construct from a buffer of length LEN. BUFFER will be read according
|
||||
to byte endianess and word endianess. Only the lower LEN bytes
|
||||
of the result are set; the remaining high bytes are cleared. */
|
||||
|
||||
double_int
|
||||
double_int::from_buffer (const unsigned char *buffer, int len)
|
||||
{
|
||||
double_int result = double_int_zero;
|
||||
int words = len / UNITS_PER_WORD;
|
||||
|
||||
gcc_assert (len * BITS_PER_UNIT <= HOST_BITS_PER_DOUBLE_INT);
|
||||
|
||||
for (int byte = 0; byte < len; byte++)
|
||||
{
|
||||
int offset;
|
||||
int bitpos = byte * BITS_PER_UNIT;
|
||||
unsigned HOST_WIDE_INT value;
|
||||
|
||||
if (len > UNITS_PER_WORD)
|
||||
{
|
||||
int word = byte / UNITS_PER_WORD;
|
||||
|
||||
if (WORDS_BIG_ENDIAN)
|
||||
word = (words - 1) - word;
|
||||
|
||||
offset = word * UNITS_PER_WORD;
|
||||
|
||||
if (BYTES_BIG_ENDIAN)
|
||||
offset += (UNITS_PER_WORD - 1) - (byte % UNITS_PER_WORD);
|
||||
else
|
||||
offset += byte % UNITS_PER_WORD;
|
||||
}
|
||||
else
|
||||
offset = BYTES_BIG_ENDIAN ? (len - 1) - byte : byte;
|
||||
|
||||
value = (unsigned HOST_WIDE_INT) buffer[offset];
|
||||
|
||||
if (bitpos < HOST_BITS_PER_WIDE_INT)
|
||||
result.low |= value << bitpos;
|
||||
else
|
||||
result.high |= value << (bitpos - HOST_BITS_PER_WIDE_INT);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* Returns mask for PREC bits. */
|
||||
|
||||
double_int
|
||||
|
|
|
@ -59,6 +59,10 @@ struct double_int
|
|||
static double_int from_shwi (HOST_WIDE_INT cst);
|
||||
static double_int from_pair (HOST_WIDE_INT high, unsigned HOST_WIDE_INT low);
|
||||
|
||||
/* Construct from a fuffer of length LEN. BUFFER will be read according
|
||||
to byte endianess and word endianess. */
|
||||
static double_int from_buffer (const unsigned char *buffer, int len);
|
||||
|
||||
/* No copy assignment operator or destructor to keep the type a POD. */
|
||||
|
||||
/* There are some special value-creation static member functions. */
|
||||
|
|
|
@ -81,6 +81,24 @@ check_real_for_fixed_mode (REAL_VALUE_TYPE *real_value, enum machine_mode mode)
|
|||
return FIXED_OK;
|
||||
}
|
||||
|
||||
|
||||
/* Construct a CONST_FIXED from a bit payload and machine mode MODE.
|
||||
The bits in PAYLOAD are used verbatim. */
|
||||
|
||||
FIXED_VALUE_TYPE
|
||||
fixed_from_double_int (double_int payload, enum machine_mode mode)
|
||||
{
|
||||
FIXED_VALUE_TYPE value;
|
||||
|
||||
gcc_assert (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_DOUBLE_INT);
|
||||
|
||||
value.data = payload;
|
||||
value.mode = mode;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
/* Initialize from a decimal or hexadecimal string. */
|
||||
|
||||
void
|
||||
|
|
|
@ -49,6 +49,22 @@ extern FIXED_VALUE_TYPE fconst1[MAX_FCONST1];
|
|||
const_fixed_from_fixed_value (r, m)
|
||||
extern rtx const_fixed_from_fixed_value (FIXED_VALUE_TYPE, enum machine_mode);
|
||||
|
||||
/* Construct a FIXED_VALUE from a bit payload and machine mode MODE.
|
||||
The bits in PAYLOAD are used verbatim. */
|
||||
extern FIXED_VALUE_TYPE fixed_from_double_int (double_int,
|
||||
enum machine_mode);
|
||||
|
||||
/* Return a CONST_FIXED from a bit payload and machine mode MODE.
|
||||
The bits in PAYLOAD are used verbatim. */
|
||||
static inline rtx
|
||||
const_fixed_from_double_int (double_int payload,
|
||||
enum machine_mode mode)
|
||||
{
|
||||
return
|
||||
const_fixed_from_fixed_value (fixed_from_double_int (payload, mode),
|
||||
mode);
|
||||
}
|
||||
|
||||
/* Initialize from a decimal or hexadecimal string. */
|
||||
extern void fixed_from_string (FIXED_VALUE_TYPE *, const char *,
|
||||
enum machine_mode);
|
||||
|
|
|
@ -7200,6 +7200,36 @@ native_encode_int (const_tree expr, unsigned char *ptr, int len)
|
|||
}
|
||||
|
||||
|
||||
/* Subroutine of native_encode_expr. Encode the FIXED_CST
|
||||
specified by EXPR into the buffer PTR of length LEN bytes.
|
||||
Return the number of bytes placed in the buffer, or zero
|
||||
upon failure. */
|
||||
|
||||
static int
|
||||
native_encode_fixed (const_tree expr, unsigned char *ptr, int len)
|
||||
{
|
||||
tree type = TREE_TYPE (expr);
|
||||
enum machine_mode mode = TYPE_MODE (type);
|
||||
int total_bytes = GET_MODE_SIZE (mode);
|
||||
FIXED_VALUE_TYPE value;
|
||||
tree i_value, i_type;
|
||||
|
||||
if (total_bytes * BITS_PER_UNIT > HOST_BITS_PER_DOUBLE_INT)
|
||||
return 0;
|
||||
|
||||
i_type = lang_hooks.types.type_for_size (GET_MODE_BITSIZE (mode), 1);
|
||||
|
||||
if (NULL_TREE == i_type
|
||||
|| TYPE_PRECISION (i_type) != total_bytes)
|
||||
return 0;
|
||||
|
||||
value = TREE_FIXED_CST (expr);
|
||||
i_value = double_int_to_tree (i_type, value.data);
|
||||
|
||||
return native_encode_int (i_value, ptr, len);
|
||||
}
|
||||
|
||||
|
||||
/* Subroutine of native_encode_expr. Encode the REAL_CST
|
||||
specified by EXPR into the buffer PTR of length LEN bytes.
|
||||
Return the number of bytes placed in the buffer, or zero
|
||||
|
@ -7345,6 +7375,9 @@ native_encode_expr (const_tree expr, unsigned char *ptr, int len)
|
|||
case REAL_CST:
|
||||
return native_encode_real (expr, ptr, len);
|
||||
|
||||
case FIXED_CST:
|
||||
return native_encode_fixed (expr, ptr, len);
|
||||
|
||||
case COMPLEX_CST:
|
||||
return native_encode_complex (expr, ptr, len);
|
||||
|
||||
|
@ -7368,47 +7401,40 @@ static tree
|
|||
native_interpret_int (tree type, const unsigned char *ptr, int len)
|
||||
{
|
||||
int total_bytes = GET_MODE_SIZE (TYPE_MODE (type));
|
||||
int byte, offset, word, words;
|
||||
unsigned char value;
|
||||
double_int result;
|
||||
|
||||
if (total_bytes > len)
|
||||
return NULL_TREE;
|
||||
if (total_bytes * BITS_PER_UNIT > HOST_BITS_PER_DOUBLE_INT)
|
||||
if (total_bytes > len
|
||||
|| total_bytes * BITS_PER_UNIT > HOST_BITS_PER_DOUBLE_INT)
|
||||
return NULL_TREE;
|
||||
|
||||
result = double_int_zero;
|
||||
words = total_bytes / UNITS_PER_WORD;
|
||||
|
||||
for (byte = 0; byte < total_bytes; byte++)
|
||||
{
|
||||
int bitpos = byte * BITS_PER_UNIT;
|
||||
if (total_bytes > UNITS_PER_WORD)
|
||||
{
|
||||
word = byte / UNITS_PER_WORD;
|
||||
if (WORDS_BIG_ENDIAN)
|
||||
word = (words - 1) - word;
|
||||
offset = word * UNITS_PER_WORD;
|
||||
if (BYTES_BIG_ENDIAN)
|
||||
offset += (UNITS_PER_WORD - 1) - (byte % UNITS_PER_WORD);
|
||||
else
|
||||
offset += byte % UNITS_PER_WORD;
|
||||
}
|
||||
else
|
||||
offset = BYTES_BIG_ENDIAN ? (total_bytes - 1) - byte : byte;
|
||||
value = ptr[offset];
|
||||
|
||||
if (bitpos < HOST_BITS_PER_WIDE_INT)
|
||||
result.low |= (unsigned HOST_WIDE_INT) value << bitpos;
|
||||
else
|
||||
result.high |= (unsigned HOST_WIDE_INT) value
|
||||
<< (bitpos - HOST_BITS_PER_WIDE_INT);
|
||||
}
|
||||
result = double_int::from_buffer (ptr, total_bytes);
|
||||
|
||||
return double_int_to_tree (type, result);
|
||||
}
|
||||
|
||||
|
||||
/* Subroutine of native_interpret_expr. Interpret the contents of
|
||||
the buffer PTR of length LEN as a FIXED_CST of type TYPE.
|
||||
If the buffer cannot be interpreted, return NULL_TREE. */
|
||||
|
||||
static tree
|
||||
native_interpret_fixed (tree type, const unsigned char *ptr, int len)
|
||||
{
|
||||
int total_bytes = GET_MODE_SIZE (TYPE_MODE (type));
|
||||
double_int result;
|
||||
FIXED_VALUE_TYPE fixed_value;
|
||||
|
||||
if (total_bytes > len
|
||||
|| total_bytes * BITS_PER_UNIT > HOST_BITS_PER_DOUBLE_INT)
|
||||
return NULL_TREE;
|
||||
|
||||
result = double_int::from_buffer (ptr, total_bytes);
|
||||
fixed_value = fixed_from_double_int (result, TYPE_MODE (type));
|
||||
|
||||
return build_fixed (type, fixed_value);
|
||||
}
|
||||
|
||||
|
||||
/* Subroutine of native_interpret_expr. Interpret the contents of
|
||||
the buffer PTR of length LEN as a REAL_CST of type TYPE.
|
||||
If the buffer cannot be interpreted, return NULL_TREE. */
|
||||
|
@ -7533,6 +7559,9 @@ native_interpret_expr (tree type, const unsigned char *ptr, int len)
|
|||
case REAL_TYPE:
|
||||
return native_interpret_real (type, ptr, len);
|
||||
|
||||
case FIXED_POINT_TYPE:
|
||||
return native_interpret_fixed (type, ptr, len);
|
||||
|
||||
case COMPLEX_TYPE:
|
||||
return native_interpret_complex (type, ptr, len);
|
||||
|
||||
|
@ -7557,6 +7586,7 @@ can_native_interpret_type_p (tree type)
|
|||
case BOOLEAN_TYPE:
|
||||
case POINTER_TYPE:
|
||||
case REFERENCE_TYPE:
|
||||
case FIXED_POINT_TYPE:
|
||||
case REAL_TYPE:
|
||||
case COMPLEX_TYPE:
|
||||
case VECTOR_TYPE:
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
2013-01-30 Georg-Johann Lay <avr@gjlay.de>
|
||||
|
||||
PR tree-optimization/56064
|
||||
* gcc.dg/fixed-point/view-convert.c: New test.
|
||||
|
||||
2013-01-30 Andreas Schwab <schwab@suse.de>
|
||||
|
||||
* lib/target-supports-dg.exp (dg-process-target): Use expr to
|
||||
|
|
|
@ -0,0 +1,122 @@
|
|||
/* PR tree-optimization/56064 */
|
||||
/* { dg-do run } */
|
||||
/* { dg-options "-std=gnu99 -O2 -fno-builtin-memcpy" } */
|
||||
|
||||
extern void abort (void);
|
||||
extern void *memcpy (void*, const void*, __SIZE_TYPE__);
|
||||
|
||||
#define f_pun_i(F, I, VAL) \
|
||||
{ \
|
||||
I i1 = VAL; \
|
||||
I i2 = VAL; \
|
||||
F q1, q2; \
|
||||
memcpy (&q1, &i1, sizeof (I)); \
|
||||
__builtin_memcpy (&q2, &i2, sizeof (I)); \
|
||||
if (q1 != q2) \
|
||||
abort(); \
|
||||
}
|
||||
|
||||
#define i_pun_f(I, F, VAL) \
|
||||
{ \
|
||||
F q1 = VAL; \
|
||||
F q2 = VAL; \
|
||||
I i1, i2; \
|
||||
memcpy (&i1, &q1, sizeof (I)); \
|
||||
__builtin_memcpy (&i2, &q2, sizeof (I)); \
|
||||
if (i1 != i2) \
|
||||
abort(); \
|
||||
}
|
||||
|
||||
|
||||
void __attribute__((noinline))
|
||||
test8 (void)
|
||||
{
|
||||
#ifdef __INT8_TYPE__
|
||||
if (sizeof (__INT8_TYPE__) == sizeof (short _Fract))
|
||||
{
|
||||
#define TEST(X) f_pun_i (short _Fract, __INT8_TYPE__, __INT8_C (X))
|
||||
TEST (123);
|
||||
TEST (-123);
|
||||
#undef TEST
|
||||
|
||||
#define TEST(X) i_pun_f (__INT8_TYPE__, short _Fract, X ## hr)
|
||||
TEST (0.1234);
|
||||
TEST (-0.987);
|
||||
#undef TEST
|
||||
}
|
||||
#endif /* __INT8_TYPE__ */
|
||||
}
|
||||
|
||||
|
||||
void __attribute__((noinline))
|
||||
test16 (void)
|
||||
{
|
||||
#ifdef __INT16_TYPE__
|
||||
|
||||
if (sizeof (__INT16_TYPE__) == sizeof (_Fract))
|
||||
{
|
||||
#define TEST(X) f_pun_i (_Fract, __INT16_TYPE__, __INT16_C (X))
|
||||
TEST (0x4321);
|
||||
TEST (-0x4321);
|
||||
TEST (0x8000);
|
||||
#undef TEST
|
||||
|
||||
#define TEST(X) i_pun_f (__INT16_TYPE__, _Fract, X ## r)
|
||||
TEST (0.12345);
|
||||
TEST (-0.98765);
|
||||
#undef TEST
|
||||
}
|
||||
#endif /* __INT16_TYPE__ */
|
||||
}
|
||||
|
||||
|
||||
void __attribute__((noinline))
|
||||
test32 (void)
|
||||
{
|
||||
#ifdef __INT32_TYPE__
|
||||
if (sizeof (__INT32_TYPE__) == sizeof (_Accum))
|
||||
{
|
||||
#define TEST(X) f_pun_i (_Accum, __INT32_TYPE__, __INT32_C (X))
|
||||
TEST (0x76543219);
|
||||
TEST (-0x76543219);
|
||||
TEST (0x80000000);
|
||||
#undef TEST
|
||||
|
||||
#define TEST(X) i_pun_f (__INT32_TYPE__, _Accum, X ## k)
|
||||
TEST (123.456789);
|
||||
TEST (-123.456789);
|
||||
#undef TEST
|
||||
}
|
||||
#endif /* __INT32_TYPE__ */
|
||||
}
|
||||
|
||||
|
||||
void __attribute__((noinline))
|
||||
test64 (void)
|
||||
{
|
||||
#ifdef __INT64_TYPE__
|
||||
if (sizeof (__INT64_TYPE__) == sizeof (long _Accum))
|
||||
{
|
||||
#define TEST(X) f_pun_i (long _Accum, __INT64_TYPE__, __INT64_C (X))
|
||||
TEST (0x12345678abcdef01);
|
||||
TEST (-0x12345678abcdef01);
|
||||
TEST (0x8000000000000000);
|
||||
#undef TEST
|
||||
|
||||
#define TEST(X) i_pun_f (__INT64_TYPE__, long _Accum, X ## lk)
|
||||
TEST (123.456789);
|
||||
TEST (-123.456789);
|
||||
#undef TEST
|
||||
}
|
||||
#endif /* __INT64_TYPE__ */
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test8();
|
||||
test16();
|
||||
test32();
|
||||
test64();
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue