204 changes: 117 additions & 87 deletions llvm/utils/TableGen/InstrInfoEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,9 @@ class InstrInfoEmitter {
private:
void emitEnums(raw_ostream &OS);

typedef std::map<std::vector<std::string>, unsigned> OperandInfoMapTy;
typedef std::vector<std::string> OperandInfoTy;
typedef std::vector<OperandInfoTy> OperandInfoListTy;
typedef std::map<OperandInfoTy, unsigned> OperandInfoMapTy;

/// The keys of this map are maps which have OpName enum values as their keys
/// and instruction operand indices as their values. The values of this map
Expand All @@ -86,9 +88,8 @@ class InstrInfoEmitter {
void emitFeatureVerifier(raw_ostream &OS, const CodeGenTarget &Target);
void emitRecord(const CodeGenInstruction &Inst, unsigned Num,
Record *InstrInfo,
std::map<std::vector<Record*>, unsigned> &EL,
const OperandInfoMapTy &OpInfo,
raw_ostream &OS);
std::map<std::vector<Record *>, unsigned> &EL,
const OperandInfoMapTy &OperandInfo, raw_ostream &OS);
void emitOperandTypeMappings(
raw_ostream &OS, const CodeGenTarget &Target,
ArrayRef<const CodeGenInstruction *> NumberedInstructions);
Expand All @@ -108,27 +109,21 @@ class InstrInfoEmitter {
ArrayRef<const CodeGenInstruction *> NumberedInstructions);

// Operand information.
void EmitOperandInfo(raw_ostream &OS, OperandInfoMapTy &OperandInfoIDs);
std::vector<std::string> GetOperandInfo(const CodeGenInstruction &Inst);
unsigned CollectOperandInfo(OperandInfoListTy &OperandInfoList,
OperandInfoMapTy &OperandInfoMap);
void EmitOperandInfo(raw_ostream &OS, OperandInfoListTy &OperandInfoList);
OperandInfoTy GetOperandInfo(const CodeGenInstruction &Inst);
};

} // end anonymous namespace

static void PrintDefList(const std::vector<Record *> &Uses, unsigned Num,
raw_ostream &OS) {
OS << "static const MCPhysReg ImplicitList" << Num << "[] = { ";
for (auto [Idx, U] : enumerate(Uses))
OS << (Idx ? ", " : "") << getQualifiedName(U);
OS << " };\n";
}

//===----------------------------------------------------------------------===//
// Operand Info Emission.
//===----------------------------------------------------------------------===//

std::vector<std::string>
InstrInfoEmitter::OperandInfoTy
InstrInfoEmitter::GetOperandInfo(const CodeGenInstruction &Inst) {
std::vector<std::string> Result;
OperandInfoTy Result;

for (auto &Op : Inst.Operands) {
// Handle aggregate operands and normal operands the same way by expanding
Expand Down Expand Up @@ -215,24 +210,30 @@ InstrInfoEmitter::GetOperandInfo(const CodeGenInstruction &Inst) {
return Result;
}

void InstrInfoEmitter::EmitOperandInfo(raw_ostream &OS,
OperandInfoMapTy &OperandInfoIDs) {
// ID #0 is for no operand info.
unsigned OperandListNum = 0;
OperandInfoIDs[std::vector<std::string>()] = ++OperandListNum;

OS << "\n";
unsigned
InstrInfoEmitter::CollectOperandInfo(OperandInfoListTy &OperandInfoList,
OperandInfoMapTy &OperandInfoMap) {
const CodeGenTarget &Target = CDP.getTargetInfo();
unsigned Offset = 0;
for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) {
std::vector<std::string> OperandInfo = GetOperandInfo(*Inst);
unsigned &N = OperandInfoIDs[OperandInfo];
if (N != 0) continue;

N = ++OperandListNum;
OS << "static const MCOperandInfo OperandInfo" << N << "[] = { ";
for (const std::string &Info : OperandInfo)
OS << "{ " << Info << " }, ";
OS << "};\n";
OperandInfoTy OperandInfo = GetOperandInfo(*Inst);
if (OperandInfoMap.insert({OperandInfo, Offset}).second) {
OperandInfoList.push_back(OperandInfo);
Offset += OperandInfo.size();
}
}
return Offset;
}

void InstrInfoEmitter::EmitOperandInfo(raw_ostream &OS,
OperandInfoListTy &OperandInfoList) {
unsigned Offset = 0;
for (auto &OperandInfo : OperandInfoList) {
OS << " /* " << Offset << " */";
for (auto &Info : OperandInfo)
OS << " { " << Info << " },";
OS << '\n';
Offset += OperandInfo.size();
}
}

Expand Down Expand Up @@ -891,54 +892,90 @@ void InstrInfoEmitter::run(raw_ostream &OS) {
emitSourceFileHeader("Target Instruction Enum Values and Descriptors", OS);
emitEnums(OS);

OS << "#ifdef GET_INSTRINFO_MC_DESC\n";
OS << "#undef GET_INSTRINFO_MC_DESC\n";

OS << "namespace llvm {\n\n";

CodeGenTarget &Target = CDP.getTargetInfo();
const std::string &TargetName = std::string(Target.getName());
Record *InstrInfo = Target.getInstructionSet();

// Keep track of all of the def lists we have emitted already.
std::map<std::vector<Record*>, unsigned> EmittedLists;
unsigned ListNumber = 0;
// Collect all of the operand info records.
Records.startTimer("Collect operand info");
OperandInfoListTy OperandInfoList;
OperandInfoMapTy OperandInfoMap;
unsigned OperandInfoSize =
CollectOperandInfo(OperandInfoList, OperandInfoMap);

// Emit all of the instruction's implicit uses and defs.
Records.startTimer("Emit uses/defs");
// Collect all of the instruction's implicit uses and defs.
Records.startTimer("Collect uses/defs");
std::map<std::vector<Record*>, unsigned> EmittedLists;
std::vector<std::vector<Record *>> ImplicitLists;
unsigned ImplicitListSize = 0;
for (const CodeGenInstruction *II : Target.getInstructionsByEnumValue()) {
std::vector<Record *> ImplicitOps = II->ImplicitUses;
llvm::append_range(ImplicitOps, II->ImplicitDefs);
if (!ImplicitOps.empty()) {
unsigned &IL = EmittedLists[ImplicitOps];
if (!IL) {
IL = ++ListNumber;
PrintDefList(ImplicitOps, IL, OS);
}
if (EmittedLists.insert({ImplicitOps, ImplicitListSize}).second) {
ImplicitLists.push_back(ImplicitOps);
ImplicitListSize += ImplicitOps.size();
}
}

OperandInfoMapTy OperandInfoIDs;
ArrayRef<const CodeGenInstruction *> NumberedInstructions =
Target.getInstructionsByEnumValue();
OS << "#if defined(GET_INSTRINFO_MC_DESC) || "
"defined(GET_INSTRINFO_CTOR_DTOR)\n";
OS << "namespace llvm {\n\n";

// Emit all of the operand info records.
Records.startTimer("Emit operand info");
EmitOperandInfo(OS, OperandInfoIDs);
OS << "struct " << TargetName << "InstrTable {\n";
OS << " MCInstrDesc Insts[" << NumberedInstructions.size() << "];\n";
OS << " static_assert(alignof(MCInstrDesc) >= alignof(MCOperandInfo), "
"\"Unwanted padding between Insts and OperandInfo\");\n";
OS << " MCOperandInfo OperandInfo[" << OperandInfoSize << "];\n";
OS << " static_assert(alignof(MCOperandInfo) >= alignof(MCPhysReg), "
"\"Unwanted padding between OperandInfo and ImplicitOps\");\n";
OS << " MCPhysReg ImplicitOps[" << std::max(ImplicitListSize, 1U) << "];\n";
OS << "};\n\n";

OS << "} // end namespace llvm\n";
OS << "#endif // defined(GET_INSTRINFO_MC_DESC) || "
"defined(GET_INSTRINFO_CTOR_DTOR)\n\n";

OS << "#ifdef GET_INSTRINFO_MC_DESC\n";
OS << "#undef GET_INSTRINFO_MC_DESC\n";
OS << "namespace llvm {\n\n";

// Emit all of the MCInstrDesc records in reverse ENUM ordering.
Records.startTimer("Emit InstrDesc records");
OS << "\nextern const MCInstrDesc " << TargetName << "Insts[] = {\n";
ArrayRef<const CodeGenInstruction*> NumberedInstructions =
Target.getInstructionsByEnumValue();
OS << "static_assert(sizeof(MCOperandInfo) % sizeof(MCPhysReg) == 0);\n";
OS << "static constexpr unsigned " << TargetName << "ImpOpBase = sizeof "
<< TargetName << "InstrTable::OperandInfo / (sizeof(MCPhysReg));\n\n";

OS << "extern const " << TargetName << "InstrTable " << TargetName
<< "Descs = {\n {\n";
SequenceToOffsetTable<std::string> InstrNames;
unsigned Num = NumberedInstructions.size();
for (const CodeGenInstruction *Inst : reverse(NumberedInstructions)) {
// Keep a list of the instruction names.
InstrNames.add(std::string(Inst->TheDef->getName()));
// Emit the record into the table.
emitRecord(*Inst, --Num, InstrInfo, EmittedLists, OperandInfoIDs, OS);
emitRecord(*Inst, --Num, InstrInfo, EmittedLists, OperandInfoMap, OS);
}
OS << "};\n\n";

OS << " }, {\n";

// Emit all of the operand info records.
Records.startTimer("Emit operand info");
EmitOperandInfo(OS, OperandInfoList);

OS << " }, {\n";

// Emit all of the instruction's implicit uses and defs.
Records.startTimer("Emit uses/defs");
for (auto &List : ImplicitLists) {
OS << " /* " << EmittedLists[List] << " */";
for (auto &Reg : List)
OS << ' ' << getQualifiedName(Reg) << ',';
OS << '\n';
}

OS << " }\n};\n\n";

// Emit the array of instruction names.
Records.startTimer("Emit instruction names");
Expand Down Expand Up @@ -1005,7 +1042,7 @@ void InstrInfoEmitter::run(raw_ostream &OS) {
Records.startTimer("Emit initialization routine");
OS << "static inline void Init" << TargetName
<< "MCInstrInfo(MCInstrInfo *II) {\n";
OS << " II->InitMCInstrInfo(" << TargetName << "Insts, " << TargetName
OS << " II->InitMCInstrInfo(" << TargetName << "Descs.Insts, " << TargetName
<< "InstrNameIndices, " << TargetName << "InstrNameData, ";
if (HasDeprecationFeatures)
OS << TargetName << "InstrDeprecationFeatures, ";
Expand Down Expand Up @@ -1053,7 +1090,8 @@ void InstrInfoEmitter::run(raw_ostream &OS) {
OS << "#undef GET_INSTRINFO_CTOR_DTOR\n";

OS << "namespace llvm {\n";
OS << "extern const MCInstrDesc " << TargetName << "Insts[];\n";
OS << "extern const " << TargetName << "InstrTable " << TargetName
<< "Descs;\n";
OS << "extern const unsigned " << TargetName << "InstrNameIndices[];\n";
OS << "extern const char " << TargetName << "InstrNameData[];\n";
if (HasDeprecationFeatures)
Expand All @@ -1067,7 +1105,7 @@ void InstrInfoEmitter::run(raw_ostream &OS) {
"CatchRetOpcode, unsigned ReturnOpcode)\n"
<< " : TargetInstrInfo(CFSetupOpcode, CFDestroyOpcode, CatchRetOpcode, "
"ReturnOpcode) {\n"
<< " InitMCInstrInfo(" << TargetName << "Insts, " << TargetName
<< " InitMCInstrInfo(" << TargetName << "Descs.Insts, " << TargetName
<< "InstrNameIndices, " << TargetName << "InstrNameData, ";
if (HasDeprecationFeatures)
OS << TargetName << "InstrDeprecationFeatures, ";
Expand Down Expand Up @@ -1101,27 +1139,34 @@ void InstrInfoEmitter::run(raw_ostream &OS) {
emitFeatureVerifier(OS, Target);
}

void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num,
Record *InstrInfo,
std::map<std::vector<Record*>, unsigned> &EmittedLists,
const OperandInfoMapTy &OpInfo,
raw_ostream &OS) {
void InstrInfoEmitter::emitRecord(
const CodeGenInstruction &Inst, unsigned Num, Record *InstrInfo,
std::map<std::vector<Record *>, unsigned> &EmittedLists,
const OperandInfoMapTy &OperandInfoMap, raw_ostream &OS) {
int MinOperands = 0;
if (!Inst.Operands.empty())
// Each logical operand can be multiple MI operands.
MinOperands = Inst.Operands.back().MIOperandNo +
Inst.Operands.back().MINumOperands;

OS << " { ";
OS << Num << ",\t" << MinOperands << ",\t"
<< Inst.Operands.NumDefs << ",\t"
OS << " { ";
OS << Num << ",\t" << MinOperands << ",\t" << Inst.Operands.NumDefs << ",\t"
<< Inst.TheDef->getValueAsInt("Size") << ",\t"
<< SchedModels.getSchedClassIdx(Inst) << ",\t"
<< Inst.ImplicitUses.size() << ",\t"
<< Inst.ImplicitDefs.size() << ",\t0";
<< SchedModels.getSchedClassIdx(Inst) << ",\t";

CodeGenTarget &Target = CDP.getTargetInfo();

// Emit the implicit use/def list...
OS << Inst.ImplicitUses.size() << ",\t" << Inst.ImplicitDefs.size() << ",\t";
std::vector<Record *> ImplicitOps = Inst.ImplicitUses;
llvm::append_range(ImplicitOps, Inst.ImplicitDefs);
OS << Target.getName() << "ImpOpBase + " << EmittedLists[ImplicitOps]
<< ",\t";

// Emit the operand info offset.
OperandInfoTy OperandInfo = GetOperandInfo(Inst);
OS << OperandInfoMap.find(OperandInfo)->second << ",\t0";

// Emit all of the target independent flags...
if (Inst.isPreISelOpcode) OS << "|(1ULL<<MCID::PreISelOpcode)";
if (Inst.isPseudo) OS << "|(1ULL<<MCID::Pseudo)";
Expand Down Expand Up @@ -1181,22 +1226,7 @@ void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num,
}
OS << ", 0x";
OS.write_hex(Value);
OS << "ULL, ";

// Emit the implicit use/def list...
std::vector<Record *> ImplicitOps = Inst.ImplicitUses;
llvm::append_range(ImplicitOps, Inst.ImplicitDefs);
if (ImplicitOps.empty())
OS << "nullptr, ";
else
OS << "ImplicitList" << EmittedLists[ImplicitOps] << ", ";

// Emit the operand info.
std::vector<std::string> OperandInfo = GetOperandInfo(Inst);
if (OperandInfo.empty())
OS << "nullptr";
else
OS << "OperandInfo" << OpInfo.find(OperandInfo)->second;
OS << "ULL";

OS << " }, // Inst #" << Num << " = " << Inst.TheDef->getName() << "\n";
}
Expand Down