[llvm] r322166 - [TableGen][AsmMatcherEmitter] Generate assembler checks for tied operands

Sander de Smalen via llvm-commits llvm-commits at lists.llvm.org
Wed Jan 10 02:10:56 PST 2018


Author: s.desmalen
Date: Wed Jan 10 02:10:56 2018
New Revision: 322166

URL: http://llvm.org/viewvc/llvm-project?rev=322166&view=rev
Log:
[TableGen][AsmMatcherEmitter] Generate assembler checks for tied operands

Summary:
This extends TableGen's AsmMatcherEmitter with code that generates
a table with tied-operand constraints. The constraints are checked
when parsing the instruction. If an operand is not equal to its tied operand,
the assembler will give an error.

Patch [2/3] in a series to add operand constraint checks for SVE's predicated ADD/SUB.

Reviewers: olista01, rengolin, mcrosier, fhahn, craig.topper, evandro, echristo

Reviewed By: fhahn

Subscribers: javed.absar, llvm-commits

Differential Revision: https://reviews.llvm.org/D41446

Modified:
    llvm/trunk/include/llvm/MC/MCParser/MCTargetAsmParser.h
    llvm/trunk/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
    llvm/trunk/utils/TableGen/AsmMatcherEmitter.cpp

Modified: llvm/trunk/include/llvm/MC/MCParser/MCTargetAsmParser.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/MC/MCParser/MCTargetAsmParser.h?rev=322166&r1=322165&r2=322166&view=diff
==============================================================================
--- llvm/trunk/include/llvm/MC/MCParser/MCTargetAsmParser.h (original)
+++ llvm/trunk/include/llvm/MC/MCParser/MCTargetAsmParser.h Wed Jan 10 02:10:56 2018
@@ -271,6 +271,7 @@ class MCTargetAsmParser : public MCAsmPa
 public:
   enum MatchResultTy {
     Match_InvalidOperand,
+    Match_InvalidTiedOperand,
     Match_MissingFeature,
     Match_MnemonicFail,
     Match_Success,

Modified: llvm/trunk/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp?rev=322166&r1=322165&r2=322166&view=diff
==============================================================================
--- llvm/trunk/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp (original)
+++ llvm/trunk/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp Wed Jan 10 02:10:56 2018
@@ -3544,6 +3544,8 @@ static std::string AArch64MnemonicSpellC
 bool AArch64AsmParser::showMatchError(SMLoc Loc, unsigned ErrCode,
                                       OperandVector &Operands) {
   switch (ErrCode) {
+  case Match_InvalidTiedOperand:
+    return Error(Loc, "operand must match destination register");
   case Match_MissingFeature:
     return Error(Loc,
                  "instruction requires a CPU feature not currently enabled");
@@ -4063,6 +4065,7 @@ bool AArch64AsmParser::MatchAndEmitInstr
 
     return showMatchError(ErrorLoc, MatchResult, Operands);
   }
+  case Match_InvalidTiedOperand:
   case Match_InvalidMemoryIndexed1:
   case Match_InvalidMemoryIndexed2:
   case Match_InvalidMemoryIndexed4:

Modified: llvm/trunk/utils/TableGen/AsmMatcherEmitter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/AsmMatcherEmitter.cpp?rev=322166&r1=322165&r2=322166&view=diff
==============================================================================
--- llvm/trunk/utils/TableGen/AsmMatcherEmitter.cpp (original)
+++ llvm/trunk/utils/TableGen/AsmMatcherEmitter.cpp Wed Jan 10 02:10:56 2018
@@ -503,6 +503,20 @@ struct MatchableInfo {
   /// removed.
   SmallVector<AsmOperand, 8> AsmOperands;
 
+  /// AsmOperandEqualityConstraints - an array of pairs holding operand
+  /// constraints.
+  /// Each constraint is represented as a pair holding position of the token of
+  /// the operand asm name.
+  /// For example, an "AsmString" "add $Vd.s, $Vn.s, $Xn" would be
+  /// split in the following list of tokens:
+  ///
+  ///    ['add', '$Vd', '.s', '$Vn', '.s', '$Xn']
+  ///
+  /// A constraint "$Vd = $Vn" (e.g. for a destructive operation) is rendered
+  /// as the pair {1,3} into this set (note that tokens are numbered starting
+  /// from 0).
+  SmallVector<std::pair<unsigned,unsigned>, 1> AsmOperandTiedConstraints;
+
   /// Predicates - The required subtarget features to match this instruction.
   SmallVector<const SubtargetFeatureInfo *, 4> RequiredFeatures;
 
@@ -885,6 +899,22 @@ extractSingletonRegisterForAsmOperand(Ma
   // be some random non-register token, just ignore it.
 }
 
+static Optional<size_t>
+getAsmOperandIdx(const SmallVectorImpl<MatchableInfo::AsmOperand> &AsmOperands,
+                 std::string Name) {
+  const auto SymbolicName = std::string("$") + Name;
+  const auto Pos =
+      std::find_if(AsmOperands.begin(), AsmOperands.end(),
+                   [&SymbolicName](const MatchableInfo::AsmOperand &A) {
+        return A.Token == SymbolicName;
+      });
+
+  if (Pos == AsmOperands.end())
+    return Optional<size_t>();
+
+  return Optional<size_t>(std::distance(AsmOperands.begin(), Pos));
+}
+
 void MatchableInfo::initialize(const AsmMatcherInfo &Info,
                                SmallPtrSetImpl<Record*> &SingletonRegisters,
                                AsmVariantInfo const &Variant,
@@ -933,6 +963,37 @@ void MatchableInfo::initialize(const Asm
 
   HasDeprecation =
       DepMask ? !DepMask->getValue()->getAsUnquotedString().empty() : false;
+
+  // Do not generate tied operand info if the instruction does not
+  // use the default AsmMatchConverter.
+  if (TheDef->getValue("AsmMatchConverter") &&
+      !TheDef->getValueAsString("AsmMatchConverter").empty())
+    return;
+
+  // Generate tied operand contraints info.
+  const auto &CGIOperands = getResultInst()->Operands;
+  for (const auto &CGIOp : CGIOperands) {
+    int TiedReg = CGIOp.getTiedRegister();
+    if (TiedReg == -1)
+      continue;
+
+    Optional<size_t> LHSIdx = getAsmOperandIdx(AsmOperands, CGIOp.Name);
+    Optional<size_t> RHSIdx =
+        getAsmOperandIdx(AsmOperands, CGIOperands[TiedReg].Name);
+    // Skipping operands with constraint but no reference in the
+    // AsmString. No need to throw a warning, as it's normal to have
+    // a $dst operand in the outs dag that is constrained to a $src
+    // operand in the ins dag but that does not appear in the AsmString.
+    if (!LHSIdx || !RHSIdx)
+      continue;
+
+    // Add the constraint. Using min/max as we consider constraint
+    // pair {A,B} and {B,A} the same
+    size_t AddMnemonicIdx = HasMnemonicFirst;
+    AsmOperandTiedConstraints.emplace_back(
+        std::min(*LHSIdx, *RHSIdx) + AddMnemonicIdx,
+        std::max(*LHSIdx, *RHSIdx) + AddMnemonicIdx);
+  }
 }
 
 /// Append an AsmOperand for the given substring of AsmString.
@@ -2831,6 +2892,80 @@ static void emitCustomOperandParsing(raw
   OS << "}\n\n";
 }
 
+static void emitAsmTiedOperandConstraints(CodeGenTarget &Target,
+                                          AsmMatcherInfo &Info,
+                                          raw_ostream &OS) {
+  std::string Buf;
+  raw_string_ostream TmpOS(Buf);
+  TmpOS << "namespace {\n";
+  TmpOS << "  struct TiedAsmOpndPair {\n";
+  TmpOS << "    unsigned Opcode;\n";
+  TmpOS << "    unsigned Opnd1;\n";
+  TmpOS << "    unsigned Opnd2;\n";
+  TmpOS << "    TiedAsmOpndPair(unsigned Opcode, unsigned Opnd1, unsigned "
+           "Opnd2)\n";
+  TmpOS << "      : Opcode(Opcode), Opnd1(Opnd1), Opnd2(Opnd2) {}\n";
+  TmpOS << "  };\n";
+  TmpOS << "} // end anonymous namespace\n\n";
+  TmpOS << "static const TiedAsmOpndPair TiedAsmOperandsTable[] = {\n";
+  bool TableEmpty = true;
+  for (const auto &Inst : Target.getInstructionsByEnumValue()) {
+    auto It = std::find_if(Info.Matchables.begin(), Info.Matchables.end(),
+                           [&Inst](const std::unique_ptr<MatchableInfo> &MI) {
+      return (MI->TheDef->getID() == Inst->TheDef->getID());
+    });
+
+    if (It == Info.Matchables.end())
+      continue;
+
+    auto &Constraints = (**It).AsmOperandTiedConstraints;
+    if (Constraints.empty())
+      continue;
+
+    std::string Namespace = Inst->TheDef->getValueAsString("Namespace");
+
+    for (const auto &C : Constraints) {
+      TableEmpty = false;
+      TmpOS << "  {";
+      TmpOS << Namespace << "::"<< (**It).TheDef->getName() << ", ";
+      TmpOS << C.first << ", " << C.second;
+      TmpOS << "},\n";
+    }
+  }
+  TmpOS << "};\n\n";
+  if (!TableEmpty)
+    OS << TmpOS.str();
+
+  OS << "static bool ";
+  OS << "checkAsmTiedOperandConstraints(const MCInst &Inst,\n";
+  OS << "                               const OperandVector &Operands,\n";
+  OS << "                               SMLoc &Loc) {\n";
+
+  if (TableEmpty) {
+    OS << "return true;\n}\n\n";
+    return;
+  }
+
+  OS << "  const TiedAsmOpndPair SearchValue(Inst.getOpcode(), 0, 0);\n";
+  OS << "  const auto Range = std::equal_range(\n";
+  OS << "      std::begin(TiedAsmOperandsTable), std::end(TiedAsmOperandsTable),\n";
+  OS << "      SearchValue, [](const TiedAsmOpndPair &a,\n";
+  OS << "                      const TiedAsmOpndPair &b) {\n";
+  OS << "        return (a.Opcode < b.Opcode);\n";
+  OS << "      });\n\n";
+  OS << "  for (auto Item = Range.first;  Item != Range.second; ++Item) {\n";
+  OS << "    MCParsedAsmOperand &Op1 = *Operands[Item->Opnd1];\n";
+  OS << "    MCParsedAsmOperand &Op2 = *Operands[Item->Opnd2];\n";
+  OS << "    if ((Op1.isReg() && Op2.isReg()) &&\n";
+  OS << "        (Op1.getReg() != Op2.getReg())) {\n";
+  OS << "      Loc = Op2.getStartLoc();\n";
+  OS << "      return false;\n";
+  OS << "    }\n";
+  OS << "  }\n";
+  OS << "  return true;\n";
+  OS << "}\n\n";
+}
+
 static void emitMnemonicSpellChecker(raw_ostream &OS, CodeGenTarget &Target,
                                      unsigned VariantCount) {
   OS << "static std::string " << Target.getName()
@@ -3078,6 +3213,9 @@ void AsmMatcherEmitter::run(raw_ostream
       Info.Target.getName(), ClassName, "ComputeAvailableFeatures",
       Info.SubtargetFeatures, OS);
 
+  if (!ReportMultipleNearMisses)
+    emitAsmTiedOperandConstraints(Target, Info, OS);
+
   StringToOffsetTable StringTable;
 
   size_t MaxNumOperands = 0;
@@ -3501,6 +3639,14 @@ void AsmMatcherEmitter::run(raw_ostream
 
   OS << "    if (matchingInlineAsm) {\n";
   OS << "      convertToMapAndConstraints(it->ConvertFn, Operands);\n";
+  if (!ReportMultipleNearMisses) {
+    OS << "      SMLoc Loc;\n";
+    OS << "      if (!checkAsmTiedOperandConstraints(Inst, Operands, Loc)) {\n";
+    OS << "        ErrorInfo = " << (HasMnemonicFirst ? "1" : "SIndex") << ";\n";
+    OS << "        return Match_InvalidTiedOperand;\n";
+    OS << "      }\n";
+    OS << "\n";
+  }
   OS << "      return Match_Success;\n";
   OS << "    }\n\n";
   OS << "    // We have selected a definite instruction, convert the parsed\n"
@@ -3575,6 +3721,15 @@ void AsmMatcherEmitter::run(raw_ostream
     OS << "    }\n";
   }
 
+  if (!ReportMultipleNearMisses) {
+    OS << "      SMLoc Loc;\n";
+    OS << "      if (!checkAsmTiedOperandConstraints(Inst, Operands, Loc)) {\n";
+    OS << "        ErrorInfo = " << (HasMnemonicFirst ? "1" : "SIndex") << ";\n";
+    OS << "        return Match_InvalidTiedOperand;\n";
+    OS << "      }\n";
+    OS << "\n";
+  }
+
   OS << "    DEBUG_WITH_TYPE(\n";
   OS << "        \"asm-matcher\",\n";
   OS << "        dbgs() << \"Opcode result: complete match, selecting this opcode\\n\");\n";




More information about the llvm-commits mailing list