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