1 //===- AsmWriterInst.h - Classes encapsulating a printable inst -----------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // These classes implement a parser for assembly strings.
11 //===----------------------------------------------------------------------===//
13 #include "AsmWriterInst.h"
14 #include "CodeGenTarget.h"
15 #include "llvm/ADT/StringExtras.h"
16 #include "llvm/TableGen/Error.h"
17 #include "llvm/TableGen/Record.h"
21 static bool isIdentChar(char C
) { return isAlnum(C
) || C
== '_'; }
23 std::string
AsmWriterOperand::getCode(bool PassSubtarget
) const {
24 if (OperandType
== isLiteralTextOperand
) {
26 return "O << '" + Str
+ "';";
27 return "O << \"" + Str
+ "\";";
30 if (OperandType
== isLiteralStatementOperand
)
33 std::string Result
= Str
+ "(MI";
35 Result
+= ", Address";
37 Result
+= ", " + utostr(MIOpNo
);
41 if (!MiModifier
.empty())
42 Result
+= ", \"" + MiModifier
+ '"';
46 /// ParseAsmString - Parse the specified Instruction's AsmString into this
49 AsmWriterInst::AsmWriterInst(const CodeGenInstruction
&CGI
, unsigned CGIIndex
,
51 : CGI(&CGI
), CGIIndex(CGIIndex
) {
53 // NOTE: Any extensions to this code need to be mirrored in the
54 // AsmPrinter::printInlineAsm code that executes as compile time (assuming
55 // that inline asm strings should also get the new feature)!
56 std::string AsmString
= CGI
.FlattenAsmStringVariants(CGI
.AsmString
, Variant
);
57 std::string::size_type LastEmitted
= 0;
58 while (LastEmitted
!= AsmString
.size()) {
59 std::string::size_type DollarPos
=
60 AsmString
.find_first_of("$\\", LastEmitted
);
61 if (DollarPos
== std::string::npos
) DollarPos
= AsmString
.size();
63 // Emit a constant string fragment.
64 if (DollarPos
!= LastEmitted
) {
65 for (; LastEmitted
!= DollarPos
; ++LastEmitted
)
66 switch (AsmString
[LastEmitted
]) {
68 AddLiteralString("\\n");
71 AddLiteralString("\\t");
74 AddLiteralString("\\\"");
77 AddLiteralString("\\\\");
80 AddLiteralString(std::string(1, AsmString
[LastEmitted
]));
83 } else if (AsmString
[DollarPos
] == '\\') {
84 if (DollarPos
+1 != AsmString
.size()) {
85 if (AsmString
[DollarPos
+1] == 'n') {
86 AddLiteralString("\\n");
87 } else if (AsmString
[DollarPos
+1] == 't') {
88 AddLiteralString("\\t");
89 } else if (std::string("${|}\\").find(AsmString
[DollarPos
+1])
90 != std::string::npos
) {
91 AddLiteralString(std::string(1, AsmString
[DollarPos
+1]));
95 "Non-supported escaped character found in instruction '" +
96 CGI
.TheDef
->getName() + "'!");
98 LastEmitted
= DollarPos
+2;
101 } else if (DollarPos
+1 != AsmString
.size() &&
102 AsmString
[DollarPos
+1] == '$') {
103 AddLiteralString("$"); // "$$" -> $
104 LastEmitted
= DollarPos
+2;
106 // Get the name of the variable.
107 std::string::size_type VarEnd
= DollarPos
+1;
109 // handle ${foo}bar as $foo by detecting whether the character following
110 // the dollar sign is a curly brace. If so, advance VarEnd and DollarPos
111 // so the variable name does not contain the leading curly brace.
112 bool hasCurlyBraces
= false;
113 if (VarEnd
< AsmString
.size() && '{' == AsmString
[VarEnd
]) {
114 hasCurlyBraces
= true;
119 while (VarEnd
< AsmString
.size() && isIdentChar(AsmString
[VarEnd
]))
121 StringRef
VarName(AsmString
.data()+DollarPos
+1, VarEnd
-DollarPos
-1);
123 // Modifier - Support ${foo:modifier} syntax, where "modifier" is passed
124 // into printOperand. Also support ${:feature}, which is passed into
126 std::string Modifier
;
128 // In order to avoid starting the next string at the terminating curly
129 // brace, advance the end position past it if we found an opening curly
131 if (hasCurlyBraces
) {
132 if (VarEnd
>= AsmString
.size())
134 CGI
.TheDef
->getLoc(),
135 "Reached end of string before terminating curly brace in '" +
136 CGI
.TheDef
->getName() + "'");
138 // Look for a modifier string.
139 if (AsmString
[VarEnd
] == ':') {
141 if (VarEnd
>= AsmString
.size())
143 CGI
.TheDef
->getLoc(),
144 "Reached end of string before terminating curly brace in '" +
145 CGI
.TheDef
->getName() + "'");
147 std::string::size_type ModifierStart
= VarEnd
;
148 while (VarEnd
< AsmString
.size() && isIdentChar(AsmString
[VarEnd
]))
150 Modifier
= std::string(AsmString
.begin()+ModifierStart
,
151 AsmString
.begin()+VarEnd
);
152 if (Modifier
.empty())
153 PrintFatalError(CGI
.TheDef
->getLoc(),
154 "Bad operand modifier name in '" +
155 CGI
.TheDef
->getName() + "'");
158 if (AsmString
[VarEnd
] != '}')
160 CGI
.TheDef
->getLoc(),
161 "Variable name beginning with '{' did not end with '}' in '" +
162 CGI
.TheDef
->getName() + "'");
165 if (VarName
.empty() && Modifier
.empty())
166 PrintFatalError(CGI
.TheDef
->getLoc(),
167 "Stray '$' in '" + CGI
.TheDef
->getName() +
168 "' asm string, maybe you want $$?");
170 if (VarName
.empty()) {
171 // Just a modifier, pass this into PrintSpecial.
172 Operands
.emplace_back("PrintSpecial", ~0U, Modifier
);
174 // Otherwise, normal operand.
175 unsigned OpNo
= CGI
.Operands
.getOperandNamed(VarName
);
176 CGIOperandList::OperandInfo OpInfo
= CGI
.Operands
[OpNo
];
178 unsigned MIOp
= OpInfo
.MIOperandNo
;
179 Operands
.emplace_back(OpInfo
.PrinterMethodName
, MIOp
, Modifier
,
180 AsmWriterOperand::isMachineInstrOperand
,
181 OpInfo
.OperandType
== "MCOI::OPERAND_PCREL");
183 LastEmitted
= VarEnd
;
187 Operands
.emplace_back("return;", AsmWriterOperand::isLiteralStatementOperand
);
190 /// MatchesAllButOneOp - If this instruction is exactly identical to the
191 /// specified instruction except for one differing operand, return the differing
192 /// operand number. If more than one operand mismatches, return ~1, otherwise
193 /// if the instructions are identical return ~0.
194 unsigned AsmWriterInst::MatchesAllButOneOp(const AsmWriterInst
&Other
)const{
195 if (Operands
.size() != Other
.Operands
.size()) return ~1;
197 unsigned MismatchOperand
= ~0U;
198 for (unsigned i
= 0, e
= Operands
.size(); i
!= e
; ++i
) {
199 if (Operands
[i
] != Other
.Operands
[i
]) {
200 if (MismatchOperand
!= ~0U) // Already have one mismatch?
205 return MismatchOperand
;