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