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