[llvm] [LLVM][TableGen] Support type casts of nodes with multiple results (PR #109728)
Stephen Chou via llvm-commits
llvm-commits at lists.llvm.org
Tue Sep 24 13:15:19 PDT 2024
https://github.com/stephenchouca updated https://github.com/llvm/llvm-project/pull/109728
>From ee9c4ce644f7a7ac1e2a1971333101fb74136013 Mon Sep 17 00:00:00 2001
From: Stephen Chou <stephenchou at google.com>
Date: Tue, 24 Sep 2024 20:13:08 +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 instance:
```
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. As an example, the following defines a pattern that matches only if the overloaded intrinsic call returns an `i16` for the first result and an `i32` for the second result:
```
def int_bar : Intrinsic<[llvm_anyint_ty, llvm_anyint_ty], []>;
def : Pat<([i16, i32] (int_bar)), ...>;
```
---
llvm/lib/TableGen/TGParser.cpp | 8 ++--
.../GlobalISelEmitter-multiple-type-casts.td | 29 ++++++++++++++
.../TableGen/dag-isel-multiple-type-casts.td | 34 ++++++++++++++++
.../TableGen/Common/CodeGenDAGPatterns.cpp | 40 +++++++++++++++----
4 files changed, 100 insertions(+), 11 deletions(-)
create mode 100644 llvm/test/TableGen/GlobalISelEmitter-multiple-type-casts.td
create mode 100644 llvm/test/TableGen/dag-isel-multiple-type-casts.td
diff --git a/llvm/lib/TableGen/TGParser.cpp b/llvm/lib/TableGen/TGParser.cpp
index 1a60c2a567a297..5ec45aae394fbb 100644
--- a/llvm/lib/TableGen/TGParser.cpp
+++ b/llvm/lib/TableGen/TGParser.cpp
@@ -2844,11 +2844,13 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType,
return ListInit::get(Vals, DeducedEltTy);
}
- case tgtok::l_paren: { // Value ::= '(' IDValue DagArgList ')'
+ case tgtok::l_paren: { // Value ::= '(' IDValue DagArgList ')'
+ // Value ::= '(' '[' ValueList ']' DagArgList ')'
Lex.Lex(); // eat the '('
if (Lex.getCode() != tgtok::Id && Lex.getCode() != tgtok::XCast &&
- Lex.getCode() != tgtok::question && Lex.getCode() != tgtok::XGetDagOp) {
- TokError("expected identifier in dag init");
+ Lex.getCode() != tgtok::question && Lex.getCode() != tgtok::XGetDagOp &&
+ Lex.getCode() != tgtok::l_square) {
+ TokError("expected identifier or list of value types in dag init");
return nullptr;
}
diff --git a/llvm/test/TableGen/GlobalISelEmitter-multiple-type-casts.td b/llvm/test/TableGen/GlobalISelEmitter-multiple-type-casts.td
new file mode 100644
index 00000000000000..1f0230b296743d
--- /dev/null
+++ b/llvm/test/TableGen/GlobalISelEmitter-multiple-type-casts.td
@@ -0,0 +1,29 @@
+// RUN: llvm-tblgen -gen-global-isel -optimize-match-table=false -warn-on-skipped-patterns -I %p/../../include -I %p/Common %s -o - < %s | FileCheck %s
+
+include "llvm/Target/Target.td"
+include "GlobalISelEmitterCommon.td"
+
+def REG : Register<"REG">;
+def GPR : RegisterClass<"MyTarget", [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);
+}
+
+// CHECK: GIM_RootCheckType, /*Op*/0, /*Type*/GILLT_s16
+// CHECK: GIM_RootCheckType, /*Op*/1, /*Type*/GILLT_s32
+// CHECK: GIR_BuildRootMI, /*Opcode*/GIMT_Encode2(::INSTR_FOO_I16_I32)
+def : Pat<([i16, i32] (int_foo)), ([i16, i32] (INSTR_FOO_I16_I32))>;
+
+// CHECK: GIM_RootCheckType, /*Op*/0, /*Type*/GILLT_s32
+// CHECK: GIM_RootCheckType, /*Op*/1, /*Type*/GILLT_s16
+// CHECK: GIR_BuildRootMI, /*Opcode*/GIMT_Encode2(::INSTR_FOO_I32_I16)
+def : Pat<([i32, i16] (int_foo)), ([i32, i16] (INSTR_FOO_I32_I16))>;
diff --git a/llvm/test/TableGen/dag-isel-multiple-type-casts.td b/llvm/test/TableGen/dag-isel-multiple-type-casts.td
new file mode 100644
index 00000000000000..5b357fb7f71666
--- /dev/null
+++ b/llvm/test/TableGen/dag-isel-multiple-type-casts.td
@@ -0,0 +1,34 @@
+// 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);
+}
+
+// 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..13994af3c51733 100644
--- a/llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp
+++ b/llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp
@@ -2896,6 +2896,35 @@ TreePatternNodePtr TreePattern::ParseTreePattern(Init *TheInit,
error("Pattern has unexpected init kind!");
return nullptr;
}
+
+ 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 (ListInit *LI = dyn_cast<ListInit>(Dag->getOperator())) {
+ // If the operator is a list (of value types), then this must be "type cast"
+ // of a leaf node with multiple results.
+ TreePatternNodePtr New = ParseCastOperand(Dag, OpName);
+
+ unsigned NumTypes = New->getNumTypes();
+ if (NumTypes != LI->size())
+ error("Invalid number of type casts!");
+
+ // Apply the type casts.
+ const CodeGenHwModes &CGH = getDAGPatterns().getTargetInfo().getHwModes();
+ for (unsigned i = 0; i < NumTypes; ++i)
+ New->UpdateNodeType(
+ i, getValueTypeByHwMode(LI->getElementAsRecord(i), CGH), *this);
+
+ return New;
+ }
+
DefInit *OpDef = dyn_cast<DefInit>(Dag->getOperator());
if (!OpDef) {
error("Pattern has unexpected operator type!");
@@ -2906,20 +2935,15 @@ TreePatternNodePtr TreePattern::ParseTreePattern(Init *TheInit,
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;
}
More information about the llvm-commits
mailing list