static void emitRegisterNameString(raw_ostream &O, StringRef AltName, const std::vector<CodeGenRegister*> &Registers) { StringToOffsetTable StringTable; O << " static const unsigned RegAsmOffset" << AltName << "[] = {\n "; for (unsigned i = 0, e = Registers.size(); i != e; ++i) { const CodeGenRegister &Reg = *Registers[i]; std::string AsmName; // "NoRegAltName" is special. We don't need to do a lookup for that, // as it's just a reference to the default register name. if (AltName == "" || AltName == "NoRegAltName") { AsmName = Reg.TheDef->getValueAsString("AsmName"); if (AsmName.empty()) AsmName = Reg.getName(); } else { // Make sure the register has an alternate name for this index. std::vector<Record*> AltNameList = Reg.TheDef->getValueAsListOfDefs("RegAltNameIndices"); unsigned Idx = 0, e; for (e = AltNameList.size(); Idx < e && (AltNameList[Idx]->getName() != AltName); ++Idx) ; // If the register has an alternate name for this index, use it. // Otherwise, leave it empty as an error flag. if (Idx < e) { std::vector<std::string> AltNames = Reg.TheDef->getValueAsListOfStrings("AltNames"); if (AltNames.size() <= Idx) throw TGError(Reg.TheDef->getLoc(), (Twine("Register definition missing alt name for '") + AltName + "'.").str()); AsmName = AltNames[Idx]; } } O << StringTable.GetOrAddStringOffset(AsmName); if (((i + 1) % 14) == 0) O << ",\n "; else O << ", "; } O << "0\n" << " };\n" << "\n"; O << " const char *AsmStrs" << AltName << " =\n"; StringTable.EmitString(O); O << ";\n"; }
void AsmWriterEmitter::EmitGetInstructionName(raw_ostream &O) { CodeGenTarget Target(Records); Record *AsmWriter = Target.getAsmWriter(); std::string ClassName = AsmWriter->getValueAsString("AsmWriterClassName"); const std::vector<const CodeGenInstruction*> &NumberedInstructions = Target.getInstructionsByEnumValue(); StringToOffsetTable StringTable; O << "\n\n#ifdef GET_INSTRUCTION_NAME\n" "#undef GET_INSTRUCTION_NAME\n\n" "/// getInstructionName: This method is automatically generated by tblgen\n" "/// from the instruction set description. This returns the enum name of the\n" "/// specified instruction.\n" "const char *" << Target.getName() << ClassName << "::getInstructionName(unsigned Opcode) {\n" << " assert(Opcode < " << NumberedInstructions.size() << " && \"Invalid instruction number!\");\n" << "\n" << " static const unsigned InstAsmOffset[] = {"; for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i) { const CodeGenInstruction &Inst = *NumberedInstructions[i]; std::string AsmName = Inst.TheDef->getName(); if ((i % 14) == 0) O << "\n "; O << StringTable.GetOrAddStringOffset(AsmName) << ", "; } O << "0\n" << " };\n" << "\n"; O << " const char *Strs =\n"; StringTable.EmitString(O); O << ";\n"; O << " return Strs+InstAsmOffset[Opcode];\n" << "}\n\n#endif\n"; }
void AsmWriterEmitter::EmitGetRegisterName(raw_ostream &O) { CodeGenTarget Target(Records); Record *AsmWriter = Target.getAsmWriter(); std::string ClassName = AsmWriter->getValueAsString("AsmWriterClassName"); const std::vector<CodeGenRegister> &Registers = Target.getRegisters(); StringToOffsetTable StringTable; O << "\n\n/// getRegisterName - This method is automatically generated by tblgen\n" "/// from the register set description. This returns the assembler name\n" "/// for the specified register.\n" "const char *" << Target.getName() << ClassName << "::getRegisterName(unsigned RegNo) {\n" << " assert(RegNo && RegNo < " << (Registers.size()+1) << " && \"Invalid register number!\");\n" << "\n" << " static const unsigned RegAsmOffset[] = {"; for (unsigned i = 0, e = Registers.size(); i != e; ++i) { const CodeGenRegister &Reg = Registers[i]; std::string AsmName = Reg.TheDef->getValueAsString("AsmName"); if (AsmName.empty()) AsmName = Reg.getName(); if ((i % 14) == 0) O << "\n "; O << StringTable.GetOrAddStringOffset(AsmName) << ", "; } O << "0\n" << " };\n" << "\n"; O << " const char *AsmStrs =\n"; StringTable.EmitString(O); O << ";\n"; O << " return AsmStrs+RegAsmOffset[RegNo-1];\n" << "}\n"; }
/// EmitPrintInstruction - Generate the code for the "printInstruction" method /// implementation. void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) { CodeGenTarget Target(Records); Record *AsmWriter = Target.getAsmWriter(); std::string ClassName = AsmWriter->getValueAsString("AsmWriterClassName"); bool isMC = AsmWriter->getValueAsBit("isMCAsmWriter"); const char *MachineInstrClassName = isMC ? "MCInst" : "MachineInstr"; O << "/// printInstruction - This method is automatically generated by tablegen\n" "/// from the instruction set description.\n" "void " << Target.getName() << ClassName << "::printInstruction(const " << MachineInstrClassName << " *MI, raw_ostream &O) {\n"; std::vector<AsmWriterInst> Instructions; for (CodeGenTarget::inst_iterator I = Target.inst_begin(), E = Target.inst_end(); I != E; ++I) if (!(*I)->AsmString.empty() && (*I)->TheDef->getName() != "PHI") Instructions.push_back( AsmWriterInst(**I, AsmWriter->getValueAsInt("Variant"), AsmWriter->getValueAsInt("FirstOperandColumn"), AsmWriter->getValueAsInt("OperandSpacing"))); // Get the instruction numbering. NumberedInstructions = Target.getInstructionsByEnumValue(); // Compute the CodeGenInstruction -> AsmWriterInst mapping. Note that not // all machine instructions are necessarily being printed, so there may be // target instructions not in this map. for (unsigned i = 0, e = Instructions.size(); i != e; ++i) CGIAWIMap.insert(std::make_pair(Instructions[i].CGI, &Instructions[i])); // Build an aggregate string, and build a table of offsets into it. StringToOffsetTable StringTable; /// OpcodeInfo - This encodes the index of the string to use for the first /// chunk of the output as well as indices used for operand printing. std::vector<unsigned> OpcodeInfo; unsigned MaxStringIdx = 0; for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i) { AsmWriterInst *AWI = CGIAWIMap[NumberedInstructions[i]]; unsigned Idx; if (AWI == 0) { // Something not handled by the asmwriter printer. Idx = ~0U; } else if (AWI->Operands[0].OperandType != AsmWriterOperand::isLiteralTextOperand || AWI->Operands[0].Str.empty()) { // Something handled by the asmwriter printer, but with no leading string. Idx = StringTable.GetOrAddStringOffset(""); } else { std::string Str = AWI->Operands[0].Str; UnescapeString(Str); Idx = StringTable.GetOrAddStringOffset(Str); MaxStringIdx = std::max(MaxStringIdx, Idx); // Nuke the string from the operand list. It is now handled! AWI->Operands.erase(AWI->Operands.begin()); } // Bias offset by one since we want 0 as a sentinel. OpcodeInfo.push_back(Idx+1); } // Figure out how many bits we used for the string index. unsigned AsmStrBits = Log2_32_Ceil(MaxStringIdx+2); // To reduce code size, we compactify common instructions into a few bits // in the opcode-indexed table. unsigned BitsLeft = 32-AsmStrBits; std::vector<std::vector<std::string> > TableDrivenOperandPrinters; while (1) { std::vector<std::string> UniqueOperandCommands; std::vector<unsigned> InstIdxs; std::vector<unsigned> NumInstOpsHandled; FindUniqueOperandCommands(UniqueOperandCommands, InstIdxs, NumInstOpsHandled); // If we ran out of operands to print, we're done. if (UniqueOperandCommands.empty()) break; // Compute the number of bits we need to represent these cases, this is // ceil(log2(numentries)). unsigned NumBits = Log2_32_Ceil(UniqueOperandCommands.size()); // If we don't have enough bits for this operand, don't include it. if (NumBits > BitsLeft) { DEBUG(errs() << "Not enough bits to densely encode " << NumBits << " more bits\n"); break; } // Otherwise, we can include this in the initial lookup table. Add it in. BitsLeft -= NumBits; for (unsigned i = 0, e = InstIdxs.size(); i != e; ++i) if (InstIdxs[i] != ~0U) OpcodeInfo[i] |= InstIdxs[i] << (BitsLeft+AsmStrBits); // Remove the info about this operand. for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i) { if (AsmWriterInst *Inst = getAsmWriterInstByID(i)) if (!Inst->Operands.empty()) { unsigned NumOps = NumInstOpsHandled[InstIdxs[i]]; assert(NumOps <= Inst->Operands.size() && "Can't remove this many ops!"); Inst->Operands.erase(Inst->Operands.begin(), Inst->Operands.begin()+NumOps); } } // Remember the handlers for this set of operands. TableDrivenOperandPrinters.push_back(UniqueOperandCommands); } O<<" static const unsigned OpInfo[] = {\n"; for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i) { O << " " << OpcodeInfo[i] << "U,\t// " << NumberedInstructions[i]->TheDef->getName() << "\n"; } // Add a dummy entry so the array init doesn't end with a comma. O << " 0U\n"; O << " };\n\n"; // Emit the string itself. O << " const char *AsmStrs = \n"; StringTable.EmitString(O); O << ";\n\n"; O << " O << \"\\t\";\n\n"; O << " // Emit the opcode for the instruction.\n" << " unsigned Bits = OpInfo[MI->getOpcode()];\n" << " assert(Bits != 0 && \"Cannot print this instruction.\");\n" << " O << AsmStrs+(Bits & " << (1 << AsmStrBits)-1 << ")-1;\n\n"; // Output the table driven operand information. BitsLeft = 32-AsmStrBits; for (unsigned i = 0, e = TableDrivenOperandPrinters.size(); i != e; ++i) { std::vector<std::string> &Commands = TableDrivenOperandPrinters[i]; // Compute the number of bits we need to represent these cases, this is // ceil(log2(numentries)). unsigned NumBits = Log2_32_Ceil(Commands.size()); assert(NumBits <= BitsLeft && "consistency error"); // Emit code to extract this field from Bits. BitsLeft -= NumBits; O << "\n // Fragment " << i << " encoded into " << NumBits << " bits for " << Commands.size() << " unique commands.\n"; if (Commands.size() == 2) { // Emit two possibilitys with if/else. O << " if ((Bits >> " << (BitsLeft+AsmStrBits) << ") & " << ((1 << NumBits)-1) << ") {\n" << Commands[1] << " } else {\n" << Commands[0] << " }\n\n"; } else if (Commands.size() == 1) { // Emit a single possibility. O << Commands[0] << "\n\n"; } else { O << " switch ((Bits >> " << (BitsLeft+AsmStrBits) << ") & " << ((1 << NumBits)-1) << ") {\n" << " default: // unreachable.\n"; // Print out all the cases. for (unsigned i = 0, e = Commands.size(); i != e; ++i) { O << " case " << i << ":\n"; O << Commands[i]; O << " break;\n"; } O << " }\n\n"; } } // Okay, delete instructions with no operand info left. for (unsigned i = 0, e = Instructions.size(); i != e; ++i) { // Entire instruction has been emitted? AsmWriterInst &Inst = Instructions[i]; if (Inst.Operands.empty()) { Instructions.erase(Instructions.begin()+i); --i; --e; } } // Because this is a vector, we want to emit from the end. Reverse all of the // elements in the vector. std::reverse(Instructions.begin(), Instructions.end()); // Now that we've emitted all of the operand info that fit into 32 bits, emit // information for those instructions that are left. This is a less dense // encoding, but we expect the main 32-bit table to handle the majority of // instructions. if (!Instructions.empty()) { // Find the opcode # of inline asm. O << " switch (MI->getOpcode()) {\n"; while (!Instructions.empty()) EmitInstructions(Instructions, O); O << " }\n"; O << " return;\n"; } O << "}\n"; }
/// \brief Emit a list of group names. /// /// This creates a long string which by itself contains a list of pascal style /// strings, which consist of a length byte directly followed by the string. /// /// \code /// static const char DiagGroupNames[] = { /// \000\020#pragma-messages\t#warnings\020CFString-literal" /// }; /// \endcode static void emitDiagGroupNames(StringToOffsetTable &GroupNames, raw_ostream &OS) { OS << "static const char DiagGroupNames[] = {\n"; GroupNames.EmitString(OS); OS << "};\n\n"; }
void EmitClangDiagGroups(RecordKeeper &Records, raw_ostream &OS) { // Compute a mapping from a DiagGroup to all of its parents. DiagGroupParentMap DGParentMap(Records); std::vector<Record*> Diags = Records.getAllDerivedDefinitions("Diagnostic"); std::vector<Record*> DiagGroups = Records.getAllDerivedDefinitions("DiagGroup"); std::map<std::string, GroupInfo> DiagsInGroup; groupDiagnostics(Diags, DiagGroups, DiagsInGroup); // All extensions are implicitly in the "pedantic" group. Record the // implicit set of groups in the "pedantic" group, and use this information // later when emitting the group information for Pedantic. RecordVec DiagsInPedantic; RecordVec GroupsInPedantic; InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup); inferPedantic.compute(&DiagsInPedantic, &GroupsInPedantic); // Walk through the groups emitting an array for each diagnostic of the diags // that are mapped to. OS << "\n#ifdef GET_DIAG_ARRAYS\n"; unsigned MaxLen = 0; OS << "static const int16_t DiagArrays[] = {\n" << " /* Empty */ -1,\n"; for (std::map<std::string, GroupInfo>::const_iterator I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) { MaxLen = std::max(MaxLen, (unsigned)I->first.size()); const bool IsPedantic = I->first == "pedantic"; const std::vector<const Record*> &V = I->second.DiagsInGroup; if (!V.empty() || (IsPedantic && !DiagsInPedantic.empty())) { OS << " /* DiagArray" << I->second.IDNo << " */ "; for (unsigned i = 0, e = V.size(); i != e; ++i) OS << "diag::" << V[i]->getName() << ", "; // Emit the diagnostics implicitly in "pedantic". if (IsPedantic) { for (unsigned i = 0, e = DiagsInPedantic.size(); i != e; ++i) OS << "diag::" << DiagsInPedantic[i]->getName() << ", "; } OS << "-1,\n"; } } OS << "};\n\n"; OS << "static const int16_t DiagSubGroups[] = {\n" << " /* Empty */ -1,\n"; for (std::map<std::string, GroupInfo>::const_iterator I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) { const bool IsPedantic = I->first == "pedantic"; const std::vector<std::string> &SubGroups = I->second.SubGroups; if (!SubGroups.empty() || (IsPedantic && !GroupsInPedantic.empty())) { OS << " /* DiagSubGroup" << I->second.IDNo << " */ "; for (unsigned i = 0, e = SubGroups.size(); i != e; ++i) { std::map<std::string, GroupInfo>::const_iterator RI = DiagsInGroup.find(SubGroups[i]); assert(RI != DiagsInGroup.end() && "Referenced without existing?"); OS << RI->second.IDNo << ", "; } // Emit the groups implicitly in "pedantic". if (IsPedantic) { for (unsigned i = 0, e = GroupsInPedantic.size(); i != e; ++i) { const std::string &GroupName = GroupsInPedantic[i]->getValueAsString("GroupName"); std::map<std::string, GroupInfo>::const_iterator RI = DiagsInGroup.find(GroupName); assert(RI != DiagsInGroup.end() && "Referenced without existing?"); OS << RI->second.IDNo << ", "; } } OS << "-1,\n"; } } OS << "};\n\n"; StringToOffsetTable GroupNames; for (std::map<std::string, GroupInfo>::const_iterator I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) { // Store a pascal-style length byte at the beginning of the string. std::string Name = char(I->first.size()) + I->first; GroupNames.GetOrAddStringOffset(Name, false); } OS << "static const char DiagGroupNames[] = {\n"; GroupNames.EmitString(OS); OS << "};\n\n"; OS << "#endif // GET_DIAG_ARRAYS\n\n"; // Emit the table now. OS << "\n#ifdef GET_DIAG_TABLE\n"; unsigned SubGroupIndex = 1, DiagArrayIndex = 1; for (std::map<std::string, GroupInfo>::const_iterator I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) { // Group option string. OS << " { /* "; if (I->first.find_first_not_of("abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789!@#$%^*-+=:?")!=std::string::npos) PrintFatalError("Invalid character in diagnostic group '" + I->first + "'"); OS << I->first << " */ " << std::string(MaxLen-I->first.size(), ' '); // Store a pascal-style length byte at the beginning of the string. std::string Name = char(I->first.size()) + I->first; OS << GroupNames.GetOrAddStringOffset(Name, false) << ", "; // Special handling for 'pedantic'. const bool IsPedantic = I->first == "pedantic"; // Diagnostics in the group. const std::vector<const Record*> &V = I->second.DiagsInGroup; const bool hasDiags = !V.empty() || (IsPedantic && !DiagsInPedantic.empty()); if (hasDiags) { OS << "/* DiagArray" << I->second.IDNo << " */ " << DiagArrayIndex << ", "; if (IsPedantic) DiagArrayIndex += DiagsInPedantic.size(); DiagArrayIndex += V.size() + 1; } else { OS << "/* Empty */ 0, "; } // Subgroups. const std::vector<std::string> &SubGroups = I->second.SubGroups; const bool hasSubGroups = !SubGroups.empty() || (IsPedantic && !GroupsInPedantic.empty()); if (hasSubGroups) { OS << "/* DiagSubGroup" << I->second.IDNo << " */ " << SubGroupIndex; if (IsPedantic) SubGroupIndex += GroupsInPedantic.size(); SubGroupIndex += SubGroups.size() + 1; } else { OS << "/* Empty */ 0"; } OS << " },\n"; } OS << "#endif // GET_DIAG_TABLE\n\n"; // Emit the category table next. DiagCategoryIDMap CategoriesByID(Records); OS << "\n#ifdef GET_CATEGORY_TABLE\n"; for (DiagCategoryIDMap::const_iterator I = CategoriesByID.begin(), E = CategoriesByID.end(); I != E; ++I) OS << "CATEGORY(\"" << *I << "\", " << getDiagCategoryEnum(*I) << ")\n"; OS << "#endif // GET_CATEGORY_TABLE\n\n"; }