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 19using namespace llvm; 20 21static bool isIdentChar(char C) { 22 return (C >= 'a' && C <= 'z') || 23 (C >= 'A' && C <= 'Z') || 24 (C >= '0' && C <= '9') || 25 C == '_'; 26} 27 28std::string AsmWriterOperand::getCode(bool PassSubtarget) const { 29 if (OperandType == isLiteralTextOperand) { 30 if (Str.size() == 1) 31 return "O << '" + Str + "';"; 32 return "O << \"" + Str + "\";"; 33 } 34 35 if (OperandType == isLiteralStatementOperand) 36 return Str; 37 38 std::string Result = Str + "(MI"; 39 if (MIOpNo != ~0U) 40 Result += ", " + utostr(MIOpNo); 41 if (PassSubtarget) 42 Result += ", STI"; 43 Result += ", O"; 44 if (!MiModifier.empty()) 45 Result += ", \"" + MiModifier + '"'; 46 return Result + ");"; 47} 48 49/// ParseAsmString - Parse the specified Instruction's AsmString into this 50/// AsmWriterInst. 51/// 52AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, unsigned CGIIndex, 53 unsigned Variant) 54 : CGI(&CGI), CGIIndex(CGIIndex) { 55 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(); 65 66 // Emit a constant string fragment. 67 if (DollarPos != LastEmitted) { 68 for (; LastEmitted != DollarPos; ++LastEmitted) 69 switch (AsmString[LastEmitted]) { 70 case '\n': 71 AddLiteralString("\\n"); 72 break; 73 case '\t': 74 AddLiteralString("\\t"); 75 break; 76 case '"': 77 AddLiteralString("\\\""); 78 break; 79 case '\\': 80 AddLiteralString("\\\\"); 81 break; 82 default: 83 AddLiteralString(std::string(1, AsmString[LastEmitted])); 84 break; 85 } 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])); 95 } else { 96 PrintFatalError( 97 CGI.TheDef->getLoc(), 98 "Non-supported escaped character found in instruction '" + 99 CGI.TheDef->getName() + "'!"); 100 } 101 LastEmitted = DollarPos+2; 102 continue; 103 } 104 } else if (DollarPos+1 != AsmString.size() && 105 AsmString[DollarPos+1] == '$') { 106 AddLiteralString("$"); // "$$" -> $ 107 LastEmitted = DollarPos+2; 108 } else { 109 // Get the name of the variable. 110 std::string::size_type VarEnd = DollarPos+1; 111 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; 118 ++DollarPos; 119 ++VarEnd; 120 } 121 122 while (VarEnd < AsmString.size() && isIdentChar(AsmString[VarEnd])) 123 ++VarEnd; 124 StringRef VarName(AsmString.data()+DollarPos+1, VarEnd-DollarPos-1); 125 126 // Modifier - Support ${foo:modifier} syntax, where "modifier" is passed 127 // into printOperand. Also support ${:feature}, which is passed into 128 // PrintSpecial. 129 std::string Modifier; 130 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 133 // brace. 134 if (hasCurlyBraces) { 135 if (VarEnd >= AsmString.size()) 136 PrintFatalError( 137 CGI.TheDef->getLoc(), 138 "Reached end of string before terminating curly brace in '" + 139 CGI.TheDef->getName() + "'"); 140 141 // Look for a modifier string. 142 if (AsmString[VarEnd] == ':') { 143 ++VarEnd; 144 if (VarEnd >= AsmString.size()) 145 PrintFatalError( 146 CGI.TheDef->getLoc(), 147 "Reached end of string before terminating curly brace in '" + 148 CGI.TheDef->getName() + "'"); 149 150 std::string::size_type ModifierStart = VarEnd; 151 while (VarEnd < AsmString.size() && isIdentChar(AsmString[VarEnd])) 152 ++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() + "'"); 159 } 160 161 if (AsmString[VarEnd] != '}') 162 PrintFatalError( 163 CGI.TheDef->getLoc(), 164 "Variable name beginning with '{' did not end with '}' in '" + 165 CGI.TheDef->getName() + "'"); 166 ++VarEnd; 167 } 168 if (VarName.empty() && Modifier.empty()) 169 PrintFatalError(CGI.TheDef->getLoc(), 170 "Stray '$' in '" + CGI.TheDef->getName() + 171 "' asm string, maybe you want $$?"); 172 173 if (VarName.empty()) { 174 // Just a modifier, pass this into PrintSpecial. 175 Operands.emplace_back("PrintSpecial", ~0U, Modifier); 176 } else { 177 // Otherwise, normal operand. 178 unsigned OpNo = CGI.Operands.getOperandNamed(VarName); 179 CGIOperandList::OperandInfo OpInfo = CGI.Operands[OpNo]; 180 181 unsigned MIOp = OpInfo.MIOperandNo; 182 Operands.emplace_back(OpInfo.PrinterMethodName, MIOp, Modifier); 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. 195unsigned AsmWriterInst::MatchesAllButOneOp(const AsmWriterInst &Other)const{ 196 if (Operands.size() != Other.Operands.size()) return ~1; 197 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? 202 return ~1U; 203 MismatchOperand = i; 204 } 205 } 206 return MismatchOperand; 207} 208