[llvm] [MC] Teach checkAsmTiedOperandConstraints about optional operands (PR #81381)

Sergei Barannikov via llvm-commits llvm-commits at lists.llvm.org
Sun Feb 18 06:26:04 PST 2024


https://github.com/s-barannikov updated https://github.com/llvm/llvm-project/pull/81381

>From fc7815b2b435bccd7c5796cebc648478af90a5a8 Mon Sep 17 00:00:00 2001
From: Sergei Barannikov <barannikov88 at gmail.com>
Date: Sun, 11 Feb 2024 00:24:47 +0300
Subject: [PATCH 1/3] [MC] Teach checkAsmTiedOperandConstraints about optional
 operands

At some point in the past, optional operands have become allowed in the
middle of an instruction. However, `checkAsmTiedOperandConstrains`
hasn't been modified to support this. This patch adds the support by
copying the necessary logic from `convertToMCInst`.
---
 llvm/utils/TableGen/AsmMatcherEmitter.cpp | 68 +++++++++++++++++------
 1 file changed, 51 insertions(+), 17 deletions(-)

diff --git a/llvm/utils/TableGen/AsmMatcherEmitter.cpp b/llvm/utils/TableGen/AsmMatcherEmitter.cpp
index b5bd9bfd21bebc..79c05d223bccbd 100644
--- a/llvm/utils/TableGen/AsmMatcherEmitter.cpp
+++ b/llvm/utils/TableGen/AsmMatcherEmitter.cpp
@@ -1956,7 +1956,7 @@ static unsigned
 emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName,
                  std::vector<std::unique_ptr<MatchableInfo>> &Infos,
                  bool HasMnemonicFirst, bool HasOptionalOperands,
-                 raw_ostream &OS) {
+                 unsigned MaxNumOperands, raw_ostream &OS) {
   SmallSetVector<CachedHashString, 16> OperandConversionKinds;
   SmallSetVector<CachedHashString, 16> InstructionConversionKinds;
   std::vector<std::vector<uint8_t>> ConversionTable;
@@ -1986,10 +1986,6 @@ emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName,
   CvtOS << "  assert(Kind < CVT_NUM_SIGNATURES && \"Invalid signature!\");\n";
   CvtOS << "  const uint8_t *Converter = ConversionTable[Kind];\n";
   if (HasOptionalOperands) {
-    size_t MaxNumOperands = 0;
-    for (const auto &MI : Infos) {
-      MaxNumOperands = std::max(MaxNumOperands, MI->AsmOperands.size());
-    }
     CvtOS << "  unsigned DefaultsOffset[" << (MaxNumOperands + 1)
           << "] = { 0 };\n";
     CvtOS << "  assert(OptionalOperandsMask.size() == " << (MaxNumOperands)
@@ -3031,18 +3027,33 @@ emitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target,
 }
 
 static void emitAsmTiedOperandConstraints(CodeGenTarget &Target,
-                                          AsmMatcherInfo &Info,
-                                          raw_ostream &OS) {
+                                          AsmMatcherInfo &Info, raw_ostream &OS,
+                                          bool HasOptionalOperands,
+                                          unsigned MaxNumOperands) {
   std::string AsmParserName =
       std::string(Info.AsmParser->getValueAsString("AsmParserClassName"));
   OS << "static bool ";
   OS << "checkAsmTiedOperandConstraints(const " << Target.getName()
      << AsmParserName << "&AsmParser,\n";
-  OS << "                               unsigned Kind,\n";
-  OS << "                               const OperandVector &Operands,\n";
+  OS << "                               unsigned Kind, const OperandVector "
+        "&Operands,\n";
+  if (HasOptionalOperands)
+    OS << "                               const SmallBitVector "
+          "&OptionalOperandsMask,\n";
   OS << "                               uint64_t &ErrorInfo) {\n";
   OS << "  assert(Kind < CVT_NUM_SIGNATURES && \"Invalid signature!\");\n";
   OS << "  const uint8_t *Converter = ConversionTable[Kind];\n";
+  if (HasOptionalOperands) {
+    OS << "  unsigned DefaultsOffset[" << (MaxNumOperands + 1)
+          << "] = { 0 };\n";
+    OS << "  assert(OptionalOperandsMask.size() == " << (MaxNumOperands)
+          << ");\n";
+    OS << "  for (unsigned i = 0, NumDefaults = 0; i < " << (MaxNumOperands)
+          << "; ++i) {\n";
+    OS << "    DefaultsOffset[i + 1] = NumDefaults;\n";
+    OS << "    NumDefaults += (OptionalOperandsMask[i] ? 1 : 0);\n";
+    OS << "  }\n";
+  }
   OS << "  for (const uint8_t *p = Converter; *p; p += 2) {\n";
   OS << "    switch (*p) {\n";
   OS << "    case CVT_Tied: {\n";
@@ -3052,6 +3063,10 @@ static void emitAsmTiedOperandConstraints(CodeGenTarget &Target,
   OS << "             \"Tied operand not found\");\n";
   OS << "      unsigned OpndNum1 = TiedAsmOperandTable[OpIdx][1];\n";
   OS << "      unsigned OpndNum2 = TiedAsmOperandTable[OpIdx][2];\n";
+  if (HasOptionalOperands) {
+    OS << "      OpndNum1 = OpndNum1 - DefaultsOffset[OpndNum1];\n";
+    OS << "      OpndNum2 = OpndNum2 - DefaultsOffset[OpndNum2];\n";
+  }
   OS << "      if (OpndNum1 != OpndNum2) {\n";
   OS << "        auto &SrcOp1 = Operands[OpndNum1];\n";
   OS << "        auto &SrcOp2 = Operands[OpndNum2];\n";
@@ -3371,12 +3386,16 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
   // Generate the function that remaps for mnemonic aliases.
   bool HasMnemonicAliases = emitMnemonicAliases(OS, Info, Target);
 
+  size_t MaxNumOperands = 0;
+  for (const auto &MI : Info.Matchables)
+    MaxNumOperands = std::max(MaxNumOperands, MI->AsmOperands.size());
+
   // Generate the convertToMCInst function to convert operands into an MCInst.
   // Also, generate the convertToMapAndConstraints function for MS-style inline
   // assembly.  The latter doesn't actually generate a MCInst.
   unsigned NumConverters =
       emitConvertFuncs(Target, ClassName, Info.Matchables, HasMnemonicFirst,
-                       HasOptionalOperands, OS);
+                       HasOptionalOperands, MaxNumOperands, OS);
 
   // Emit the enumeration for classes which participate in matching.
   emitMatchClassEnumeration(Target, Info.Classes, OS);
@@ -3405,15 +3424,14 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
       Info.SubtargetFeatures, OS);
 
   if (!ReportMultipleNearMisses)
-    emitAsmTiedOperandConstraints(Target, Info, OS);
+    emitAsmTiedOperandConstraints(Target, Info, OS, HasOptionalOperands,
+                                  MaxNumOperands);
 
   StringToOffsetTable StringTable;
 
-  size_t MaxNumOperands = 0;
   unsigned MaxMnemonicIndex = 0;
   bool HasDeprecation = false;
   for (const auto &MI : Info.Matchables) {
-    MaxNumOperands = std::max(MaxNumOperands, MI->AsmOperands.size());
     HasDeprecation |= MI->HasDeprecation;
 
     // Store a pascal-style length byte in the mnemonic.
@@ -3931,8 +3949,16 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
   OS << "    if (matchingInlineAsm) {\n";
   OS << "      convertToMapAndConstraints(it->ConvertFn, Operands);\n";
   if (!ReportMultipleNearMisses) {
-    OS << "      if (!checkAsmTiedOperandConstraints(*this, it->ConvertFn, "
-          "Operands, ErrorInfo))\n";
+    if (HasOptionalOperands) {
+      OS << "      if (!checkAsmTiedOperandConstraints(*this, it->ConvertFn, "
+            "Operands,\n";
+      OS << "                                          OptionalOperandsMask, "
+            "ErrorInfo))\n";
+    } else {
+      OS << "      if (!checkAsmTiedOperandConstraints(*this, it->ConvertFn, "
+            "Operands,\n";
+      OS << "                                          ErrorInfo))\n";
+    }
     OS << "        return Match_InvalidTiedOperand;\n";
     OS << "\n";
   }
@@ -4022,8 +4048,16 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
   }
 
   if (!ReportMultipleNearMisses) {
-    OS << "    if (!checkAsmTiedOperandConstraints(*this, it->ConvertFn, "
-          "Operands, ErrorInfo))\n";
+    if (HasOptionalOperands) {
+      OS << "    if (!checkAsmTiedOperandConstraints(*this, it->ConvertFn, "
+            "Operands,\n";
+      OS << "                                         OptionalOperandsMask, "
+            "ErrorInfo))\n";
+    } else {
+      OS << "    if (!checkAsmTiedOperandConstraints(*this, it->ConvertFn, "
+            "Operands,\n";
+      OS << "                                         ErrorInfo))\n";
+    }
     OS << "      return Match_InvalidTiedOperand;\n";
     OS << "\n";
   }

>From 367e9076705e19fc679ce2cba03e7f2ac62d8176 Mon Sep 17 00:00:00 2001
From: Sergei Barannikov <barannikov88 at gmail.com>
Date: Sun, 11 Feb 2024 00:34:10 +0300
Subject: [PATCH 2/3] Apply clang-format suggestion.

---
 llvm/utils/TableGen/AsmMatcherEmitter.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/llvm/utils/TableGen/AsmMatcherEmitter.cpp b/llvm/utils/TableGen/AsmMatcherEmitter.cpp
index 79c05d223bccbd..e1f2961319fe90 100644
--- a/llvm/utils/TableGen/AsmMatcherEmitter.cpp
+++ b/llvm/utils/TableGen/AsmMatcherEmitter.cpp
@@ -3045,11 +3045,11 @@ static void emitAsmTiedOperandConstraints(CodeGenTarget &Target,
   OS << "  const uint8_t *Converter = ConversionTable[Kind];\n";
   if (HasOptionalOperands) {
     OS << "  unsigned DefaultsOffset[" << (MaxNumOperands + 1)
-          << "] = { 0 };\n";
+       << "] = { 0 };\n";
     OS << "  assert(OptionalOperandsMask.size() == " << (MaxNumOperands)
-          << ");\n";
+       << ");\n";
     OS << "  for (unsigned i = 0, NumDefaults = 0; i < " << (MaxNumOperands)
-          << "; ++i) {\n";
+       << "; ++i) {\n";
     OS << "    DefaultsOffset[i + 1] = NumDefaults;\n";
     OS << "    NumDefaults += (OptionalOperandsMask[i] ? 1 : 0);\n";
     OS << "  }\n";

>From a38f0a0e1ef7d2c68bbbec24bd785f788734634d Mon Sep 17 00:00:00 2001
From: Sergei Barannikov <barannikov88 at gmail.com>
Date: Sun, 11 Feb 2024 01:37:35 +0300
Subject: [PATCH 3/3] Pull the duplicated logic to a common place

---
 llvm/utils/TableGen/AsmMatcherEmitter.cpp | 65 +++++++++--------------
 1 file changed, 26 insertions(+), 39 deletions(-)

diff --git a/llvm/utils/TableGen/AsmMatcherEmitter.cpp b/llvm/utils/TableGen/AsmMatcherEmitter.cpp
index e1f2961319fe90..455cb445022266 100644
--- a/llvm/utils/TableGen/AsmMatcherEmitter.cpp
+++ b/llvm/utils/TableGen/AsmMatcherEmitter.cpp
@@ -1956,7 +1956,7 @@ static unsigned
 emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName,
                  std::vector<std::unique_ptr<MatchableInfo>> &Infos,
                  bool HasMnemonicFirst, bool HasOptionalOperands,
-                 unsigned MaxNumOperands, raw_ostream &OS) {
+                 raw_ostream &OS) {
   SmallSetVector<CachedHashString, 16> OperandConversionKinds;
   SmallSetVector<CachedHashString, 16> InstructionConversionKinds;
   std::vector<std::vector<uint8_t>> ConversionTable;
@@ -1976,7 +1976,8 @@ emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName,
           << "convertToMCInst(unsigned Kind, MCInst &Inst, "
           << "unsigned Opcode,\n"
           << "                const OperandVector &Operands,\n"
-          << "                const SmallBitVector &OptionalOperandsMask) {\n";
+          << "                const SmallBitVector &OptionalOperandsMask,\n"
+          << "                ArrayRef<unsigned> DefaultsOffset) {\n";
   } else {
     CvtOS << "void " << Target.getName() << ClassName << "::\n"
           << "convertToMCInst(unsigned Kind, MCInst &Inst, "
@@ -1985,17 +1986,6 @@ emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName,
   }
   CvtOS << "  assert(Kind < CVT_NUM_SIGNATURES && \"Invalid signature!\");\n";
   CvtOS << "  const uint8_t *Converter = ConversionTable[Kind];\n";
-  if (HasOptionalOperands) {
-    CvtOS << "  unsigned DefaultsOffset[" << (MaxNumOperands + 1)
-          << "] = { 0 };\n";
-    CvtOS << "  assert(OptionalOperandsMask.size() == " << (MaxNumOperands)
-          << ");\n";
-    CvtOS << "  for (unsigned i = 0, NumDefaults = 0; i < " << (MaxNumOperands)
-          << "; ++i) {\n";
-    CvtOS << "    DefaultsOffset[i + 1] = NumDefaults;\n";
-    CvtOS << "    NumDefaults += (OptionalOperandsMask[i] ? 1 : 0);\n";
-    CvtOS << "  }\n";
-  }
   CvtOS << "  unsigned OpIdx;\n";
   CvtOS << "  Inst.setOpcode(Opcode);\n";
   CvtOS << "  for (const uint8_t *p = Converter; *p; p += 2) {\n";
@@ -3028,8 +3018,7 @@ emitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target,
 
 static void emitAsmTiedOperandConstraints(CodeGenTarget &Target,
                                           AsmMatcherInfo &Info, raw_ostream &OS,
-                                          bool HasOptionalOperands,
-                                          unsigned MaxNumOperands) {
+                                          bool HasOptionalOperands) {
   std::string AsmParserName =
       std::string(Info.AsmParser->getValueAsString("AsmParserClassName"));
   OS << "static bool ";
@@ -3038,22 +3027,10 @@ static void emitAsmTiedOperandConstraints(CodeGenTarget &Target,
   OS << "                               unsigned Kind, const OperandVector "
         "&Operands,\n";
   if (HasOptionalOperands)
-    OS << "                               const SmallBitVector "
-          "&OptionalOperandsMask,\n";
+    OS << "                               ArrayRef<unsigned> DefaultsOffset,\n";
   OS << "                               uint64_t &ErrorInfo) {\n";
   OS << "  assert(Kind < CVT_NUM_SIGNATURES && \"Invalid signature!\");\n";
   OS << "  const uint8_t *Converter = ConversionTable[Kind];\n";
-  if (HasOptionalOperands) {
-    OS << "  unsigned DefaultsOffset[" << (MaxNumOperands + 1)
-       << "] = { 0 };\n";
-    OS << "  assert(OptionalOperandsMask.size() == " << (MaxNumOperands)
-       << ");\n";
-    OS << "  for (unsigned i = 0, NumDefaults = 0; i < " << (MaxNumOperands)
-       << "; ++i) {\n";
-    OS << "    DefaultsOffset[i + 1] = NumDefaults;\n";
-    OS << "    NumDefaults += (OptionalOperandsMask[i] ? 1 : 0);\n";
-    OS << "  }\n";
-  }
   OS << "  for (const uint8_t *p = Converter; *p; p += 2) {\n";
   OS << "    switch (*p) {\n";
   OS << "    case CVT_Tied: {\n";
@@ -3306,7 +3283,8 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
        << "unsigned Opcode,\n"
        << "                       const OperandVector &Operands,\n"
        << "                       const SmallBitVector "
-          "&OptionalOperandsMask);\n";
+          "&OptionalOperandsMask,\n"
+       << "                       ArrayRef<unsigned> DefaultsOffset);\n";
   } else {
     OS << "  void convertToMCInst(unsigned Kind, MCInst &Inst, "
        << "unsigned Opcode,\n"
@@ -3386,16 +3364,12 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
   // Generate the function that remaps for mnemonic aliases.
   bool HasMnemonicAliases = emitMnemonicAliases(OS, Info, Target);
 
-  size_t MaxNumOperands = 0;
-  for (const auto &MI : Info.Matchables)
-    MaxNumOperands = std::max(MaxNumOperands, MI->AsmOperands.size());
-
   // Generate the convertToMCInst function to convert operands into an MCInst.
   // Also, generate the convertToMapAndConstraints function for MS-style inline
   // assembly.  The latter doesn't actually generate a MCInst.
   unsigned NumConverters =
       emitConvertFuncs(Target, ClassName, Info.Matchables, HasMnemonicFirst,
-                       HasOptionalOperands, MaxNumOperands, OS);
+                       HasOptionalOperands, OS);
 
   // Emit the enumeration for classes which participate in matching.
   emitMatchClassEnumeration(Target, Info.Classes, OS);
@@ -3424,14 +3398,15 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
       Info.SubtargetFeatures, OS);
 
   if (!ReportMultipleNearMisses)
-    emitAsmTiedOperandConstraints(Target, Info, OS, HasOptionalOperands,
-                                  MaxNumOperands);
+    emitAsmTiedOperandConstraints(Target, Info, OS, HasOptionalOperands);
 
   StringToOffsetTable StringTable;
 
+  size_t MaxNumOperands = 0;
   unsigned MaxMnemonicIndex = 0;
   bool HasDeprecation = false;
   for (const auto &MI : Info.Matchables) {
+    MaxNumOperands = std::max(MaxNumOperands, MI->AsmOperands.size());
     HasDeprecation |= MI->HasDeprecation;
 
     // Store a pascal-style length byte in the mnemonic.
@@ -3946,13 +3921,25 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
     OS << "    }\n\n";
   }
 
+  if (HasOptionalOperands) {
+    OS << "    unsigned DefaultsOffset[" << (MaxNumOperands + 1)
+       << "] = { 0 };\n";
+    OS << "    assert(OptionalOperandsMask.size() == " << (MaxNumOperands)
+       << ");\n";
+    OS << "    for (unsigned i = 0, NumDefaults = 0; i < " << (MaxNumOperands)
+       << "; ++i) {\n";
+    OS << "      DefaultsOffset[i + 1] = NumDefaults;\n";
+    OS << "      NumDefaults += (OptionalOperandsMask[i] ? 1 : 0);\n";
+    OS << "    }\n\n";
+  }
+
   OS << "    if (matchingInlineAsm) {\n";
   OS << "      convertToMapAndConstraints(it->ConvertFn, Operands);\n";
   if (!ReportMultipleNearMisses) {
     if (HasOptionalOperands) {
       OS << "      if (!checkAsmTiedOperandConstraints(*this, it->ConvertFn, "
             "Operands,\n";
-      OS << "                                          OptionalOperandsMask, "
+      OS << "                                          DefaultsOffset, "
             "ErrorInfo))\n";
     } else {
       OS << "      if (!checkAsmTiedOperandConstraints(*this, it->ConvertFn, "
@@ -3968,7 +3955,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
      << "    // operands into the appropriate MCInst.\n";
   if (HasOptionalOperands) {
     OS << "    convertToMCInst(it->ConvertFn, Inst, it->Opcode, Operands,\n"
-       << "                    OptionalOperandsMask);\n";
+       << "                    OptionalOperandsMask, DefaultsOffset);\n";
   } else {
     OS << "    convertToMCInst(it->ConvertFn, Inst, it->Opcode, Operands);\n";
   }
@@ -4051,7 +4038,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
     if (HasOptionalOperands) {
       OS << "    if (!checkAsmTiedOperandConstraints(*this, it->ConvertFn, "
             "Operands,\n";
-      OS << "                                         OptionalOperandsMask, "
+      OS << "                                         DefaultsOffset, "
             "ErrorInfo))\n";
     } else {
       OS << "    if (!checkAsmTiedOperandConstraints(*this, it->ConvertFn, "



More information about the llvm-commits mailing list