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
) {
22 return (C
>= 'a' && C
<= 'z') ||
23 (C
>= 'A' && C
<= 'Z') ||
24 (C
>= '0' && C
<= '9') ||
28 std::string
AsmWriterOperand::getCode(bool PassSubtarget
) const {
29 if (OperandType
== isLiteralTextOperand
) {
31 return "O << '" + Str
+ "';";
32 return "O << \"" + Str
+ "\";";
35 if (OperandType
== isLiteralStatementOperand
)
38 std::string Result
= Str
+ "(MI";
40 Result
+= ", " + utostr(MIOpNo
);
44 if (!MiModifier
.empty())
45 Result
+= ", \"" + MiModifier
+ '"';
49 /// ParseAsmString - Parse the specified Instruction's AsmString into this
52 AsmWriterInst::AsmWriterInst(const CodeGenInstruction
&CGI
, unsigned CGIIndex
,
54 : CGI(&CGI
), CGIIndex(CGIIndex
) {
56 // NOTE: Any extensions to this code need to be mirrored in the
57 // AsmPrinter::printInlineAsm code that executes as compile time (assuming
58 // that inline asm strings should also get the new feature)!
59 std::string AsmString
= CGI
.FlattenAsmStringVariants(CGI
.AsmString
, Variant
);
60 std::string::size_type LastEmitted
= 0;
61 while (LastEmitted
!= AsmString
.size()) {
62 std::string::size_type DollarPos
=
63 AsmString
.find_first_of("$\\", LastEmitted
);
64 if (DollarPos
== std::string::npos
) DollarPos
= AsmString
.size();
66 // Emit a constant string fragment.
67 if (DollarPos
!= LastEmitted
) {
68 for (; LastEmitted
!= DollarPos
; ++LastEmitted
)
69 switch (AsmString
[LastEmitted
]) {
71 AddLiteralString("\\n");
74 AddLiteralString("\\t");
77 AddLiteralString("\\\"");
80 AddLiteralString("\\\\");
83 AddLiteralString(std::string(1, AsmString
[LastEmitted
]));
86 } else if (AsmString
[DollarPos
] == '\\') {
87 if (DollarPos
+1 != AsmString
.size()) {
88 if (AsmString
[DollarPos
+1] == 'n') {
89 AddLiteralString("\\n");
90 } else if (AsmString
[DollarPos
+1] == 't') {
91 AddLiteralString("\\t");
92 } else if (std::string("${|}\\").find(AsmString
[DollarPos
+1])
93 != std::string::npos
) {
94 AddLiteralString(std::string(1, AsmString
[DollarPos
+1]));
98 "Non-supported escaped character found in instruction '" +
99 CGI
.TheDef
->getName() + "'!");
101 LastEmitted
= DollarPos
+2;
104 } else if (DollarPos
+1 != AsmString
.size() &&
105 AsmString
[DollarPos
+1] == '$') {
106 AddLiteralString("$"); // "$$" -> $
107 LastEmitted
= DollarPos
+2;
109 // Get the name of the variable.
110 std::string::size_type VarEnd
= DollarPos
+1;
112 // handle ${foo}bar as $foo by detecting whether the character following
113 // the dollar sign is a curly brace. If so, advance VarEnd and DollarPos
114 // so the variable name does not contain the leading curly brace.
115 bool hasCurlyBraces
= false;
116 if (VarEnd
< AsmString
.size() && '{' == AsmString
[VarEnd
]) {
117 hasCurlyBraces
= true;
122 while (VarEnd
< AsmString
.size() && isIdentChar(AsmString
[VarEnd
]))
124 StringRef
VarName(AsmString
.data()+DollarPos
+1, VarEnd
-DollarPos
-1);
126 // Modifier - Support ${foo:modifier} syntax, where "modifier" is passed
127 // into printOperand. Also support ${:feature}, which is passed into
129 std::string Modifier
;
131 // In order to avoid starting the next string at the terminating curly
132 // brace, advance the end position past it if we found an opening curly
134 if (hasCurlyBraces
) {
135 if (VarEnd
>= AsmString
.size())
137 CGI
.TheDef
->getLoc(),
138 "Reached end of string before terminating curly brace in '" +
139 CGI
.TheDef
->getName() + "'");
141 // Look for a modifier string.
142 if (AsmString
[VarEnd
] == ':') {
144 if (VarEnd
>= AsmString
.size())
146 CGI
.TheDef
->getLoc(),
147 "Reached end of string before terminating curly brace in '" +
148 CGI
.TheDef
->getName() + "'");
150 std::string::size_type ModifierStart
= VarEnd
;
151 while (VarEnd
< AsmString
.size() && isIdentChar(AsmString
[VarEnd
]))
153 Modifier
= std::string(AsmString
.begin()+ModifierStart
,
154 AsmString
.begin()+VarEnd
);
155 if (Modifier
.empty())
156 PrintFatalError(CGI
.TheDef
->getLoc(),
157 "Bad operand modifier name in '" +
158 CGI
.TheDef
->getName() + "'");
161 if (AsmString
[VarEnd
] != '}')
163 CGI
.TheDef
->getLoc(),
164 "Variable name beginning with '{' did not end with '}' in '" +
165 CGI
.TheDef
->getName() + "'");
168 if (VarName
.empty() && Modifier
.empty())
169 PrintFatalError(CGI
.TheDef
->getLoc(),
170 "Stray '$' in '" + CGI
.TheDef
->getName() +
171 "' asm string, maybe you want $$?");
173 if (VarName
.empty()) {
174 // Just a modifier, pass this into PrintSpecial.
175 Operands
.emplace_back("PrintSpecial", ~0U, Modifier
);
177 // Otherwise, normal operand.
178 unsigned OpNo
= CGI
.Operands
.getOperandNamed(VarName
);
179 CGIOperandList::OperandInfo OpInfo
= CGI
.Operands
[OpNo
];
181 unsigned MIOp
= OpInfo
.MIOperandNo
;
182 Operands
.emplace_back(OpInfo
.PrinterMethodName
, MIOp
, Modifier
);
184 LastEmitted
= VarEnd
;
188 Operands
.emplace_back("return;", AsmWriterOperand::isLiteralStatementOperand
);
191 /// MatchesAllButOneOp - If this instruction is exactly identical to the
192 /// specified instruction except for one differing operand, return the differing
193 /// operand number. If more than one operand mismatches, return ~1, otherwise
194 /// if the instructions are identical return ~0.
195 unsigned AsmWriterInst::MatchesAllButOneOp(const AsmWriterInst
&Other
)const{
196 if (Operands
.size() != Other
.Operands
.size()) return ~1;
198 unsigned MismatchOperand
= ~0U;
199 for (unsigned i
= 0, e
= Operands
.size(); i
!= e
; ++i
) {
200 if (Operands
[i
] != Other
.Operands
[i
]) {
201 if (MismatchOperand
!= ~0U) // Already have one mismatch?
206 return MismatchOperand
;