This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Fix PR optimization/14235
- From: Eric Botcazou <ebotcazou at libertysurf dot fr>
- To: gcc-patches at gcc dot gnu dot org
- Date: Wed, 3 Mar 2004 11:07:59 +0100
- Subject: [PATCH] Fix PR optimization/14235
Hi,
This is an ICE in verify_local_live_at start at -O3, a regression present on
mainline and 3.4 branch.
The call to update_life_info comes from regrename which, by renaming one
register, causes the liveness of another one to be propagated up in the insn
chains. However, I think the real problem comes for the middle-end and
pertain to this chunk of code:
typedef signed char int8_t;
typedef unsigned long long uint64_t;
uint64_t tempA = 0;
tempA = (int8_t)tempA;
The .01.rtl file contains this:
(insn 21 19 23 (set (reg/v:DI 70 [ tempA ])
(const_int 0 [0x0])) -1 (nil)
(nil))
(insn 46 45 47 (clobber (reg/v:DI 70 [ tempA ])) -1 (nil)
(nil))
(insn 47 46 48 (set (subreg:SI (reg/v:DI 70 [ tempA ]) 0)
(sign_extend:SI (subreg:QI (reg/v:DI 70 [ tempA ]) 0))) -1 (nil)
(nil))
(insn 48 47 49 (parallel [
(set (reg/v:DI 70 [ tempA ])
(sign_extend:DI (subreg:SI (reg/v:DI 70 [ tempA ]) 0)))
(clobber (reg:CC 17 flags))
(clobber (scratch:SI))
]) -1 (nil)
(nil))
that is, the CLOBBER hides the initial SET.
The CLOBBER is issued by convert_move:
/* Next, try converting via full word. */
else if (GET_MODE_BITSIZE (from_mode) < BITS_PER_WORD
&& ((code = can_extend_p (to_mode, word_mode, unsignedp))
!= CODE_FOR_nothing))
{
if (GET_CODE (to) == REG)
emit_insn (gen_rtx_CLOBBER (VOIDmode, to));
convert_move (gen_lowpart (word_mode, to), from, unsignedp);
emit_unop_insn (code, to,
gen_lowpart (word_mode, to), equiv_code);
return;
}
I'm not really sure what is the best place to fix this. After various
attempts, I settled for the expander of NOP_EXPR.
2004-03-03 Eric Botcazou <ebotcazou@libertysurf.fr>
PR optimization/14235
* expr.c (expand_expr_real) <NOP_EXPR>: Return a new
pseudo when converting from a sub-word source to a
larger-than-word register which conflicts with the source.
2004-03-03 Eric Botcazou <ebotcazou@libertysurf.fr>
* gcc.c-torture/compile/20040303-1.c: New test.
--
Eric Botcazou
Index: expr.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/expr.c,v
retrieving revision 1.615.4.5
diff -u -p -r1.615.4.5 expr.c
--- expr.c 27 Feb 2004 08:14:59 -0000 1.615.4.5
+++ expr.c 2 Mar 2004 08:26:21 -0000
@@ -7555,9 +7560,18 @@ expand_expr_real (tree exp, rtx target,
return
convert_to_mode (mode, op0,
TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))));
- else
- convert_move (target, op0,
- TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))));
+
+ /* Check if convert_move may do the conversion by using a low-part,
+ after clobbering the whole target which is known to conflict with
+ the source. In this case, play safe and make a new pseudo. */
+ if (GET_CODE (target) == REG
+ && GET_MODE_BITSIZE (GET_MODE (op0)) < BITS_PER_WORD
+ && GET_MODE_BITSIZE (mode) > BITS_PER_WORD
+ && ! safe_from_p (target, TREE_OPERAND (exp, 0), 1))
+ target = gen_reg_rtx (mode);
+
+ convert_move (target, op0,
+ TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))));
return target;
case VIEW_CONVERT_EXPR:
/* PR optimization/14235 */
/* Origin: <senor_fjord@yahoo.com> */
typedef signed char int8_t;
typedef short int16_t;
typedef int int32_t;
typedef unsigned long long uint64_t;
static const uint64_t LOW_BYTE_MASK = 0x00000000000000ffULL;
static const uint64_t HIGH_BYTE_MASK = 0x000000000000ff00ULL;
static const uint64_t WORD_MASK = 0x000000000000ffffULL;
static const uint64_t DWORD_MASK = 0x00000000ffffffffULL;
extern uint64_t *srca_mask;
extern int *assert_thrown;
void foo()
{
uint64_t tempA = 0; /* actually a bunch of code to set A */
uint64_t tempB = 0; /* actually a bunch of code to set B */
/* cast A to right size */
tempA = (((*srca_mask == LOW_BYTE_MASK) ||
(*srca_mask == HIGH_BYTE_MASK)) ?
((int8_t)tempA) :
((*srca_mask == WORD_MASK) ?
((int16_t)tempA) :
((*srca_mask == DWORD_MASK) ?
((int32_t)tempA) :
tempA)));
/* cast B to right size */
tempB = (((*srca_mask == LOW_BYTE_MASK) ||
(*srca_mask == HIGH_BYTE_MASK)) ?
((int8_t)tempB) :
((*srca_mask == WORD_MASK) ?
((int16_t)tempB) :
((*srca_mask == DWORD_MASK) ?
((int32_t)tempB) :
tempB)));
if ((int) tempA > (int) tempB) {
*assert_thrown = 1;
}
}