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 @@ -130,25 +130,20 @@ // 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[] = { - "binary", - "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. +#define DXIL_OP_OPERATION_TABLE +#include "DXILOperation.inc" +#undef DXIL_OP_OPERATION_TABLE static std::string constructOverloadName(OverloadKind Kind, Type *Ty, const OpCodeProperty &Prop) { @@ -160,27 +155,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}, - {DXIL::OpCode::UMax, "UMax", OpCodeClass::Binary, - OverloadKind::I16 | OverloadKind::I32 | OverloadKind::I64, - 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); @@ -225,6 +199,7 @@ Args.append(CI->arg_begin(), CI->arg_end()); B.SetInsertPoint(CI); CallInst *DXILCI = B.CreateCall(DXILOpFn, Args); + LLVM_DEBUG(DXILCI->setName(getOpCodeName(DXILOp))); CI->replaceAllUsesWith(DXILCI); CI->eraseFromParent(); } 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,10 +11,11 @@ // //===----------------------------------------------------------------------===// -#include "llvm/ADT/MapVector.h" +#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" @@ -191,7 +192,7 @@ } // Emit map from llvm intrinsic to DXIL operation. -static void EmitDXILIntrinsicMap(std::vector &DXILOps, +static void emitDXILIntrinsicMap(std::vector &DXILOps, raw_ostream &OS) { OS << "\n"; // FIXME: use array instead of SmallDenseMap. @@ -208,6 +209,140 @@ OS << "\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; + 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 << " assert(Prop && \"fail to find OpCodeProperty\");\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 { void EmitDXILOperation(RecordKeeper &Records, raw_ostream &OS) { @@ -226,9 +361,12 @@ OS << "#endif\n\n"; OS << "#ifdef DXIL_OP_INTRINSIC_MAP\n"; - EmitDXILIntrinsicMap(DXILOps, OS); + emitDXILIntrinsicMap(DXILOps, OS); OS << "#endif\n\n"; + OS << "#ifdef DXIL_OP_OPERATION_TABLE\n"; + emitDXILOperationTable(DXILOps, OS); + OS << "#endif\n\n"; OS << "\n"; }