TableGen: Defining an instruction with a shared operand and multiple register classes

Hello everyone! I’m implementing a custom target in LLVM’s TableGen and ran into two related issues when defining my instructions:

  1. I have instructions where the destination and source are the same register (e.g. an increment). How do I tell TableGen that $dst and $src are actually the same operand, rather than two independent register operands?
  2. Some of my instructions take a single register index but that index refers to a general-purpose register (GPR) and a floating-point register (FPR), like (ins GPR:$src, FPR:$src).

Any advice or examples of how to fold $dst and $src into one physical operand and to let a single index use two register classes, would be greatly appreciated!

1 Like
  1. Use let Constraints = "$dst = $src" on the instruction.
  2. Such constraints are poorly modeled in LLVM. The only built-in way is to define a superregister containing both GPR and FPR as subregisters. See RegisterTuples.
1 Like

Thank you very much for your reply! I have one more question. Am I right in assuming that multiple output operands are fully supported? If so, how can I create a pattern that returns multiple registers if it is not an intrinsic?

When it comes to writing patterns, this is fully supported only for patterns embedded into instruction definitions (let Pattern = ...). Top-level patterns (def Pat : ...) have very limited support: they require that the source and destination results match in order and belong to the same node/instruction.

Example:

def MyInstr {
  let OutOperandList = (outs RC:$dst1, RC:$dst2);
  let InOperandList = (ins RC:$src1, RC:$src2);
  let Pattern = [(set RC:$dst2, RC:$dst1, (divrem $src1, $src2))];
}

where divrem has two results in reverse order compared to your instruction.

If you need more than one pattern or you don’t like embedded patterns you will have to write custom selection code in C++.

I’m sorry, but I do not understand how to create a pattern for dags with two or more different output branches (It is not intuitive how to process all these nodes in general):
    $src1         $src2
          \            /
              add
              /     \
         abs     abs
            |          |
        $dst1    neg
                       |
                   $dst2
let Pattern = [(set GPR:$dst1, GPR:$dst2, (???))];.

In this case $dst1 and $dst2 belong to different nodes (abs and neg). It is not possible to write a pattern for this example.

Is it true that a dag always has one output node? And if the semantics of the instruction is like that, then how to describe such instructions?

Yes, they have one root node.

I’m not sure I understand the question. Instruction semantics is opaque to LLVM. It only knows about inputs/outputs and properties like hasSideEffects etc.

1 Like

Thanks a lot! I now understand it a little better. However, I thought that it was possible to create a pattern with multiple root (output) nodes. :smiling_face_with_tear:

To achieve such behavior, you have to define a new SDNode, i believe

Alternatively, you can also use Complex Patterns and implement the Cpp function to match it. I recommend “LLVM Code Generation” by Quentin Colombet, i just started it and it cleared up a lot of my confusion about this