[llvm] [TableGen] Fix crashes on invalid instruction patterns (PR #115600)

via llvm-commits llvm-commits at lists.llvm.org
Sat Nov 9 04:11:32 PST 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-tablegen

Author: Sergei Barannikov (s-barannikov)

<details>
<summary>Changes</summary>

There were out-of-bounds accesses due to invalid indexing of instruction operand list.

---
Full diff: https://github.com/llvm/llvm-project/pull/115600.diff


2 Files Affected:

- (added) llvm/test/TableGen/dag-isel-invalid-patterns.td (+42) 
- (modified) llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp (+25-17) 


``````````diff
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..f2ead88f339412
--- /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 | 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: output operand $rd does not appear in the instruction pattern
+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: output operand $rs occurs in pattern but not in operands list
+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: output operand $rs1 occurs in pattern but not in operands list
+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 c8186d6e69523f..c65ceaae1a6b32 100644
--- a/llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp
+++ b/llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp
@@ -3799,25 +3799,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();
@@ -3840,10 +3836,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()) {
@@ -3900,6 +3905,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));

``````````

</details>


https://github.com/llvm/llvm-project/pull/115600


More information about the llvm-commits mailing list