diff --git a/llvm/lib/Target/DirectX/CMakeLists.txt b/llvm/lib/Target/DirectX/CMakeLists.txt --- a/llvm/lib/Target/DirectX/CMakeLists.txt +++ b/llvm/lib/Target/DirectX/CMakeLists.txt @@ -7,6 +7,7 @@ set(LLVM_TARGET_DEFINITIONS DXIL.td) tablegen(LLVM DXILConstants.inc -gen-dxil-enum) tablegen(LLVM DXILIntrinsicMap.inc -gen-dxil-intrinsic-map) +tablegen(LLVM DXILOperationTable.inc -gen-dxil-operation-table) add_public_tablegen_target(DirectXCommonTableGen) diff --git a/llvm/lib/Target/DirectX/DXILOpLowering.cpp b/llvm/lib/Target/DirectX/DXILOpLowering.cpp --- a/llvm/lib/Target/DirectX/DXILOpLowering.cpp +++ b/llvm/lib/Target/DirectX/DXILOpLowering.cpp @@ -129,24 +129,18 @@ // Static properties. struct OpCodeProperty { DXIL::OpCode OpCode; - // FIXME: change OpCodeName into index to a large string constant when move to - // tableGen. - const char *OpCodeName; + // Offset in DXILOpCodeNameTable. + unsigned OpCodeNameOffset; DXIL::OpCodeClass OpCodeClass; + // Offset in DXILOpCodeClassNameTable. + unsigned OpCodeClassNameOffset; uint16_t OverloadTys; llvm::Attribute::AttrKind FuncAttr; }; -static const char *getOpCodeClassName(const OpCodeProperty &Prop) { - // FIXME: generate this table with tableGen. - static const char *OpCodeClassNames[] = { - "unary", - }; - unsigned Index = static_cast(Prop.OpCodeClass); - assert(Index < (sizeof(OpCodeClassNames) / sizeof(OpCodeClassNames[0])) && - "Out of bound OpCodeClass"); - return OpCodeClassNames[Index]; -} +// Include getOpCodeClassName getOpCodeProperty and getOpCodeName which +// generated by tableGen. +#include "DXILOperationTable.inc" static std::string constructOverloadName(OverloadKind Kind, Type *Ty, const OpCodeProperty &Prop) { @@ -158,24 +152,6 @@ .str(); } -static const OpCodeProperty *getOpCodeProperty(DXIL::OpCode DXILOp) { - // FIXME: generate this table with tableGen. - static const OpCodeProperty OpCodeProps[] = { - {DXIL::OpCode::Sin, "Sin", OpCodeClass::Unary, - OverloadKind::FLOAT | OverloadKind::HALF, Attribute::AttrKind::ReadNone}, - }; - // FIXME: change search to indexing with - // DXILOp once all DXIL op is added. - OpCodeProperty TmpProp; - TmpProp.OpCode = DXILOp; - const OpCodeProperty *Prop = - llvm::lower_bound(OpCodeProps, TmpProp, - [](const OpCodeProperty &A, const OpCodeProperty &B) { - return A.OpCode < B.OpCode; - }); - return Prop; -} - static FunctionCallee createDXILOpFunction(DXIL::OpCode DXILOp, Function &F, Module &M) { const OpCodeProperty *Prop = getOpCodeProperty(DXILOp); diff --git a/llvm/utils/TableGen/DXILEmitter.cpp b/llvm/utils/TableGen/DXILEmitter.cpp --- a/llvm/utils/TableGen/DXILEmitter.cpp +++ b/llvm/utils/TableGen/DXILEmitter.cpp @@ -11,9 +11,11 @@ // //===----------------------------------------------------------------------===// +#include "SequenceToOffsetTable.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringSet.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" @@ -158,6 +160,140 @@ OS << "\n};\n\n"; } +static std::string emitDXILOperationFnAttr(StringRef FnAttr) { + return StringSwitch(FnAttr) + .Case("rn", "Attribute::ReadNone") + .Case("ro", "Attribute::ReadOnly") + .Default("Attribute::None"); +} + +static std::string getOverloadKind(StringRef Overload) { + return StringSwitch(Overload) + .Case("half", "OverloadKind::HALF") + .Case("float", "OverloadKind::FLOAT") + .Case("double", "OverloadKind::DOUBLE") + .Case("i1", "OverloadKind::I1") + .Case("i16", "OverloadKind::I16") + .Case("i32", "OverloadKind::I32") + .Case("i64", "OverloadKind::I64") + .Case("udt", "OverloadKind::UserDefineType") + .Case("obj", "OverloadKind::ObjectType") + .Default("OverloadKind::VOID"); +} + +static std::string getDXILOperationOverload(StringRef Overloads) { + SmallVector OverloadStrs; + Overloads.split(OverloadStrs, ';', /*MaxSplit*/ -1, /*KeepEmpty*/ false); + // Format is: OverloadKind::FLOAT | OverloadKind::HALF + assert(!OverloadStrs.empty() && "Invalid overloads"); + auto It = OverloadStrs.begin(); + std::string Result; + raw_string_ostream OS(Result); + OS << getOverloadKind(*It); + for (++It; It != OverloadStrs.end(); ++It) { + OS << " | " << getOverloadKind(*It); + } + return OS.str(); +} + +static std::string lowerFirstLetter(StringRef Name) { + if (Name.empty()) + return ""; + + std::string LowerName = Name.str(); + LowerName[0] = llvm::toLower(Name[0]); + return LowerName; +} + +static std::string getDXILOpClassName(StringRef DXILOpClass) { + // Lower first letter expect for special case. + return StringSwitch(DXILOpClass) + .Case("CBufferLoad", "cbufferLoad") + .Case("CBufferLoadLegacy", "cbufferLoadLegacy") + .Case("GSInstanceID", "gsInstanceID") + .Default(lowerFirstLetter(DXILOpClass)); +} + +static void emitDXILOperationTable(std::vector &DXILOps, + raw_ostream &OS) { + // Sort by DXILOpID. + std::sort(DXILOps.begin(), DXILOps.end(), + [](DXILOperationData &A, DXILOperationData &B) { + return A.DXILOpID == B.DXILOpID; + }); + + // Collect Names. + SequenceToOffsetTable OpClassStrings; + SequenceToOffsetTable OpStrings; + + StringSet<> ClassSet; + StringRef PrevCategory = ""; + for (auto &DXILOp : DXILOps) { + OpStrings.add(DXILOp.DXILOp.str()); + + if (ClassSet.find(DXILOp.DXILClass) != ClassSet.end()) + continue; + ClassSet.insert(DXILOp.DXILClass); + OpClassStrings.add(getDXILOpClassName(DXILOp.DXILClass)); + } + + // Layout names. + OpStrings.layout(); + OpClassStrings.layout(); + + // Emit the DXIL operation table. + //{DXIL::OpCode::Sin, OpCodeNameIndex, OpCodeClass::Unary, + //OpCodeClassNameIndex, + // OverloadKind::FLOAT | OverloadKind::HALF, Attribute::AttrKind::ReadNone}, + OS << "static const OpCodeProperty *getOpCodeProperty(DXIL::OpCode DXILOp) " + "{\n"; + + OS << " static const OpCodeProperty OpCodeProps[] = {\n"; + for (auto &DXILOp : DXILOps) { + OS << " { DXIL::OpCode::" << DXILOp.DXILOp << ", " + << OpStrings.get(DXILOp.DXILOp.str()) + << ", OpCodeClass::" << DXILOp.DXILClass << ", " + << OpClassStrings.get(getDXILOpClassName(DXILOp.DXILClass)) << ", " + << getDXILOperationOverload(DXILOp.OverloadTypes) << ", " + << emitDXILOperationFnAttr(DXILOp.FnAttr) << " },\n"; + } + OS << " };\n"; + + OS << " // FIXME: change search to indexing with\n"; + OS << " // DXILOp once all DXIL op is added.\n"; + OS << " OpCodeProperty TmpProp;\n"; + OS << " TmpProp.OpCode = DXILOp;\n"; + OS << " const OpCodeProperty *Prop =\n"; + OS << " llvm::lower_bound(OpCodeProps, TmpProp,\n"; + OS << " [](const OpCodeProperty &A, const " + "OpCodeProperty &B) {\n"; + OS << " return A.OpCode < B.OpCode;\n"; + OS << " });\n"; + OS << " return Prop;\n"; + OS << "}\n\n"; + + // Emit the string tables. + OS << "static const char *getOpCodeName(DXIL::OpCode DXILOp) {\n\n"; + + OpStrings.emitStringLiteralDef(OS, + " static const char DXILOpCodeNameTable[]"); + + OS << " auto *Prop = getOpCodeProperty(DXILOp);\n"; + OS << " unsigned Index = Prop->OpCodeNameOffset;\n"; + OS << " return DXILOpCodeNameTable + Index;\n"; + OS << "}\n\n"; + + OS << "static const char *getOpCodeClassName(const OpCodeProperty &Prop) " + "{\n\n"; + + OpClassStrings.emitStringLiteralDef( + OS, " static const char DXILOpCodeClassNameTable[]"); + + OS << " unsigned Index = Prop.OpCodeClassNameOffset;\n"; + OS << " return DXILOpCodeClassNameTable + Index;\n"; + OS << "}\n "; +} + namespace llvm { // Emit enum declaration for DXIL. void EmitDXILEnum(RecordKeeper &Records, raw_ostream &OS) { @@ -192,4 +328,21 @@ OS << "\n"; } +void EmitDXILOperationTable(RecordKeeper &Records, raw_ostream &OS) { + std::vector Ops = Records.getAllDerivedDefinitions("dxil_op"); + + OS << "// Generated code, do not edit.\n"; + OS << "\n"; + std::vector DXILOps; + DXILOps.reserve(Ops.size()); + for (auto *Record : Ops) { + DXILOperationData DXILOp(Record); + DXILOps.emplace_back(DXILOp); + } + + emitDXILOperationTable(DXILOps, OS); + + OS << "\n"; +} + } // namespace llvm diff --git a/llvm/utils/TableGen/TableGen.cpp b/llvm/utils/TableGen/TableGen.cpp --- a/llvm/utils/TableGen/TableGen.cpp +++ b/llvm/utils/TableGen/TableGen.cpp @@ -60,6 +60,7 @@ GenDirectivesEnumImpl, GenDXILEnum, GenDXILIntrinsicMap, + GenDXILOperationTable, }; namespace llvm { @@ -146,7 +147,9 @@ "Generate directive related implementation code"), clEnumValN(GenDXILEnum, "gen-dxil-enum", "Generate enum for DXIL"), clEnumValN(GenDXILIntrinsicMap, "gen-dxil-intrinsic-map", - "Generate map from llvm intrinsic to DXIL operation"))); + "Generate map from llvm intrinsic to DXIL operation"), + clEnumValN(GenDXILOperationTable, "gen-dxil-operation-table", + "Generate DXIL operation table"))); cl::OptionCategory PrintEnumsCat("Options for -print-enums"); cl::opt Class("class", cl::desc("Print Enum list for this class"), @@ -289,6 +292,9 @@ case GenDXILIntrinsicMap: EmitDXILIntrinsicMap(Records, OS); break; + case GenDXILOperationTable: + EmitDXILOperationTable(Records, OS); + break; } return false; diff --git a/llvm/utils/TableGen/TableGenBackends.h b/llvm/utils/TableGen/TableGenBackends.h --- a/llvm/utils/TableGen/TableGenBackends.h +++ b/llvm/utils/TableGen/TableGenBackends.h @@ -96,6 +96,7 @@ void EmitDirectivesImpl(RecordKeeper &RK, raw_ostream &OS); void EmitDXILEnum(RecordKeeper &RK, raw_ostream &OS); void EmitDXILIntrinsicMap(RecordKeeper &RK, raw_ostream &OS); +void EmitDXILOperationTable(RecordKeeper &RK, raw_ostream &OS); } // End llvm namespace