This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[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;
  }
}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]