Commit cc06c01d by Georg-Johann Lay Committed by Georg-Johann Lay

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
parent d394a308
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> 2013-01-30 Richard Biener <rguenther@suse.de>
* tree-ssa-structalias.c (final_solutions, final_solutions_obstack): * tree-ssa-structalias.c (final_solutions, final_solutions_obstack):
......
...@@ -641,6 +641,54 @@ div_and_round_double (unsigned code, int uns, ...@@ -641,6 +641,54 @@ div_and_round_double (unsigned code, int uns,
return overflow; 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. */ /* Returns mask for PREC bits. */
double_int double_int
......
...@@ -59,6 +59,10 @@ struct double_int ...@@ -59,6 +59,10 @@ struct double_int
static double_int from_shwi (HOST_WIDE_INT cst); static double_int from_shwi (HOST_WIDE_INT cst);
static double_int from_pair (HOST_WIDE_INT high, unsigned HOST_WIDE_INT low); 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. */ /* No copy assignment operator or destructor to keep the type a POD. */
/* There are some special value-creation static member functions. */ /* 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) ...@@ -81,6 +81,24 @@ check_real_for_fixed_mode (REAL_VALUE_TYPE *real_value, enum machine_mode mode)
return FIXED_OK; 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. */ /* Initialize from a decimal or hexadecimal string. */
void void
......
...@@ -49,6 +49,22 @@ extern FIXED_VALUE_TYPE fconst1[MAX_FCONST1]; ...@@ -49,6 +49,22 @@ extern FIXED_VALUE_TYPE fconst1[MAX_FCONST1];
const_fixed_from_fixed_value (r, m) const_fixed_from_fixed_value (r, m)
extern rtx const_fixed_from_fixed_value (FIXED_VALUE_TYPE, enum machine_mode); 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. */ /* Initialize from a decimal or hexadecimal string. */
extern void fixed_from_string (FIXED_VALUE_TYPE *, const char *, extern void fixed_from_string (FIXED_VALUE_TYPE *, const char *,
enum machine_mode); enum machine_mode);
......
...@@ -7200,6 +7200,36 @@ native_encode_int (const_tree expr, unsigned char *ptr, int len) ...@@ -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 /* Subroutine of native_encode_expr. Encode the REAL_CST
specified by EXPR into the buffer PTR of length LEN bytes. specified by EXPR into the buffer PTR of length LEN bytes.
Return the number of bytes placed in the buffer, or zero 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) ...@@ -7345,6 +7375,9 @@ native_encode_expr (const_tree expr, unsigned char *ptr, int len)
case REAL_CST: case REAL_CST:
return native_encode_real (expr, ptr, len); return native_encode_real (expr, ptr, len);
case FIXED_CST:
return native_encode_fixed (expr, ptr, len);
case COMPLEX_CST: case COMPLEX_CST:
return native_encode_complex (expr, ptr, len); return native_encode_complex (expr, ptr, len);
...@@ -7368,44 +7401,37 @@ static tree ...@@ -7368,44 +7401,37 @@ static tree
native_interpret_int (tree type, const unsigned char *ptr, int len) native_interpret_int (tree type, const unsigned char *ptr, int len)
{ {
int total_bytes = GET_MODE_SIZE (TYPE_MODE (type)); int total_bytes = GET_MODE_SIZE (TYPE_MODE (type));
int byte, offset, word, words;
unsigned char value;
double_int result; double_int result;
if (total_bytes > len) if (total_bytes > len
return NULL_TREE; || total_bytes * BITS_PER_UNIT > HOST_BITS_PER_DOUBLE_INT)
if (total_bytes * BITS_PER_UNIT > HOST_BITS_PER_DOUBLE_INT)
return NULL_TREE; return NULL_TREE;
result = double_int_zero; result = double_int::from_buffer (ptr, total_bytes);
words = total_bytes / UNITS_PER_WORD;
for (byte = 0; byte < total_bytes; byte++) return double_int_to_tree (type, result);
{ }
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);
}
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);
} }
...@@ -7533,6 +7559,9 @@ native_interpret_expr (tree type, const unsigned char *ptr, int len) ...@@ -7533,6 +7559,9 @@ native_interpret_expr (tree type, const unsigned char *ptr, int len)
case REAL_TYPE: case REAL_TYPE:
return native_interpret_real (type, ptr, len); return native_interpret_real (type, ptr, len);
case FIXED_POINT_TYPE:
return native_interpret_fixed (type, ptr, len);
case COMPLEX_TYPE: case COMPLEX_TYPE:
return native_interpret_complex (type, ptr, len); return native_interpret_complex (type, ptr, len);
...@@ -7557,6 +7586,7 @@ can_native_interpret_type_p (tree type) ...@@ -7557,6 +7586,7 @@ can_native_interpret_type_p (tree type)
case BOOLEAN_TYPE: case BOOLEAN_TYPE:
case POINTER_TYPE: case POINTER_TYPE:
case REFERENCE_TYPE: case REFERENCE_TYPE:
case FIXED_POINT_TYPE:
case REAL_TYPE: case REAL_TYPE:
case COMPLEX_TYPE: case COMPLEX_TYPE:
case VECTOR_TYPE: case VECTOR_TYPE:
......
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> 2013-01-30 Andreas Schwab <schwab@suse.de>
* lib/target-supports-dg.exp (dg-process-target): Use expr to * lib/target-supports-dg.exp (dg-process-target): Use expr to
......
/* 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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment