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 "Record.h" 17 #include "llvm/ADT/StringExtras.h" 18 19 using namespace llvm; 20 21 static bool isIdentChar(char C) { 22 return (C >= 'a' && C <= 'z') || 23 (C >= 'A' && C <= 'Z') || 24 (C >= '0' && C <= '9') || 25 C == '_'; 26 } 27 28 std::string AsmWriterOperand::getCode() 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 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, 51 unsigned Variant, 52 int FirstOperandColumn, 53 int OperandSpacing) { 54 this->CGI = &CGI; 55 56 unsigned CurVariant = ~0U; // ~0 if we are outside a {.|.|.} region, other #. 57 58 // This is the number of tabs we've seen if we're doing columnar layout. 59 unsigned CurColumn = 0; 60 61 62 // NOTE: Any extensions to this code need to be mirrored in the 63 // AsmPrinter::printInlineAsm code that executes as compile time (assuming 64 // that inline asm strings should also get the new feature)! 65 const std::string &AsmString = CGI.AsmString; 66 std::string::size_type LastEmitted = 0; 67 while (LastEmitted != AsmString.size()) { 68 std::string::size_type DollarPos = 69 AsmString.find_first_of("${|}\\", LastEmitted); 70 if (DollarPos == std::string::npos) DollarPos = AsmString.size(); 71 72 // Emit a constant string fragment. 73 74 if (DollarPos != LastEmitted) { 75 if (CurVariant == Variant || CurVariant == ~0U) { 76 for (; LastEmitted != DollarPos; ++LastEmitted) 77 switch (AsmString[LastEmitted]) { 78 case '\n': 79 AddLiteralString("\\n"); 80 break; 81 case '\t': 82 // If the asm writer is not using a columnar layout, \t is not 83 // magic. 84 if (FirstOperandColumn == -1 || OperandSpacing == -1) { 85 AddLiteralString("\\t"); 86 } else { 87 // We recognize a tab as an operand delimeter. 88 unsigned DestColumn = FirstOperandColumn + 89 CurColumn++ * OperandSpacing; 90 Operands.push_back( 91 AsmWriterOperand( 92 "O.PadToColumn(" + 93 utostr(DestColumn) + ");\n", 94 AsmWriterOperand::isLiteralStatementOperand)); 95 } 96 break; 97 case '"': 98 AddLiteralString("\\\""); 99 break; 100 case '\\': 101 AddLiteralString("\\\\"); 102 break; 103 default: 104 AddLiteralString(std::string(1, AsmString[LastEmitted])); 105 break; 106 } 107 } else { 108 LastEmitted = DollarPos; 109 } 110 } else if (AsmString[DollarPos] == '\\') { 111 if (DollarPos+1 != AsmString.size() && 112 (CurVariant == Variant || CurVariant == ~0U)) { 113 if (AsmString[DollarPos+1] == 'n') { 114 AddLiteralString("\\n"); 115 } else if (AsmString[DollarPos+1] == 't') { 116 // If the asm writer is not using a columnar layout, \t is not 117 // magic. 118 if (FirstOperandColumn == -1 || OperandSpacing == -1) { 119 AddLiteralString("\\t"); 120 break; 121 } 122 123 // We recognize a tab as an operand delimeter. 124 unsigned DestColumn = FirstOperandColumn + 125 CurColumn++ * OperandSpacing; 126 Operands.push_back( 127 AsmWriterOperand("O.PadToColumn(" + utostr(DestColumn) + ");\n", 128 AsmWriterOperand::isLiteralStatementOperand)); 129 break; 130 } else if (std::string("${|}\\").find(AsmString[DollarPos+1]) 131 != std::string::npos) { 132 AddLiteralString(std::string(1, AsmString[DollarPos+1])); 133 } else { 134 throw "Non-supported escaped character found in instruction '" + 135 CGI.TheDef->getName() + "'!"; 136 } 137 LastEmitted = DollarPos+2; 138 continue; 139 } 140 } else if (AsmString[DollarPos] == '{') { 141 if (CurVariant != ~0U) 142 throw "Nested variants found for instruction '" + 143 CGI.TheDef->getName() + "'!"; 144 LastEmitted = DollarPos+1; 145 CurVariant = 0; // We are now inside of the variant! 146 } else if (AsmString[DollarPos] == '|') { 147 if (CurVariant == ~0U) 148 throw "'|' character found outside of a variant in instruction '" 149 + CGI.TheDef->getName() + "'!"; 150 ++CurVariant; 151 ++LastEmitted; 152 } else if (AsmString[DollarPos] == '}') { 153 if (CurVariant == ~0U) 154 throw "'}' character found outside of a variant in instruction '" 155 + CGI.TheDef->getName() + "'!"; 156 ++LastEmitted; 157 CurVariant = ~0U; 158 } else if (DollarPos+1 != AsmString.size() && 159 AsmString[DollarPos+1] == '$') { 160 if (CurVariant == Variant || CurVariant == ~0U) { 161 AddLiteralString("$"); // "$$" -> $ 162 } 163 LastEmitted = DollarPos+2; 164 } else { 165 // Get the name of the variable. 166 std::string::size_type VarEnd = DollarPos+1; 167 168 // handle ${foo}bar as $foo by detecting whether the character following 169 // the dollar sign is a curly brace. If so, advance VarEnd and DollarPos 170 // so the variable name does not contain the leading curly brace. 171 bool hasCurlyBraces = false; 172 if (VarEnd < AsmString.size() && '{' == AsmString[VarEnd]) { 173 hasCurlyBraces = true; 174 ++DollarPos; 175 ++VarEnd; 176 } 177 178 while (VarEnd < AsmString.size() && isIdentChar(AsmString[VarEnd])) 179 ++VarEnd; 180 std::string VarName(AsmString.begin()+DollarPos+1, 181 AsmString.begin()+VarEnd); 182 183 // Modifier - Support ${foo:modifier} syntax, where "modifier" is passed 184 // into printOperand. Also support ${:feature}, which is passed into 185 // PrintSpecial. 186 std::string Modifier; 187 188 // In order to avoid starting the next string at the terminating curly 189 // brace, advance the end position past it if we found an opening curly 190 // brace. 191 if (hasCurlyBraces) { 192 if (VarEnd >= AsmString.size()) 193 throw "Reached end of string before terminating curly brace in '" 194 + CGI.TheDef->getName() + "'"; 195 196 // Look for a modifier string. 197 if (AsmString[VarEnd] == ':') { 198 ++VarEnd; 199 if (VarEnd >= AsmString.size()) 200 throw "Reached end of string before terminating curly brace in '" 201 + CGI.TheDef->getName() + "'"; 202 203 unsigned ModifierStart = VarEnd; 204 while (VarEnd < AsmString.size() && isIdentChar(AsmString[VarEnd])) 205 ++VarEnd; 206 Modifier = std::string(AsmString.begin()+ModifierStart, 207 AsmString.begin()+VarEnd); 208 if (Modifier.empty()) 209 throw "Bad operand modifier name in '"+ CGI.TheDef->getName() + "'"; 210 } 211 212 if (AsmString[VarEnd] != '}') 213 throw "Variable name beginning with '{' did not end with '}' in '" 214 + CGI.TheDef->getName() + "'"; 215 ++VarEnd; 216 } 217 if (VarName.empty() && Modifier.empty()) 218 throw "Stray '$' in '" + CGI.TheDef->getName() + 219 "' asm string, maybe you want $$?"; 220 221 if (VarName.empty()) { 222 // Just a modifier, pass this into PrintSpecial. 223 Operands.push_back(AsmWriterOperand("PrintSpecial", 224 ~0U, 225 ~0U, 226 Modifier)); 227 } else { 228 // Otherwise, normal operand. 229 unsigned OpNo = CGI.getOperandNamed(VarName); 230 CodeGenInstruction::OperandInfo OpInfo = CGI.OperandList[OpNo]; 231 232 if (CurVariant == Variant || CurVariant == ~0U) { 233 unsigned MIOp = OpInfo.MIOperandNo; 234 Operands.push_back(AsmWriterOperand(OpInfo.PrinterMethodName, 235 OpNo, 236 MIOp, 237 Modifier)); 238 } 239 } 240 LastEmitted = VarEnd; 241 } 242 } 243 244 Operands.push_back(AsmWriterOperand("return;", 245 AsmWriterOperand::isLiteralStatementOperand)); 246 } 247 248 /// MatchesAllButOneOp - If this instruction is exactly identical to the 249 /// specified instruction except for one differing operand, return the differing 250 /// operand number. If more than one operand mismatches, return ~1, otherwise 251 /// if the instructions are identical return ~0. 252 unsigned AsmWriterInst::MatchesAllButOneOp(const AsmWriterInst &Other)const{ 253 if (Operands.size() != Other.Operands.size()) return ~1; 254 255 unsigned MismatchOperand = ~0U; 256 for (unsigned i = 0, e = Operands.size(); i != e; ++i) { 257 if (Operands[i] != Other.Operands[i]) { 258 if (MismatchOperand != ~0U) // Already have one mismatch? 259 return ~1U; 260 else 261 MismatchOperand = i; 262 } 263 } 264 return MismatchOperand; 265 } 266