157006b14SXiang Li //===- DXILOpBuilder.cpp - Helper class for build DIXLOp functions --------===// 257006b14SXiang Li // 357006b14SXiang Li // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 457006b14SXiang Li // See https://llvm.org/LICENSE.txt for license information. 557006b14SXiang Li // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 657006b14SXiang Li // 757006b14SXiang Li //===----------------------------------------------------------------------===// 857006b14SXiang Li /// 957006b14SXiang Li /// \file This file contains class to help build DXIL op functions. 1057006b14SXiang Li //===----------------------------------------------------------------------===// 1157006b14SXiang Li 1257006b14SXiang Li #include "DXILOpBuilder.h" 1357006b14SXiang Li #include "DXILConstants.h" 1457006b14SXiang Li #include "llvm/IR/Module.h" 15db6bf921SJustin Bogner #include "llvm/Support/DXILABI.h" 1657006b14SXiang Li #include "llvm/Support/ErrorHandling.h" 17cdfd884bSS. Bharadwaj Yadavalli #include <optional> 1857006b14SXiang Li 1957006b14SXiang Li using namespace llvm; 20e77c40ffSChris Bieneman using namespace llvm::dxil; 2157006b14SXiang Li 2257006b14SXiang Li constexpr StringLiteral DXILOpNamePrefix = "dx.op."; 2357006b14SXiang Li 2457006b14SXiang Li namespace { 2557006b14SXiang Li enum OverloadKind : uint16_t { 26cdfd884bSS. Bharadwaj Yadavalli UNDEFINED = 0, 2757006b14SXiang Li VOID = 1, 2857006b14SXiang Li HALF = 1 << 1, 2957006b14SXiang Li FLOAT = 1 << 2, 3057006b14SXiang Li DOUBLE = 1 << 3, 3157006b14SXiang Li I1 = 1 << 4, 3257006b14SXiang Li I8 = 1 << 5, 3357006b14SXiang Li I16 = 1 << 6, 3457006b14SXiang Li I32 = 1 << 7, 3557006b14SXiang Li I64 = 1 << 8, 3657006b14SXiang Li UserDefineType = 1 << 9, 3757006b14SXiang Li ObjectType = 1 << 10, 3857006b14SXiang Li }; 39cdfd884bSS. Bharadwaj Yadavalli struct Version { 40cdfd884bSS. Bharadwaj Yadavalli unsigned Major = 0; 41cdfd884bSS. Bharadwaj Yadavalli unsigned Minor = 0; 42cdfd884bSS. Bharadwaj Yadavalli }; 4357006b14SXiang Li 44cdfd884bSS. Bharadwaj Yadavalli struct OpOverload { 45cdfd884bSS. Bharadwaj Yadavalli Version DXILVersion; 46cdfd884bSS. Bharadwaj Yadavalli uint16_t ValidTys; 47cdfd884bSS. Bharadwaj Yadavalli }; 4857006b14SXiang Li } // namespace 4957006b14SXiang Li 50cdfd884bSS. Bharadwaj Yadavalli struct OpStage { 51cdfd884bSS. Bharadwaj Yadavalli Version DXILVersion; 52cdfd884bSS. Bharadwaj Yadavalli uint32_t ValidStages; 53cdfd884bSS. Bharadwaj Yadavalli }; 54cdfd884bSS. Bharadwaj Yadavalli 5557006b14SXiang Li static const char *getOverloadTypeName(OverloadKind Kind) { 5657006b14SXiang Li switch (Kind) { 5757006b14SXiang Li case OverloadKind::HALF: 5857006b14SXiang Li return "f16"; 5957006b14SXiang Li case OverloadKind::FLOAT: 6057006b14SXiang Li return "f32"; 6157006b14SXiang Li case OverloadKind::DOUBLE: 6257006b14SXiang Li return "f64"; 6357006b14SXiang Li case OverloadKind::I1: 6457006b14SXiang Li return "i1"; 6557006b14SXiang Li case OverloadKind::I8: 6657006b14SXiang Li return "i8"; 6757006b14SXiang Li case OverloadKind::I16: 6857006b14SXiang Li return "i16"; 6957006b14SXiang Li case OverloadKind::I32: 7057006b14SXiang Li return "i32"; 7157006b14SXiang Li case OverloadKind::I64: 7257006b14SXiang Li return "i64"; 7357006b14SXiang Li case OverloadKind::VOID: 74cdfd884bSS. Bharadwaj Yadavalli case OverloadKind::UNDEFINED: 75cdfd884bSS. Bharadwaj Yadavalli return "void"; 7657006b14SXiang Li case OverloadKind::ObjectType: 7757006b14SXiang Li case OverloadKind::UserDefineType: 7857006b14SXiang Li break; 7957006b14SXiang Li } 8057006b14SXiang Li llvm_unreachable("invalid overload type for name"); 8157006b14SXiang Li } 8257006b14SXiang Li 8357006b14SXiang Li static OverloadKind getOverloadKind(Type *Ty) { 847d60f464SJustin Bogner if (!Ty) 857d60f464SJustin Bogner return OverloadKind::VOID; 867d60f464SJustin Bogner 8757006b14SXiang Li Type::TypeID T = Ty->getTypeID(); 8857006b14SXiang Li switch (T) { 8957006b14SXiang Li case Type::VoidTyID: 9057006b14SXiang Li return OverloadKind::VOID; 9157006b14SXiang Li case Type::HalfTyID: 9257006b14SXiang Li return OverloadKind::HALF; 9357006b14SXiang Li case Type::FloatTyID: 9457006b14SXiang Li return OverloadKind::FLOAT; 9557006b14SXiang Li case Type::DoubleTyID: 9657006b14SXiang Li return OverloadKind::DOUBLE; 9757006b14SXiang Li case Type::IntegerTyID: { 9857006b14SXiang Li IntegerType *ITy = cast<IntegerType>(Ty); 9957006b14SXiang Li unsigned Bits = ITy->getBitWidth(); 10057006b14SXiang Li switch (Bits) { 10157006b14SXiang Li case 1: 10257006b14SXiang Li return OverloadKind::I1; 10357006b14SXiang Li case 8: 10457006b14SXiang Li return OverloadKind::I8; 10557006b14SXiang Li case 16: 10657006b14SXiang Li return OverloadKind::I16; 10757006b14SXiang Li case 32: 10857006b14SXiang Li return OverloadKind::I32; 10957006b14SXiang Li case 64: 11057006b14SXiang Li return OverloadKind::I64; 11157006b14SXiang Li default: 11257006b14SXiang Li llvm_unreachable("invalid overload type"); 11357006b14SXiang Li return OverloadKind::VOID; 11457006b14SXiang Li } 11557006b14SXiang Li } 11657006b14SXiang Li case Type::PointerTyID: 11757006b14SXiang Li return OverloadKind::UserDefineType; 1183f22756fSJustin Bogner case Type::StructTyID: { 1193f22756fSJustin Bogner // TODO: This is a hack. As described in DXILEmitter.cpp, we need to rework 1203f22756fSJustin Bogner // how we're handling overloads and remove the `OverloadKind` proxy enum. 1213f22756fSJustin Bogner StructType *ST = cast<StructType>(Ty); 1223f22756fSJustin Bogner return getOverloadKind(ST->getElementType(0)); 1233f22756fSJustin Bogner } 12457006b14SXiang Li default: 12576be3a00SJustin Bogner return OverloadKind::UNDEFINED; 12657006b14SXiang Li } 12757006b14SXiang Li } 12857006b14SXiang Li 12957006b14SXiang Li static std::string getTypeName(OverloadKind Kind, Type *Ty) { 13057006b14SXiang Li if (Kind < OverloadKind::UserDefineType) { 13157006b14SXiang Li return getOverloadTypeName(Kind); 13257006b14SXiang Li } else if (Kind == OverloadKind::UserDefineType) { 13357006b14SXiang Li StructType *ST = cast<StructType>(Ty); 13457006b14SXiang Li return ST->getStructName().str(); 13557006b14SXiang Li } else if (Kind == OverloadKind::ObjectType) { 13657006b14SXiang Li StructType *ST = cast<StructType>(Ty); 13757006b14SXiang Li return ST->getStructName().str(); 13857006b14SXiang Li } else { 13957006b14SXiang Li std::string Str; 14057006b14SXiang Li raw_string_ostream OS(Str); 14157006b14SXiang Li Ty->print(OS); 14257006b14SXiang Li return OS.str(); 14357006b14SXiang Li } 14457006b14SXiang Li } 14557006b14SXiang Li 14657006b14SXiang Li // Static properties. 14757006b14SXiang Li struct OpCodeProperty { 148e77c40ffSChris Bieneman dxil::OpCode OpCode; 14957006b14SXiang Li // Offset in DXILOpCodeNameTable. 15057006b14SXiang Li unsigned OpCodeNameOffset; 151e77c40ffSChris Bieneman dxil::OpCodeClass OpCodeClass; 15257006b14SXiang Li // Offset in DXILOpCodeClassNameTable. 15357006b14SXiang Li unsigned OpCodeClassNameOffset; 154cdfd884bSS. Bharadwaj Yadavalli llvm::SmallVector<OpOverload> Overloads; 155cdfd884bSS. Bharadwaj Yadavalli llvm::SmallVector<OpStage> Stages; 15657006b14SXiang Li int OverloadParamIndex; // parameter index which control the overload. 15757006b14SXiang Li // When < 0, should be only 1 overload type. 15857006b14SXiang Li }; 15957006b14SXiang Li 16057006b14SXiang Li // Include getOpCodeClassName getOpCodeProperty, getOpCodeName and 16157006b14SXiang Li // getOpCodeParameterKind which generated by tableGen. 16257006b14SXiang Li #define DXIL_OP_OPERATION_TABLE 16357006b14SXiang Li #include "DXILOperation.inc" 16457006b14SXiang Li #undef DXIL_OP_OPERATION_TABLE 16557006b14SXiang Li 16657006b14SXiang Li static std::string constructOverloadName(OverloadKind Kind, Type *Ty, 16757006b14SXiang Li const OpCodeProperty &Prop) { 16857006b14SXiang Li if (Kind == OverloadKind::VOID) { 16957006b14SXiang Li return (Twine(DXILOpNamePrefix) + getOpCodeClassName(Prop)).str(); 17057006b14SXiang Li } 17157006b14SXiang Li return (Twine(DXILOpNamePrefix) + getOpCodeClassName(Prop) + "." + 17257006b14SXiang Li getTypeName(Kind, Ty)) 17357006b14SXiang Li .str(); 17457006b14SXiang Li } 17557006b14SXiang Li 17657006b14SXiang Li static std::string constructOverloadTypeName(OverloadKind Kind, 17757006b14SXiang Li StringRef TypeName) { 17857006b14SXiang Li if (Kind == OverloadKind::VOID) 17957006b14SXiang Li return TypeName.str(); 18057006b14SXiang Li 18157006b14SXiang Li assert(Kind < OverloadKind::UserDefineType && "invalid overload kind"); 18257006b14SXiang Li return (Twine(TypeName) + getOverloadTypeName(Kind)).str(); 18357006b14SXiang Li } 18457006b14SXiang Li 18557006b14SXiang Li static StructType *getOrCreateStructType(StringRef Name, 18657006b14SXiang Li ArrayRef<Type *> EltTys, 18757006b14SXiang Li LLVMContext &Ctx) { 18857006b14SXiang Li StructType *ST = StructType::getTypeByName(Ctx, Name); 18957006b14SXiang Li if (ST) 19057006b14SXiang Li return ST; 19157006b14SXiang Li 19257006b14SXiang Li return StructType::create(Ctx, EltTys, Name); 19357006b14SXiang Li } 19457006b14SXiang Li 1953f22756fSJustin Bogner static StructType *getResRetType(Type *ElementTy) { 1963f22756fSJustin Bogner LLVMContext &Ctx = ElementTy->getContext(); 1973f22756fSJustin Bogner OverloadKind Kind = getOverloadKind(ElementTy); 19857006b14SXiang Li std::string TypeName = constructOverloadTypeName(Kind, "dx.types.ResRet."); 1993f22756fSJustin Bogner Type *FieldTypes[5] = {ElementTy, ElementTy, ElementTy, ElementTy, 20057006b14SXiang Li Type::getInt32Ty(Ctx)}; 20157006b14SXiang Li return getOrCreateStructType(TypeName, FieldTypes, Ctx); 20257006b14SXiang Li } 20357006b14SXiang Li 20457006b14SXiang Li static StructType *getHandleType(LLVMContext &Ctx) { 2057b9d73c2SPaulo Matos return getOrCreateStructType("dx.types.Handle", PointerType::getUnqual(Ctx), 2067b9d73c2SPaulo Matos Ctx); 20757006b14SXiang Li } 20857006b14SXiang Li 209aa61925eSJustin Bogner static StructType *getResBindType(LLVMContext &Context) { 210aa61925eSJustin Bogner if (auto *ST = StructType::getTypeByName(Context, "dx.types.ResBind")) 211aa61925eSJustin Bogner return ST; 212aa61925eSJustin Bogner Type *Int32Ty = Type::getInt32Ty(Context); 213aa61925eSJustin Bogner Type *Int8Ty = Type::getInt8Ty(Context); 214aa61925eSJustin Bogner return StructType::create({Int32Ty, Int32Ty, Int32Ty, Int8Ty}, 215aa61925eSJustin Bogner "dx.types.ResBind"); 216aa61925eSJustin Bogner } 217aa61925eSJustin Bogner 218aa61925eSJustin Bogner static StructType *getResPropsType(LLVMContext &Context) { 219aa61925eSJustin Bogner if (auto *ST = 220aa61925eSJustin Bogner StructType::getTypeByName(Context, "dx.types.ResourceProperties")) 221aa61925eSJustin Bogner return ST; 222aa61925eSJustin Bogner Type *Int32Ty = Type::getInt32Ty(Context); 223aa61925eSJustin Bogner return StructType::create({Int32Ty, Int32Ty}, "dx.types.ResourceProperties"); 224aa61925eSJustin Bogner } 225aa61925eSJustin Bogner 226481bce01Sjoaosaffran static StructType *getSplitDoubleType(LLVMContext &Context) { 227481bce01Sjoaosaffran if (auto *ST = StructType::getTypeByName(Context, "dx.types.splitdouble")) 228481bce01Sjoaosaffran return ST; 229481bce01Sjoaosaffran Type *Int32Ty = Type::getInt32Ty(Context); 230481bce01Sjoaosaffran return StructType::create({Int32Ty, Int32Ty}, "dx.types.splitdouble"); 231481bce01Sjoaosaffran } 232481bce01Sjoaosaffran 233f357fe37SJustin Bogner static Type *getTypeFromOpParamType(OpParamType Kind, LLVMContext &Ctx, 2348cf85653SJustin Bogner Type *OverloadTy) { 23557006b14SXiang Li switch (Kind) { 236f357fe37SJustin Bogner case OpParamType::VoidTy: 23757006b14SXiang Li return Type::getVoidTy(Ctx); 238f357fe37SJustin Bogner case OpParamType::HalfTy: 23957006b14SXiang Li return Type::getHalfTy(Ctx); 240f357fe37SJustin Bogner case OpParamType::FloatTy: 24157006b14SXiang Li return Type::getFloatTy(Ctx); 242f357fe37SJustin Bogner case OpParamType::DoubleTy: 24357006b14SXiang Li return Type::getDoubleTy(Ctx); 244f357fe37SJustin Bogner case OpParamType::Int1Ty: 24557006b14SXiang Li return Type::getInt1Ty(Ctx); 246f357fe37SJustin Bogner case OpParamType::Int8Ty: 24757006b14SXiang Li return Type::getInt8Ty(Ctx); 248f357fe37SJustin Bogner case OpParamType::Int16Ty: 24957006b14SXiang Li return Type::getInt16Ty(Ctx); 250f357fe37SJustin Bogner case OpParamType::Int32Ty: 25157006b14SXiang Li return Type::getInt32Ty(Ctx); 252f357fe37SJustin Bogner case OpParamType::Int64Ty: 25357006b14SXiang Li return Type::getInt64Ty(Ctx); 254f357fe37SJustin Bogner case OpParamType::OverloadTy: 25557006b14SXiang Li return OverloadTy; 2563f22756fSJustin Bogner case OpParamType::ResRetHalfTy: 2573f22756fSJustin Bogner return getResRetType(Type::getHalfTy(Ctx)); 2583f22756fSJustin Bogner case OpParamType::ResRetFloatTy: 2593f22756fSJustin Bogner return getResRetType(Type::getFloatTy(Ctx)); 260cba9bd5cSJustin Bogner case OpParamType::ResRetDoubleTy: 261cba9bd5cSJustin Bogner return getResRetType(Type::getDoubleTy(Ctx)); 2623f22756fSJustin Bogner case OpParamType::ResRetInt16Ty: 2633f22756fSJustin Bogner return getResRetType(Type::getInt16Ty(Ctx)); 2643f22756fSJustin Bogner case OpParamType::ResRetInt32Ty: 2653f22756fSJustin Bogner return getResRetType(Type::getInt32Ty(Ctx)); 266cba9bd5cSJustin Bogner case OpParamType::ResRetInt64Ty: 267cba9bd5cSJustin Bogner return getResRetType(Type::getInt64Ty(Ctx)); 268f357fe37SJustin Bogner case OpParamType::HandleTy: 26957006b14SXiang Li return getHandleType(Ctx); 270aa61925eSJustin Bogner case OpParamType::ResBindTy: 271aa61925eSJustin Bogner return getResBindType(Ctx); 272aa61925eSJustin Bogner case OpParamType::ResPropsTy: 273aa61925eSJustin Bogner return getResPropsType(Ctx); 274481bce01Sjoaosaffran case OpParamType::SplitDoubleTy: 275481bce01Sjoaosaffran return getSplitDoubleType(Ctx); 27657006b14SXiang Li } 27757006b14SXiang Li llvm_unreachable("Invalid parameter kind"); 27857006b14SXiang Li return nullptr; 27957006b14SXiang Li } 28057006b14SXiang Li 281cdfd884bSS. Bharadwaj Yadavalli static ShaderKind getShaderKindEnum(Triple::EnvironmentType EnvType) { 282cdfd884bSS. Bharadwaj Yadavalli switch (EnvType) { 283cdfd884bSS. Bharadwaj Yadavalli case Triple::Pixel: 284cdfd884bSS. Bharadwaj Yadavalli return ShaderKind::pixel; 285cdfd884bSS. Bharadwaj Yadavalli case Triple::Vertex: 286cdfd884bSS. Bharadwaj Yadavalli return ShaderKind::vertex; 287cdfd884bSS. Bharadwaj Yadavalli case Triple::Geometry: 288cdfd884bSS. Bharadwaj Yadavalli return ShaderKind::geometry; 289cdfd884bSS. Bharadwaj Yadavalli case Triple::Hull: 290cdfd884bSS. Bharadwaj Yadavalli return ShaderKind::hull; 291cdfd884bSS. Bharadwaj Yadavalli case Triple::Domain: 292cdfd884bSS. Bharadwaj Yadavalli return ShaderKind::domain; 293cdfd884bSS. Bharadwaj Yadavalli case Triple::Compute: 294cdfd884bSS. Bharadwaj Yadavalli return ShaderKind::compute; 295cdfd884bSS. Bharadwaj Yadavalli case Triple::Library: 296cdfd884bSS. Bharadwaj Yadavalli return ShaderKind::library; 297cdfd884bSS. Bharadwaj Yadavalli case Triple::RayGeneration: 298cdfd884bSS. Bharadwaj Yadavalli return ShaderKind::raygeneration; 299cdfd884bSS. Bharadwaj Yadavalli case Triple::Intersection: 300cdfd884bSS. Bharadwaj Yadavalli return ShaderKind::intersection; 301cdfd884bSS. Bharadwaj Yadavalli case Triple::AnyHit: 302cdfd884bSS. Bharadwaj Yadavalli return ShaderKind::anyhit; 303cdfd884bSS. Bharadwaj Yadavalli case Triple::ClosestHit: 304cdfd884bSS. Bharadwaj Yadavalli return ShaderKind::closesthit; 305cdfd884bSS. Bharadwaj Yadavalli case Triple::Miss: 306cdfd884bSS. Bharadwaj Yadavalli return ShaderKind::miss; 307cdfd884bSS. Bharadwaj Yadavalli case Triple::Callable: 308cdfd884bSS. Bharadwaj Yadavalli return ShaderKind::callable; 309cdfd884bSS. Bharadwaj Yadavalli case Triple::Mesh: 310cdfd884bSS. Bharadwaj Yadavalli return ShaderKind::mesh; 311cdfd884bSS. Bharadwaj Yadavalli case Triple::Amplification: 312cdfd884bSS. Bharadwaj Yadavalli return ShaderKind::amplification; 313cdfd884bSS. Bharadwaj Yadavalli default: 314cdfd884bSS. Bharadwaj Yadavalli break; 315cdfd884bSS. Bharadwaj Yadavalli } 316cdfd884bSS. Bharadwaj Yadavalli llvm_unreachable( 317cdfd884bSS. Bharadwaj Yadavalli "Shader Kind Not Found - Invalid DXIL Environment Specified"); 318cdfd884bSS. Bharadwaj Yadavalli } 319cdfd884bSS. Bharadwaj Yadavalli 320f357fe37SJustin Bogner static SmallVector<Type *> 321f357fe37SJustin Bogner getArgTypesFromOpParamTypes(ArrayRef<dxil::OpParamType> Types, 322f357fe37SJustin Bogner LLVMContext &Context, Type *OverloadTy) { 323f357fe37SJustin Bogner SmallVector<Type *> ArgTys; 324f357fe37SJustin Bogner ArgTys.emplace_back(Type::getInt32Ty(Context)); 325f357fe37SJustin Bogner for (dxil::OpParamType Ty : Types) 326f357fe37SJustin Bogner ArgTys.emplace_back(getTypeFromOpParamType(Ty, Context, OverloadTy)); 327f357fe37SJustin Bogner return ArgTys; 328f357fe37SJustin Bogner } 329f357fe37SJustin Bogner 330b1c8b9f8SS. Bharadwaj Yadavalli /// Construct DXIL function type. This is the type of a function with 331b1c8b9f8SS. Bharadwaj Yadavalli /// the following prototype 332b1c8b9f8SS. Bharadwaj Yadavalli /// OverloadType dx.op.<opclass>.<return-type>(int opcode, <param types>) 333b1c8b9f8SS. Bharadwaj Yadavalli /// <param-types> are constructed from types in Prop. 334f357fe37SJustin Bogner static FunctionType *getDXILOpFunctionType(dxil::OpCode OpCode, 3358cf85653SJustin Bogner LLVMContext &Context, 3368cf85653SJustin Bogner Type *OverloadTy) { 33757006b14SXiang Li 338f357fe37SJustin Bogner switch (OpCode) { 339f357fe37SJustin Bogner #define DXIL_OP_FUNCTION_TYPE(OpCode, RetType, ...) \ 340f357fe37SJustin Bogner case OpCode: \ 341f357fe37SJustin Bogner return FunctionType::get( \ 342f357fe37SJustin Bogner getTypeFromOpParamType(RetType, Context, OverloadTy), \ 343f357fe37SJustin Bogner getArgTypesFromOpParamTypes({__VA_ARGS__}, Context, OverloadTy), \ 344f357fe37SJustin Bogner /*isVarArg=*/false); 345f357fe37SJustin Bogner #include "DXILOperation.inc" 34657006b14SXiang Li } 347f357fe37SJustin Bogner llvm_unreachable("Invalid OpCode?"); 34857006b14SXiang Li } 34957006b14SXiang Li 350cdfd884bSS. Bharadwaj Yadavalli /// Get index of the property from PropList valid for the most recent 351cdfd884bSS. Bharadwaj Yadavalli /// DXIL version not greater than DXILVer. 352cdfd884bSS. Bharadwaj Yadavalli /// PropList is expected to be sorted in ascending order of DXIL version. 353cdfd884bSS. Bharadwaj Yadavalli template <typename T> 354cdfd884bSS. Bharadwaj Yadavalli static std::optional<size_t> getPropIndex(ArrayRef<T> PropList, 355cdfd884bSS. Bharadwaj Yadavalli const VersionTuple DXILVer) { 356cdfd884bSS. Bharadwaj Yadavalli size_t Index = PropList.size() - 1; 357cdfd884bSS. Bharadwaj Yadavalli for (auto Iter = PropList.rbegin(); Iter != PropList.rend(); 358cdfd884bSS. Bharadwaj Yadavalli Iter++, Index--) { 359cdfd884bSS. Bharadwaj Yadavalli const T &Prop = *Iter; 360cdfd884bSS. Bharadwaj Yadavalli if (VersionTuple(Prop.DXILVersion.Major, Prop.DXILVersion.Minor) <= 361cdfd884bSS. Bharadwaj Yadavalli DXILVer) { 362cdfd884bSS. Bharadwaj Yadavalli return Index; 363cdfd884bSS. Bharadwaj Yadavalli } 364cdfd884bSS. Bharadwaj Yadavalli } 365cdfd884bSS. Bharadwaj Yadavalli return std::nullopt; 366cdfd884bSS. Bharadwaj Yadavalli } 367cdfd884bSS. Bharadwaj Yadavalli 368*011b6186SFinn Plummer // Helper function to pack an OpCode and VersionTuple into a uint64_t for use 369*011b6186SFinn Plummer // in a switch statement 370*011b6186SFinn Plummer constexpr static uint64_t computeSwitchEnum(dxil::OpCode OpCode, 371*011b6186SFinn Plummer uint16_t VersionMajor, 372*011b6186SFinn Plummer uint16_t VersionMinor) { 373*011b6186SFinn Plummer uint64_t OpCodePack = (uint64_t)OpCode; 374*011b6186SFinn Plummer return (OpCodePack << 32) | (VersionMajor << 16) | VersionMinor; 375*011b6186SFinn Plummer } 376*011b6186SFinn Plummer 377*011b6186SFinn Plummer // Retreive all the set attributes for a DXIL OpCode given the targeted 378*011b6186SFinn Plummer // DXILVersion 379*011b6186SFinn Plummer static dxil::Attributes getDXILAttributes(dxil::OpCode OpCode, 380*011b6186SFinn Plummer VersionTuple DXILVersion) { 381*011b6186SFinn Plummer // Instantiate all versions to iterate through 382*011b6186SFinn Plummer SmallVector<Version> Versions = { 383*011b6186SFinn Plummer #define DXIL_VERSION(MAJOR, MINOR) {MAJOR, MINOR}, 384*011b6186SFinn Plummer #include "DXILOperation.inc" 385*011b6186SFinn Plummer }; 386*011b6186SFinn Plummer 387*011b6186SFinn Plummer dxil::Attributes Attributes; 388*011b6186SFinn Plummer for (auto Version : Versions) { 389*011b6186SFinn Plummer if (DXILVersion < VersionTuple(Version.Major, Version.Minor)) 390*011b6186SFinn Plummer continue; 391*011b6186SFinn Plummer 392*011b6186SFinn Plummer // Switch through and match an OpCode with the specific version and set the 393*011b6186SFinn Plummer // corresponding flag(s) if available 394*011b6186SFinn Plummer switch (computeSwitchEnum(OpCode, Version.Major, Version.Minor)) { 395*011b6186SFinn Plummer #define DXIL_OP_ATTRIBUTES(OpCode, VersionMajor, VersionMinor, ...) \ 396*011b6186SFinn Plummer case computeSwitchEnum(OpCode, VersionMajor, VersionMinor): { \ 397*011b6186SFinn Plummer auto Other = dxil::Attributes{__VA_ARGS__}; \ 398*011b6186SFinn Plummer Attributes |= Other; \ 399*011b6186SFinn Plummer break; \ 400*011b6186SFinn Plummer }; 401*011b6186SFinn Plummer #include "DXILOperation.inc" 402*011b6186SFinn Plummer } 403*011b6186SFinn Plummer } 404*011b6186SFinn Plummer return Attributes; 405*011b6186SFinn Plummer } 406*011b6186SFinn Plummer 407*011b6186SFinn Plummer // Retreive the set of DXIL Attributes given the version and map them to an 408*011b6186SFinn Plummer // llvm function attribute that is set onto the instruction 409*011b6186SFinn Plummer static void setDXILAttributes(CallInst *CI, dxil::OpCode OpCode, 410*011b6186SFinn Plummer VersionTuple DXILVersion) { 411*011b6186SFinn Plummer dxil::Attributes Attributes = getDXILAttributes(OpCode, DXILVersion); 412*011b6186SFinn Plummer if (Attributes.ReadNone) 413*011b6186SFinn Plummer CI->setDoesNotAccessMemory(); 414*011b6186SFinn Plummer if (Attributes.ReadOnly) 415*011b6186SFinn Plummer CI->setOnlyReadsMemory(); 416*011b6186SFinn Plummer if (Attributes.NoReturn) 417*011b6186SFinn Plummer CI->setDoesNotReturn(); 418*011b6186SFinn Plummer if (Attributes.NoDuplicate) 419*011b6186SFinn Plummer CI->setCannotDuplicate(); 420*011b6186SFinn Plummer return; 421*011b6186SFinn Plummer } 422*011b6186SFinn Plummer 4233f395712SS. Bharadwaj Yadavalli namespace llvm { 4243f395712SS. Bharadwaj Yadavalli namespace dxil { 4253f395712SS. Bharadwaj Yadavalli 426cdfd884bSS. Bharadwaj Yadavalli // No extra checks on TargetTriple need be performed to verify that the 427cdfd884bSS. Bharadwaj Yadavalli // Triple is well-formed or that the target is supported since these checks 428cdfd884bSS. Bharadwaj Yadavalli // would have been done at the time the module M is constructed in the earlier 429cdfd884bSS. Bharadwaj Yadavalli // stages of compilation. 430e56ad22bSJustin Bogner DXILOpBuilder::DXILOpBuilder(Module &M) : M(M), IRB(M.getContext()) { 431cdfd884bSS. Bharadwaj Yadavalli Triple TT(Triple(M.getTargetTriple())); 432cdfd884bSS. Bharadwaj Yadavalli DXILVersion = TT.getDXILVersion(); 433cdfd884bSS. Bharadwaj Yadavalli ShaderStage = TT.getEnvironment(); 434cdfd884bSS. Bharadwaj Yadavalli // Ensure Environment type is known 435cdfd884bSS. Bharadwaj Yadavalli if (ShaderStage == Triple::UnknownEnvironment) { 436cdfd884bSS. Bharadwaj Yadavalli report_fatal_error( 437cdfd884bSS. Bharadwaj Yadavalli Twine(DXILVersion.getAsString()) + 438cdfd884bSS. Bharadwaj Yadavalli ": Unknown Compilation Target Shader Stage specified ", 439cdfd884bSS. Bharadwaj Yadavalli /*gen_crash_diag*/ false); 440cdfd884bSS. Bharadwaj Yadavalli } 441cdfd884bSS. Bharadwaj Yadavalli } 442cdfd884bSS. Bharadwaj Yadavalli 4438cf85653SJustin Bogner static Error makeOpError(dxil::OpCode OpCode, Twine Msg) { 4448cf85653SJustin Bogner return make_error<StringError>( 4458cf85653SJustin Bogner Twine("Cannot create ") + getOpCodeName(OpCode) + " operation: " + Msg, 4468cf85653SJustin Bogner inconvertibleErrorCode()); 4478cf85653SJustin Bogner } 448cdfd884bSS. Bharadwaj Yadavalli 4498cf85653SJustin Bogner Expected<CallInst *> DXILOpBuilder::tryCreateOp(dxil::OpCode OpCode, 4508cf85653SJustin Bogner ArrayRef<Value *> Args, 4513d129016SJustin Bogner const Twine &Name, 4528cf85653SJustin Bogner Type *RetTy) { 4533f395712SS. Bharadwaj Yadavalli const OpCodeProperty *Prop = getOpCodeProperty(OpCode); 4548cf85653SJustin Bogner 4558cf85653SJustin Bogner Type *OverloadTy = nullptr; 4568cf85653SJustin Bogner if (Prop->OverloadParamIndex == 0) { 4578cf85653SJustin Bogner if (!RetTy) 4588cf85653SJustin Bogner return makeOpError(OpCode, "Op overloaded on unknown return type"); 4598cf85653SJustin Bogner OverloadTy = RetTy; 4608cf85653SJustin Bogner } else if (Prop->OverloadParamIndex > 0) { 4618cf85653SJustin Bogner // The index counts including the return type 4628cf85653SJustin Bogner unsigned ArgIndex = Prop->OverloadParamIndex - 1; 4638cf85653SJustin Bogner if (static_cast<unsigned>(ArgIndex) >= Args.size()) 4648cf85653SJustin Bogner return makeOpError(OpCode, "Wrong number of arguments"); 4658cf85653SJustin Bogner OverloadTy = Args[ArgIndex]->getType(); 4668cf85653SJustin Bogner } 4673f22756fSJustin Bogner 4688cf85653SJustin Bogner FunctionType *DXILOpFT = 469f357fe37SJustin Bogner getDXILOpFunctionType(OpCode, M.getContext(), OverloadTy); 4708cf85653SJustin Bogner 471cdfd884bSS. Bharadwaj Yadavalli std::optional<size_t> OlIndexOrErr = 472cdfd884bSS. Bharadwaj Yadavalli getPropIndex(ArrayRef(Prop->Overloads), DXILVersion); 4738cf85653SJustin Bogner if (!OlIndexOrErr.has_value()) 4748cf85653SJustin Bogner return makeOpError(OpCode, Twine("No valid overloads for DXIL version ") + 4758cf85653SJustin Bogner DXILVersion.getAsString()); 4768cf85653SJustin Bogner 477cdfd884bSS. Bharadwaj Yadavalli uint16_t ValidTyMask = Prop->Overloads[*OlIndexOrErr].ValidTys; 47857006b14SXiang Li 4797d60f464SJustin Bogner OverloadKind Kind = getOverloadKind(OverloadTy); 480cdfd884bSS. Bharadwaj Yadavalli 481cdfd884bSS. Bharadwaj Yadavalli // Check if the operation supports overload types and OverloadTy is valid 482cdfd884bSS. Bharadwaj Yadavalli // per the specified types for the operation 483cdfd884bSS. Bharadwaj Yadavalli if ((ValidTyMask != OverloadKind::UNDEFINED) && 4848cf85653SJustin Bogner (ValidTyMask & (uint16_t)Kind) == 0) 4858cf85653SJustin Bogner return makeOpError(OpCode, "Invalid overload type"); 486cdfd884bSS. Bharadwaj Yadavalli 487cdfd884bSS. Bharadwaj Yadavalli // Perform necessary checks to ensure Opcode is valid in the targeted shader 488cdfd884bSS. Bharadwaj Yadavalli // kind 489cdfd884bSS. Bharadwaj Yadavalli std::optional<size_t> StIndexOrErr = 490cdfd884bSS. Bharadwaj Yadavalli getPropIndex(ArrayRef(Prop->Stages), DXILVersion); 4918cf85653SJustin Bogner if (!StIndexOrErr.has_value()) 4928cf85653SJustin Bogner return makeOpError(OpCode, Twine("No valid stage for DXIL version ") + 4938cf85653SJustin Bogner DXILVersion.getAsString()); 4948cf85653SJustin Bogner 495cdfd884bSS. Bharadwaj Yadavalli uint16_t ValidShaderKindMask = Prop->Stages[*StIndexOrErr].ValidStages; 496cdfd884bSS. Bharadwaj Yadavalli 497cdfd884bSS. Bharadwaj Yadavalli // Ensure valid shader stage properties are specified 4988cf85653SJustin Bogner if (ValidShaderKindMask == ShaderKind::removed) 4998cf85653SJustin Bogner return makeOpError(OpCode, "Operation has been removed"); 500cdfd884bSS. Bharadwaj Yadavalli 501cdfd884bSS. Bharadwaj Yadavalli // Shader stage need not be validated since getShaderKindEnum() fails 502cdfd884bSS. Bharadwaj Yadavalli // for unknown shader stage. 503cdfd884bSS. Bharadwaj Yadavalli 504cdfd884bSS. Bharadwaj Yadavalli // Verify the target shader stage is valid for the DXIL operation 505cdfd884bSS. Bharadwaj Yadavalli ShaderKind ModuleStagekind = getShaderKindEnum(ShaderStage); 5068cf85653SJustin Bogner if (!(ValidShaderKindMask & ModuleStagekind)) 5078cf85653SJustin Bogner return makeOpError(OpCode, "Invalid stage"); 50857006b14SXiang Li 5093f395712SS. Bharadwaj Yadavalli std::string DXILFnName = constructOverloadName(Kind, OverloadTy, *Prop); 5108cf85653SJustin Bogner FunctionCallee DXILFn = M.getOrInsertFunction(DXILFnName, DXILOpFT); 5118cf85653SJustin Bogner 5128cf85653SJustin Bogner // We need to inject the opcode as the first argument. 5138cf85653SJustin Bogner SmallVector<Value *> OpArgs; 514e56ad22bSJustin Bogner OpArgs.push_back(IRB.getInt32(llvm::to_underlying(OpCode))); 5158cf85653SJustin Bogner OpArgs.append(Args.begin(), Args.end()); 5168cf85653SJustin Bogner 517*011b6186SFinn Plummer // Create the function call instruction 518*011b6186SFinn Plummer CallInst *CI = IRB.CreateCall(DXILFn, OpArgs, Name); 519*011b6186SFinn Plummer 520*011b6186SFinn Plummer // We then need to attach available function attributes 521*011b6186SFinn Plummer setDXILAttributes(CI, OpCode, DXILVersion); 522*011b6186SFinn Plummer 523*011b6186SFinn Plummer return CI; 52457006b14SXiang Li } 525060df78cSFarzon Lotfi 52671d54faaSJustin Bogner CallInst *DXILOpBuilder::createOp(dxil::OpCode OpCode, ArrayRef<Value *> Args, 5273d129016SJustin Bogner const Twine &Name, Type *RetTy) { 5283d129016SJustin Bogner Expected<CallInst *> Result = tryCreateOp(OpCode, Args, Name, RetTy); 5298cf85653SJustin Bogner if (Error E = Result.takeError()) 5308cf85653SJustin Bogner llvm_unreachable("Invalid arguments for operation"); 5318cf85653SJustin Bogner return *Result; 53257006b14SXiang Li } 53357006b14SXiang Li 5343f22756fSJustin Bogner StructType *DXILOpBuilder::getResRetType(Type *ElementTy) { 5353f22756fSJustin Bogner return ::getResRetType(ElementTy); 5363f22756fSJustin Bogner } 5373f22756fSJustin Bogner 538481bce01Sjoaosaffran StructType *DXILOpBuilder::getSplitDoubleType(LLVMContext &Context) { 539481bce01Sjoaosaffran return ::getSplitDoubleType(Context); 540481bce01Sjoaosaffran } 541481bce01Sjoaosaffran 542aa61925eSJustin Bogner StructType *DXILOpBuilder::getHandleType() { 543aa61925eSJustin Bogner return ::getHandleType(IRB.getContext()); 544aa61925eSJustin Bogner } 545aa61925eSJustin Bogner 546aa61925eSJustin Bogner Constant *DXILOpBuilder::getResBind(uint32_t LowerBound, uint32_t UpperBound, 547aa61925eSJustin Bogner uint32_t SpaceID, dxil::ResourceClass RC) { 548aa61925eSJustin Bogner Type *Int32Ty = IRB.getInt32Ty(); 549aa61925eSJustin Bogner Type *Int8Ty = IRB.getInt8Ty(); 550aa61925eSJustin Bogner return ConstantStruct::get( 551aa61925eSJustin Bogner getResBindType(IRB.getContext()), 552aa61925eSJustin Bogner {ConstantInt::get(Int32Ty, LowerBound), 553aa61925eSJustin Bogner ConstantInt::get(Int32Ty, UpperBound), 554aa61925eSJustin Bogner ConstantInt::get(Int32Ty, SpaceID), 555aa61925eSJustin Bogner ConstantInt::get(Int8Ty, llvm::to_underlying(RC))}); 556aa61925eSJustin Bogner } 557aa61925eSJustin Bogner 558aa61925eSJustin Bogner Constant *DXILOpBuilder::getResProps(uint32_t Word0, uint32_t Word1) { 559aa61925eSJustin Bogner Type *Int32Ty = IRB.getInt32Ty(); 560aa61925eSJustin Bogner return ConstantStruct::get( 561aa61925eSJustin Bogner getResPropsType(IRB.getContext()), 562aa61925eSJustin Bogner {ConstantInt::get(Int32Ty, Word0), ConstantInt::get(Int32Ty, Word1)}); 563aa61925eSJustin Bogner } 564aa61925eSJustin Bogner 565e77c40ffSChris Bieneman const char *DXILOpBuilder::getOpCodeName(dxil::OpCode DXILOp) { 56657006b14SXiang Li return ::getOpCodeName(DXILOp); 56757006b14SXiang Li } 568e77c40ffSChris Bieneman } // namespace dxil 56957006b14SXiang Li } // namespace llvm 570