[tblgen] Rewriting of a result instruction DAG node for InstAlias

Hi, I’m working with LLVM TableGen and trying to define an InstAlias for a family of instructions that inherit from a base class MyInst. Each instruction ends with an operand of type ImmOpndA, and I want to create an alternative assembly syntax that implicitly sets this last operand to 0. Here is the base instrution class:

class MyInst<...> {
  let AsmString = "...";
  let OutOperandList = ...;
  let InOpernadList = (ins ..., ImmOpndA:$a);
}

Last operand for all inherited instructions is of type ImmOpndA. To define an alternative assembly syntax that sets $a to 0, I defined a helper multiclass like this:

multiclass AlternateSyntax<MyInst Inst> {
  defvar ResultPattern = !con(!setdagop(Inst.OutOperandList, Inst),
                                                  !setdagop(Inst.InOperandList, Inst));
 def _Alternate : Instalias<"some asm syntax", ResultPattern>;
}

def InstABC : MyInst<...> { ... };
defm ABC : AlternateSyntax<InstABC>;

However, the tablegen does not provide operations like splice, filter or remove for DAG, I could not find a way to manipulate the ResultPattern.

Here is a workaround that I tried to set the last arg 0 and the name with an empty string:

setvar UpdatedDAG = !setdagname(!setdagarg(ResultPattern , "a", 0), "a", "");

but it causes an error in tablegen compilation here: llvm-project/llvm/utils/TableGen/Common/CodeGenInstAlias.cpp at 101ad14f535461236ba0a656554d884d6d0b25a0 · llvm/llvm-project · GitHub .

If I comment out this check, the alias works as expected. However, I’m looking for a way to achieve this without such a hacky workaround.

To support this, could we add a bang operand, such as !removedagarg? Or is there a better way to do this?

You can just write 0 on that operand:

InstAlias<"bar $rd, $rs", (FOO GPR:$rd, GPR:$rs, 0)>

The problem is that AlternateSyntax must be a reusable multiclass, so I need to apply the alias to every instruction without explicitly describing AsmStr and a pattern for each alias.

I think I have found a solution. I can replace the last dag argument with an integer with the following code:

defvar UpdatedPattern = !setdagname(!setdagarg(ResultPattern , "a", 0), "a", ?);
def _Alternate : Instalias<"some asm syntax", UpdatedPattern>;

Reflecting on this:

This should’ve been named setdagargname. setdagname sounds like it changes the name of the dag. setdagargname would also be consistent with setdagarg (which should’ve been named setdagargvalue). Or maybe we could just have setdagarg that sets both the name and the value.

FWIW it doesn’t actually remove the argument, it replaces it with 0:? (which seems like what you want).

Yes, my mistake. I intended to replace it with an int value without a name. Thanks for correcting.

Alternatively, you could do something like this:

multiclass MyInstWithAlias<dag out_ops, dag in_ops, dag asm_string> {
  def NAME : MyInst<out_ops, !con(in_ops, (ins ImmOpndA:$a)), asm_string # ", $a">;
  defvar ResultPattern = !con(!setdagop(out_ops, NAME),
                              !setdagop(in_ops, NAME),
                              0);
  def : InstAlias<asm_string, ResultPattern>;
}

defm MyInst1 : MyInstWithAlias<(outs ...), (ins ...), "some asm syntax">;

That is, define an instruction and an alias for it in multiclass.

Thanks for the suggestion. I’ve considered a similar design, but there are a bunch of existing instruction definitions that would require significant effort to refactor.