Tablegen pattern: How to emit a SDNode in an output pattern?

I’m trying to write a tablegen pattern to that matches a sequence of SDNodes and emits again an SDNode and another instruction.
The pattern I’ve written looks like the folowing:

def : Pat<(foo (bar GPR:$rs1), simm12:$imm1),
(bar (BAZ GPR:$rs1, simm12:$imm1))>;

foo and bar are SDNodes, BAZ is an instruction. In particular, bar is defined as follows:

def bar : SDNode<“ISD::BAR”, SDTIntUnaryOp>;

The basic idea of this pattern is to propagate bar over certain instructions until they reach a sink pattern, which only emits an instruction.
However, it seems that SDNodes in output patterns are not supported, because when building LLVM, I get the following error message:

error: In anonymous_826: Cannot use ‘bar’ in an output pattern!

What are the limits of tablegen here?
What are alternatives to propagate the bar node over instructions to reach the same behavior is the pattern-based approach?

Thank you in advance!
Cheers,
Max

Hi Max,

I'm trying to write a tablegen pattern to that matches a sequence of SDNodes and emits again an SDNode and another instruction.
The pattern I've written looks like the folowing:

def : Pat<(foo (bar GPR:$rs1), simm12:$imm1),
(bar (BAZ GPR:$rs1, simm12:$imm1))>;

foo and bar are SDNodes, BAZ is an instruction. In particular, bar is defined as follows:

def bar : SDNode<"ISD::BAR", SDTIntUnaryOp>;

The basic idea of this pattern is to propagate bar over certain instructions until they reach a sink pattern, which only emits an instruction.
However, it seems that SDNodes in output patterns are not supported, because when building LLVM, I get the following error message:

error: In anonymous_826: Cannot use 'bar' in an output pattern!

What are the limits of tablegen here?

This is technically not a limit of TableGen per se, but a limit of the DAG selection machinery. The -gen-dag-isel backend of TableGen generates a bytecode which is interpreted by the machinery in SelectionDAGISel::SelectCodeCommon, which is expected to generate machine nodes directly -- what you're trying to do would require some sort of recursion / iteration.

What are alternatives to propagate the bar node over instructions to reach the same behavior is the pattern-based approach?

It looks a bit like you want a kind of instcombine either before or after the instruction selection, but overall it's hard to say without a concrete problem description.

Cheers,
Nicolai

Firstly, are you sure you can’t do this in combine() or in preprocessiseldag()? Most of the time you may find it better to do things there (we use the latter for cases where the optimization may interfere with DAG canonicalization, and so we need to do it late).

Secondly, if you do need to do it in Select(), you can write custom C++ code in Select() for that purpose. It gets a little finicky because you will have to reposition the new DAG nodes you create in order to put them in order. For example, see the following function:

inline void InsertDAGNode(SelectionDAG &DAG, SDValue Pos, SDValue N) {
  if (N->getNodeId() == -1 ||
      (SelectionDAGISel::getUninvalidatedNodeId(N.getNode()) >
       SelectionDAGISel::getUninvalidatedNodeId(Pos.getNode()))) {
    DAG.RepositionNode(Pos->getIterator(), N.getNode());
    // Mark Node as invalid for pruning as after this it may be a successor to a
    // selected node but otherwise be in the same position of Pos.
    // Conservatively mark it with the same -abs(Id) to assure node id
    // invariant is preserved.
    N->setNodeId(Pos->getNodeId());
    SelectionDAGISel::InvalidateNodeId(N.getNode());
  }
}

I have no idea how “bad” this is, but we use it internally.

—escha