This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
Use-and-clobber insns and some ancient combine.c code
- From: Ulrich Weigand <weigand at i1 dot informatik dot uni-erlangen dot de>
- To: kenner at vlsi1 dot ultra dot nyu dot edu, richard dot earnshaw at arm dot com
- Cc: gcc at gcc dot gnu dot org
- Date: Thu, 17 Jun 2004 15:16:38 +0200 (CEST)
- Subject: Use-and-clobber insns and some ancient combine.c code
Hello Richard and Richard,
when evaluating the use of ADD LOGICAL WITH CARRY instructions on s390
(see also the patch I checked in today), I've noticed two places in
combine that prevent those instructions to be exploited fully.
Both of these are due to code you added to combine a long time ago;
I was wondering if you still recall why these changes were necessary
-- I don't really understand it in the context of the current code.
In both cases, the issues arise from instructions that both use and
clobber a hard register within a single PARALLEL. This happens
naturally with an 'add with carry' type instruction: it uses the
condition code (which is a hard reg on s390), and at the same time
clobbers it. There doesn't appear to be anything wrong with such
types of insns as far as I can see; however, those two places prevent
combine from generating such insns in several cases.
The first place is in can_combine_p. This check:
/* Don't substitute for a register intended as a clobberable operand.
Similarly, don't substitute an expression containing a register that
will be clobbered in I3. */
if (GET_CODE (PATTERN (i3)) == PARALLEL)
for (i = XVECLEN (PATTERN (i3), 0) - 1; i >= 0; i--)
if (GET_CODE (XVECEXP (PATTERN (i3), 0, i)) == CLOBBER
&& (reg_overlap_mentioned_p (XEXP (XVECEXP (PATTERN (i3), 0, i), 0),
src)
|| rtx_equal_p (XEXP (XVECEXP (PATTERN (i3), 0, i), 0), dest)))
return 0;
simply refuses to combine any expression containing the CC hard reg
into a insn that clobbers CC. I would like this to happen to allow
combining a sCOND-type instruction with a regular add into an add-
with-carry instruction.
I guess I can see why we wouldn't want to substitute into the operand
of a CLOBBER itself. But why prevent substitution of an expression
containing a register that will be clobbered? This second clause was
added under this ChangeLog entry:
Wed Oct 28 05:34:11 1992 Richard Kenner (kenner at vlsi1.ultra.nyu.edu)
* reload1.c (gen_input_reload): In PLUS, if OP0 and OP1 are the
same, use RELOADREG when generating the addition.
* reload.c (find_reloads_address): When copying memref after we've
made recursive calls on it, copy any replacements we made.
* combine.c (can_combine_p): Don't substitute an expression
containing a register that will be clobbered in I3.
* objc/core.c, objc/hash.c: Include tconfig.h, not config.h.
Include gstdarg.h.
* objc/object.m: Include tconfig.h, not config.h.
Include gstdarg.h before stdio.h.
* objc/objc.h: Don't include gstdarg.h here.
* objc/objc-proto.h (CLASS_LOCATION_SHIFT): Use HOST_BITS_PER_LONG,
not BITS_PER_WORD.
(setClassNumber, getClassNumber): `info' field is long, not int.
The second place is reg_dead_at_p. This is used when adding hard-reg
clobbers in recog_for_combine to ensure no clobber is added for a reg
that is actually live at this point. However, this routine always
considers all registers showing up as input in NEWPAT as live:
Hard regs marked as being live in NEWPAT_USED_REGS
must be assumed to be always live.
Now, I'd like to see a SImode sCOND type insn followed by an extension
to DImode be combined into a single DImode sCOND. However, as the
extend insn doesn't clobber CC, that clobber would need to be added --
but since the new pattern uses CC as input, reg_dead_at_p refuses to
make this substitution. (As my sCOND insns are in fact implemented
as add-with-carry, they implicitly clobber CC.)
Again, I do not understand why this is being prevented (shouldn't
it be enough to mark all *output* registers from newpat as live?).
The code was added under this ChangeLog entry:
Sat Mar 19 17:13:47 1994 Richard Earnshaw (rwe11@cl.cam.ac.uk)
* combine.c (newpat_used_regs): New variable.
(mark_used_regs_combine): New function.
(try_combine): Use them.
(reg_dead_at_p): Registers marked in newpat_used_regs must always be
considered to be live.
I've simply reverted those two changes in my current tree, and this
bootstrapped and tested without regressions on s390-ibm-linux and
s390x-ibm-linux; the resulting compiler does perform the optimizations
I'm expecting. However, I'm not sure about simply removing code the
purpose of which I don't understand. I'm aware that this code is
over a decade old, but if you still remember anything about its
history, I'd be glad for any hints ...
Bye,
Ulrich
--
Dr. Ulrich Weigand
weigand@informatik.uni-erlangen.de