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