[llvm] [TableGen] Fix crashes on invalid instruction patterns (PR #115600)
Sergey Barannikov via llvm-commits
llvm-commits at lists.llvm.org
Thu Dec 19 04:46:25 PST 2024
https://github.com/s-barannikov updated https://github.com/llvm/llvm-project/pull/115600
>From 8615d94f56983f35da43e7ec0d1ac76e9bcc8aba Mon Sep 17 00:00:00 2001
From: Sergei Barannikov <barannikov88 at gmail.com>
Date: Sat, 9 Nov 2024 15:00:37 +0300
Subject: [PATCH] [TableGen] Fix crashes on invalid instruction patterns
There were out-of-bounds accesses due to invalid indexing
of instruction operand list.
---
.../TableGen/dag-isel-invalid-patterns.td | 42 +++++++++++++++++++
.../TableGen/Common/CodeGenDAGPatterns.cpp | 42 +++++++++++--------
2 files changed, 67 insertions(+), 17 deletions(-)
create mode 100644 llvm/test/TableGen/dag-isel-invalid-patterns.td
diff --git a/llvm/test/TableGen/dag-isel-invalid-patterns.td b/llvm/test/TableGen/dag-isel-invalid-patterns.td
new file mode 100644
index 00000000000000..04889d25be997c
--- /dev/null
+++ b/llvm/test/TableGen/dag-isel-invalid-patterns.td
@@ -0,0 +1,42 @@
+// RUN: not llvm-tblgen -gen-dag-isel -I %p/../../include %s 2>&1 >/dev/null | FileCheck %s
+
+include "llvm/Target/Target.td"
+
+def R0 : Register<"gr0">;
+def GPR : RegisterClass<"My", [i32], 32, (add R0)>;
+
+def my_node_1 : SDNode<"MYISD::NODE1", SDTypeProfile<1, 0, []>>;
+def my_node_2 : SDNode<"MYISD::NODE2", SDTypeProfile<2, 0, []>>;
+def my_node_3 : SDNode<"MYISD::NODE3", SDTypeProfile<2, 1, []>>;
+
+// CHECK: In Instr1: instruction output operand $rd does not appear in pattern outputs
+def Instr1 : Instruction {
+ let Namespace = "My";
+ let OutOperandList = (outs GPR:$rd);
+ let InOperandList = (ins GPR:$rs);
+ let Pattern = [(set GPR:$rt, (my_node_1))];
+}
+
+// CHECK: In Instr2: pattern output operand $rs does not appear in instruction outputs
+def Instr2 : Instruction {
+ let Namespace = "My";
+ let OutOperandList = (outs GPR:$rd);
+ let InOperandList = (ins);
+ let Pattern = [(set GPR:$rd, GPR:$rs, (my_node_2))];
+}
+
+// CHECK: In Instr3: pattern output operand $rs1 does not appear in instruction outputs
+def Instr3 : Instruction {
+ let Namespace = "My";
+ let OutOperandList = (outs GPR:$rd);
+ let InOperandList = (ins GPR:$rs1, GPR:$rs2);
+ let Pattern = [(set GPR:$rd, GPR:$rs1, (my_node_3 GPR:$rs2))];
+}
+
+def MyInstrInfo : InstrInfo;
+
+def My : Target {
+ let InstructionSet = MyInstrInfo;
+}
+
+// CHECK: llvm-tblgen: 3 errors.
diff --git a/llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp b/llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp
index 31bf9a98943e56..46baef6e09fc22 100644
--- a/llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp
+++ b/llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp
@@ -3803,25 +3803,21 @@ void CodeGenDAGPatterns::parseInstructionPattern(CodeGenInstruction &CGI,
std::vector<const Record *> Results;
std::vector<unsigned> ResultIndices;
SmallVector<TreePatternNodePtr, 2> ResNodes;
- for (unsigned i = 0; i != NumResults; ++i) {
- if (i == CGI.Operands.size()) {
- const std::string &OpName =
- llvm::find_if(
- InstResults,
- [](const std::pair<std::string, TreePatternNodePtr> &P) {
- return P.second;
- })
- ->first;
-
- I.error("'" + OpName + "' set but does not appear in operand list!");
- }
-
+ for (unsigned i = 0; i != CGI.Operands.NumDefs; ++i) {
+ const CGIOperandList::OperandInfo &Op = CGI.Operands[i];
const std::string &OpName = CGI.Operands[i].Name;
// Check that it exists in InstResults.
- auto InstResultIter = InstResults.find(OpName);
- if (InstResultIter == InstResults.end() || !InstResultIter->second)
- I.error("Operand $" + OpName + " does not exist in operand list!");
+ auto InstResultIter = InstResults.find(Op.Name);
+ if (InstResultIter == InstResults.end() || !InstResultIter->second) {
+ // If this operand is optional and has a default value, ignore it.
+ if (Op.Rec->isSubClassOf("OptionalDefOperand") &&
+ !getDefaultOperand(Op.Rec).DefaultOps.empty())
+ continue;
+ I.error("instruction output operand $" + OpName +
+ " does not appear in pattern outputs");
+ continue;
+ }
TreePatternNodePtr RNode = InstResultIter->second;
const Record *R = cast<DefInit>(RNode->getLeafValue())->getDef();
@@ -3844,10 +3840,19 @@ void CodeGenDAGPatterns::parseInstructionPattern(CodeGenInstruction &CGI,
InstResultIter->second = nullptr;
}
+ auto FirstExtraResult = llvm::find_if(
+ InstResults, [](const std::pair<std::string, TreePatternNodePtr> &P) {
+ return P.second;
+ });
+ if (FirstExtraResult != InstResults.end())
+ I.error("pattern output operand $" + FirstExtraResult->first +
+ " does not appear in instruction outputs");
+
// Loop over the inputs next.
std::vector<TreePatternNodePtr> ResultNodeOperands;
std::vector<const Record *> Operands;
- for (unsigned i = NumResults, e = CGI.Operands.size(); i != e; ++i) {
+ for (unsigned i = CGI.Operands.NumDefs, e = CGI.Operands.size(); i != e;
+ ++i) {
CGIOperandList::OperandInfo &Op = CGI.Operands[i];
const std::string &OpName = Op.Name;
if (OpName.empty()) {
@@ -3904,6 +3909,9 @@ void CodeGenDAGPatterns::parseInstructionPattern(CodeGenInstruction &CGI,
I.error("Input operand $" + InstInputs.begin()->first +
" occurs in pattern but not in operands list!");
+ if (I.hasError())
+ return;
+
TreePatternNodePtr ResultPattern = makeIntrusiveRefCnt<TreePatternNode>(
I.getRecord(), std::move(ResultNodeOperands),
GetNumNodeResults(I.getRecord(), *this));
More information about the llvm-commits
mailing list