| //===- 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 "CodeGenInstruction.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 isAlnum(C) || 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 (PCRel) | 
 |     Result += ", Address"; | 
 |   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 = AsmString.substr(ModifierStart, VarEnd - ModifierStart); | 
 |           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, | 
 |                               AsmWriterOperand::isMachineInstrOperand, | 
 |                               OpInfo.OperandType == "MCOI::OPERAND_PCREL"); | 
 |       } | 
 |       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; | 
 | } |