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 "CodeGenTarget.h" 16 #include "llvm/ADT/StringExtras.h" 17 #include "llvm/TableGen/Error.h" 18 #include "llvm/TableGen/Record.h" 19 20 using namespace llvm; 21 22 static bool isIdentChar(char C) { return isAlnum(C) || C == '_'; } 23 24 std::string AsmWriterOperand::getCode(bool PassSubtarget) const { 25 if (OperandType == isLiteralTextOperand) { 26 if (Str.size() == 1) 27 return "O << '" + Str + "';"; 28 return "O << \"" + Str + "\";"; 29 } 30 31 if (OperandType == isLiteralStatementOperand) 32 return Str; 33 34 std::string Result = Str + "(MI"; 35 if (PCRel) 36 Result += ", Address"; 37 if (MIOpNo != ~0U) 38 Result += ", " + utostr(MIOpNo); 39 if (PassSubtarget) 40 Result += ", STI"; 41 Result += ", O"; 42 if (!MiModifier.empty()) 43 Result += ", \"" + MiModifier + '"'; 44 return Result + ");"; 45 } 46 47 /// ParseAsmString - Parse the specified Instruction's AsmString into this 48 /// AsmWriterInst. 49 /// 50 AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, unsigned CGIIndex, 51 unsigned Variant) 52 : CGI(&CGI), CGIIndex(CGIIndex) { 53 54 // NOTE: Any extensions to this code need to be mirrored in the 55 // AsmPrinter::printInlineAsm code that executes as compile time (assuming 56 // that inline asm strings should also get the new feature)! 57 std::string AsmString = CGI.FlattenAsmStringVariants(CGI.AsmString, Variant); 58 std::string::size_type LastEmitted = 0; 59 while (LastEmitted != AsmString.size()) { 60 std::string::size_type DollarPos = 61 AsmString.find_first_of("$\\", LastEmitted); 62 if (DollarPos == std::string::npos) 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, VarEnd-DollarPos-1); 123 124 // Modifier - Support ${foo:modifier} syntax, where "modifier" is passed 125 // into printOperand. Also support ${:feature}, which is passed into 126 // PrintSpecial. 127 std::string Modifier; 128 129 // In order to avoid starting the next string at the terminating curly 130 // brace, advance the end position past it if we found an opening curly 131 // brace. 132 if (hasCurlyBraces) { 133 if (VarEnd >= AsmString.size()) 134 PrintFatalError( 135 CGI.TheDef->getLoc(), 136 "Reached end of string before terminating curly brace in '" + 137 CGI.TheDef->getName() + "'"); 138 139 // Look for a modifier string. 140 if (AsmString[VarEnd] == ':') { 141 ++VarEnd; 142 if (VarEnd >= AsmString.size()) 143 PrintFatalError( 144 CGI.TheDef->getLoc(), 145 "Reached end of string before terminating curly brace in '" + 146 CGI.TheDef->getName() + "'"); 147 148 std::string::size_type ModifierStart = VarEnd; 149 while (VarEnd < AsmString.size() && isIdentChar(AsmString[VarEnd])) 150 ++VarEnd; 151 Modifier = AsmString.substr(ModifierStart, VarEnd - ModifierStart); 152 if (Modifier.empty()) 153 PrintFatalError(CGI.TheDef->getLoc(), 154 "Bad operand modifier name in '" + 155 CGI.TheDef->getName() + "'"); 156 } 157 158 if (AsmString[VarEnd] != '}') 159 PrintFatalError( 160 CGI.TheDef->getLoc(), 161 "Variable name beginning with '{' did not end with '}' in '" + 162 CGI.TheDef->getName() + "'"); 163 ++VarEnd; 164 } 165 if (VarName.empty() && Modifier.empty()) 166 PrintFatalError(CGI.TheDef->getLoc(), 167 "Stray '$' in '" + CGI.TheDef->getName() + 168 "' asm string, maybe you want $$?"); 169 170 if (VarName.empty()) { 171 // Just a modifier, pass this into PrintSpecial. 172 Operands.emplace_back("PrintSpecial", ~0U, Modifier); 173 } else { 174 // Otherwise, normal operand. 175 unsigned OpNo = CGI.Operands.getOperandNamed(VarName); 176 CGIOperandList::OperandInfo OpInfo = CGI.Operands[OpNo]; 177 178 unsigned MIOp = OpInfo.MIOperandNo; 179 Operands.emplace_back(OpInfo.PrinterMethodName, MIOp, Modifier, 180 AsmWriterOperand::isMachineInstrOperand, 181 OpInfo.OperandType == "MCOI::OPERAND_PCREL"); 182 } 183 LastEmitted = VarEnd; 184 } 185 } 186 187 Operands.emplace_back("return;", AsmWriterOperand::isLiteralStatementOperand); 188 } 189 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; 196 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? 201 return ~1U; 202 MismatchOperand = i; 203 } 204 } 205 return MismatchOperand; 206 } 207