On Fri, May 22, 2009 at 05:04:22PM -0700, Jamie Prescott wrote:
> 
> > From: Jamie Prescott <jpre...@yahoo.com>
> > To: gcc@gcc.gnu.org
> > Sent: Friday, May 22, 2009 10:36:47 AM
> > Subject: Seeking suggestion
> > 
> > 
> > Suppose you're writing the backend for a VM supporting two architectures, 
> > in 
> > which
> > one of them clobbers the CC registers for certain instructions, while the 
> > other 
> > does not.
> > The instructions themselves are exactly the same.
> > What is the best/shortest/more-elegant way to write this, possibly w/out 
> > duplicating the
> > instructions?
> > I know I can write a define_expand and redirect, based on the TARGET, to 
> > two 
> > different
> > instructions (one with "clobber", the other w/out), but that's basically 
> > three 
> > declarations
> > for each insns. Is there a shorter way?
> 
> I ended up doing something like this (long way, but the only one I know of).
> Example, for addsi3:
> 
> (define_insn "addsi3_xxx2"
>   [(set (match_operand:SI 0 "fullreg_operand" "=r,r")
>         (plus:SI (match_operand:SI 1 "fullreg_operand" "0,r")
>                  (match_operand:SI 2 "fullreg_or_imm_operand" "rn,rn")))]
>   ""
>   "@
>    add\t%0,%2,%0
>    add\t%1,%2,%0"
> )
> 
> (define_insn "addsi3_xxx"
>   [(set (match_operand:SI 0 "fullreg_operand" "=r,r")
>         (plus:SI (match_operand:SI 1 "fullreg_operand" "0,r")
>                  (match_operand:SI 2 "fullreg_or_imm_operand" "rn,rn")))
>    (clobber (reg:CC CC_REG))]
>   ""
>   "@
>    add\t%0,%2,%0
>    add\t%1,%2,%0"
> )
> 
> (define_expand "addsi3"
>   [(set (match_operand:SI 0 "fullreg_operand" "=r,r")
>         (plus:SI (match_operand:SI 1 "fullreg_operand" "0,r")
>                  (match_operand:SI 2 "fullreg_or_imm_operand" "rn,rn")))]
>   ""
>   {
>     if (!TARGET_XXX2)
>       emit_insn(gen_addsi3_xxx(operands[0], operands[1], operands[2]));
>     else
>       emit_insn(gen_addsi3_xxx2(operands[0], operands[1], operands[2]));
>     DONE;
>   }
> )

One way is to use match_scratch, and different register classes for the two
cases.

(define_insn "add<mode>3"
  [(set (match_operand:SI 0 "register_operand" "=x,y")
        (plus:SI (match_operand:SI 1 "register_operand" "%x,y")
                 (match_operand:SI 2 "register_operand" "x,y")))
   (clobber (match_scratch:CC 3 "=X,z"))]
  ""
  "add %0,%1,%2")


(define_register_constraint "x" "TARGET_MACHINE ? GENERAL_REGS : NO_REGS"
  "@internal")

(define_register_constraint "y" "!TARGET_MACHINE ? GENERAL_REGS : NO_REGS"
  "@internal")

(define_register_constraint "z" CR_REGS "@interal")

This assumes you have a register class for the condition code register.  Most
machines however, use the normal define_expand with two different insns.

In theory, you could define a second condition code register that doesn't
actually exist in the machine, and change the clobber from the main CC to the
fake one.

 
> But now I get and invalid rtx sharing from the push/pop parallels:
> 
> 
> xxxx.c: In function 'test_dashr':
> xxxx.c:32: error: invalid rtl sharing found in the insn
> (insn 26 3 28 2 xxxx.c:26 (parallel [
>             (insn/f 25 0 0 (set (reg/f:SI 51 SP)
>                     (minus:SI (reg/f:SI 51 SP)
>                         (const_int 4 [0x4]))) -1 (nil))
>             (set/f (mem:SI (reg/f:SI 51 SP) [0 S4 A8])
>                 (reg:SI 8 r8))
>         ]) -1 (nil))
> xxxx.c:32: error: shared rtx
> (insn/f 25 0 0 (set (reg/f:SI 51 SP)
>         (minus:SI (reg/f:SI 51 SP)
>             (const_int 4 [0x4]))) -1 (nil))
> xxxx.c:32: internal compiler error: internal consistency failure

I suspect you don't have the proper guards on the push/pop insns, and the
combiner is eliminating the clobber.  You probably need to have parallel insns
for the push and pop.

-- 
Michael Meissner, IBM
4 Technology Place Drive, MS 2203A, Westford, MA, 01886, USA
meiss...@linux.vnet.ibm.com

Reply via email to