This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
purge_addressof bug
- To: egcs-patches at cygnus dot com
- Subject: purge_addressof bug
- From: Richard Henderson <rth at cygnus dot com>
- Date: Wed, 30 Sep 1998 14:59:45 -0700
- Reply-To: Richard Henderson <rth at cygnus dot com>
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 (®_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 (®_NOTES (insn), NULL_RTX, 0, 0);
}
}