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