Path: blob/main/contrib/llvm-project/llvm/utils/TableGen/Common/AsmWriterInst.cpp
35290 views
//===- AsmWriterInst.h - Classes encapsulating a printable inst -----------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// These classes implement a parser for assembly strings.9//10//===----------------------------------------------------------------------===//1112#include "AsmWriterInst.h"13#include "CodeGenInstruction.h"14#include "llvm/ADT/StringExtras.h"15#include "llvm/TableGen/Error.h"16#include "llvm/TableGen/Record.h"1718using namespace llvm;1920static bool isIdentChar(char C) { return isAlnum(C) || C == '_'; }2122std::string AsmWriterOperand::getCode(bool PassSubtarget) const {23if (OperandType == isLiteralTextOperand) {24if (Str.size() == 1)25return "O << '" + Str + "';";26return "O << \"" + Str + "\";";27}2829if (OperandType == isLiteralStatementOperand)30return Str;3132std::string Result = Str + "(MI";33if (PCRel)34Result += ", Address";35if (MIOpNo != ~0U)36Result += ", " + utostr(MIOpNo);37if (PassSubtarget)38Result += ", STI";39Result += ", O";40if (!MiModifier.empty())41Result += ", \"" + MiModifier + '"';42return Result + ");";43}4445/// ParseAsmString - Parse the specified Instruction's AsmString into this46/// AsmWriterInst.47///48AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, unsigned CGIIndex,49unsigned Variant)50: CGI(&CGI), CGIIndex(CGIIndex) {5152// NOTE: Any extensions to this code need to be mirrored in the53// AsmPrinter::printInlineAsm code that executes as compile time (assuming54// that inline asm strings should also get the new feature)!55std::string AsmString = CGI.FlattenAsmStringVariants(CGI.AsmString, Variant);56std::string::size_type LastEmitted = 0;57while (LastEmitted != AsmString.size()) {58std::string::size_type DollarPos =59AsmString.find_first_of("$\\", LastEmitted);60if (DollarPos == std::string::npos)61DollarPos = AsmString.size();6263// Emit a constant string fragment.64if (DollarPos != LastEmitted) {65for (; LastEmitted != DollarPos; ++LastEmitted)66switch (AsmString[LastEmitted]) {67case '\n':68AddLiteralString("\\n");69break;70case '\t':71AddLiteralString("\\t");72break;73case '"':74AddLiteralString("\\\"");75break;76case '\\':77AddLiteralString("\\\\");78break;79default:80AddLiteralString(std::string(1, AsmString[LastEmitted]));81break;82}83} else if (AsmString[DollarPos] == '\\') {84if (DollarPos + 1 != AsmString.size()) {85if (AsmString[DollarPos + 1] == 'n') {86AddLiteralString("\\n");87} else if (AsmString[DollarPos + 1] == 't') {88AddLiteralString("\\t");89} else if (std::string("${|}\\").find(AsmString[DollarPos + 1]) !=90std::string::npos) {91AddLiteralString(std::string(1, AsmString[DollarPos + 1]));92} else {93PrintFatalError(94CGI.TheDef->getLoc(),95"Non-supported escaped character found in instruction '" +96CGI.TheDef->getName() + "'!");97}98LastEmitted = DollarPos + 2;99continue;100}101} else if (DollarPos + 1 != AsmString.size() &&102AsmString[DollarPos + 1] == '$') {103AddLiteralString("$"); // "$$" -> $104LastEmitted = DollarPos + 2;105} else {106// Get the name of the variable.107std::string::size_type VarEnd = DollarPos + 1;108109// handle ${foo}bar as $foo by detecting whether the character following110// the dollar sign is a curly brace. If so, advance VarEnd and DollarPos111// so the variable name does not contain the leading curly brace.112bool hasCurlyBraces = false;113if (VarEnd < AsmString.size() && '{' == AsmString[VarEnd]) {114hasCurlyBraces = true;115++DollarPos;116++VarEnd;117}118119while (VarEnd < AsmString.size() && isIdentChar(AsmString[VarEnd]))120++VarEnd;121StringRef VarName(AsmString.data() + DollarPos + 1,122VarEnd - DollarPos - 1);123124// Modifier - Support ${foo:modifier} syntax, where "modifier" is passed125// into printOperand. Also support ${:feature}, which is passed into126// PrintSpecial.127std::string Modifier;128129// In order to avoid starting the next string at the terminating curly130// brace, advance the end position past it if we found an opening curly131// brace.132if (hasCurlyBraces) {133if (VarEnd >= AsmString.size())134PrintFatalError(135CGI.TheDef->getLoc(),136"Reached end of string before terminating curly brace in '" +137CGI.TheDef->getName() + "'");138139// Look for a modifier string.140if (AsmString[VarEnd] == ':') {141++VarEnd;142if (VarEnd >= AsmString.size())143PrintFatalError(144CGI.TheDef->getLoc(),145"Reached end of string before terminating curly brace in '" +146CGI.TheDef->getName() + "'");147148std::string::size_type ModifierStart = VarEnd;149while (VarEnd < AsmString.size() && isIdentChar(AsmString[VarEnd]))150++VarEnd;151Modifier = AsmString.substr(ModifierStart, VarEnd - ModifierStart);152if (Modifier.empty())153PrintFatalError(CGI.TheDef->getLoc(),154"Bad operand modifier name in '" +155CGI.TheDef->getName() + "'");156}157158if (AsmString[VarEnd] != '}')159PrintFatalError(160CGI.TheDef->getLoc(),161"Variable name beginning with '{' did not end with '}' in '" +162CGI.TheDef->getName() + "'");163++VarEnd;164}165if (VarName.empty() && Modifier.empty())166PrintFatalError(CGI.TheDef->getLoc(),167"Stray '$' in '" + CGI.TheDef->getName() +168"' asm string, maybe you want $$?");169170if (VarName.empty()) {171// Just a modifier, pass this into PrintSpecial.172Operands.emplace_back("PrintSpecial", ~0U, Modifier);173} else {174// Otherwise, normal operand.175unsigned OpNo = CGI.Operands.getOperandNamed(VarName);176CGIOperandList::OperandInfo OpInfo = CGI.Operands[OpNo];177178unsigned MIOp = OpInfo.MIOperandNo;179Operands.emplace_back(OpInfo.PrinterMethodName, MIOp, Modifier,180AsmWriterOperand::isMachineInstrOperand,181OpInfo.OperandType == "MCOI::OPERAND_PCREL");182}183LastEmitted = VarEnd;184}185}186187Operands.emplace_back("return;", AsmWriterOperand::isLiteralStatementOperand);188}189190/// MatchesAllButOneOp - If this instruction is exactly identical to the191/// specified instruction except for one differing operand, return the differing192/// operand number. If more than one operand mismatches, return ~1, otherwise193/// if the instructions are identical return ~0.194unsigned AsmWriterInst::MatchesAllButOneOp(const AsmWriterInst &Other) const {195if (Operands.size() != Other.Operands.size())196return ~1;197198unsigned MismatchOperand = ~0U;199for (unsigned i = 0, e = Operands.size(); i != e; ++i) {200if (Operands[i] != Other.Operands[i]) {201if (MismatchOperand != ~0U) // Already have one mismatch?202return ~1U;203MismatchOperand = i;204}205}206return MismatchOperand;207}208209210