1 //===- AsmWriterEmitter.cpp - Generate an assembly writer -----------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file was developed by the LLVM research group and is distributed under 6 // the University of Illinois Open Source License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This tablegen backend is emits an assembly printer for the current target. 11 // Note that this is currently fairly skeletal, but will grow over time. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #include "AsmWriterEmitter.h" 16 #include "CodeGenTarget.h" 17 #include "Record.h" 18 #include <algorithm> 19 #include <ostream> 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 namespace { 30 struct AsmWriterOperand { 31 enum { isLiteralTextOperand, isMachineInstrOperand } OperandType; 32 33 /// Str - For isLiteralTextOperand, this IS the literal text. For 34 /// isMachineInstrOperand, this is the PrinterMethodName for the operand. 35 std::string Str; 36 37 /// MiOpNo - For isMachineInstrOperand, this is the operand number of the 38 /// machine instruction. 39 unsigned MIOpNo; 40 41 /// OpVT - For isMachineInstrOperand, this is the value type for the 42 /// operand. 43 MVT::ValueType OpVT; 44 45 AsmWriterOperand(const std::string &LitStr) 46 : OperandType(isLiteralTextOperand), Str(LitStr) {} 47 48 AsmWriterOperand(const std::string &Printer, unsigned OpNo, 49 MVT::ValueType VT) : OperandType(isMachineInstrOperand), 50 Str(Printer), MIOpNo(OpNo), OpVT(VT){} 51 52 bool operator!=(const AsmWriterOperand &Other) const { 53 if (OperandType != Other.OperandType || Str != Other.Str) return true; 54 if (OperandType == isMachineInstrOperand) 55 return MIOpNo != Other.MIOpNo || OpVT != Other.OpVT; 56 return false; 57 } 58 bool operator==(const AsmWriterOperand &Other) const { 59 return !operator!=(Other); 60 } 61 void EmitCode(std::ostream &OS) const; 62 }; 63 64 struct AsmWriterInst { 65 std::vector<AsmWriterOperand> Operands; 66 const CodeGenInstruction *CGI; 67 68 AsmWriterInst(const CodeGenInstruction &CGI, unsigned Variant); 69 70 /// MatchesAllButOneOp - If this instruction is exactly identical to the 71 /// specified instruction except for one differing operand, return the 72 /// differing operand number. Otherwise return ~0. 73 unsigned MatchesAllButOneOp(const AsmWriterInst &Other) const; 74 75 private: 76 void AddLiteralString(const std::string &Str) { 77 // If the last operand was already a literal text string, append this to 78 // it, otherwise add a new operand. 79 if (!Operands.empty() && 80 Operands.back().OperandType == AsmWriterOperand::isLiteralTextOperand) 81 Operands.back().Str.append(Str); 82 else 83 Operands.push_back(AsmWriterOperand(Str)); 84 } 85 }; 86 } 87 88 89 void AsmWriterOperand::EmitCode(std::ostream &OS) const { 90 if (OperandType == isLiteralTextOperand) 91 OS << "O << \"" << Str << "\"; "; 92 else 93 OS << Str << "(MI, " << MIOpNo << ", MVT::" << getEnumName(OpVT) << "); "; 94 } 95 96 97 /// ParseAsmString - Parse the specified Instruction's AsmString into this 98 /// AsmWriterInst. 99 /// 100 AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, unsigned Variant) { 101 this->CGI = &CGI; 102 bool inVariant = false; // True if we are inside a {.|.|.} region. 103 104 const std::string &AsmString = CGI.AsmString; 105 std::string::size_type LastEmitted = 0; 106 while (LastEmitted != AsmString.size()) { 107 std::string::size_type DollarPos = 108 AsmString.find_first_of("${|}", LastEmitted); 109 if (DollarPos == std::string::npos) DollarPos = AsmString.size(); 110 111 // Emit a constant string fragment. 112 if (DollarPos != LastEmitted) { 113 // TODO: this should eventually handle escaping. 114 AddLiteralString(std::string(AsmString.begin()+LastEmitted, 115 AsmString.begin()+DollarPos)); 116 LastEmitted = DollarPos; 117 } else if (AsmString[DollarPos] == '{') { 118 if (inVariant) 119 throw "Nested variants found for instruction '" + 120 CGI.TheDef->getName() + "'!"; 121 LastEmitted = DollarPos+1; 122 inVariant = true; // We are now inside of the variant! 123 for (unsigned i = 0; i != Variant; ++i) { 124 // Skip over all of the text for an irrelevant variant here. The 125 // next variant starts at |, or there may not be text for this 126 // variant if we see a }. 127 std::string::size_type NP = 128 AsmString.find_first_of("|}", LastEmitted); 129 if (NP == std::string::npos) 130 throw "Incomplete variant for instruction '" + 131 CGI.TheDef->getName() + "'!"; 132 LastEmitted = NP+1; 133 if (AsmString[NP] == '}') { 134 inVariant = false; // No text for this variant. 135 break; 136 } 137 } 138 } else if (AsmString[DollarPos] == '|') { 139 if (!inVariant) 140 throw "'|' character found outside of a variant in instruction '" 141 + CGI.TheDef->getName() + "'!"; 142 // Move to the end of variant list. 143 std::string::size_type NP = AsmString.find('}', LastEmitted); 144 if (NP == std::string::npos) 145 throw "Incomplete variant for instruction '" + 146 CGI.TheDef->getName() + "'!"; 147 LastEmitted = NP+1; 148 inVariant = false; 149 } else if (AsmString[DollarPos] == '}') { 150 if (!inVariant) 151 throw "'}' character found outside of a variant in instruction '" 152 + CGI.TheDef->getName() + "'!"; 153 LastEmitted = DollarPos+1; 154 inVariant = false; 155 } else if (DollarPos+1 != AsmString.size() && 156 AsmString[DollarPos+1] == '$') { 157 AddLiteralString("$"); // "$$" -> $ 158 LastEmitted = DollarPos+2; 159 } else { 160 // Get the name of the variable. 161 std::string::size_type VarEnd = DollarPos+1; 162 163 // handle ${foo}bar as $foo by detecting whether the character following 164 // the dollar sign is a curly brace. If so, advance VarEnd and DollarPos 165 // so the variable name does not contain the leading curly brace. 166 bool hasCurlyBraces = false; 167 if (VarEnd < AsmString.size() && '{' == AsmString[VarEnd]) { 168 hasCurlyBraces = true; 169 ++DollarPos; 170 ++VarEnd; 171 } 172 173 while (VarEnd < AsmString.size() && isIdentChar(AsmString[VarEnd])) 174 ++VarEnd; 175 std::string VarName(AsmString.begin()+DollarPos+1, 176 AsmString.begin()+VarEnd); 177 178 // In order to avoid starting the next string at the terminating curly 179 // brace, advance the end position past it if we found an opening curly 180 // brace. 181 if (hasCurlyBraces) { 182 if (VarEnd >= AsmString.size()) 183 throw "Reached end of string before terminating curly brace in '" 184 + CGI.TheDef->getName() + "'"; 185 if (AsmString[VarEnd] != '}') 186 throw "Variant name beginning with '{' did not end with '}' in '" 187 + CGI.TheDef->getName() + "'"; 188 ++VarEnd; 189 } 190 if (VarName.empty()) 191 throw "Stray '$' in '" + CGI.TheDef->getName() + 192 "' asm string, maybe you want $$?"; 193 194 unsigned OpNo = CGI.getOperandNamed(VarName); 195 CodeGenInstruction::OperandInfo OpInfo = CGI.OperandList[OpNo]; 196 197 // If this is a two-address instruction and we are not accessing the 198 // 0th operand, remove an operand. 199 unsigned MIOp = OpInfo.MIOperandNo; 200 if (CGI.isTwoAddress && MIOp != 0) { 201 if (MIOp == 1) 202 throw "Should refer to operand #0 instead of #1 for two-address" 203 " instruction '" + CGI.TheDef->getName() + "'!"; 204 --MIOp; 205 } 206 207 Operands.push_back(AsmWriterOperand(OpInfo.PrinterMethodName, 208 MIOp, OpInfo.Ty)); 209 LastEmitted = VarEnd; 210 } 211 } 212 213 AddLiteralString("\\n"); 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 return MismatchOperand; 232 } 233 234 static void PrintCases(std::vector<std::pair<std::string, 235 AsmWriterOperand> > &OpsToPrint, std::ostream &O) { 236 O << " case " << OpsToPrint.back().first << ": "; 237 AsmWriterOperand TheOp = OpsToPrint.back().second; 238 OpsToPrint.pop_back(); 239 240 // Check to see if any other operands are identical in this list, and if so, 241 // emit a case label for them. 242 for (unsigned i = OpsToPrint.size(); i != 0; --i) 243 if (OpsToPrint[i-1].second == TheOp) { 244 O << "\n case " << OpsToPrint[i-1].first << ": "; 245 OpsToPrint.erase(OpsToPrint.begin()+i-1); 246 } 247 248 // Finally, emit the code. 249 TheOp.EmitCode(O); 250 O << "break;\n"; 251 } 252 253 254 /// EmitInstructions - Emit the last instruction in the vector and any other 255 /// instructions that are suitably similar to it. 256 static void EmitInstructions(std::vector<AsmWriterInst> &Insts, 257 std::ostream &O) { 258 AsmWriterInst FirstInst = Insts.back(); 259 Insts.pop_back(); 260 261 std::vector<AsmWriterInst> SimilarInsts; 262 unsigned DifferingOperand = ~0; 263 for (unsigned i = Insts.size(); i != 0; --i) { 264 unsigned DiffOp = Insts[i-1].MatchesAllButOneOp(FirstInst); 265 if (DiffOp != ~1U) { 266 if (DifferingOperand == ~0U) // First match! 267 DifferingOperand = DiffOp; 268 269 // If this differs in the same operand as the rest of the instructions in 270 // this class, move it to the SimilarInsts list. 271 if (DifferingOperand == DiffOp || DiffOp == ~0U) { 272 SimilarInsts.push_back(Insts[i-1]); 273 Insts.erase(Insts.begin()+i-1); 274 } 275 } 276 } 277 278 std::string Namespace = FirstInst.CGI->Namespace; 279 280 O << " case " << Namespace << "::" 281 << FirstInst.CGI->TheDef->getName() << ":\n"; 282 for (unsigned i = 0, e = SimilarInsts.size(); i != e; ++i) 283 O << " case " << Namespace << "::" 284 << SimilarInsts[i].CGI->TheDef->getName() << ":\n"; 285 for (unsigned i = 0, e = FirstInst.Operands.size(); i != e; ++i) { 286 if (i != DifferingOperand) { 287 // If the operand is the same for all instructions, just print it. 288 O << " "; 289 FirstInst.Operands[i].EmitCode(O); 290 } else { 291 // If this is the operand that varies between all of the instructions, 292 // emit a switch for just this operand now. 293 O << " switch (MI->getOpcode()) {\n"; 294 std::vector<std::pair<std::string, AsmWriterOperand> > OpsToPrint; 295 OpsToPrint.push_back(std::make_pair(Namespace+"::"+ 296 FirstInst.CGI->TheDef->getName(), 297 FirstInst.Operands[i])); 298 299 for (unsigned si = 0, e = SimilarInsts.size(); si != e; ++si) { 300 AsmWriterInst &AWI = SimilarInsts[si]; 301 OpsToPrint.push_back(std::make_pair(Namespace+"::"+ 302 AWI.CGI->TheDef->getName(), 303 AWI.Operands[i])); 304 } 305 std::reverse(OpsToPrint.begin(), OpsToPrint.end()); 306 while (!OpsToPrint.empty()) 307 PrintCases(OpsToPrint, O); 308 O << " }"; 309 } 310 O << "\n"; 311 } 312 313 O << " break;\n"; 314 } 315 316 void AsmWriterEmitter::run(std::ostream &O) { 317 EmitSourceFileHeader("Assembly Writer Source Fragment", O); 318 319 CodeGenTarget Target; 320 Record *AsmWriter = Target.getAsmWriter(); 321 std::string ClassName = AsmWriter->getValueAsString("AsmWriterClassName"); 322 unsigned Variant = AsmWriter->getValueAsInt("Variant"); 323 324 O << 325 "/// printInstruction - This method is automatically generated by tablegen\n" 326 "/// from the instruction set description. This method returns true if the\n" 327 "/// machine instruction was sufficiently described to print it, otherwise\n" 328 "/// it returns false.\n" 329 "bool " << Target.getName() << ClassName 330 << "::printInstruction(const MachineInstr *MI) {\n"; 331 332 std::string Namespace = Target.inst_begin()->second.Namespace; 333 334 std::vector<AsmWriterInst> Instructions; 335 336 for (CodeGenTarget::inst_iterator I = Target.inst_begin(), 337 E = Target.inst_end(); I != E; ++I) 338 if (!I->second.AsmString.empty()) 339 Instructions.push_back(AsmWriterInst(I->second, Variant)); 340 341 // If all of the instructions start with a constant string (a very very common 342 // occurance), emit all of the constant strings as a big table lookup instead 343 // of requiring a switch for them. 344 bool AllStartWithString = true; 345 346 for (unsigned i = 0, e = Instructions.size(); i != e; ++i) 347 if (Instructions[i].Operands.empty() || 348 Instructions[i].Operands[0].OperandType != 349 AsmWriterOperand::isLiteralTextOperand) { 350 AllStartWithString = false; 351 break; 352 } 353 354 if (AllStartWithString) { 355 // Compute the CodeGenInstruction -> AsmWriterInst mapping. Note that not 356 // all machine instructions are necessarily being printed, so there may be 357 // target instructions not in this map. 358 std::map<const CodeGenInstruction*, AsmWriterInst*> CGIAWIMap; 359 for (unsigned i = 0, e = Instructions.size(); i != e; ++i) 360 CGIAWIMap.insert(std::make_pair(Instructions[i].CGI, &Instructions[i])); 361 362 // Emit a table of constant strings. 363 std::vector<const CodeGenInstruction*> NumberedInstructions; 364 Target.getInstructionsByEnumValue(NumberedInstructions); 365 366 O << " static const char * const OpStrs[] = {\n"; 367 for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i) { 368 AsmWriterInst *AWI = CGIAWIMap[NumberedInstructions[i]]; 369 if (AWI == 0) { 370 // Something not handled by the asmwriter printer. 371 O << " 0,\t// "; 372 } else { 373 O << " \"" << AWI->Operands[0].Str << "\",\t// "; 374 // Nuke the string from the operand list. It is now handled! 375 AWI->Operands.erase(AWI->Operands.begin()); 376 } 377 O << NumberedInstructions[i]->TheDef->getName() << "\n"; 378 } 379 O << " };\n\n" 380 << " // Emit the opcode for the instruction.\n" 381 << " if (const char *AsmStr = OpStrs[MI->getOpcode()])\n" 382 << " O << AsmStr;\n\n"; 383 } 384 385 // Because this is a vector we want to emit from the end. Reverse all of the 386 // elements in the vector. 387 std::reverse(Instructions.begin(), Instructions.end()); 388 389 O << " switch (MI->getOpcode()) {\n" 390 " default: return false;\n"; 391 392 while (!Instructions.empty()) 393 EmitInstructions(Instructions, O); 394 395 O << " }\n" 396 " return true;\n" 397 "}\n"; 398 } 399