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 "CodeGenTarget.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) DollarPos = AsmString.size(); 62 63 // Emit a constant string fragment. 64 if (DollarPos != LastEmitted) { 65 for (; LastEmitted != DollarPos; ++LastEmitted) 66 switch (AsmString[LastEmitted]) { 67 case '\n': 68 AddLiteralString("\\n"); 69 break; 70 case '\t': 71 AddLiteralString("\\t"); 72 break; 73 case '"': 74 AddLiteralString("\\\""); 75 break; 76 case '\\': 77 AddLiteralString("\\\\"); 78 break; 79 default: 80 AddLiteralString(std::string(1, AsmString[LastEmitted])); 81 break; 82 } 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])); 92 } else { 93 PrintFatalError( 94 CGI.TheDef->getLoc(), 95 "Non-supported escaped character found in instruction '" + 96 CGI.TheDef->getName() + "'!"); 97 } 98 LastEmitted = DollarPos+2; 99 continue; 100 } 101 } else if (DollarPos+1 != AsmString.size() && 102 AsmString[DollarPos+1] == '$') { 103 AddLiteralString("$"); // "$$" -> $ 104 LastEmitted = DollarPos+2; 105 } else { 106 // Get the name of the variable. 107 std::string::size_type VarEnd = DollarPos+1; 108 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; 115 ++DollarPos; 116 ++VarEnd; 117 } 118 119 while (VarEnd < AsmString.size() && isIdentChar(AsmString[VarEnd])) 120 ++VarEnd; 121 StringRef VarName(AsmString.data()+DollarPos+1, VarEnd-DollarPos-1); 122 123 // Modifier - Support ${foo:modifier} syntax, where "modifier" is passed 124 // into printOperand. Also support ${:feature}, which is passed into 125 // PrintSpecial. 126 std::string Modifier; 127 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 130 // brace. 131 if (hasCurlyBraces) { 132 if (VarEnd >= AsmString.size()) 133 PrintFatalError( 134 CGI.TheDef->getLoc(), 135 "Reached end of string before terminating curly brace in '" + 136 CGI.TheDef->getName() + "'"); 137 138 // Look for a modifier string. 139 if (AsmString[VarEnd] == ':') { 140 ++VarEnd; 141 if (VarEnd >= AsmString.size()) 142 PrintFatalError( 143 CGI.TheDef->getLoc(), 144 "Reached end of string before terminating curly brace in '" + 145 CGI.TheDef->getName() + "'"); 146 147 std::string::size_type ModifierStart = VarEnd; 148 while (VarEnd < AsmString.size() && isIdentChar(AsmString[VarEnd])) 149 ++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() + "'"); 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