Skip to content

Commit ec61311

Browse files
[LLVM][TableGen] Support type casts of nodes with multiple results (llvm#109728)
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)), ...>; ```
1 parent 2da417e commit ec61311

File tree

4 files changed

+116
-12
lines changed

4 files changed

+116
-12
lines changed

llvm/lib/TableGen/TGParser.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2866,11 +2866,13 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType,
28662866

28672867
return ListInit::get(Vals, DeducedEltTy);
28682868
}
2869-
case tgtok::l_paren: { // Value ::= '(' IDValue DagArgList ')'
2869+
case tgtok::l_paren: { // Value ::= '(' IDValue DagArgList ')'
2870+
// Value ::= '(' '[' ValueList ']' DagArgList ')'
28702871
Lex.Lex(); // eat the '('
28712872
if (Lex.getCode() != tgtok::Id && Lex.getCode() != tgtok::XCast &&
2872-
Lex.getCode() != tgtok::question && Lex.getCode() != tgtok::XGetDagOp) {
2873-
TokError("expected identifier in dag init");
2873+
Lex.getCode() != tgtok::question && Lex.getCode() != tgtok::XGetDagOp &&
2874+
Lex.getCode() != tgtok::l_square) {
2875+
TokError("expected identifier or list of value types in dag init");
28742876
return nullptr;
28752877
}
28762878

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// RUN: not llvm-tblgen -gen-dag-isel -I %p/../../include -I %p/Common -DERROR1 %s 2>&1 | FileCheck --check-prefix=ERROR1 %s
2+
// RUN: not llvm-tblgen -gen-dag-isel -I %p/../../include -I %p/Common -DERROR2 %s 2>&1 | FileCheck --check-prefix=ERROR2 %s
3+
// RUN: not llvm-tblgen -gen-dag-isel -I %p/../../include -I %p/Common -DERROR3 %s 2>&1 | FileCheck --check-prefix=ERROR3 %s
4+
// RUN: not llvm-tblgen -gen-dag-isel -I %p/../../include -I %p/Common -DERROR4 %s 2>&1 | FileCheck --check-prefix=ERROR4 %s
5+
6+
include "llvm/Target/Target.td"
7+
include "GlobalISelEmitterCommon.td"
8+
9+
def int_foo : Intrinsic<[llvm_anyint_ty, llvm_anyint_ty], [llvm_i32_ty]>;
10+
def int_bar : Intrinsic<[], []>;
11+
12+
def INSTR_FOO : Instruction {
13+
let OutOperandList = (outs GPR32:$a, GPR32:$b);
14+
let InOperandList = (ins GPR32:$c);
15+
}
16+
def INSTR_BAR : Instruction {
17+
let OutOperandList = (outs);
18+
let InOperandList = (ins);
19+
}
20+
21+
#ifdef ERROR1
22+
// ERROR1: [[@LINE+1]]:1: error: {{.*}} Invalid number of type casts!
23+
def : Pat<([i32, i32, i32] (int_foo (i32 GPR32:$a))), ([i32, i32, i32] (INSTR_FOO $a))>;
24+
#endif
25+
26+
#ifdef ERROR2
27+
// ERROR2: [[@LINE+1]]:1: error: {{.*}} Invalid number of type casts!
28+
def : Pat<([]<ValueType> (int_bar)), ([]<ValueType> (INSTR_BAR))>;
29+
#endif
30+
31+
#ifdef ERROR3
32+
// ERROR3: [[@LINE+1]]:1: error: {{.*}} Type cast only takes one operand!
33+
def : Pat<([i32, i32] (int_foo), (int_foo)), ([i32, i32] (INSTR_FOO))>;
34+
#endif
35+
36+
#ifdef ERROR4
37+
// ERROR4: [[@LINE+1]]:1: error: {{.*}} Type cast should not have a name!
38+
def : Pat<([i32, i32] ([i32, i32] (int_foo)):$name), ([i32, i32] (INSTR_FOO))>;
39+
#endif
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// RUN: llvm-tblgen -gen-dag-isel -I %p/../../include -I %p/Common %s | FileCheck -check-prefix=SDAG %s
2+
// RUN: llvm-tblgen -gen-global-isel -optimize-match-table=false -warn-on-skipped-patterns -I %p/../../include -I %p/Common %s -o - < %s | FileCheck -check-prefix=GISEL %s
3+
4+
include "llvm/Target/Target.td"
5+
include "GlobalISelEmitterCommon.td"
6+
7+
def REG : Register<"REG">;
8+
def GPR : RegisterClass<"MyTarget", [i16, i32], 32, (add REG)>;
9+
10+
def int_foo : Intrinsic<[llvm_anyint_ty, llvm_anyint_ty], []>;
11+
12+
def INSTR_FOO_I16_I32 : Instruction {
13+
let OutOperandList = (outs GPR:$a, GPR:$b);
14+
let InOperandList = (ins);
15+
}
16+
def INSTR_FOO_I32_I16 : Instruction {
17+
let OutOperandList = (outs GPR:$a, GPR:$b);
18+
let InOperandList = (ins);
19+
}
20+
21+
// SDAG: 7*/ OPC_SwitchType {{.*}}, 10, /*MVT::i16*/6
22+
// SDAG: OPC_CheckTypeRes, 1, /*MVT::i32*/7
23+
// SDAG: OPC_MorphNodeTo2Chain, TARGET_VAL(::INSTR_FOO_I16_I32)
24+
25+
// GISEL: GIM_RootCheckType, /*Op*/0, /*Type*/GILLT_s16
26+
// GISEL: GIM_RootCheckType, /*Op*/1, /*Type*/GILLT_s32
27+
// GISEL: GIR_BuildRootMI, /*Opcode*/GIMT_Encode2(::INSTR_FOO_I16_I32)
28+
def : Pat<([i16, i32] (int_foo)), ([i16, i32] (INSTR_FOO_I16_I32))>;
29+
30+
// SDAG: 20*/ /*SwitchType*/ {{.*}} /*MVT::i32*/7
31+
// SDAG: OPC_CheckTypeRes, 1, /*MVT::i16*/6
32+
// SDAG: OPC_MorphNodeTo2Chain, TARGET_VAL(::INSTR_FOO_I32_I16)
33+
34+
// GISEL: GIM_RootCheckType, /*Op*/0, /*Type*/GILLT_s32
35+
// GISEL: GIM_RootCheckType, /*Op*/1, /*Type*/GILLT_s16
36+
// GISEL: GIR_BuildRootMI, /*Opcode*/GIMT_Encode2(::INSTR_FOO_I32_I16)
37+
def : Pat<([i32, i16] (int_foo)), ([i32, i16] (INSTR_FOO_I32_I16))>;

llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2886,6 +2886,35 @@ TreePatternNodePtr TreePattern::ParseTreePattern(Init *TheInit,
28862886
error("Pattern has unexpected init kind!");
28872887
return nullptr;
28882888
}
2889+
2890+
auto ParseCastOperand = [this](DagInit *Dag, StringRef OpName) {
2891+
if (Dag->getNumArgs() != 1)
2892+
error("Type cast only takes one operand!");
2893+
2894+
if (!OpName.empty())
2895+
error("Type cast should not have a name!");
2896+
2897+
return ParseTreePattern(Dag->getArg(0), Dag->getArgNameStr(0));
2898+
};
2899+
2900+
if (ListInit *LI = dyn_cast<ListInit>(Dag->getOperator())) {
2901+
// If the operator is a list (of value types), then this must be "type cast"
2902+
// of a leaf node with multiple results.
2903+
TreePatternNodePtr New = ParseCastOperand(Dag, OpName);
2904+
2905+
size_t NumTypes = New->getNumTypes();
2906+
if (LI->empty() || LI->size() != NumTypes)
2907+
error("Invalid number of type casts!");
2908+
2909+
// Apply the type casts.
2910+
const CodeGenHwModes &CGH = getDAGPatterns().getTargetInfo().getHwModes();
2911+
for (unsigned i = 0; i < std::min(NumTypes, LI->size()); ++i)
2912+
New->UpdateNodeType(
2913+
i, getValueTypeByHwMode(LI->getElementAsRecord(i), CGH), *this);
2914+
2915+
return New;
2916+
}
2917+
28892918
DefInit *OpDef = dyn_cast<DefInit>(Dag->getOperator());
28902919
if (!OpDef) {
28912920
error("Pattern has unexpected operator type!");
@@ -2896,20 +2925,15 @@ TreePatternNodePtr TreePattern::ParseTreePattern(Init *TheInit,
28962925
if (Operator->isSubClassOf("ValueType")) {
28972926
// If the operator is a ValueType, then this must be "type cast" of a leaf
28982927
// node.
2899-
if (Dag->getNumArgs() != 1)
2900-
error("Type cast only takes one operand!");
2928+
TreePatternNodePtr New = ParseCastOperand(Dag, OpName);
29012929

2902-
TreePatternNodePtr New =
2903-
ParseTreePattern(Dag->getArg(0), Dag->getArgNameStr(0));
2930+
if (New->getNumTypes() != 1)
2931+
error("ValueType cast can only have one type!");
29042932

29052933
// Apply the type cast.
2906-
if (New->getNumTypes() != 1)
2907-
error("Type cast can only have one type!");
29082934
const CodeGenHwModes &CGH = getDAGPatterns().getTargetInfo().getHwModes();
29092935
New->UpdateNodeType(0, getValueTypeByHwMode(Operator, CGH), *this);
29102936

2911-
if (!OpName.empty())
2912-
error("ValueType cast should not have a name!");
29132937
return New;
29142938
}
29152939

@@ -4223,8 +4247,10 @@ void CodeGenDAGPatterns::ParseOnePattern(
42234247
Pattern.InlinePatternFragments();
42244248
Result.InlinePatternFragments();
42254249

4226-
if (Result.getNumTrees() != 1)
4250+
if (Result.getNumTrees() != 1) {
42274251
Result.error("Cannot use multi-alternative fragments in result pattern!");
4252+
return;
4253+
}
42284254

42294255
// Infer types.
42304256
bool IterateInference;

0 commit comments

Comments
 (0)