[llvm] [LLVM][TableGen] Support type casts of nodes with multiple results (PR #109728)

Stephen Chou via llvm-commits llvm-commits at lists.llvm.org
Mon Sep 23 16:11:17 PDT 2024


https://github.com/stephenchouca created https://github.com/llvm/llvm-project/pull/109728

Currently, type casts can only be used to pattern match for intrinsics with a single overloaded return value. For example:
```
def int_foo : Intrinsic<[llvm_anyint_ty], []>;
def : Pat<(i32 (int_foo)), ...>;
```

This patch extends type casts to support matching intrinsics with multiple overloaded return values. This is enabled with a new `ValueTypeList` class that can be used to define the target of a type cast. As an example, the following defines a pattern that matches only if the results of the overloaded intrinsic call are both `i32`:
```
def int_bar : Intrinsic<[llvm_anyint_ty, llvm_anyint_ty], []>;
def i32_i32 : ValueTypeList<[i32, i32]>;
def : Pat<(i32_i32 (int_bar)), ...>;
```

>From 65f0c3a8f0a66d11172e57397dda93a3ed35e64d Mon Sep 17 00:00:00 2001
From: Stephen Chou <stephenchou at google.com>
Date: Mon, 23 Sep 2024 23:05:51 +0000
Subject: [PATCH] [LLVM][TableGen] Support type casts of nodes with multiple
 results.

Currently, type casts can only be used to pattern match for intrinsics with a single overloaded return value. For example:
```
def int_foo : Intrinsic<[llvm_anyint_ty], []>;
def : Pat<(i32 (int_foo)), ...>;
```

This patch extends type casts to support matching intrinsics with multiple overloaded return values. This is enabled with a new `ValueTypeList` class that can be used to define the target of a type cast. As an example, the following defines a pattern that matches only if the results of the overloaded intrinsic call are both `i32`:
```
def int_bar : Intrinsic<[llvm_anyint_ty, llvm_anyint_ty], []>;
def i32_i32 : ValueTypeList<[i32, i32]>;
def : Pat<(i32_i32 (int_bar)), ...>;
```
---
 .../include/llvm/Target/TargetSelectionDAG.td | 15 +++++++
 llvm/test/TableGen/dag-isel-valuetypelist.td  | 38 ++++++++++++++++++
 .../TableGen/Common/CodeGenDAGPatterns.cpp    | 39 +++++++++++++++----
 3 files changed, 84 insertions(+), 8 deletions(-)
 create mode 100644 llvm/test/TableGen/dag-isel-valuetypelist.td

diff --git a/llvm/include/llvm/Target/TargetSelectionDAG.td b/llvm/include/llvm/Target/TargetSelectionDAG.td
index adf8a75f620225..df50cc07d5cb22 100644
--- a/llvm/include/llvm/Target/TargetSelectionDAG.td
+++ b/llvm/include/llvm/Target/TargetSelectionDAG.td
@@ -2070,3 +2070,18 @@ class ComplexPattern<ValueType ty, int numops, string fn,
   list<SDNodeProperty> Properties = props;
   int Complexity = complexity;
 }
+
+//===----------------------------------------------------------------------===//
+// Value type list.
+//
+// This can be used to pattern match for intrinsics with multiple overloaded
+// return values. For example:
+//
+// def int_foo : Irtrinsic<[llvm_anyint_ty, llvm_anyint_ty], []>;
+// def i32_i32 : ValueTypeList<[i32, i32]>;
+// def : Pat<(i32_i32 (int_foo)), ...>;
+//
+
+class ValueTypeList<list<ValueType> vts> {
+  list<ValueType> VTs = vts ;
+}
diff --git a/llvm/test/TableGen/dag-isel-valuetypelist.td b/llvm/test/TableGen/dag-isel-valuetypelist.td
new file mode 100644
index 00000000000000..db0b30695522d9
--- /dev/null
+++ b/llvm/test/TableGen/dag-isel-valuetypelist.td
@@ -0,0 +1,38 @@
+// RUN: llvm-tblgen -gen-dag-isel -I %p/../../include %s | FileCheck %s
+
+include "llvm/Target/Target.td"
+
+def TestTargetInstrInfo : InstrInfo;
+
+def TestTarget : Target {
+  let InstructionSet = TestTargetInstrInfo;
+}
+
+def REG : Register<"REG">;
+def GPR : RegisterClass<"TestTarget", [i16, i32], 32, (add REG)>;
+
+def int_foo : Intrinsic<[llvm_anyint_ty, llvm_anyint_ty], []>;
+
+def INSTR_FOO_I16_I32 : Instruction {
+  let OutOperandList = (outs GPR:$a, GPR:$b);
+  let InOperandList = (ins);
+}
+
+def INSTR_FOO_I32_I16 : Instruction {
+  let OutOperandList = (outs GPR:$a, GPR:$b);
+  let InOperandList = (ins);
+}
+
+def i16_i32 : ValueTypeList<[i16, i32]>;
+def i32_i16 : ValueTypeList<[i32, i16]>;
+
+// CHECK:      OPC_CheckOpcode, TARGET_VAL(ISD::INTRINSIC_W_CHAIN)
+// CHECK: 7*/  OPC_SwitchType {{.*}}, 10, /*MVT::i16*/6
+// CHECK:       OPC_CheckTypeRes, 1, /*MVT::i32*/7
+// CHECK:       OPC_MorphNodeTo2Chain, TARGET_VAL(::INSTR_FOO_I16_I32)
+def : Pat<(i16_i32 (int_foo)), (i16_i32 (INSTR_FOO_I16_I32))>;
+
+// CHECK: 20*/ /*SwitchType*/ {{.*}} /*MVT::i32*/7
+// CHECK:       OPC_CheckTypeRes, 1, /*MVT::i16*/6
+// CHECK:       OPC_MorphNodeTo2Chain, TARGET_VAL(::INSTR_FOO_I32_I16)
+def : Pat<(i32_i16 (int_foo)), (i32_i16 (INSTR_FOO_I32_I16))>;
diff --git a/llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp b/llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp
index fd80bc681c70d9..578275c36b69cd 100644
--- a/llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp
+++ b/llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp
@@ -2903,23 +2903,46 @@ TreePatternNodePtr TreePattern::ParseTreePattern(Init *TheInit,
   }
   Record *Operator = OpDef->getDef();
 
+  auto ParseCastOperand = [this](DagInit *Dag, StringRef OpName) {
+    if (Dag->getNumArgs() != 1)
+      error("Type cast only takes one operand!");
+
+    if (!OpName.empty())
+      error("Type cast should not have a name!");
+
+    return ParseTreePattern(Dag->getArg(0), Dag->getArgNameStr(0));
+  };
+
   if (Operator->isSubClassOf("ValueType")) {
     // If the operator is a ValueType, then this must be "type cast" of a leaf
     // node.
-    if (Dag->getNumArgs() != 1)
-      error("Type cast only takes one operand!");
+    TreePatternNodePtr New = ParseCastOperand(Dag, OpName);
 
-    TreePatternNodePtr New =
-        ParseTreePattern(Dag->getArg(0), Dag->getArgNameStr(0));
+    if (New->getNumTypes() != 1)
+      error("ValueType cast can only have one type!");
 
     // Apply the type cast.
-    if (New->getNumTypes() != 1)
-      error("Type cast can only have one type!");
     const CodeGenHwModes &CGH = getDAGPatterns().getTargetInfo().getHwModes();
     New->UpdateNodeType(0, getValueTypeByHwMode(Operator, CGH), *this);
 
-    if (!OpName.empty())
-      error("ValueType cast should not have a name!");
+    return New;
+  }
+
+  if (Operator->isSubClassOf("ValueTypeList")) {
+    // If the operator is a ValueTypeList, then this must be "type cast" of a
+    // leaf node with multiple results.
+    TreePatternNodePtr New = ParseCastOperand(Dag, OpName);
+
+    ListInit *LI = Operator->getValueAsListInit("VTs");
+    if (New->getNumTypes() != LI->size())
+      error("Invalid number of type casts!");
+
+    // Apply the type casts.
+    const CodeGenHwModes &CGH = getDAGPatterns().getTargetInfo().getHwModes();
+    for (unsigned i = 0, e = New->getNumTypes(); i != e; ++i)
+      New->UpdateNodeType(
+          i, getValueTypeByHwMode(LI->getElementAsRecord(i), CGH), *this);
+
     return New;
   }
 



More information about the llvm-commits mailing list