1 //===- AsmWriterInst.h - Classes encapsulating a printable inst -----------===// 2 // 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 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // These classes implement a parser for assembly strings. 10 // 11 //===----------------------------------------------------------------------===// 12 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" 18 19 using namespace llvm; 20 21 static bool isIdentChar(char C) { return isAlnum(C) || C == '_'; } 22 23 std::string AsmWriterOperand::getCode(bool PassSubtarget) const { 24 if (OperandType == isLiteralTextOperand) { 25 if (Str.size() == 1) 26 return "O << '" + Str + "';"; 27 return "O << \"" + Str + "\";"; 28 } 29 30 if (OperandType == isLiteralStatementOperand) 31 return Str; 32 33 std::string Result = Str + "(MI"; 34 if (PCRel) 35 Result += ", Address"; 36 if (MIOpNo != ~0U) 37 Result += ", " + utostr(MIOpNo); 38 if (PassSubtarget) 39 Result += ", STI"; 40 Result += ", O"; 41 if (!MiModifier.empty()) 42 Result += ", \"" + MiModifier + '"'; 43 return Result + ");"; 44 } 45 46 /// ParseAsmString - Parse the specified Instruction's AsmString into this 47 /// AsmWriterInst. 48 /// 49 AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, unsigned CGIIndex, 50 unsigned Variant) 51 : CGI(&CGI), CGIIndex(CGIIndex) { 52 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) 62 DollarPos = AsmString.size(); 63 64 // Emit a constant string fragment. 65 if (DollarPos != LastEmitted) { 66 for (; LastEmitted != DollarPos; ++LastEmitted) 67 switch (AsmString[LastEmitted]) { 68 case '\n': 69 AddLiteralString("\\n"); 70 break; 71 case '\t': 72 AddLiteralString("\\t"); 73 break; 74 case '"': 75 AddLiteralString("\\\""); 76 break; 77 case '\\': 78 AddLiteralString("\\\\"); 79 break; 80 default: 81 AddLiteralString(std::string(1, AsmString[LastEmitted])); 82 break; 83 } 84 } else if (AsmString[DollarPos] == '\\') { 85 if (DollarPos + 1 != AsmString.size()) { 86 if (AsmString[DollarPos + 1] == 'n') { 87 AddLiteralString("\\n"); 88 } else if (AsmString[DollarPos + 1] == 't') { 89 AddLiteralString("\\t"); 90 } else if (std::string("${|}\\").find(AsmString[DollarPos + 1]) != 91 std::string::npos) { 92 AddLiteralString(std::string(1, AsmString[DollarPos + 1])); 93 } else { 94 PrintFatalError( 95 CGI.TheDef->getLoc(), 96 "Non-supported escaped character found in instruction '" + 97 CGI.TheDef->getName() + "'!"); 98 } 99 LastEmitted = DollarPos + 2; 100 continue; 101 } 102 } else if (DollarPos + 1 != AsmString.size() && 103 AsmString[DollarPos + 1] == '$') { 104 AddLiteralString("$"); // "$$" -> $ 105 LastEmitted = DollarPos + 2; 106 } else { 107 // Get the name of the variable. 108 std::string::size_type VarEnd = DollarPos + 1; 109 110 // handle ${foo}bar as $foo by detecting whether the character following 111 // the dollar sign is a curly brace. If so, advance VarEnd and DollarPos 112 // so the variable name does not contain the leading curly brace. 113 bool hasCurlyBraces = false; 114 if (VarEnd < AsmString.size() && '{' == AsmString[VarEnd]) { 115 hasCurlyBraces = true; 116 ++DollarPos; 117 ++VarEnd; 118 } 119 120 while (VarEnd < AsmString.size() && isIdentChar(AsmString[VarEnd])) 121 ++VarEnd; 122 StringRef VarName(AsmString.data() + DollarPos + 1, 123 VarEnd - DollarPos - 1); 124 125 // Modifier - Support ${foo:modifier} syntax, where "modifier" is passed 126 // into printOperand. Also support ${:feature}, which is passed into 127 // PrintSpecial. 128 std::string Modifier; 129 130 // In order to avoid starting the next string at the terminating curly 131 // brace, advance the end position past it if we found an opening curly 132 // brace. 133 if (hasCurlyBraces) { 134 if (VarEnd >= AsmString.size()) 135 PrintFatalError( 136 CGI.TheDef->getLoc(), 137 "Reached end of string before terminating curly brace in '" + 138 CGI.TheDef->getName() + "'"); 139 140 // Look for a modifier string. 141 if (AsmString[VarEnd] == ':') { 142 ++VarEnd; 143 if (VarEnd >= AsmString.size()) 144 PrintFatalError( 145 CGI.TheDef->getLoc(), 146 "Reached end of string before terminating curly brace in '" + 147 CGI.TheDef->getName() + "'"); 148 149 std::string::size_type ModifierStart = VarEnd; 150 while (VarEnd < AsmString.size() && isIdentChar(AsmString[VarEnd])) 151 ++VarEnd; 152 Modifier = AsmString.substr(ModifierStart, VarEnd - ModifierStart); 153 if (Modifier.empty()) 154 PrintFatalError(CGI.TheDef->getLoc(), 155 "Bad operand modifier name in '" + 156 CGI.TheDef->getName() + "'"); 157 } 158 159 if (AsmString[VarEnd] != '}') 160 PrintFatalError( 161 CGI.TheDef->getLoc(), 162 "Variable name beginning with '{' did not end with '}' in '" + 163 CGI.TheDef->getName() + "'"); 164 ++VarEnd; 165 } 166 if (VarName.empty() && Modifier.empty()) 167 PrintFatalError(CGI.TheDef->getLoc(), 168 "Stray '$' in '" + CGI.TheDef->getName() + 169 "' asm string, maybe you want $$?"); 170 171 if (VarName.empty()) { 172 // Just a modifier, pass this into PrintSpecial. 173 Operands.emplace_back("PrintSpecial", ~0U, Modifier); 174 } else { 175 // Otherwise, normal operand. 176 unsigned OpNo = CGI.Operands.getOperandNamed(VarName); 177 CGIOperandList::OperandInfo OpInfo = CGI.Operands[OpNo]; 178 179 unsigned MIOp = OpInfo.MIOperandNo; 180 Operands.emplace_back(OpInfo.PrinterMethodName, MIOp, Modifier, 181 AsmWriterOperand::isMachineInstrOperand, 182 OpInfo.OperandType == "MCOI::OPERAND_PCREL"); 183 } 184 LastEmitted = VarEnd; 185 } 186 } 187 188 Operands.emplace_back("return;", AsmWriterOperand::isLiteralStatementOperand); 189 } 190 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()) 197 return ~1; 198 199 unsigned MismatchOperand = ~0U; 200 for (unsigned i = 0, e = Operands.size(); i != e; ++i) { 201 if (Operands[i] != Other.Operands[i]) { 202 if (MismatchOperand != ~0U) // Already have one mismatch? 203 return ~1U; 204 MismatchOperand = i; 205 } 206 } 207 return MismatchOperand; 208 } 209