TableGen list merging

Hi,

In the PPC backend, there is a "helper" class used to define instructions that implicitly define a condition register:

class isDOT {
  list<Register> Defs = [CR0];
  bit RC = 1;
}

and this gets used on instructions such as:

def ADDICo : DForm_2<13, (outs GPRC:$rD), (ins GPRC:$rA, s16imm:$imm),
                     "addic. $rD, $rA, $imm", IntGeneral,
                     []>, isDOT;

but there is a small problem. If these instructions are also part of a larger block which also defines registers, like this:

let Defs = [CARRY] in
def ADDICo : DForm_2<13, (outs GPRC:$rD), (ins GPRC:$rA, s16imm:$imm),
                     "addic. $rD, $rA, $imm", IntGeneral,
                     []>, isDOT;

then the fact that isDOT puts CR0 into Defs is lost (only CARRY ends up in the list of implicitly-defined registers). How can I modify things to make them work correctly?

Thanks again,
Hal

let Defs = [CARRY, CR0] in…

I think it can already be tricky to figure out where TableGen instruction definitions get all their properties. If we add syntax that allows them to come from multiple places at once, it becomes even harder to figure out.

For readability, just combine them explicitly.

You may also want to look at ARM's use of optional defs for instructions that can optionally set the flags.

/jakob

From: "Jakob Stoklund Olesen" <stoklund@2pi.dk>
To: "Hal Finkel" <hfinkel@anl.gov>
Cc: "LLVM Developers Mailing List" <llvmdev@cs.uiuc.edu>
Sent: Friday, April 12, 2013 11:36:49 AM
Subject: Re: [LLVMdev] TableGen list merging

> In the PPC backend, there is a "helper" class used to define
> instructions that implicitly define a condition register:
>
> class isDOT {
> list<Register> Defs = [CR0];
> bit RC = 1;
> }
>
> and this gets used on instructions such as:
>
> def ADDICo : DForm_2<13, (outs GPRC:$rD), (ins GPRC:$rA,
> s16imm:$imm),
> "addic. $rD, $rA, $imm", IntGeneral,
> []>, isDOT;
>
> but there is a small problem. If these instructions are also part
> of a larger block which also defines registers, like this:
>
> let Defs = [CARRY] in
> def ADDICo : DForm_2<13, (outs GPRC:$rD), (ins GPRC:$rA,
> s16imm:$imm),
> "addic. $rD, $rA, $imm", IntGeneral,
> []>, isDOT;
>
> then the fact that isDOT puts CR0 into Defs is lost (only CARRY
> ends up in the list of implicitly-defined registers). How can I
> modify things to make them work correctly?

let Defs = [CARRY, CR0] in…

I think it can already be tricky to figure out where TableGen
instruction definitions get all their properties. If we add syntax
that allows them to come from multiple places at once, it becomes
even harder to figure out.

For readability, just combine them explicitly.

Okay, will do.

You may also want to look at ARM's use of optional defs for
instructions that can optionally set the flags.

As far as I can tell, this makes it the job of the C++ code to add the implicit register definition (as is done at the end of ARMBaseInstrInfo::optimizeCompareInstr). Is that right?

Thanks again,
Hal

For readability, just combine them explicitly.

Okay, will do.

Thanks.

You may also want to look at ARM's use of optional defs for
instructions that can optionally set the flags.

As far as I can tell, this makes it the job of the C++ code to add the implicit register definition (as is done at the end of ARMBaseInstrInfo::optimizeCompareInstr). Is that right?

Yes, there is also some magic in ARMTargetLowering::AdjustInstrPostInstrSelection() which gets called right after the MI is created.

But it seems like we're still defining ADDS, SUBS, … pseudo-instructions for use by SelectionDAG, so there aren't really any benefits if you're looking for simpler instruction set definitions.

/jakob