209 lines · cpp
1//===- AsmWriterInst.h - Classes encapsulating a printable inst -----------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// These classes implement a parser for assembly strings.10//11//===----------------------------------------------------------------------===//12 13#include "AsmWriterInst.h"14#include "CodeGenInstruction.h"15#include "llvm/ADT/StringExtras.h"16#include "llvm/TableGen/Error.h"17#include "llvm/TableGen/Record.h"18 19using namespace llvm;20 21static bool isIdentChar(char C) { return isAlnum(C) || C == '_'; }22 23std::string AsmWriterOperand::getCode(bool PassSubtarget) const {24 if (OperandType == isLiteralTextOperand) {25 if (Str.size() == 1)26 return "O << '" + Str + "';";27 return "O << \"" + Str + "\";";28 }29 30 if (OperandType == isLiteralStatementOperand)31 return Str;32 33 std::string Result = Str + "(MI";34 if (PCRel)35 Result += ", Address";36 if (MIOpNo != ~0U)37 Result += ", " + utostr(MIOpNo);38 if (PassSubtarget)39 Result += ", STI";40 Result += ", O";41 if (!MiModifier.empty())42 Result += ", \"" + MiModifier + '"';43 return Result + ");";44}45 46/// ParseAsmString - Parse the specified Instruction's AsmString into this47/// AsmWriterInst.48///49AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, unsigned CGIIndex,50 unsigned Variant)51 : CGI(&CGI), CGIIndex(CGIIndex) {52 53 // NOTE: Any extensions to this code need to be mirrored in the54 // AsmPrinter::printInlineAsm code that executes as compile time (assuming55 // that inline asm strings should also get the new feature)!56 std::string AsmString = CGI.FlattenAsmStringVariants(CGI.AsmString, Variant);57 std::string::size_type LastEmitted = 0;58 while (LastEmitted != AsmString.size()) {59 std::string::size_type DollarPos =60 AsmString.find_first_of("$\\", LastEmitted);61 if (DollarPos == std::string::npos)62 DollarPos = AsmString.size();63 64 // Emit a constant string fragment.65 if (DollarPos != LastEmitted) {66 for (; LastEmitted != DollarPos; ++LastEmitted)67 switch (AsmString[LastEmitted]) {68 case '\n':69 AddLiteralString("\\n");70 break;71 case '\t':72 AddLiteralString("\\t");73 break;74 case '"':75 AddLiteralString("\\\"");76 break;77 case '\\':78 AddLiteralString("\\\\");79 break;80 default:81 AddLiteralString(std::string(1, AsmString[LastEmitted]));82 break;83 }84 } else if (AsmString[DollarPos] == '\\') {85 if (DollarPos + 1 != AsmString.size()) {86 if (AsmString[DollarPos + 1] == 'n') {87 AddLiteralString("\\n");88 } else if (AsmString[DollarPos + 1] == 't') {89 AddLiteralString("\\t");90 } else if (std::string("${|}\\").find(AsmString[DollarPos + 1]) !=91 std::string::npos) {92 AddLiteralString(std::string(1, AsmString[DollarPos + 1]));93 } else {94 PrintFatalError(95 CGI.TheDef->getLoc(),96 "Non-supported escaped character found in instruction '" +97 CGI.getName() + "'!");98 }99 LastEmitted = DollarPos + 2;100 continue;101 }102 } else if (DollarPos + 1 != AsmString.size() &&103 AsmString[DollarPos + 1] == '$') {104 AddLiteralString("$"); // "$$" -> $105 LastEmitted = DollarPos + 2;106 } else {107 // Get the name of the variable.108 std::string::size_type VarEnd = DollarPos + 1;109 110 // handle ${foo}bar as $foo by detecting whether the character following111 // the dollar sign is a curly brace. If so, advance VarEnd and DollarPos112 // so the variable name does not contain the leading curly brace.113 bool hasCurlyBraces = false;114 if (VarEnd < AsmString.size() && '{' == AsmString[VarEnd]) {115 hasCurlyBraces = true;116 ++DollarPos;117 ++VarEnd;118 }119 120 while (VarEnd < AsmString.size() && isIdentChar(AsmString[VarEnd]))121 ++VarEnd;122 StringRef VarName(AsmString.data() + DollarPos + 1,123 VarEnd - DollarPos - 1);124 125 // Modifier - Support ${foo:modifier} syntax, where "modifier" is passed126 // into printOperand. Also support ${:feature}, which is passed into127 // PrintSpecial.128 std::string Modifier;129 130 // In order to avoid starting the next string at the terminating curly131 // brace, advance the end position past it if we found an opening curly132 // brace.133 if (hasCurlyBraces) {134 if (VarEnd >= AsmString.size())135 PrintFatalError(136 CGI.TheDef->getLoc(),137 "Reached end of string before terminating curly brace in '" +138 CGI.getName() + "'");139 140 // Look for a modifier string.141 if (AsmString[VarEnd] == ':') {142 ++VarEnd;143 if (VarEnd >= AsmString.size())144 PrintFatalError(145 CGI.TheDef->getLoc(),146 "Reached end of string before terminating curly brace in '" +147 CGI.getName() + "'");148 149 std::string::size_type ModifierStart = VarEnd;150 while (VarEnd < AsmString.size() && isIdentChar(AsmString[VarEnd]))151 ++VarEnd;152 Modifier = AsmString.substr(ModifierStart, VarEnd - ModifierStart);153 if (Modifier.empty())154 PrintFatalError(CGI.TheDef->getLoc(),155 "Bad operand modifier name in '" + CGI.getName() +156 "'");157 }158 159 if (AsmString[VarEnd] != '}')160 PrintFatalError(161 CGI.TheDef->getLoc(),162 "Variable name beginning with '{' did not end with '}' in '" +163 CGI.getName() + "'");164 ++VarEnd;165 }166 if (VarName.empty() && Modifier.empty())167 PrintFatalError(CGI.TheDef->getLoc(),168 "Stray '$' in '" + CGI.getName() +169 "' asm string, maybe you want $$?");170 171 if (VarName.empty()) {172 // Just a modifier, pass this into PrintSpecial.173 Operands.emplace_back("PrintSpecial", ~0U, Modifier);174 } else {175 // Otherwise, normal operand.176 unsigned OpNo = CGI.Operands.getOperandNamed(VarName);177 CGIOperandList::OperandInfo OpInfo = CGI.Operands[OpNo];178 179 unsigned MIOp = OpInfo.MIOperandNo;180 Operands.emplace_back(OpInfo.PrinterMethodName.str(), MIOp, Modifier,181 AsmWriterOperand::isMachineInstrOperand,182 OpInfo.OperandType == "MCOI::OPERAND_PCREL");183 }184 LastEmitted = VarEnd;185 }186 }187 188 Operands.emplace_back("return;", AsmWriterOperand::isLiteralStatementOperand);189}190 191/// MatchesAllButOneOp - If this instruction is exactly identical to the192/// specified instruction except for one differing operand, return the differing193/// operand number. If more than one operand mismatches, return ~1, otherwise194/// if the instructions are identical return ~0.195unsigned AsmWriterInst::MatchesAllButOneOp(const AsmWriterInst &Other) const {196 if (Operands.size() != Other.Operands.size())197 return ~1;198 199 unsigned MismatchOperand = ~0U;200 for (unsigned i = 0, e = Operands.size(); i != e; ++i) {201 if (Operands[i] != Other.Operands[i]) {202 if (MismatchOperand != ~0U) // Already have one mismatch?203 return ~1U;204 MismatchOperand = i;205 }206 }207 return MismatchOperand;208}209