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