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]
Other format: [Raw text]

Re: [PATCH] Rename/export combine_insn_cost as insn_rtx_cost


On Fri, 16 Jul 2004, Zack Weinberg wrote:
> Experimentally, GCC (CVS mainline as of this morning) targeted at
> ia64-elf is unable to generate conditional calls.  Attached to this
> message are the test case I used and the resulting .s file.  It may
> well be a problem in the ia64 backend.  Would you be willing to
> investigate this a little?

Ok, I've analyzed why GCC's if-conversion fails to convert your example
code into a conditional call instruction.

> extern void foo(void);
>
> void bar(int n) { if(n) foo(); }


The problem is two-fold.  The first is that the "then" block in this
function gets extened from just the single "call" instruction at
.26.postreload, to include the following additional instruction by
.28.flow2.

(insn 33 32 21 1 (set (reg:DI 1 r1)
        (reg:DI 34 r35)) 5 {*movdi_internal} (nil)
    (expr_list:REG_DEAD (reg:DI 34 r35)
        (nil)))

I'm guessing that this something to do with the IA-64's ABI, even
though the function doesn't return a value?


In theory, this is still manageable, if-conversion can make both
instructions conditional on the same condition, provided that the
condition isn't modified by the first instruction.  And there's
the rub...

ifcvt.c's cond_exec_process_insns calls modified_in_p to check
whether "(eq (reg:BI 262 p6 [340]) (const_int 0 [0x0]))" is
modified in

(call_insn 32 17 33 1 (parallel [
            (call (mem:DI (symbol_ref:DI ("foo") [flags 0x41]
<function_decl 0x20000000001bddc0 foo>) [0 S8 A64])
                (const_int 0 [0x0]))
            (clobber (reg:DI 320 b0))
        ]) 232 {call_nogp} (nil)
    (expr_list:REG_DEAD (reg:DI 1 r1)
        (expr_list:REG_UNUSED (reg:DI 320 b0)
            (expr_list:REG_EH_REGION (const_int 0 [0x0])
                (nil))))
    (expr_list (use (reg:DI 1 r1))
        (nil)))


which in turn calls reg_set_p to check whether "(reg:BI 262 p6 [340])"
is set in the above instruction, which contains the following code:

/* Internals of reg_set_between_p.  */
int
reg_set_p (rtx reg, rtx insn)
{
  /* We can be passed an insn or part of one.  If we are passed an insn,
     check if a side-effect of the insn clobbers REG.  */
  if (INSN_P (insn)
      && (FIND_REG_INC_NOTE (insn, reg)
          || (CALL_P (insn)
              /* We'd like to test call_used_regs here, but rtlanal.c can't
                 reference that variable due to its use in genattrtab.  So
                 we'll just be more conservative.

                 ??? Unless we could ensure that the CALL_INSN_FUNCTION_USAGE
                 information holds all clobbered registers.  */
              && ((REG_P (reg)
                   && REGNO (reg) < FIRST_PSEUDO_REGISTER)
                  || MEM_P (reg)
                  || find_reg_fusage (insn, CLOBBER, reg)))))
    return 1;

  return set_of (reg, insn) != NULL_RTX;
}


So rather than use call_used_regs to check whether "p6" is clobbered
by the function call, or can be used as an EPIC qualifying predicate,
we assume the worst.  I've no idea whether on IA-64 "p6" is call-saved
or not, but the combination of above events block the transformation.


Without knowing anything more about IA-64, isn't there some way of
untangling rtlanal.c from the gen*.c programs, such that rtx_set_p
can use call_used_regs.  Perhaps an IN_GENATTRTAB macro, or linking
a dummy call_used_regs to genattrtab.c that's initialized to true
for all hard registers??


Any comments of the IA-64 issues would also be appreciated.

Roger
--


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