This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[Committed] 4.1: pr14261 ifcvt and store_bit_field patches
- From: Andreas Krebbel <krebbel1 at de dot ibm dot com>
- To: Roger Sayle <roger at eyesopen dot com>
- Cc: gcc-patches at gcc dot gnu dot org
- Date: Mon, 15 May 2006 15:45:07 +0200
- Subject: [Committed] 4.1: pr14261 ifcvt and store_bit_field patches
- References: <20060419115758.GA3942@de.ibm.com> <Pine.LNX.4.44.0604230750570.13062-100000@www.eyesopen.com>
Hello Roger,
I've committed both patches after retesting. The patches
fix the related testcases and pass bootstrap and regtesting
on i686, s390 and s390x.
http://gcc.gnu.org/ml/gcc-patches/2006-04/msg00697.html
http://gcc.gnu.org/ml/gcc-patches/2006-04/msg00951.html
For the list: I've got an offlist approval for committing
this to gcc 4.1 from Roger.
Bye,
-Andreas-
2006-05-15 Andreas Krebbel <krebbel1@de.ibm.com>
PR rtl-optimization/14261
* ifcvt.c (noce_emit_move_insn): Call store_bit_field if the resulting
move would be an INSV insn.
(noce_process_if_block): Don't optimize if the destination is a
ZERO_EXTRACT which can't be handled by noce_emit_move_insn.
2006-05-15 Andreas Krebbel <krebbel1@de.ibm.com>
* expmed.c (store_bit_field): Handle paradoxical subregs on big endian
machines.
2006-05-15 Andreas Krebbel <krebbel1@de.ibm.com>
* gcc.dg/20060515-1.c: New testcase.
2006-05-15 Andreas Krebbel <krebbel1@de.ibm.com>
PR rtl-optimization/14261
* gcc.c-torture/compile/20060515-1.c: Likewise.
Index: gcc/ifcvt.c
===================================================================
*** gcc/ifcvt.c.orig 2006-04-07 12:34:23.000000000 +0200
--- gcc/ifcvt.c 2006-04-18 13:44:49.000000000 +0200
*************** noce_emit_move_insn (rtx x, rtx y)
*** 702,748 ****
end_sequence();
if (recog_memoized (insn) <= 0)
! switch (GET_RTX_CLASS (GET_CODE (y)))
! {
! case RTX_UNARY:
! ot = code_to_optab[GET_CODE (y)];
! if (ot)
! {
! start_sequence ();
! target = expand_unop (GET_MODE (y), ot, XEXP (y, 0), x, 0);
! if (target != NULL_RTX)
! {
! if (target != x)
! emit_move_insn (x, target);
! seq = get_insns ();
! }
! end_sequence ();
! }
! break;
!
! case RTX_BIN_ARITH:
! case RTX_COMM_ARITH:
! ot = code_to_optab[GET_CODE (y)];
! if (ot)
! {
! start_sequence ();
! target = expand_binop (GET_MODE (y), ot,
! XEXP (y, 0), XEXP (y, 1),
! x, 0, OPTAB_DIRECT);
! if (target != NULL_RTX)
! {
! if (target != x)
! emit_move_insn (x, target);
! seq = get_insns ();
! }
! end_sequence ();
! }
! break;
! default:
! break;
! }
emit_insn (seq);
return;
}
--- 702,777 ----
end_sequence();
if (recog_memoized (insn) <= 0)
! {
! if (GET_CODE (x) == ZERO_EXTRACT)
! {
! rtx op = XEXP (x, 0);
! unsigned HOST_WIDE_INT size = INTVAL (XEXP (x, 1));
! unsigned HOST_WIDE_INT start = INTVAL (XEXP (x, 2));
!
! /* store_bit_field expects START to be relative to
! BYTES_BIG_ENDIAN and adjusts this value for machines with
! BITS_BIG_ENDIAN != BYTES_BIG_ENDIAN. In order to be able to
! invoke store_bit_field again it is necessary to have the START
! value from the first call. */
! if (BITS_BIG_ENDIAN != BYTES_BIG_ENDIAN)
! {
! if (MEM_P (op))
! start = BITS_PER_UNIT - start - size;
! else
! {
! gcc_assert (REG_P (op));
! start = BITS_PER_WORD - start - size;
! }
! }
! gcc_assert (start < (MEM_P (op) ? BITS_PER_UNIT : BITS_PER_WORD));
! store_bit_field (op, size, start, GET_MODE (x), y);
! return;
! }
+ switch (GET_RTX_CLASS (GET_CODE (y)))
+ {
+ case RTX_UNARY:
+ ot = code_to_optab[GET_CODE (y)];
+ if (ot)
+ {
+ start_sequence ();
+ target = expand_unop (GET_MODE (y), ot, XEXP (y, 0), x, 0);
+ if (target != NULL_RTX)
+ {
+ if (target != x)
+ emit_move_insn (x, target);
+ seq = get_insns ();
+ }
+ end_sequence ();
+ }
+ break;
+
+ case RTX_BIN_ARITH:
+ case RTX_COMM_ARITH:
+ ot = code_to_optab[GET_CODE (y)];
+ if (ot)
+ {
+ start_sequence ();
+ target = expand_binop (GET_MODE (y), ot,
+ XEXP (y, 0), XEXP (y, 1),
+ x, 0, OPTAB_DIRECT);
+ if (target != NULL_RTX)
+ {
+ if (target != x)
+ emit_move_insn (x, target);
+ seq = get_insns ();
+ }
+ end_sequence ();
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
emit_insn (seq);
return;
}
*************** noce_process_if_block (struct ce_if_bloc
*** 2231,2236 ****
--- 2260,2271 ----
{
if (no_new_pseudos || GET_MODE (x) == BLKmode)
return FALSE;
+
+ if (GET_MODE (x) == ZERO_EXTRACT
+ && (GET_CODE (XEXP (x, 1)) != CONST_INT
+ || GET_CODE (XEXP (x, 2)) != CONST_INT))
+ return FALSE;
+
x = gen_reg_rtx (GET_MODE (GET_CODE (x) == STRICT_LOW_PART
? XEXP (x, 0) : x));
}
Index: gcc/testsuite/gcc.c-torture/compile/20060515-1.c
===================================================================
*** /dev/null 1970-01-01 00:00:00.000000000 +0000
--- gcc/testsuite/gcc.c-torture/compile/20060515-1.c 2006-04-18 13:33:10.000000000 +0200
***************
*** 0 ****
--- 1,21 ----
+ /* This failed because if conversion didn't handle insv patterns properly. */
+
+ union y
+ {
+ int a;
+ unsigned short b;
+ };
+
+ extern void bar (unsigned short u, union y v);
+
+ void
+ foo (int check)
+ {
+ union y x;
+
+ if (check != 0)
+ x.b = 1;
+ else
+ x.b = 2;
+ bar (x.b, x);
+ }
Index: gcc/expmed.c
===================================================================
*** gcc/expmed.c.orig 2006-05-15 10:33:32.000000000 +0200
--- gcc/expmed.c 2006-05-15 12:57:43.000000000 +0200
*************** store_bit_field (rtx str_rtx, unsigned H
*** 353,359 ****
meaningful at a much higher level; when structures are copied
between memory and regs, the higher-numbered regs
always get higher addresses. */
! bitnum += SUBREG_BYTE (op0) * BITS_PER_UNIT;
op0 = SUBREG_REG (op0);
}
--- 353,377 ----
meaningful at a much higher level; when structures are copied
between memory and regs, the higher-numbered regs
always get higher addresses. */
! int inner_mode_size = GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0)));
! int outer_mode_size = GET_MODE_SIZE (GET_MODE (op0));
!
! byte_offset = 0;
!
! /* Paradoxical subregs need special handling on big endian machines. */
! if (SUBREG_BYTE (op0) == 0 && inner_mode_size < outer_mode_size)
! {
! int difference = inner_mode_size - outer_mode_size;
!
! if (WORDS_BIG_ENDIAN)
! byte_offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
! if (BYTES_BIG_ENDIAN)
! byte_offset += difference % UNITS_PER_WORD;
! }
! else
! byte_offset = SUBREG_BYTE (op0);
!
! bitnum += byte_offset * BITS_PER_UNIT;
op0 = SUBREG_REG (op0);
}
Index: gcc/testsuite/gcc.dg/20060515-1.c
===================================================================
*** /dev/null 1970-01-01 00:00:00.000000000 +0000
--- gcc/testsuite/gcc.dg/20060515-1.c 2006-05-15 12:57:43.000000000 +0200
***************
*** 0 ****
--- 1,38 ----
+ /* { dg-do run } */
+ /* { dg-options "-O1" } */
+
+ /* This failed because if conversion didn't handle insv patterns properly. */
+
+ void abort (void);
+
+ union y
+ {
+ int a;
+ unsigned short b;
+ };
+
+ void __attribute__ ((noinline))
+ bar (unsigned short u, union y v)
+ {
+ if (u != 1)
+ abort ();
+ }
+
+ void __attribute__ ((noinline))
+ foo (int check)
+ {
+ union y x;
+
+ if (check != 0)
+ x.b = 1;
+ else
+ x.b = 2;
+ bar (x.b, x);
+ }
+
+ int
+ main ()
+ {
+ foo (1);
+ return 0;
+ }