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]

purge_addressof bug


The following program is mis-compiled on x86 by c++ with -O3. 

Due to some difference I didn't care to ponder, it does not
fail compiled as c.  Not that it matters much, since the
problem exposed below is still a problem.

---------
typedef struct st { unsigned char a, b, c, d; } st;
void testme(int, int, int);

static void stupid_func(st s) { testme(s.a, s.b, s.c); }

main()
{
        st s;
        s.a = s.b = s.c = 216;
        stupid_func(s);
        return 0;
}    

void testme(int a, int b, int c)
{
  if (a != 216 && b != 216 && c != 216)
    abort();
}
---------

The root problem is that purge_addressof_1 turns

   (insn 43 16 45 (set (mem/s:QI (addressof:SI (reg:SI 23) 22) 0)
           (reg:QI 32)) 64 {movqi+1} (nil)
       (nil))

into 

   (insn 43 16 45 (set (subreg:QI (reg:SI 23) 0)
           (reg:QI 32)) 64 {movqi+1} (nil)
       (nil))

which is incorrect -- a strict_low_part is required.

The following patch changes things up to use proper bit insertion
and extraction routines.  As a bonus, we can now avoid dropping
the register to memory in this case on big-endian machines.


r~


	* function.c (purge_addressof_1): Use bitfield manipulation
	routines to handle mem mode < reg mode.

Index: function.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/function.c,v
retrieving revision 1.43
diff -c -p -d -r1.43 function.c
*** function.c	1998/09/30 10:09:59	1.43
--- function.c	1998/09/30 21:44:59
*************** static int *record_insns	PROTO((rtx));
*** 457,463 ****
  static int contains		PROTO((rtx, int *));
  #endif /* HAVE_prologue || HAVE_epilogue */
  static void put_addressof_into_stack PROTO((rtx));
! static void purge_addressof_1	PROTO((rtx *, rtx, int));
  
  /* Pointer to chain of `struct function' for containing functions.  */
  struct function *outer_function_chain;
--- 457,463 ----
  static int contains		PROTO((rtx, int *));
  #endif /* HAVE_prologue || HAVE_epilogue */
  static void put_addressof_into_stack PROTO((rtx));
! static void purge_addressof_1	PROTO((rtx *, rtx, int, int));
  
  /* Pointer to chain of `struct function' for containing functions.  */
  struct function *outer_function_chain;
*************** put_addressof_into_stack (r)
*** 2812,2821 ****
     the stack.  */
  
  static void
! purge_addressof_1 (loc, insn, force)
       rtx *loc;
       rtx insn;
!      int force;
  {
    rtx x;
    RTX_CODE code;
--- 2812,2821 ----
     the stack.  */
  
  static void
! purge_addressof_1 (loc, insn, force, store)
       rtx *loc;
       rtx insn;
!      int force, store;
  {
    rtx x;
    RTX_CODE code;
*************** purge_addressof_1 (loc, insn, force)
*** 2847,2853 ****
  			     0))
  	abort ();
  
!       insns = get_insns ();
        end_sequence ();
        emit_insns_before (insns, insn);
        return;
--- 2847,2853 ----
  			     0))
  	abort ();
  
!       insns = gen_sequence ();
        end_sequence ();
        emit_insns_before (insns, insn);
        return;
*************** purge_addressof_1 (loc, insn, force)
*** 2867,2877 ****
  	}
        else if (GET_CODE (sub) == REG && GET_MODE (x) != GET_MODE (sub))
  	{
! 	  if (! BYTES_BIG_ENDIAN && ! WORDS_BIG_ENDIAN)
  	    {
! 	      rtx sub2 = gen_rtx_SUBREG (GET_MODE (x), sub, 0);
! 	      if (validate_change (insn, loc, sub2, 0))
! 		goto restart;
  	    }
  	}
        else if (validate_change (insn, loc, sub, 0))
--- 2867,2939 ----
  	}
        else if (GET_CODE (sub) == REG && GET_MODE (x) != GET_MODE (sub))
  	{
! 	  int size_x, size_sub;
! 
! 	  size_x = GET_MODE_BITSIZE (GET_MODE (x));
! 	  size_sub = GET_MODE_BITSIZE (GET_MODE (sub));
! 
! 	  /* Don't even consider working with paradoxical subregs,
! 	     or the moral equivalent seen here.  */
! 	  if (size_x < size_sub)
  	    {
! 	      /* Do a bitfield insertion to mirror what would happen
! 		 in memory.  */
! 
! 	      int bitpos;
! 	      rtx val, seq;
! 
! 	      bitpos = 0;
! 	      if (WORDS_BIG_ENDIAN)
! 		{
! 		  bitpos += (size_sub / BITS_PER_WORD) * BITS_PER_WORD;
! 		  bitpos += (size_x / BITS_PER_WORD) * BITS_PER_WORD;
! 		}
! 	      if (BYTES_BIG_ENDIAN)
! 		{
! 		  bitpos += size_sub % BITS_PER_WORD;
! 		  bitpos -= size_x % BITS_PER_WORD;
! 		}
! 
! 	      if (store)
! 		{
! 		  /* If we can't replace with a register, be afraid.  */
! 
! 		  start_sequence ();
! 		  val = gen_reg_rtx (GET_MODE (x));
! 		  if (! validate_change (insn, loc, val, 0))
! 		    abort ();
! 		  seq = gen_sequence ();
! 		  end_sequence ();
! 		  emit_insn_before (seq, insn);
! 	      
! 		  start_sequence ();
! 		  store_bit_field (sub, size_x, bitpos, GET_MODE (x),
! 				   val, GET_MODE_SIZE (GET_MODE (sub)),
! 				   GET_MODE_SIZE (GET_MODE (sub)));
! 
! 		  seq = gen_sequence ();
! 		  end_sequence ();
! 		  emit_insn_after (seq, insn);
! 		}
! 	      else
! 		{
! 		  start_sequence ();
! 		  val = extract_bit_field (sub, size_x, bitpos, 1, NULL_RTX,
! 					   GET_MODE (x), GET_MODE (x),
! 					   GET_MODE_SIZE (GET_MODE (sub)),
! 					   GET_MODE_SIZE (GET_MODE (sub)));
! 
! 		  /* If we can't replace with a register, be afraid.  */
! 		  if (! validate_change (insn, loc, val, 0))
! 		    abort ();
! 
! 		  seq = gen_sequence ();
! 		  end_sequence ();
! 		  emit_insn_before (seq, insn);
! 		}
! 
! 	      /* We replaced with a reg -- all done.  */
! 	      return;
  	    }
  	}
        else if (validate_change (insn, loc, sub, 0))
*************** purge_addressof_1 (loc, insn, force)
*** 2883,2898 ****
        put_addressof_into_stack (x);
        return;
      }
  
    /* Scan all subexpressions. */
    fmt = GET_RTX_FORMAT (code);
    for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
      {
        if (*fmt == 'e')
! 	purge_addressof_1 (&XEXP (x, i), insn, force);
        else if (*fmt == 'E')
  	for (j = 0; j < XVECLEN (x, i); j++)
! 	  purge_addressof_1 (&XVECEXP (x, i, j), insn, force);
      }
  }
  
--- 2945,2966 ----
        put_addressof_into_stack (x);
        return;
      }
+   else if (code == SET)
+     {
+       purge_addressof_1 (&SET_DEST (x), insn, force, 1);
+       purge_addressof_1 (&SET_SRC (x), insn, force, 0);
+       return;
+     }
  
    /* Scan all subexpressions. */
    fmt = GET_RTX_FORMAT (code);
    for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
      {
        if (*fmt == 'e')
! 	purge_addressof_1 (&XEXP (x, i), insn, force, 0);
        else if (*fmt == 'E')
  	for (j = 0; j < XVECLEN (x, i); j++)
! 	  purge_addressof_1 (&XVECEXP (x, i, j), insn, force, 0);
      }
  }
  
*************** purge_addressof (insns)
*** 2910,2917 ****
  	|| GET_CODE (insn) == CALL_INSN)
        {
  	purge_addressof_1 (&PATTERN (insn), insn,
! 			   asm_noperands (PATTERN (insn)) > 0);
! 	purge_addressof_1 (&REG_NOTES (insn), NULL_RTX, 0);
        }
  }
  
--- 2978,2985 ----
  	|| GET_CODE (insn) == CALL_INSN)
        {
  	purge_addressof_1 (&PATTERN (insn), insn,
! 			   asm_noperands (PATTERN (insn)) > 0, 0);
! 	purge_addressof_1 (&REG_NOTES (insn), NULL_RTX, 0, 0);
        }
  }
  


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