1 //===- AsmWriterInst.h - Classes encapsulating a printable inst -----------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // These classes implement a parser for assembly strings. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "AsmWriterInst.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) { 23 return (C >= 'a' && C <= 'z') || 24 (C >= 'A' && C <= 'Z') || 25 (C >= '0' && C <= '9') || 26 C == '_'; 27 } 28 29 std::string AsmWriterOperand::getCode(bool PassSubtarget) const { 30 if (OperandType == isLiteralTextOperand) { 31 if (Str.size() == 1) 32 return "O << '" + Str + "';"; 33 return "O << \"" + Str + "\";"; 34 } 35 36 if (OperandType == isLiteralStatementOperand) 37 return Str; 38 39 std::string Result = Str + "(MI"; 40 if (MIOpNo != ~0U) 41 Result += ", " + utostr(MIOpNo); 42 if (PassSubtarget) 43 Result += ", STI"; 44 Result += ", O"; 45 if (!MiModifier.empty()) 46 Result += ", \"" + MiModifier + '"'; 47 return Result + ");"; 48 } 49 50 /// ParseAsmString - Parse the specified Instruction's AsmString into this 51 /// AsmWriterInst. 52 /// 53 AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, unsigned CGIIndex, 54 unsigned Variant) 55 : CGI(&CGI), CGIIndex(CGIIndex) { 56 57 // NOTE: Any extensions to this code need to be mirrored in the 58 // AsmPrinter::printInlineAsm code that executes as compile time (assuming 59 // that inline asm strings should also get the new feature)! 60 std::string AsmString = CGI.FlattenAsmStringVariants(CGI.AsmString, Variant); 61 std::string::size_type LastEmitted = 0; 62 while (LastEmitted != AsmString.size()) { 63 std::string::size_type DollarPos = 64 AsmString.find_first_of("$\\", LastEmitted); 65 if (DollarPos == std::string::npos) DollarPos = AsmString.size(); 66 67 // Emit a constant string fragment. 68 if (DollarPos != LastEmitted) { 69 for (; LastEmitted != DollarPos; ++LastEmitted) 70 switch (AsmString[LastEmitted]) { 71 case '\n': 72 AddLiteralString("\\n"); 73 break; 74 case '\t': 75 AddLiteralString("\\t"); 76 break; 77 case '"': 78 AddLiteralString("\\\""); 79 break; 80 case '\\': 81 AddLiteralString("\\\\"); 82 break; 83 default: 84 AddLiteralString(std::string(1, AsmString[LastEmitted])); 85 break; 86 } 87 } else if (AsmString[DollarPos] == '\\') { 88 if (DollarPos+1 != AsmString.size()) { 89 if (AsmString[DollarPos+1] == 'n') { 90 AddLiteralString("\\n"); 91 } else if (AsmString[DollarPos+1] == 't') { 92 AddLiteralString("\\t"); 93 } else if (std::string("${|}\\").find(AsmString[DollarPos+1]) 94 != std::string::npos) { 95 AddLiteralString(std::string(1, AsmString[DollarPos+1])); 96 } else { 97 PrintFatalError("Non-supported escaped character found in instruction '" + 98 CGI.TheDef->getName() + "'!"); 99 } 100 LastEmitted = DollarPos+2; 101 continue; 102 } 103 } else if (DollarPos+1 != AsmString.size() && 104 AsmString[DollarPos+1] == '$') { 105 AddLiteralString("$"); // "$$" -> $ 106 LastEmitted = DollarPos+2; 107 } else { 108 // Get the name of the variable. 109 std::string::size_type VarEnd = DollarPos+1; 110 111 // handle ${foo}bar as $foo by detecting whether the character following 112 // the dollar sign is a curly brace. If so, advance VarEnd and DollarPos 113 // so the variable name does not contain the leading curly brace. 114 bool hasCurlyBraces = false; 115 if (VarEnd < AsmString.size() && '{' == AsmString[VarEnd]) { 116 hasCurlyBraces = true; 117 ++DollarPos; 118 ++VarEnd; 119 } 120 121 while (VarEnd < AsmString.size() && isIdentChar(AsmString[VarEnd])) 122 ++VarEnd; 123 StringRef VarName(AsmString.data()+DollarPos+1, 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("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("Reached end of string before terminating curly brace in '" 143 + CGI.TheDef->getName() + "'"); 144 145 std::string::size_type ModifierStart = VarEnd; 146 while (VarEnd < AsmString.size() && isIdentChar(AsmString[VarEnd])) 147 ++VarEnd; 148 Modifier = std::string(AsmString.begin()+ModifierStart, 149 AsmString.begin()+VarEnd); 150 if (Modifier.empty()) 151 PrintFatalError("Bad operand modifier name in '"+ CGI.TheDef->getName() + "'"); 152 } 153 154 if (AsmString[VarEnd] != '}') 155 PrintFatalError("Variable name beginning with '{' did not end with '}' in '" 156 + CGI.TheDef->getName() + "'"); 157 ++VarEnd; 158 } 159 if (VarName.empty() && Modifier.empty()) 160 PrintFatalError("Stray '$' in '" + CGI.TheDef->getName() + 161 "' asm string, maybe you want $$?"); 162 163 if (VarName.empty()) { 164 // Just a modifier, pass this into PrintSpecial. 165 Operands.emplace_back("PrintSpecial", ~0U, Modifier); 166 } else { 167 // Otherwise, normal operand. 168 unsigned OpNo = CGI.Operands.getOperandNamed(VarName); 169 CGIOperandList::OperandInfo OpInfo = CGI.Operands[OpNo]; 170 171 unsigned MIOp = OpInfo.MIOperandNo; 172 Operands.emplace_back(OpInfo.PrinterMethodName, MIOp, Modifier); 173 } 174 LastEmitted = VarEnd; 175 } 176 } 177 178 Operands.emplace_back("return;", AsmWriterOperand::isLiteralStatementOperand); 179 } 180 181 /// MatchesAllButOneOp - If this instruction is exactly identical to the 182 /// specified instruction except for one differing operand, return the differing 183 /// operand number. If more than one operand mismatches, return ~1, otherwise 184 /// if the instructions are identical return ~0. 185 unsigned AsmWriterInst::MatchesAllButOneOp(const AsmWriterInst &Other)const{ 186 if (Operands.size() != Other.Operands.size()) return ~1; 187 188 unsigned MismatchOperand = ~0U; 189 for (unsigned i = 0, e = Operands.size(); i != e; ++i) { 190 if (Operands[i] != Other.Operands[i]) { 191 if (MismatchOperand != ~0U) // Already have one mismatch? 192 return ~1U; 193 MismatchOperand = i; 194 } 195 } 196 return MismatchOperand; 197 } 198