AsmWriterEmitter.cpp revision 953c6fe11277c2511744440f5d8d90aca1354e18
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 <ostream> 19using namespace llvm; 20 21static bool isIdentChar(char C) { 22 return (C >= 'a' && C <= 'z') || 23 (C >= 'A' && C <= 'Z') || 24 (C >= '0' && C <= '9') || 25 C == '_'; 26} 27 28void AsmWriterEmitter::run(std::ostream &O) { 29 EmitSourceFileHeader("Assembly Writer Source Fragment", O); 30 O << "namespace llvm {\n\n"; 31 32 CodeGenTarget Target; 33 Record *AsmWriter = Target.getAsmWriter(); 34 std::string ClassName = AsmWriter->getValueAsString("AsmWriterClassName"); 35 unsigned Variant = AsmWriter->getValueAsInt("Variant"); 36 37 O << 38 "/// printInstruction - This method is automatically generated by tablegen\n" 39 "/// from the instruction set description. This method returns true if the\n" 40 "/// machine instruction was sufficiently described to print it, otherwise\n" 41 "/// it returns false.\n" 42 "bool " << Target.getName() << ClassName 43 << "::printInstruction(const MachineInstr *MI) {\n"; 44 O << " switch (MI->getOpcode()) {\n" 45 " default: return false;\n"; 46 47 std::string Namespace = Target.inst_begin()->second.Namespace; 48 49 bool inVariant = false; // True if we are inside a {.|.|.} region. 50 51 for (CodeGenTarget::inst_iterator I = Target.inst_begin(), 52 E = Target.inst_end(); I != E; ++I) 53 if (!I->second.AsmString.empty()) { 54 const std::string &AsmString = I->second.AsmString; 55 O << " case " << Namespace << "::" << I->first << ": O "; 56 57 std::string::size_type LastEmitted = 0; 58 while (LastEmitted != AsmString.size()) { 59 std::string::size_type DollarPos = 60 AsmString.find_first_of("${|}", LastEmitted); 61 if (DollarPos == std::string::npos) DollarPos = AsmString.size(); 62 63 // Emit a constant string fragment. 64 if (DollarPos != LastEmitted) { 65 // TODO: this should eventually handle escaping. 66 O << " << \"" << std::string(AsmString.begin()+LastEmitted, 67 AsmString.begin()+DollarPos) << "\""; 68 LastEmitted = DollarPos; 69 } else if (AsmString[DollarPos] == '{') { 70 if (inVariant) 71 throw "Nested variants found for instruction '" + I->first + "'!"; 72 LastEmitted = DollarPos+1; 73 inVariant = true; // We are now inside of the variant! 74 for (unsigned i = 0; i != Variant; ++i) { 75 // Skip over all of the text for an irrelevant variant here. The 76 // next variant starts at |, or there may not be text for this 77 // variant if we see a }. 78 std::string::size_type NP = 79 AsmString.find_first_of("|}", LastEmitted); 80 if (NP == std::string::npos) 81 throw "Incomplete variant for instruction '" + I->first + "'!"; 82 LastEmitted = NP+1; 83 if (AsmString[NP] == '}') { 84 inVariant = false; // No text for this variant. 85 break; 86 } 87 } 88 } else if (AsmString[DollarPos] == '|') { 89 if (!inVariant) 90 throw "'|' character found outside of a variant in instruction '" 91 + I->first + "'!"; 92 // Move to the end of variant list. 93 std::string::size_type NP = AsmString.find('}', LastEmitted); 94 if (NP == std::string::npos) 95 throw "Incomplete variant for instruction '" + I->first + "'!"; 96 LastEmitted = NP+1; 97 inVariant = false; 98 } else if (AsmString[DollarPos] == '}') { 99 if (!inVariant) 100 throw "'}' character found outside of a variant in instruction '" 101 + I->first + "'!"; 102 LastEmitted = DollarPos+1; 103 inVariant = false; 104 } else if (DollarPos+1 != AsmString.size() && 105 AsmString[DollarPos+1] == '$') { 106 O << " << '$'"; // "$$" -> $ 107 } else { 108 // Get the name of the variable. 109 // TODO: should eventually handle ${foo}bar as $foo 110 std::string::size_type VarEnd = DollarPos+1; 111 while (VarEnd < AsmString.size() && isIdentChar(AsmString[VarEnd])) 112 ++VarEnd; 113 std::string VarName(AsmString.begin()+DollarPos+1, 114 AsmString.begin()+VarEnd); 115 if (VarName.empty()) 116 throw "Stray '$' in '" + I->first + 117 "' asm string, maybe you want $$?"; 118 unsigned OpNo = I->second.getOperandNamed(VarName); 119 120 // If this is a two-address instruction and we are not accessing the 121 // 0th operand, remove an operand. 122 unsigned MIOp = I->second.OperandList[OpNo].MIOperandNo; 123 if (I->second.isTwoAddress && MIOp != 0) { 124 if (MIOp == 1) 125 throw "Should refer to operand #0 instead of #1 for two-address" 126 " instruction '" + I->first + "'!"; 127 --MIOp; 128 } 129 130 O << "; " << I->second.OperandList[OpNo].PrinterMethodName 131 << "(MI, " << MIOp << ", MVT::" 132 << getName(I->second.OperandList[OpNo].Ty) << "); O "; 133 LastEmitted = VarEnd; 134 } 135 } 136 137 O << " << '\\n'; break;\n"; 138 } 139 140 O << " }\n" 141 " return true;\n" 142 "}\n"; 143 O << "} // End llvm namespace \n"; 144} 145