diff options
Diffstat (limited to 'llvm/utils/TableGen/AsmWriterInst.cpp')
| -rw-r--r-- | llvm/utils/TableGen/AsmWriterInst.cpp | 207 | 
1 files changed, 207 insertions, 0 deletions
| diff --git a/llvm/utils/TableGen/AsmWriterInst.cpp b/llvm/utils/TableGen/AsmWriterInst.cpp new file mode 100644 index 000000000000..c26e0e421183 --- /dev/null +++ b/llvm/utils/TableGen/AsmWriterInst.cpp @@ -0,0 +1,207 @@ +//===- AsmWriterInst.h - Classes encapsulating a printable inst -----------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// These classes implement a parser for assembly strings. +// +//===----------------------------------------------------------------------===// + +#include "AsmWriterInst.h" +#include "CodeGenTarget.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Record.h" + +using namespace llvm; + +static bool isIdentChar(char C) { +  return (C >= 'a' && C <= 'z') || +  (C >= 'A' && C <= 'Z') || +  (C >= '0' && C <= '9') || +  C == '_'; +} + +std::string AsmWriterOperand::getCode(bool PassSubtarget) const { +  if (OperandType == isLiteralTextOperand) { +    if (Str.size() == 1) +      return "O << '" + Str + "';"; +    return "O << \"" + Str + "\";"; +  } + +  if (OperandType == isLiteralStatementOperand) +    return Str; + +  std::string Result = Str + "(MI"; +  if (MIOpNo != ~0U) +    Result += ", " + utostr(MIOpNo); +  if (PassSubtarget) +    Result += ", STI"; +  Result += ", O"; +  if (!MiModifier.empty()) +    Result += ", \"" + MiModifier + '"'; +  return Result + ");"; +} + +/// ParseAsmString - Parse the specified Instruction's AsmString into this +/// AsmWriterInst. +/// +AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, unsigned CGIIndex, +                             unsigned Variant) +    : CGI(&CGI), CGIIndex(CGIIndex) { + +  // NOTE: Any extensions to this code need to be mirrored in the +  // AsmPrinter::printInlineAsm code that executes as compile time (assuming +  // that inline asm strings should also get the new feature)! +  std::string AsmString = CGI.FlattenAsmStringVariants(CGI.AsmString, Variant); +  std::string::size_type LastEmitted = 0; +  while (LastEmitted != AsmString.size()) { +    std::string::size_type DollarPos = +      AsmString.find_first_of("$\\", LastEmitted); +    if (DollarPos == std::string::npos) DollarPos = AsmString.size(); + +    // Emit a constant string fragment. +    if (DollarPos != LastEmitted) { +      for (; LastEmitted != DollarPos; ++LastEmitted) +        switch (AsmString[LastEmitted]) { +          case '\n': +            AddLiteralString("\\n"); +            break; +          case '\t': +            AddLiteralString("\\t"); +            break; +          case '"': +            AddLiteralString("\\\""); +            break; +          case '\\': +            AddLiteralString("\\\\"); +            break; +          default: +            AddLiteralString(std::string(1, AsmString[LastEmitted])); +            break; +        } +    } else if (AsmString[DollarPos] == '\\') { +      if (DollarPos+1 != AsmString.size()) { +        if (AsmString[DollarPos+1] == 'n') { +          AddLiteralString("\\n"); +        } else if (AsmString[DollarPos+1] == 't') { +          AddLiteralString("\\t"); +        } else if (std::string("${|}\\").find(AsmString[DollarPos+1]) +                   != std::string::npos) { +          AddLiteralString(std::string(1, AsmString[DollarPos+1])); +        } else { +          PrintFatalError( +              CGI.TheDef->getLoc(), +              "Non-supported escaped character found in instruction '" + +                  CGI.TheDef->getName() + "'!"); +        } +        LastEmitted = DollarPos+2; +        continue; +      } +    } else if (DollarPos+1 != AsmString.size() && +               AsmString[DollarPos+1] == '$') { +      AddLiteralString("$");  // "$$" -> $ +      LastEmitted = DollarPos+2; +    } else { +      // Get the name of the variable. +      std::string::size_type VarEnd = DollarPos+1; + +      // handle ${foo}bar as $foo by detecting whether the character following +      // the dollar sign is a curly brace.  If so, advance VarEnd and DollarPos +      // so the variable name does not contain the leading curly brace. +      bool hasCurlyBraces = false; +      if (VarEnd < AsmString.size() && '{' == AsmString[VarEnd]) { +        hasCurlyBraces = true; +        ++DollarPos; +        ++VarEnd; +      } + +      while (VarEnd < AsmString.size() && isIdentChar(AsmString[VarEnd])) +        ++VarEnd; +      StringRef VarName(AsmString.data()+DollarPos+1, VarEnd-DollarPos-1); + +      // Modifier - Support ${foo:modifier} syntax, where "modifier" is passed +      // into printOperand.  Also support ${:feature}, which is passed into +      // PrintSpecial. +      std::string Modifier; + +      // In order to avoid starting the next string at the terminating curly +      // brace, advance the end position past it if we found an opening curly +      // brace. +      if (hasCurlyBraces) { +        if (VarEnd >= AsmString.size()) +          PrintFatalError( +              CGI.TheDef->getLoc(), +              "Reached end of string before terminating curly brace in '" + +                  CGI.TheDef->getName() + "'"); + +        // Look for a modifier string. +        if (AsmString[VarEnd] == ':') { +          ++VarEnd; +          if (VarEnd >= AsmString.size()) +            PrintFatalError( +                CGI.TheDef->getLoc(), +                "Reached end of string before terminating curly brace in '" + +                    CGI.TheDef->getName() + "'"); + +          std::string::size_type ModifierStart = VarEnd; +          while (VarEnd < AsmString.size() && isIdentChar(AsmString[VarEnd])) +            ++VarEnd; +          Modifier = std::string(AsmString.begin()+ModifierStart, +                                 AsmString.begin()+VarEnd); +          if (Modifier.empty()) +            PrintFatalError(CGI.TheDef->getLoc(), +                            "Bad operand modifier name in '" + +                                CGI.TheDef->getName() + "'"); +        } + +        if (AsmString[VarEnd] != '}') +          PrintFatalError( +              CGI.TheDef->getLoc(), +              "Variable name beginning with '{' did not end with '}' in '" + +                  CGI.TheDef->getName() + "'"); +        ++VarEnd; +      } +      if (VarName.empty() && Modifier.empty()) +        PrintFatalError(CGI.TheDef->getLoc(), +                        "Stray '$' in '" + CGI.TheDef->getName() + +                            "' asm string, maybe you want $$?"); + +      if (VarName.empty()) { +        // Just a modifier, pass this into PrintSpecial. +        Operands.emplace_back("PrintSpecial", ~0U, Modifier); +      } else { +        // Otherwise, normal operand. +        unsigned OpNo = CGI.Operands.getOperandNamed(VarName); +        CGIOperandList::OperandInfo OpInfo = CGI.Operands[OpNo]; + +        unsigned MIOp = OpInfo.MIOperandNo; +        Operands.emplace_back(OpInfo.PrinterMethodName, MIOp, Modifier); +      } +      LastEmitted = VarEnd; +    } +  } + +  Operands.emplace_back("return;", AsmWriterOperand::isLiteralStatementOperand); +} + +/// MatchesAllButOneOp - If this instruction is exactly identical to the +/// specified instruction except for one differing operand, return the differing +/// operand number.  If more than one operand mismatches, return ~1, otherwise +/// if the instructions are identical return ~0. +unsigned AsmWriterInst::MatchesAllButOneOp(const AsmWriterInst &Other)const{ +  if (Operands.size() != Other.Operands.size()) return ~1; + +  unsigned MismatchOperand = ~0U; +  for (unsigned i = 0, e = Operands.size(); i != e; ++i) { +    if (Operands[i] != Other.Operands[i]) { +      if (MismatchOperand != ~0U)  // Already have one mismatch? +        return ~1U; +      MismatchOperand = i; +    } +  } +  return MismatchOperand; +} | 
