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 "CodeGenInstruction.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
= AsmString
.substr(ModifierStart
, VarEnd
- ModifierStart
);
151 if (Modifier
.empty())
152 PrintFatalError(CGI
.TheDef
->getLoc(),
153 "Bad operand modifier name in '" +
154 CGI
.TheDef
->getName() + "'");
157 if (AsmString
[VarEnd
] != '}')
159 CGI
.TheDef
->getLoc(),
160 "Variable name beginning with '{' did not end with '}' in '" +
161 CGI
.TheDef
->getName() + "'");
164 if (VarName
.empty() && Modifier
.empty())
165 PrintFatalError(CGI
.TheDef
->getLoc(),
166 "Stray '$' in '" + CGI
.TheDef
->getName() +
167 "' asm string, maybe you want $$?");
169 if (VarName
.empty()) {
170 // Just a modifier, pass this into PrintSpecial.
171 Operands
.emplace_back("PrintSpecial", ~0U, Modifier
);
173 // Otherwise, normal operand.
174 unsigned OpNo
= CGI
.Operands
.getOperandNamed(VarName
);
175 CGIOperandList::OperandInfo OpInfo
= CGI
.Operands
[OpNo
];
177 unsigned MIOp
= OpInfo
.MIOperandNo
;
178 Operands
.emplace_back(OpInfo
.PrinterMethodName
, MIOp
, Modifier
,
179 AsmWriterOperand::isMachineInstrOperand
,
180 OpInfo
.OperandType
== "MCOI::OPERAND_PCREL");
182 LastEmitted
= VarEnd
;
186 Operands
.emplace_back("return;", AsmWriterOperand::isLiteralStatementOperand
);
189 /// MatchesAllButOneOp - If this instruction is exactly identical to the
190 /// specified instruction except for one differing operand, return the differing
191 /// operand number. If more than one operand mismatches, return ~1, otherwise
192 /// if the instructions are identical return ~0.
193 unsigned AsmWriterInst::MatchesAllButOneOp(const AsmWriterInst
&Other
)const{
194 if (Operands
.size() != Other
.Operands
.size()) return ~1;
196 unsigned MismatchOperand
= ~0U;
197 for (unsigned i
= 0, e
= Operands
.size(); i
!= e
; ++i
) {
198 if (Operands
[i
] != Other
.Operands
[i
]) {
199 if (MismatchOperand
!= ~0U) // Already have one mismatch?
204 return MismatchOperand
;