This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
buglet in force_to_mode in combine.c
- To: egcs at cygnus dot com
- Subject: buglet in force_to_mode in combine.c
- From: chris at lslsun dot epfl dot ch (Christian Iseli)
- Date: Tue, 25 Nov 1997 14:02:12 +0100
Hi folks,
I have finally tracked down a problem I had with the combiner. The symptom was
the following: Given three insn
i1 = (set (reg:QI A) (and:QI (reg:QI B) 3))
i2 = (set (reg:QI C) (plus:QI (reg:QI A) 8))
i3 = (set (reg:HI D) (sign_extend:HI (reg:QI C)))
try_combine succeeded and returned (set (reg:HI D) 8), which is obviously wrong.
The executive summary is that force_to_mode can be called with operands of the form
force_to_mode((clobber:QI 0), HImode, 0xcc00, ...)
which leads it to return const0_rtx. The clobber is the result of some previous
function which returned clobber to indicate that some operation could not be done.
The patch below fixes that problem.
A more detailed investigation of the bug follows.
Tue Nov 25 13:57:59 1997 Christian Iseli <Christian.Iseli@lslsun.epfl.ch>
* combine.c (force_to_mode): return immediately if operand is a CLOBBER.
*** combine.c~ Mon Nov 24 14:08:42 1997
--- combine.c Tue Nov 25 09:47:42 1997
*************** force_to_mode (x, mode, mask, reg, just_
*** 6042,6048 ****
/* If this is a CALL or ASM_OPERANDS, don't do anything. Some of the
code below will do the wrong thing since the mode of such an
expression is VOIDmode. */
! if (code == CALL || code == ASM_OPERANDS)
return x;
/* We want to perform the operation is its present mode unless we know
--- 6042,6048 ----
/* If this is a CALL or ASM_OPERANDS, don't do anything. Some of the
code below will do the wrong thing since the mode of such an
expression is VOIDmode. */
! if (code == CALL || code == ASM_OPERANDS || code == CLOBBER)
return x;
/* We want to perform the operation is its present mode unless we know
Detailed blurb...
By tracing execution, I found out that things went as follow.
- First, simplify determines that the plus can be replaced by an ior, since
the bits of its operands do not overlap.
- Next, a distributive law is applied and IOR and AND are exchanged,
producing a compound operation of the form:
(sign_extend:HI (and:QI (ior:QI (reg:QI B) 8) 11))
- Now, expand_compound operation tries to replace the sign_extend by two
shifts, one left and one right, by 8 positions, by calling simplify_shift_const
with a result mode of HImode.
- The AND is kept as outer_op, with the outer const being 2816 (11 << 8). The
remaining part (ior:QI (reg:QI B) 8) is split in two, and each part is fed
to simplify_shift_const again.
simplify_shift_const(0, ASHIFT, HImode, (reg:QI B), 8) ends up calling
gen_lowpart_for_combine(HImode, (reg:QI B)) since the reg is not in the right mode.
Now, since UNITS_PER_WORD is 1 for my target (an 8-bit machine),
gen_lowpart_for_combine returns (clobber:QI 0)
8 becomes 2048, so the result of combining the two splitted operands of the
IOR is (ior:HI (clobber:QI 0) 2048)
- Since the outer_op was set to AND,
simplify_and_const_int(0, Himode, (ior:HI (clobber:QI 0) 2048), 2816) is now
called. simplify_and_const_int will in turn call itself on each operand of
the IOR, thus it will call simplify_and_const_int(0, Himode, (clobber:QI 0), 2816).
The first thing done in simplify_and_const_int is to call force_to_mode, leading
to this bug report...
Note that another way to fix this bug would be to make the test for CLOBBER before calling
force_to_mode in simplify_and_const_int. But then, force_to_mode could still produce
incorrect results in some other cases...
Christian