tablegen dag syntax question

What is the difference between these two fragments (taken from two different tblgen record dumps)?

dag OutOperandList = (outs GPR:$rd);

dag OutOperandList = (outs R2);

The first is from the RISCV backend record dump. There will be a substitution at some point for $rd. In the second, I’m specifying R2, no substitution necessary.

If I specify GPR64:R2 or i64:R2 in my Instruction def, rather than just R2, tblgen complains:

error: expected variable name in dag literal

If I use R1000 (which isn’t defined) I get what I’d expect:

error: Variable not defined: ‘R1000’

There isn’t any documentation (that I could find) for this syntax. Consequently, I’m a little worried that using R2 rather than something:R2 is somehow wrong.

Why does the RISCV dag use GPR:$rd rather than just $rd?
C

A specific register shouldn’t be in the “outs” list. outs is for registers the register allocator has freedom over. The GPR in RISCV tells the register allocator what register class to pick registers from. It’s also used to tell the autogenerated assembly parser what type of operand it should be looking for when parsing. The $rd will also be mentioned in an assembly string to know where it goes relative to other operands.

If you instruction always write to a specific register this is what we call an implicit definition. It should be listed as “let Defs=[R2] in” before the instruction definition. There’s a simpler Uses for implicit uses.

Thanks. So I was right to be worried about this and I’m glad I asked.

Chris

I think the comment for this in Target.td is confusing:

dag OutOperandList; // An dag containing the MI def operand list.
dag InOperandList; // An dag containing the MI use operand list.

It’s not an MI, MachineInstr. It’s a an MCInst. Also, the comment could mention allocable registers.

On the other hand, there are plenty of examples of Uses and Defs in the various backends to go by.
Its comment in Target.td isn’t helpful either:

// The follow state will eventually be inferred automatically from the
// instruction pattern.

That could mention implicit registers.

C

What is the difference between these two fragments (taken from two different tblgen record dumps)?

dag OutOperandList = (outs GPR:$rd);
dag OutOperandList = (outs R2);

The first is from the RISCV backend record dump. There will be a substitution at some point for $rd. In the second, I'm specifying R2, no substitution necessary.

If I specify GPR64:R2 or i64:R2 in my Instruction def, rather than just R2, tblgen complains:

error: expected variable name in dag literal

This is because the syntax for dag operands is <value>:$name, where both parts are optional, and your attempt to use a TableGen value in place of the name makes no sense.

The value is typically a TableGen record (something that was created with a `def`), though in contexts other than the OutOperandList it could also be an integer, as you often see in ISel patterns.

The name is simply a symbolic name that has no meaning in the TableGen language itself, but is interpreted by the TableGen backend in order to link various parts of the instruction definition together. For example, the names in the OutOperandList are linked to the names mentioned in the definition of the textual assembly, and this link is used to automatically generated assembly printer and parser tables and code.

For this reason, operands in the OutOperandList really always need a name.

Cheers,
Nicolai