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