xref: /llvm-project/llvm/utils/TableGen/Common/AsmWriterInst.cpp (revision fa3d789df15bd1f58fb8ba4ea3be909218cf7f03)
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