From cb132036cfa5ea01283af5de6b8ecea15c141ac6 Mon Sep 17 00:00:00 2001 From: Simon Moll Date: Mon, 27 Jan 2025 09:49:06 +0100 Subject: [PATCH 1/4] [SER] Patch 1: HitObject type lowering and SM 6.9 enablement Reduction of the complete SER implementation to just the HitObject type and its default constructor. Specification PR: https://github.com/microsoft/hlsl-specs/pull/277 --- include/dxc/DXIL/DxilUtil.h | 2 + include/dxc/HlslIntrinsicOp.h | 1 + include/dxc/Support/HLSLOptions.h | 1 + include/dxc/dxcapi.internal.h | 6 +- lib/DXIL/DxilUtil.cpp | 21 +++ lib/DxcSupport/HLSLOptions.cpp | 3 + lib/HLSL/HLLowerUDT.cpp | 6 +- lib/HLSL/HLOperationLower.cpp | 10 ++ tools/clang/include/clang/AST/HlslTypes.h | 3 + .../clang/Basic/DiagnosticSemaKinds.td | 4 + tools/clang/include/clang/Basic/LangOptions.h | 1 + .../include/clang/Frontend/CodeGenOptions.h | 2 + tools/clang/include/clang/Sema/Sema.h | 4 + tools/clang/lib/AST/ASTContextHLSL.cpp | 37 ++++- tools/clang/lib/AST/HlslTypes.cpp | 16 ++ tools/clang/lib/CodeGen/CGCall.cpp | 8 +- tools/clang/lib/CodeGen/CGExprScalar.cpp | 13 ++ tools/clang/lib/CodeGen/CGHLSLMS.cpp | 36 ++++- .../lib/CodeGen/CGHLSLMSFinishCodeGen.cpp | 50 ++++++ tools/clang/lib/CodeGen/CGHLSLMSHelper.h | 1 + tools/clang/lib/CodeGen/CGHLSLRuntime.h | 4 + tools/clang/lib/CodeGen/CodeGenFunction.cpp | 12 +- tools/clang/lib/CodeGen/CodeGenTypes.cpp | 13 +- tools/clang/lib/CodeGen/TargetInfo.cpp | 20 ++- tools/clang/lib/SPIRV/AstTypeProbe.cpp | 7 + tools/clang/lib/Sema/SemaCXXScopeSpec.cpp | 9 +- tools/clang/lib/Sema/SemaHLSL.cpp | 143 ++++++++++++++++-- tools/clang/lib/Sema/SemaHLSLDiagnoseTU.cpp | 39 +++++ .../ser/hitobject-unused-id-pre-sm69.hlsl | 9 ++ .../ser/reorder-unclaimed-pre-sm69.hlsl | 13 ++ .../HitObject/hitobject-entry-errors.hlsl | 57 +++++++ .../HitObject/hitobject-in-buffer.hlsl | 8 + .../hitobject-target-profile-error.hlsl | 7 + .../hitobject-unclaimed-pre-sm69.hlsl | 18 +++ .../HitObject/hitobject-unsupported-vs.hlsl | 8 + .../clang/tools/dxcompiler/dxcompilerobj.cpp | 4 + tools/clang/unittests/HLSL/ExtensionTest.cpp | 83 +++++----- utils/hct/gen_intrin_main.txt | 9 +- utils/hct/hctdb.py | 29 +++- utils/hct/hctdb_instrhelp.py | 7 +- 40 files changed, 638 insertions(+), 86 deletions(-) create mode 100644 tools/clang/test/SemaHLSL/hlsl/intrinsics/ser/hitobject-unused-id-pre-sm69.hlsl create mode 100644 tools/clang/test/SemaHLSL/hlsl/intrinsics/ser/reorder-unclaimed-pre-sm69.hlsl create mode 100644 tools/clang/test/SemaHLSL/hlsl/objects/HitObject/hitobject-entry-errors.hlsl create mode 100644 tools/clang/test/SemaHLSL/hlsl/objects/HitObject/hitobject-in-buffer.hlsl create mode 100644 tools/clang/test/SemaHLSL/hlsl/objects/HitObject/hitobject-target-profile-error.hlsl create mode 100644 tools/clang/test/SemaHLSL/hlsl/objects/HitObject/hitobject-unclaimed-pre-sm69.hlsl create mode 100644 tools/clang/test/SemaHLSL/hlsl/objects/HitObject/hitobject-unsupported-vs.hlsl diff --git a/include/dxc/DXIL/DxilUtil.h b/include/dxc/DXIL/DxilUtil.h index 490f335db5..5652c56f50 100644 --- a/include/dxc/DXIL/DxilUtil.h +++ b/include/dxc/DXIL/DxilUtil.h @@ -162,6 +162,8 @@ GetHLSLResourceProperties(llvm::Type *Ty); bool IsHLSLResourceType(llvm::Type *Ty); bool IsHLSLObjectType(llvm::Type *Ty); bool IsHLSLRayQueryType(llvm::Type *Ty); +llvm::Type *GetHLSLHitObjectType(llvm::Module *M); +bool IsHLSLHitObjectType(llvm::Type *Ty); bool IsHLSLResourceDescType(llvm::Type *Ty); bool IsResourceSingleComponent(llvm::Type *Ty); uint8_t GetResourceComponentCount(llvm::Type *Ty); diff --git a/include/dxc/HlslIntrinsicOp.h b/include/dxc/HlslIntrinsicOp.h index fcc9bb11b1..b393aa4891 100644 --- a/include/dxc/HlslIntrinsicOp.h +++ b/include/dxc/HlslIntrinsicOp.h @@ -343,6 +343,7 @@ enum class IntrinsicOp { MOP_TraceRayInline, MOP_WorldRayDirection, MOP_WorldRayOrigin, + MOP_HitObject_MakeNop, MOP_Count, MOP_FinishedCrossGroupSharing, MOP_GetGroupNodeOutputRecords, diff --git a/include/dxc/Support/HLSLOptions.h b/include/dxc/Support/HLSLOptions.h index 887591ae82..89aab8f643 100644 --- a/include/dxc/Support/HLSLOptions.h +++ b/include/dxc/Support/HLSLOptions.h @@ -249,6 +249,7 @@ class DxcOpts { bool PrintAfterAll; // OPT_print_after_all std::set PrintAfter; // OPT_print_after bool EnablePayloadQualifiers = false; // OPT_enable_payload_qualifiers + bool EnableShaderExecutionReordering = false; bool HandleExceptions = false; // OPT_disable_exception_handling // Rewriter Options diff --git a/include/dxc/dxcapi.internal.h b/include/dxc/dxcapi.internal.h index b0f9a467a4..028016131f 100644 --- a/include/dxc/dxcapi.internal.h +++ b/include/dxc/dxcapi.internal.h @@ -126,7 +126,10 @@ enum LEGAL_INTRINSIC_COMPTYPES { LICOMPTYPE_GROUP_NODE_OUTPUT_RECORDS = 49, LICOMPTYPE_THREAD_NODE_OUTPUT_RECORDS = 50, - LICOMPTYPE_COUNT = 51 + LICOMPTYPE_RAY_QUERY = 51, + LICOMPTYPE_HIT_OBJECT = 52, + + LICOMPTYPE_COUNT = 53 }; static const BYTE IA_SPECIAL_BASE = 0xf0; @@ -165,6 +168,7 @@ struct HLSL_INTRINSIC { BOOL bReadOnly; // Only read memory BOOL bReadNone; // Not read memory BOOL bIsWave; // Is a wave-sensitive op + BOOL bStaticMember; // HLSL static member function INT iOverloadParamIndex; // Parameter decide the overload type, -1 means ret // type UINT uNumArgs; // Count of arguments in pArgs. diff --git a/lib/DXIL/DxilUtil.cpp b/lib/DXIL/DxilUtil.cpp index 757a0bc3ee..0b56ecc979 100644 --- a/lib/DXIL/DxilUtil.cpp +++ b/lib/DXIL/DxilUtil.cpp @@ -549,6 +549,9 @@ bool IsHLSLObjectType(llvm::Type *Ty) { if (name.startswith("dx.types.wave_t")) return true; + if (name == "dx.types.HitObject") + return true; + if (name.compare("dx.types.Handle") == 0) return true; @@ -587,6 +590,24 @@ bool IsHLSLRayQueryType(llvm::Type *Ty) { return false; } +llvm::Type *GetHLSLHitObjectType(llvm::Module *M) { + using namespace llvm; + StructType *HitObjectTy = M->getTypeByName("dx.types.HitObject"); + if (!HitObjectTy) + HitObjectTy = StructType::create({Type::getInt8PtrTy(M->getContext(), 0)}, + "dx.types.HitObject", false); + return HitObjectTy; +} + +bool IsHLSLHitObjectType(llvm::Type *Ty) { + llvm::StructType *ST = dyn_cast(Ty); + if (!ST) + return false; + if (!ST->hasName()) + return false; + return ST->getName() == "dx.types.HitObject"; +} + bool IsHLSLResourceDescType(llvm::Type *Ty) { if (llvm::StructType *ST = dyn_cast(Ty)) { if (!ST->hasName()) diff --git a/lib/DxcSupport/HLSLOptions.cpp b/lib/DxcSupport/HLSLOptions.cpp index 3daf880f6d..ac5023e2d9 100644 --- a/lib/DxcSupport/HLSLOptions.cpp +++ b/lib/DxcSupport/HLSLOptions.cpp @@ -904,6 +904,9 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude, return 1; } + opts.EnableShaderExecutionReordering = + DXIL::CompareVersions(Major, Minor, 6, 9) >= 0; + opts.HandleExceptions = !Args.hasFlag(OPT_disable_exception_handling, OPT_INVALID, false); diff --git a/lib/HLSL/HLLowerUDT.cpp b/lib/HLSL/HLLowerUDT.cpp index 11c38fcea7..efdaf09e23 100644 --- a/lib/HLSL/HLLowerUDT.cpp +++ b/lib/HLSL/HLLowerUDT.cpp @@ -62,9 +62,11 @@ StructType *hlsl::GetLoweredUDT(StructType *structTy, } else if (HLMatrixType Mat = HLMatrixType::dyn_cast(EltTy)) { NewTy = ArrayType::get(Mat.getElementType(/*MemRepr*/ true), Mat.getNumElements()); - } else if (dxilutil::IsHLSLObjectType(EltTy) || + } else if ((dxilutil::IsHLSLObjectType(EltTy) && + !dxilutil::IsHLSLHitObjectType(EltTy)) || dxilutil::IsHLSLRayQueryType(EltTy)) { - // We cannot lower a structure with an embedded object type + // We cannot lower a structure with an embedded object type, except for + // HitObject. return nullptr; } else if (StructType *ST = dyn_cast(EltTy)) { NewTy = GetLoweredUDT(ST); diff --git a/lib/HLSL/HLOperationLower.cpp b/lib/HLSL/HLOperationLower.cpp index 6377bba8c5..2ce4feb934 100644 --- a/lib/HLSL/HLOperationLower.cpp +++ b/lib/HLSL/HLOperationLower.cpp @@ -6062,6 +6062,13 @@ Value *TranslateUnpack(CallInst *CI, IntrinsicOp IOP, OP::OpCode opcode, return ResVec; } +Value *TranslateHitObjectMake(CallInst *CI, IntrinsicOp IOP, OP::OpCode opcode, + HLOperationLowerHelper &helper, + HLObjectOperationLowerHelper *pObjHelper, + bool &Translated) { + return UndefValue::get(CI->getType()); // TODO: Merge SER DXIL patches +} + } // namespace // Resource Handle. @@ -6738,6 +6745,9 @@ IntrinsicLower gLowerTable[] = { DXIL::OpCode::RayQuery_WorldRayDirection}, {IntrinsicOp::MOP_WorldRayOrigin, TranslateRayQueryFloat3Getter, DXIL::OpCode::RayQuery_WorldRayOrigin}, + {IntrinsicOp::MOP_HitObject_MakeNop, TranslateHitObjectMake, + DXIL::OpCode::NumOpCodes_Dxil_1_8}, // FIXME: Just a placeholder Dxil + // opcode {IntrinsicOp::MOP_Count, TranslateNodeGetInputRecordCount, DXIL::OpCode::GetInputRecordCount}, {IntrinsicOp::MOP_FinishedCrossGroupSharing, diff --git a/tools/clang/include/clang/AST/HlslTypes.h b/tools/clang/include/clang/AST/HlslTypes.h index d11fd598e6..68726cca1b 100644 --- a/tools/clang/include/clang/AST/HlslTypes.h +++ b/tools/clang/include/clang/AST/HlslTypes.h @@ -388,6 +388,7 @@ clang::CXXRecordDecl *DeclareUIntTemplatedTypeWithHandleInDeclContext( clang::CXXRecordDecl *DeclareConstantBufferViewType(clang::ASTContext &context, bool bTBuf); clang::CXXRecordDecl *DeclareRayQueryType(clang::ASTContext &context); +clang::CXXRecordDecl *DeclareHitObjectType(clang::ASTContext &context); clang::CXXRecordDecl *DeclareResourceType(clang::ASTContext &context, bool bSampler); @@ -469,6 +470,7 @@ bool IsHLSLNodeInputType(clang::QualType type); bool IsHLSLDynamicResourceType(clang::QualType type); bool IsHLSLDynamicSamplerType(clang::QualType type); bool IsHLSLNodeType(clang::QualType type); +bool IsHLSLHitObjectType(clang::QualType type); bool IsHLSLObjectWithImplicitMemberAccess(clang::QualType type); bool IsHLSLObjectWithImplicitROMemberAccess(clang::QualType type); @@ -542,6 +544,7 @@ clang::CXXMethodDecl *CreateObjectFunctionDeclarationWithParams( clang::QualType resultType, llvm::ArrayRef paramTypes, llvm::ArrayRef paramNames, clang::DeclarationName declarationName, bool isConst, + clang::StorageClass SC = clang::StorageClass::SC_None, bool isTemplateFunction = false); DXIL::ResourceClass GetResourceClassForType(const clang::ASTContext &context, diff --git a/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td b/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td index f79b8f6045..7c15f769ee 100644 --- a/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -7929,6 +7929,10 @@ def err_hlsl_node_record_type : Error< "%0 is not valid as a node record type - struct/class required">; def err_hlsl_node_record_object : Error< "object %0 may not appear in a node record">; +def err_hlsl_ser_invalid_shader_kind : Error< + "Shader kind '%0' incompatible with shader execution reordering (has to be raygeneration, closesthit or miss)">; +def err_hlsl_ser_invalid_version : Error< + "Shader execution reordering requires target profile lib_6_9+ (was %0)">; def err_hlsl_array_disallowed : Error< "%select{entry parameter|declaration}1 of type %0 may not be an array">; def err_hlsl_inputpatch_size: Error< diff --git a/tools/clang/include/clang/Basic/LangOptions.h b/tools/clang/include/clang/Basic/LangOptions.h index 8dc15da5d8..ec764ee121 100644 --- a/tools/clang/include/clang/Basic/LangOptions.h +++ b/tools/clang/include/clang/Basic/LangOptions.h @@ -162,6 +162,7 @@ class LangOptions : public LangOptionsBase { bool EnableDX9CompatMode = false; bool EnableFXCCompatMode = false; bool EnablePayloadAccessQualifiers = false; + bool EnableShaderExecutionReordering = false; bool DumpImplicitTopLevelDecls = true; bool ExportShadersOnly = false; hlsl::DXIL::DefaultLinkage DefaultLinkage = diff --git a/tools/clang/include/clang/Frontend/CodeGenOptions.h b/tools/clang/include/clang/Frontend/CodeGenOptions.h index 859cba53da..b06af518dc 100644 --- a/tools/clang/include/clang/Frontend/CodeGenOptions.h +++ b/tools/clang/include/clang/Frontend/CodeGenOptions.h @@ -244,6 +244,8 @@ class CodeGenOptions : public CodeGenOptionsBase { bool HLSLEnableLifetimeMarkers = false; /// Put shader sources and options in the module bool HLSLEmbedSourcesInModule = false; + /// Enable Shader Execution Reordering. + bool HLSLEnableShaderExecutionReordering = false; /// Enable generation of payload access qualifier metadata. bool HLSLEnablePayloadAccessQualifiers = false; /// Binding table for HLSL resources diff --git a/tools/clang/include/clang/Sema/Sema.h b/tools/clang/include/clang/Sema/Sema.h index 42ab80b617..a3f05e1535 100644 --- a/tools/clang/include/clang/Sema/Sema.h +++ b/tools/clang/include/clang/Sema/Sema.h @@ -3809,6 +3809,10 @@ class Sema { SourceLocation Loc); void CheckHLSLFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall, const FunctionProtoType *Proto); + void DiagnoseShaderExecutionReordering(CallExpr *CE, + hlsl::DXIL::ShaderKind EntrySK, + const FunctionDecl *EntryDecl, + const hlsl::ShaderModel *SM); void DiagnoseReachableHLSLCall(CallExpr *CE, const hlsl::ShaderModel *SM, hlsl::DXIL::ShaderKind EntrySK, hlsl::DXIL::NodeLaunchType NodeLaunchTy, diff --git a/tools/clang/lib/AST/ASTContextHLSL.cpp b/tools/clang/lib/AST/ASTContextHLSL.cpp index 3c058950e0..8d19e337bd 100644 --- a/tools/clang/lib/AST/ASTContextHLSL.cpp +++ b/tools/clang/lib/AST/ASTContextHLSL.cpp @@ -23,6 +23,7 @@ #include "clang/AST/ExternalASTSource.h" #include "clang/AST/HlslBuiltinTypeDeclBuilder.h" #include "clang/AST/TypeLoc.h" +#include "clang/Basic/Specifiers.h" #include "clang/Sema/Overload.h" #include "clang/Sema/Sema.h" #include "clang/Sema/SemaDiagnostic.h" @@ -1033,7 +1034,7 @@ static void CreateConstructorDeclaration( static void CreateObjectFunctionDeclaration( ASTContext &context, CXXRecordDecl *recordDecl, QualType resultType, ArrayRef args, DeclarationName declarationName, bool isConst, - CXXMethodDecl **functionDecl, TypeSourceInfo **tinfo) { + StorageClass SC, CXXMethodDecl **functionDecl, TypeSourceInfo **tinfo) { DXASSERT_NOMSG(recordDecl != nullptr); DXASSERT_NOMSG(functionDecl != nullptr); @@ -1045,8 +1046,8 @@ static void CreateObjectFunctionDeclaration( *tinfo = context.getTrivialTypeSourceInfo(functionQT, NoLoc); DXASSERT_NOMSG(*tinfo != nullptr); *functionDecl = CXXMethodDecl::Create( - context, recordDecl, NoLoc, declNameInfo, functionQT, *tinfo, - StorageClass::SC_None, InlineSpecifiedFalse, IsConstexprFalse, NoLoc); + context, recordDecl, NoLoc, declNameInfo, functionQT, *tinfo, SC, + InlineSpecifiedFalse, IsConstexprFalse, NoLoc); DXASSERT_NOMSG(*functionDecl != nullptr); (*functionDecl)->setLexicalDeclContext(recordDecl); (*functionDecl)->setAccess(AccessSpecifier::AS_public); @@ -1055,7 +1056,8 @@ static void CreateObjectFunctionDeclaration( CXXMethodDecl *hlsl::CreateObjectFunctionDeclarationWithParams( ASTContext &context, CXXRecordDecl *recordDecl, QualType resultType, ArrayRef paramTypes, ArrayRef paramNames, - DeclarationName declarationName, bool isConst, bool isTemplateFunction) { + DeclarationName declarationName, bool isConst, StorageClass SC, + bool isTemplateFunction) { DXASSERT_NOMSG(recordDecl != nullptr); DXASSERT_NOMSG(!resultType.isNull()); DXASSERT_NOMSG(paramTypes.size() == paramNames.size()); @@ -1063,7 +1065,7 @@ CXXMethodDecl *hlsl::CreateObjectFunctionDeclarationWithParams( TypeSourceInfo *tinfo; CXXMethodDecl *functionDecl; CreateObjectFunctionDeclaration(context, recordDecl, resultType, paramTypes, - declarationName, isConst, &functionDecl, + declarationName, isConst, SC, &functionDecl, &tinfo); // Create and associate parameters to method. @@ -1161,6 +1163,31 @@ CXXRecordDecl *hlsl::DeclareRayQueryType(ASTContext &context) { return typeDeclBuilder.getRecordDecl(); } +CXXRecordDecl *hlsl::DeclareHitObjectType(ASTContext &Context) { + // HitObject { ... } + BuiltinTypeDeclBuilder TypeDeclBuilder(Context.getTranslationUnitDecl(), + "HitObject"); + TypeDeclBuilder.startDefinition(); + CXXRecordDecl *RecordDecl = TypeDeclBuilder.getRecordDecl(); + + // Add constructor that will be lowered to the intrinsic that produces + // the HitObject handle for this object. + CanQualType canQualType = Context.getCanonicalType( + Context.getRecordType(TypeDeclBuilder.getRecordDecl())); + + CXXConstructorDecl *pConstructorDecl = nullptr; + TypeSourceInfo *pTypeSourceInfo = nullptr; + CreateConstructorDeclaration( + Context, RecordDecl, Context.VoidTy, {}, + Context.DeclarationNames.getCXXConstructorName(canQualType), false, + &pConstructorDecl, &pTypeSourceInfo); + RecordDecl->addDecl(pConstructorDecl); + // The 'implicit' lets us distinguish SER HitObject (SM6.9+) from a + // user-defined type named 'HitObject' (pre-SM6.9). + RecordDecl->setImplicit(true); + return RecordDecl; +} + CXXRecordDecl *hlsl::DeclareResourceType(ASTContext &context, bool bSampler) { // struct ResourceDescriptor { uint8 desc; } StringRef Name = bSampler ? ".Sampler" : ".Resource"; diff --git a/tools/clang/lib/AST/HlslTypes.cpp b/tools/clang/lib/AST/HlslTypes.cpp index d83b307463..c170683966 100644 --- a/tools/clang/lib/AST/HlslTypes.cpp +++ b/tools/clang/lib/AST/HlslTypes.cpp @@ -613,6 +613,22 @@ bool IsHLSLResourceType(clang::QualType type) { return false; } +bool IsHLSLHitObjectType(QualType type) { + type = type.getCanonicalType(); + const RecordType *RT = dyn_cast(type); + if (!RT) + return false; + + const CXXRecordDecl *cxxRecordDecl = dyn_cast(RT->getDecl()); + // Only match the 'implicit' type generated by hlsl::DeclareHitObjectType(..). + // User-defined types named 'HitObject' pre-SM6.9 are never 'implicit' and + // will not be mistaken for the SER HitObject type. + if (!cxxRecordDecl || !cxxRecordDecl->isImplicit()) + return false; + + return RT->getDecl()->getName() == "HitObject"; +} + static HLSLNodeObjectAttr *getNodeAttr(clang::QualType type) { if (const RecordType *RT = type->getAs()) { if (const auto *Spec = diff --git a/tools/clang/lib/CodeGen/CGCall.cpp b/tools/clang/lib/CodeGen/CGCall.cpp index f781e66a0d..6429ee3732 100644 --- a/tools/clang/lib/CodeGen/CGCall.cpp +++ b/tools/clang/lib/CodeGen/CGCall.cpp @@ -15,13 +15,15 @@ #include "CGCall.h" #include "ABIInfo.h" #include "CGCXXABI.h" +#include "CGHLSLRuntime.h" // HLSL Change #include "CodeGenFunction.h" #include "CodeGenModule.h" -#include "CGHLSLRuntime.h" // HLSL Change #include "TargetInfo.h" +#include "dxc/DXIL/DxilUtil.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/HlslTypes.h" #include "clang/Basic/TargetInfo.h" #include "clang/CodeGen/CGFunctionInfo.h" #include "clang/Frontend/CodeGenOptions.h" @@ -30,8 +32,8 @@ #include "llvm/IR/CallSite.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/InlineAsm.h" -#include "llvm/IR/Intrinsics.h" #include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/Intrinsics.h" #include "llvm/Transforms/Utils/Local.h" using namespace clang; using namespace CodeGen; @@ -1902,7 +1904,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, case ABIArgInfo::Extend: case ABIArgInfo::Direct: { // HLSL Change Begins - if (hlsl::IsHLSLMatType(Ty)) { + if (hlsl::IsHLSLMatType(Ty) || hlsl::IsHLSLHitObjectType(Ty)) { assert(NumIRArgs == 1); auto AI = FnArgs[FirstIRArg]; llvm::Value *V = AI; diff --git a/tools/clang/lib/CodeGen/CGExprScalar.cpp b/tools/clang/lib/CodeGen/CGExprScalar.cpp index 0cb993e6f4..2feb7b965e 100644 --- a/tools/clang/lib/CodeGen/CGExprScalar.cpp +++ b/tools/clang/lib/CodeGen/CGExprScalar.cpp @@ -339,6 +339,8 @@ class ScalarExprEmitter Value *VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { return EmitLoadOfLValue(E); } + Value *VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *E); + Value *VisitCXXConstructExpr(CXXConstructExpr *E); Value *VisitInitListExpr(InitListExpr *E); @@ -1101,6 +1103,17 @@ void ScalarExprEmitter::EmitBinOpCheck( // Visitor Methods //===----------------------------------------------------------------------===// +Value *ScalarExprEmitter::VisitCXXConstructExpr(CXXConstructExpr *E) { + return CGF.CGM.getHLSLRuntime().EmitHLSLScalarObjectDefaultConstructor(CGF, + E); +} + +Value * +ScalarExprEmitter::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *E) { + return CGF.CGM.getHLSLRuntime().EmitHLSLScalarObjectDefaultConstructor(CGF, + E); +} + Value *ScalarExprEmitter::VisitExpr(Expr *E) { CGF.ErrorUnsupported(E, "scalar expression"); if (E->getType()->isVoidType()) diff --git a/tools/clang/lib/CodeGen/CGHLSLMS.cpp b/tools/clang/lib/CodeGen/CGHLSLMS.cpp index 72f5a791ab..ecdc829cb9 100644 --- a/tools/clang/lib/CodeGen/CGHLSLMS.cpp +++ b/tools/clang/lib/CodeGen/CGHLSLMS.cpp @@ -252,6 +252,9 @@ class CGMSHLSLRuntime : public CGHLSLRuntime { void EmitHLSLOutParamConversionCopyBack( CodeGenFunction &CGF, llvm::SmallVector &castArgList, llvm::SmallVector &lifetimeCleanupList) override; + llvm::Value * + EmitHLSLScalarObjectDefaultConstructor(CodeGenFunction &CGF, + const clang::Expr *E) override; Value *EmitHLSLMatrixOperationCall(CodeGenFunction &CGF, const clang::Expr *E, llvm::Type *RetType, @@ -2500,9 +2503,11 @@ void CGMSHLSLRuntime::AddHLSLFunctionInfo(Function *F, const FunctionDecl *FD) { // Type annotation for this pointer. if (const CXXMethodDecl *MFD = dyn_cast(FD)) { - const CXXRecordDecl *RD = MFD->getParent(); - QualType Ty = CGM.getContext().getTypeDeclType(RD); - AddTypeAnnotation(Ty, dxilTypeSys, arrayEltSize); + if (!MFD->isStatic()) { + const CXXRecordDecl *RD = MFD->getParent(); + QualType Ty = CGM.getContext().getTypeDeclType(RD); + AddTypeAnnotation(Ty, dxilTypeSys, arrayEltSize); + } } for (const ValueDecl *param : FD->params()) { @@ -3904,6 +3909,10 @@ void CGMSHLSLRuntime::FinishCodeGen() { // Create Global variable and type annotation for each CBuffer. FinishCBuffer(HLM, CBufferType, m_ConstVarAnnotationMap); + // Translate calls to the HitObject constructor into hl HitObject_MakeNop + // calls + TranslateHitObjectConstructor(HLM); + // Translate calls to RayQuery constructor into hl Allocate calls TranslateRayQueryConstructor(HLM); @@ -6562,6 +6571,27 @@ void CGMSHLSLRuntime::EmitHLSLOutParamConversionCopyBack( } } +llvm::Value * +CGMSHLSLRuntime::EmitHLSLScalarObjectDefaultConstructor(CodeGenFunction &CGF, + const Expr *E) { + if (!hlsl::IsHLSLHitObjectType(E->getType())) + CGF.ErrorUnsupported(E, "scalar expression"); + + llvm::Module &M = CGF.CGM.getModule(); + + // Construct declaration + llvm::IntegerType *i32Ty = llvm::Type::getInt32Ty(M.getContext()); + unsigned OpCode = (unsigned)IntrinsicOp::MOP_HitObject_MakeNop; + llvm::ConstantInt *opVal = llvm::ConstantInt::get(i32Ty, OpCode, false); + + llvm::Type *HitType = hlsl::dxilutil::GetHLSLHitObjectType(&M); + llvm::FunctionType *MakeNopFuncTy = + llvm::FunctionType::get(HitType, i32Ty, false); + Function *MakeNopFunc = GetOrCreateHLFunction( + M, MakeNopFuncTy, HLOpcodeGroup::HLIntrinsic, OpCode); + return CGF.Builder.CreateCall(MakeNopFunc, opVal); +} + ScopeInfo *CGMSHLSLRuntime::GetScopeInfo(Function *F) { auto it = m_ScopeMap.find(F); if (it == m_ScopeMap.end()) diff --git a/tools/clang/lib/CodeGen/CGHLSLMSFinishCodeGen.cpp b/tools/clang/lib/CodeGen/CGHLSLMSFinishCodeGen.cpp index 8af96cc3cd..dbdebdccea 100644 --- a/tools/clang/lib/CodeGen/CGHLSLMSFinishCodeGen.cpp +++ b/tools/clang/lib/CodeGen/CGHLSLMSFinishCodeGen.cpp @@ -2794,6 +2794,56 @@ unsigned AlignBufferOffsetInLegacy(unsigned offset, unsigned size, return offset; } +// Translate HitObject constructor to dx.op.hitObject_MakeNop +void TranslateHitObjectConstructor(HLModule &HLM) { + llvm::Module &M = *HLM.GetModule(); + Function *HitObjectCtor = nullptr; + for (auto &F : M.functions()) { + llvm::Type *Ty = F.getReturnType(); + if (!Ty->isPointerTy() || + !dxilutil::IsHLSLHitObjectType(Ty->getPointerElementType())) + continue; + + // Match the HitObject constructor signature. It should be impossible to + // achieve the same signature from HLSL. + if (!F.getName().startswith("\01??0HitObject@@")) + continue; + DXASSERT(F.arg_size() == 1 && Ty == F.arg_begin()->getType(), + "Wrong signature for apparent HitObject constructor"); + + DXASSERT(!HitObjectCtor, + "Multiple candidate functions that quality as HitObject " + "constructor when there must be at most one"); + HitObjectCtor = &F; + } + + if (!HitObjectCtor) + return; + + // Construct declaration + llvm::IntegerType *i32Ty = llvm::Type::getInt32Ty(M.getContext()); + unsigned OpCode = (unsigned)IntrinsicOp::MOP_HitObject_MakeNop; + llvm::ConstantInt *opVal = llvm::ConstantInt::get(i32Ty, OpCode, false); + + llvm::Type *HitType = dxilutil::GetHLSLHitObjectType(&M); + FunctionType *MakeNopFuncTy = FunctionType::get(HitType, i32Ty, false); + Function *MakeNopFunc = GetOrCreateHLFunction( + M, MakeNopFuncTy, HLOpcodeGroup::HLIntrinsic, OpCode); + + while (!HitObjectCtor->user_empty()) { + Value *V = *HitObjectCtor->user_begin(); + llvm::CallInst *CI = cast(V); // Must be call + IRBuilder<> Builder(CI); + Value *NopHit = Builder.CreateCall(MakeNopFunc, opVal); + Value *HitObjectPtr = CI->getArgOperand(0); + Builder.CreateStore(NopHit, HitObjectPtr); + CI->replaceAllUsesWith(HitObjectPtr); + CI->eraseFromParent(); + } + + HitObjectCtor->eraseFromParent(); +} + // Translate RayQuery constructor. From: // %call = call %"RayQuery" @(%"RayQuery" %ptr) // To: diff --git a/tools/clang/lib/CodeGen/CGHLSLMSHelper.h b/tools/clang/lib/CodeGen/CGHLSLMSHelper.h index 9058ed4f6d..948a0b7ab6 100644 --- a/tools/clang/lib/CodeGen/CGHLSLMSHelper.h +++ b/tools/clang/lib/CodeGen/CGHLSLMSHelper.h @@ -226,6 +226,7 @@ void CollectCtorFunctions(llvm::Module &M, llvm::StringRef globalName, llvm::SmallVector &Ctors, clang::CodeGen::CodeGenModule &CGM); +void TranslateHitObjectConstructor(hlsl::HLModule &HLM); void TranslateRayQueryConstructor(hlsl::HLModule &HLM); void TranslateInputNodeRecordArgToHandle( hlsl::HLModule &HLM, diff --git a/tools/clang/lib/CodeGen/CGHLSLRuntime.h b/tools/clang/lib/CodeGen/CGHLSLRuntime.h index 3e27951e86..793f10f1fd 100644 --- a/tools/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/tools/clang/lib/CodeGen/CGHLSLRuntime.h @@ -89,6 +89,10 @@ class CGHLSLRuntime { virtual void EmitHLSLOutParamConversionCopyBack( CodeGenFunction &CGF, llvm::SmallVector &castArgList, llvm::SmallVector &lifetimeCleanupList) = 0; + virtual llvm::Value * + EmitHLSLScalarObjectDefaultConstructor(CodeGenFunction &CGF, + const clang::Expr *E) = 0; + virtual void MarkPotentialResourceTemp(CodeGenFunction &CGF, llvm::Value *V, clang::QualType QaulTy) = 0; virtual llvm::Value * diff --git a/tools/clang/lib/CodeGen/CodeGenFunction.cpp b/tools/clang/lib/CodeGen/CodeGenFunction.cpp index 397b38bc0c..bf8d9d8d21 100644 --- a/tools/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/tools/clang/lib/CodeGen/CodeGenFunction.cpp @@ -12,18 +12,20 @@ //===----------------------------------------------------------------------===// #include "CodeGenFunction.h" -#include "CGCleanup.h" #include "CGCUDARuntime.h" -#include "CGHLSLRuntime.h" // HLSL Change #include "CGCXXABI.h" +#include "CGCleanup.h" #include "CGDebugInfo.h" +#include "CGHLSLRuntime.h" // HLSL Change #include "CGOpenMPRuntime.h" #include "CodeGenModule.h" #include "CodeGenPGO.h" #include "TargetInfo.h" +#include "dxc/DXIL/DxilMetadataHelper.h" // HLSL Change #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/HlslTypes.h" #include "clang/AST/StmtCXX.h" #include "clang/Basic/TargetInfo.h" #include "clang/CodeGen/CGFunctionInfo.h" @@ -32,7 +34,6 @@ #include "llvm/IR/Intrinsics.h" #include "llvm/IR/MDBuilder.h" #include "llvm/IR/Operator.h" -#include "dxc/DXIL/DxilMetadataHelper.h" // HLSL Change using namespace clang; using namespace CodeGen; @@ -165,6 +166,11 @@ TypeEvaluationKind CodeGenFunction::getEvaluationKind(QualType type) { // Treat hlsl matrix as scalar type too. return TEK_Scalar; } + if (hlsl::IsHLSLHitObjectType(type)) { + // Pass HitObject as scalar (by value) + return TEK_Scalar; + } + // HLSL Change Ends return TEK_Aggregate; diff --git a/tools/clang/lib/CodeGen/CodeGenTypes.cpp b/tools/clang/lib/CodeGen/CodeGenTypes.cpp index d11575d359..d26dc36fa2 100644 --- a/tools/clang/lib/CodeGen/CodeGenTypes.cpp +++ b/tools/clang/lib/CodeGen/CodeGenTypes.cpp @@ -14,21 +14,23 @@ #include "CodeGenTypes.h" #include "CGCXXABI.h" #include "CGCall.h" +#include "CGHLSLRuntime.h" // HLSL Change #include "CGOpenCLRuntime.h" #include "CGRecordLayout.h" +#include "CodeGenModule.h" // HLSL Change #include "TargetInfo.h" +#include "dxc/DXIL/DxilUtil.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclCXX.h" -#include "clang/AST/DeclTemplate.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" +#include "clang/AST/HlslTypes.h" #include "clang/AST/RecordLayout.h" #include "clang/CodeGen/CGFunctionInfo.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Module.h" -#include "CodeGenModule.h" // HLSL Change -#include "CGHLSLRuntime.h" // HLSL Change using namespace clang; using namespace CodeGen; @@ -365,8 +367,9 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) { .getConstantArrayType(eltTy, llvm::APInt(32, count), ArrayType::ArraySizeModifier::Normal, 0) .getTypePtr(); - } - else + } else if (hlsl::IsHLSLHitObjectType(T)) { + return hlsl::dxilutil::GetHLSLHitObjectType(&TheModule); + } else return ConvertRecordDeclType(RT->getDecl()); } // HLSL Change Ends diff --git a/tools/clang/lib/CodeGen/TargetInfo.cpp b/tools/clang/lib/CodeGen/TargetInfo.cpp index aba43964d9..fbaf0f4a8f 100644 --- a/tools/clang/lib/CodeGen/TargetInfo.cpp +++ b/tools/clang/lib/CodeGen/TargetInfo.cpp @@ -17,6 +17,7 @@ #include "CGCXXABI.h" #include "CGValue.h" #include "CodeGenFunction.h" +#include "clang/AST/HlslTypes.h" #include "clang/AST/RecordLayout.h" #include "clang/CodeGen/CGFunctionInfo.h" #include "clang/Frontend/CodeGenOptions.h" @@ -44,6 +45,8 @@ static void AssignToArrayRange(CodeGen::CGBuilderTy &Builder, } static bool isAggregateTypeForABI(QualType T) { + if (hlsl::IsHLSLHitObjectType(T)) + return false; return !CodeGenFunction::hasScalarEvaluationKind(T) || T->isMemberFunctionPointerType(); } @@ -6189,7 +6192,12 @@ class MSDXILABIInfo : public ABIInfo { RetTy = EnumTy->getDecl()->getIntegerType(); // do not use extend for hlsl. - return ABIArgInfo::getDirect(CGT.ConvertType(RetTy)); + ABIArgInfo RetInfo = ABIArgInfo::getDirect(CGT.ConvertType(RetTy)); + + // Maintain opacity of dx.types.HitObject and never flatten it + if (hlsl::IsHLSLHitObjectType(RetTy)) + RetInfo.setCanBeFlattened(false); + return RetInfo; } ABIArgInfo classifyArgumentType(QualType Ty) const; @@ -6220,8 +6228,14 @@ ABIArgInfo MSDXILABIInfo::classifyArgumentType(QualType Ty) const { if (isAggregateTypeForABI(Ty)) return ABIArgInfo::getIndirect(0, /* byval */ false); - return (Ty->isPromotableIntegerType() ? ABIArgInfo::getExtend() - : ABIArgInfo::getDirect()); + ABIArgInfo ArgInfo = + (Ty->isPromotableIntegerType() ? ABIArgInfo::getExtend() + : ABIArgInfo::getDirect()); + + // Maintain opacity of dx.types.HitObject and never flatten it + if (hlsl::IsHLSLHitObjectType(Ty)) + ArgInfo.setCanBeFlattened(false); + return ArgInfo; } void MSDXILABIInfo::computeInfo(CGFunctionInfo &FI) const { diff --git a/tools/clang/lib/SPIRV/AstTypeProbe.cpp b/tools/clang/lib/SPIRV/AstTypeProbe.cpp index 31a9bd8f7d..99184802ba 100644 --- a/tools/clang/lib/SPIRV/AstTypeProbe.cpp +++ b/tools/clang/lib/SPIRV/AstTypeProbe.cpp @@ -1101,6 +1101,13 @@ bool isOpaqueType(QualType type) { if (name == "SubpassInput") return true; + + if (name == "HitObject") { + const CXXRecordDecl *typeRecordDecl = type->getAsCXXRecordDecl(); + return typeRecordDecl && + typeRecordDecl + ->isImplicit(); // This is only our builtin, if SER is enabled + } } return false; } diff --git a/tools/clang/lib/Sema/SemaCXXScopeSpec.cpp b/tools/clang/lib/Sema/SemaCXXScopeSpec.cpp index bacda174d7..240cb04eb6 100644 --- a/tools/clang/lib/Sema/SemaCXXScopeSpec.cpp +++ b/tools/clang/lib/Sema/SemaCXXScopeSpec.cpp @@ -11,15 +11,16 @@ // //===----------------------------------------------------------------------===// -#include "clang/Sema/SemaInternal.h" #include "TypeLocBuilder.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/HlslTypes.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/Lookup.h" +#include "clang/Sema/SemaInternal.h" #include "clang/Sema/Template.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/raw_ostream.h" @@ -200,9 +201,13 @@ bool Sema::RequireCompleteDeclContext(CXXScopeSpec &SS, // If we're currently defining this type, then lookup into the // type is okay: don't complain that it isn't complete yet. + // HLSL: If this is a builtin type, add all method definitions and complete + // the type. QualType type = Context.getTypeDeclType(tag); const TagType *tagType = type->getAs(); - if (tagType && tagType->isBeingDefined()) + if (tagType && tagType->isBeingDefined() && + (hlsl::IsUserDefinedRecordType(type) || + hlsl::IsHLSLObjectWithImplicitMemberAccess(type))) return false; SourceLocation loc = SS.getLastQualifierNameLoc(); diff --git a/tools/clang/lib/Sema/SemaHLSL.cpp b/tools/clang/lib/Sema/SemaHLSL.cpp index ba0801dd52..79ebefd015 100644 --- a/tools/clang/lib/Sema/SemaHLSL.cpp +++ b/tools/clang/lib/Sema/SemaHLSL.cpp @@ -31,6 +31,8 @@ #include "clang/AST/HlslTypes.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/Diagnostic.h" +#include "clang/Basic/Specifiers.h" +#include "clang/Parse/ParseDiagnostic.h" #include "clang/Sema/ExternalSemaSource.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" @@ -40,6 +42,7 @@ #include "clang/Sema/TemplateDeduction.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include @@ -219,6 +222,9 @@ enum ArBasicKind { // RayQuery AR_OBJECT_RAY_QUERY, + // Shader Execution Reordering + AR_OBJECT_HIT_OBJECT, + // Heap Resource AR_OBJECT_HEAP_RESOURCE, AR_OBJECT_HEAP_SAMPLER, @@ -566,9 +572,10 @@ const UINT g_uBasicKindProps[] = { 0, // AR_OBJECT_PROCEDURAL_PRIMITIVE_HIT_GROUP, 0, // AR_OBJECT_RAYTRACING_PIPELINE_CONFIG1, - BPROP_OBJECT, // AR_OBJECT_RAY_QUERY, - BPROP_OBJECT, // AR_OBJECT_HEAP_RESOURCE, - BPROP_OBJECT, // AR_OBJECT_HEAP_SAMPLER, + LICOMPTYPE_RAY_QUERY, // AR_OBJECT_RAY_QUERY, + LICOMPTYPE_HIT_OBJECT, // AR_OBJECT_HIT_OBJECT, + BPROP_OBJECT, // AR_OBJECT_HEAP_RESOURCE, + BPROP_OBJECT, // AR_OBJECT_HEAP_SAMPLER, BPROP_OBJECT | BPROP_RWBUFFER, // AR_OBJECT_RWTEXTURE2DMS BPROP_OBJECT | BPROP_RWBUFFER, // AR_OBJECT_RWTEXTURE2DMS_ARRAY @@ -1115,6 +1122,11 @@ static const ArBasicKind g_ResourceCT[] = {AR_OBJECT_HEAP_RESOURCE, static const ArBasicKind g_RayDescCT[] = {AR_OBJECT_RAY_DESC, AR_BASIC_UNKNOWN}; +static const ArBasicKind g_RayQueryCT[] = {AR_OBJECT_RAY_QUERY, + AR_BASIC_UNKNOWN}; +static const ArBasicKind g_HitObjectCT[] = {AR_OBJECT_HIT_OBJECT, + AR_BASIC_UNKNOWN}; + static const ArBasicKind g_AccelerationStructCT[] = { AR_OBJECT_ACCELERATION_STRUCT, AR_BASIC_UNKNOWN}; @@ -1267,6 +1279,8 @@ const ArBasicKind *g_LegalIntrinsicCompTypes[] = { g_AnyOutputRecordCT, // LICOMPTYPE_ANY_NODE_OUTPUT_RECORD g_GroupNodeOutputRecordsCT, // LICOMPTYPE_GROUP_NODE_OUTPUT_RECORDS g_ThreadNodeOutputRecordsCT, // LICOMPTYPE_THREAD_NODE_OUTPUT_RECORDS + g_RayQueryCT, // LICOMPTYPE_RAY_QUERY + g_HitObjectCT, // LICOMPTYPE_HIT_OBJECT }; static_assert( ARRAYSIZE(g_LegalIntrinsicCompTypes) == LICOMPTYPE_COUNT, @@ -1341,7 +1355,8 @@ static const ArBasicKind g_ArBasicKindsAsTypes[] = { AR_OBJECT_TRIANGLE_HIT_GROUP, AR_OBJECT_PROCEDURAL_PRIMITIVE_HIT_GROUP, AR_OBJECT_RAYTRACING_PIPELINE_CONFIG1, - AR_OBJECT_RAY_QUERY, AR_OBJECT_HEAP_RESOURCE, AR_OBJECT_HEAP_SAMPLER, + AR_OBJECT_RAY_QUERY, AR_OBJECT_HIT_OBJECT, AR_OBJECT_HEAP_RESOURCE, + AR_OBJECT_HEAP_SAMPLER, AR_OBJECT_RWTEXTURE2DMS, // RWTexture2DMS AR_OBJECT_RWTEXTURE2DMS_ARRAY, // RWTexture2DMSArray @@ -1449,6 +1464,7 @@ static const uint8_t g_ArBasicKindsTemplateCount[] = { 0, // AR_OBJECT_RAYTRACING_PIPELINE_CONFIG1, 1, // AR_OBJECT_RAY_QUERY, + 0, // AR_OBJECT_HIT_OBJECT, 0, // AR_OBJECT_HEAP_RESOURCE, 0, // AR_OBJECT_HEAP_SAMPLER, @@ -1594,6 +1610,7 @@ static const SubscriptOperatorRecord g_ArBasicKindsSubscripts[] = { {0, MipsFalse, SampleFalse}, // AR_OBJECT_RAYTRACING_PIPELINE_CONFIG1, {0, MipsFalse, SampleFalse}, // AR_OBJECT_RAY_QUERY, + {0, MipsFalse, SampleFalse}, // AR_OBJECT_HIT_OBJECT, {0, MipsFalse, SampleFalse}, // AR_OBJECT_HEAP_RESOURCE, {0, MipsFalse, SampleFalse}, // AR_OBJECT_HEAP_SAMPLER, @@ -1675,7 +1692,7 @@ static const char *g_ArBasicTypeNames[] = { "RaytracingPipelineConfig", "TriangleHitGroup", "ProceduralPrimitiveHitGroup", "RaytracingPipelineConfig1", - "RayQuery", "HEAP_Resource", "HEAP_Sampler", + "RayQuery", "HitObject", "HEAP_Resource", "HEAP_Sampler", "RWTexture2DMS", "RWTexture2DMSArray", @@ -1856,12 +1873,14 @@ AddHLSLIntrinsicFunction(ASTContext &context, NamespaceDecl *NS, const QualType fnReturnType = functionArgQualTypes[0]; std::vector fnArgTypes(functionArgQualTypes.begin() + 1, functionArgQualTypes.end()); + + StorageClass SC = pIntrinsic->bStaticMember ? SC_Static : SC_Extern; QualType functionType = context.getFunctionType(fnReturnType, fnArgTypes, protoInfo, paramMods); FunctionDecl *functionDecl = FunctionDecl::Create( context, currentDeclContext, NoLoc, - DeclarationNameInfo(functionName, NoLoc), functionType, nullptr, - StorageClass::SC_Extern, InlineSpecifiedFalse, HasWrittenPrototypeTrue); + DeclarationNameInfo(functionName, NoLoc), functionType, nullptr, SC, + InlineSpecifiedFalse, HasWrittenPrototypeTrue); currentDeclContext->addDecl(functionDecl); functionDecl->setLexicalDeclContext(currentDeclContext); @@ -2270,6 +2289,10 @@ static void GetIntrinsicMethods(ArBasicKind kind, *intrinsics = g_RayQueryMethods; *intrinsicCount = _countof(g_RayQueryMethods); break; + case AR_OBJECT_HIT_OBJECT: + *intrinsics = g_HitObjectMethods; + *intrinsicCount = _countof(g_HitObjectMethods); + break; case AR_OBJECT_RWTEXTURE2DMS: *intrinsics = g_RWTexture2DMSMethods; *intrinsicCount = _countof(g_RWTexture2DMSMethods); @@ -3048,10 +3071,13 @@ class HLSLExternalSource : public ExternalSemaSource { IdentifierInfo *ii = &m_context->Idents.get(StringRef(intrinsic->pArgs[0].pName)); DeclarationName declarationName = DeclarationName(ii); + + StorageClass SC = intrinsic->bStaticMember ? SC_Static : SC_None; + CXXMethodDecl *functionDecl = CreateObjectFunctionDeclarationWithParams( *m_context, recordDecl, functionResultQT, ArrayRef(argsQTs, numParams), - ArrayRef(argNames, numParams), declarationName, true, + ArrayRef(argNames, numParams), declarationName, true, SC, templateParamNamedDeclsCount > 0); functionDecl->setImplicit(true); @@ -3253,7 +3279,7 @@ class HLSLExternalSource : public ExternalSemaSource { *m_context, recordDecl, resultType, ArrayRef(indexType), ArrayRef(StringRef("index")), m_context->DeclarationNames.getCXXOperatorName(OO_Subscript), true, - true); + StorageClass::SC_None, true); hlsl::CreateFunctionTemplateDecl( *m_context, recordDecl, functionDecl, reinterpret_cast(&templateTypeParmDecl), 1); @@ -3453,13 +3479,13 @@ class HLSLExternalSource : public ExternalSemaSource { InitParamMods(intrinsic, paramMods); // Create FunctionDecl. + StorageClass SC = intrinsic->bStaticMember ? SC_Static : SC_Extern; QualType fnType = VkIntrinsicFunctionType(paramTypes, paramMods); TypeSourceInfo *TInfo = m_sema->getASTContext().CreateTypeSourceInfo(fnType, 0); FunctionDecl *functionDecl = FunctionDecl::Create( context, m_vkNSDecl, NoLoc, DeclarationNameInfo(functionName, NoLoc), - fnType, TInfo, StorageClass::SC_Extern, InlineSpecifiedFalse, - HasWrittenPrototypeTrue); + fnType, TInfo, SC, InlineSpecifiedFalse, HasWrittenPrototypeTrue); // Create and set ParmVarDecl. SmallVector paramDecls = @@ -3530,6 +3556,8 @@ class HLSLExternalSource : public ExternalSemaSource { const auto *SM = hlsl::ShaderModel::GetByName(m_sema->getLangOpts().HLSLProfile.c_str()); CXXRecordDecl *nodeOutputDecl = nullptr, *emptyNodeOutputDecl = nullptr; + const bool EnableSER = + m_sema->getLangOpts().EnableShaderExecutionReordering; for (unsigned i = 0; i < _countof(g_ArBasicKindsAsTypes); i++) { ArBasicKind kind = g_ArBasicKindsAsTypes[i]; @@ -3590,6 +3618,10 @@ class HLSLExternalSource : public ExternalSemaSource { recordDecl = DeclareConstantBufferViewType(*m_context, /*bTBuf*/ true); } else if (kind == AR_OBJECT_RAY_QUERY) { recordDecl = DeclareRayQueryType(*m_context); + } else if (kind == AR_OBJECT_HIT_OBJECT) { + if (EnableSER) { + recordDecl = DeclareHitObjectType(*m_context); + } } else if (kind == AR_OBJECT_HEAP_RESOURCE) { recordDecl = DeclareResourceType(*m_context, /*bSampler*/ false); if (SM->IsSM66Plus()) { @@ -3967,6 +3999,13 @@ class HLSLExternalSource : public ExternalSemaSource { return IsRayQueryBasicKind(GetTypeElementKind(type)); } + bool IsHitObjectBasicKind(ArBasicKind kind) { + return kind == AR_OBJECT_HIT_OBJECT; + } + bool IsHitObjectType(QualType type) { + return IsHitObjectBasicKind(GetTypeElementKind(type)); + } + void WarnMinPrecision(QualType Type, SourceLocation Loc) { Type = Type->getCanonicalTypeUnqualified(); if (IsVectorType(m_sema, Type) || IsMatrixType(m_sema, Type)) { @@ -4571,6 +4610,7 @@ class HLSLExternalSource : public ExternalSemaSource { case AR_OBJECT_WAVE: case AR_OBJECT_ACCELERATION_STRUCT: case AR_OBJECT_RAY_DESC: + case AR_OBJECT_HIT_OBJECT: case AR_OBJECT_TRIANGLE_INTERSECTION_ATTRIBUTES: case AR_OBJECT_RWTEXTURE2DMS: case AR_OBJECT_RWTEXTURE2DMS_ARRAY: @@ -4740,6 +4780,17 @@ class HLSLExternalSource : public ExternalSemaSource { nameIdentifier, argumentCount)); } + bool IsEnabledIntrinsic(const HLSL_INTRINSIC *pIntrinsic, + const LangOptions LangOpts) { + switch ((hlsl::IntrinsicOp)pIntrinsic->Op) { + default: + return true; + + case hlsl::IntrinsicOp::MOP_HitObject_MakeNop: + return LangOpts.EnableShaderExecutionReordering; + } + } + bool AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE, ArrayRef Args, OverloadCandidateSet &CandidateSet, @@ -4786,9 +4837,17 @@ class HLSLExternalSource : public ExternalSemaSource { table, tableCount, IntrinsicTableDefIter::CreateEnd(m_intrinsicTables)); for (; cursor != end; ++cursor) { + const HLSL_INTRINSIC *pIntrinsic = *cursor; + + // Check whether this intrinsic is enabled in the current configuration. + // Note that this not necessary for member functions: if the builtin type + // is never declared, neither will any type be linked to the member + // intrinsics table. + if (!IsEnabledIntrinsic(*cursor, m_sema->getLangOpts())) + continue; + // If this is the intrinsic we're interested in, build up a representation // of the types we need. - const HLSL_INTRINSIC *pIntrinsic = *cursor; LPCSTR tableName = cursor.GetTableName(); LPCSTR lowering = cursor.GetLoweringStrategy(); DXASSERT(pIntrinsic->uNumArgs <= g_MaxIntrinsicParamCount + 1, @@ -5506,11 +5565,12 @@ class HLSLExternalSource : public ExternalSemaSource { Params.push_back(paramDecl); } + StorageClass SC = intrinsic->bStaticMember ? SC_Static : SC_Extern; QualType T = TInfo->getType(); DeclarationNameInfo NameInfo(FunctionTemplate->getDeclName(), NoLoc); CXXMethodDecl *method = CXXMethodDecl::Create( *m_context, dyn_cast(owner), NoLoc, NameInfo, T, TInfo, - SC_Extern, InlineSpecifiedFalse, IsConstexprFalse, NoLoc); + SC, InlineSpecifiedFalse, IsConstexprFalse, NoLoc); // Add intrinsic attr AddHLSLIntrinsicAttr(method, *m_context, tableName, lowering, intrinsic); @@ -7771,7 +7831,8 @@ void HLSLExternalSource::InitializeInitSequenceForHLSL( DXASSERT_NOMSG(initSequence != nullptr); // In HLSL there are no default initializers, eg float4x4 m(); - // Except for RayQuery constructor (also handle InitializationKind::IK_Value) + // Except for RayQuery and HitObject constructors (also handle + // InitializationKind::IK_Value) if (Kind.getKind() == InitializationKind::IK_Default || Kind.getKind() == InitializationKind::IK_Value) { QualType destBaseType = m_context->getBaseElementType(Entity.getType()); @@ -7782,7 +7843,9 @@ void HLSLExternalSource::InitializeInitSequenceForHLSL( GetRecordDeclForBuiltInOrStruct(typeRecordDecl)); DXASSERT(index != -1, "otherwise can't find type we already determined was an object"); - if (g_ArBasicKindsAsTypes[index] == AR_OBJECT_RAY_QUERY) { + + if (g_ArBasicKindsAsTypes[index] == AR_OBJECT_RAY_QUERY || + g_ArBasicKindsAsTypes[index] == AR_OBJECT_HIT_OBJECT) { CXXConstructorDecl *Constructor = *typeRecordDecl->ctor_begin(); initSequence->AddConstructorInitializationStep( Constructor, AccessSpecifier::AS_public, destBaseType, false, false, @@ -11365,6 +11428,54 @@ static bool isStringLiteral(QualType type) { return eType->isSpecificBuiltinType(BuiltinType::Char_S); } +void Sema::DiagnoseShaderExecutionReordering(CallExpr *CE, + DXIL::ShaderKind EntrySK, + const FunctionDecl *EntryFD, + const hlsl::ShaderModel *SM) { + FunctionDecl *FD = CE->getDirectCallee(); + if (!FD) + return; + HLSLIntrinsicAttr *IntrinsicAttr = FD->getAttr(); + if (!IntrinsicAttr) + return; + if (!IsBuiltinTable(IntrinsicAttr->getGroup())) + return; + + SourceLocation Loc = CE->getExprLoc(); + hlsl::IntrinsicOp opCode = (IntrinsicOp)IntrinsicAttr->getOpcode(); + + bool ValidEntryForHitObject = false; + switch (EntrySK) { + default: + break; + case DXIL::ShaderKind::RayGeneration: + case DXIL::ShaderKind::ClosestHit: + case DXIL::ShaderKind::Miss: + ValidEntryForHitObject = true; + break; + } + + // Return for anything that is not a HitObject intrinsic. + unsigned ErrDiagID = 0; + switch (opCode) { + default: + return; + case hlsl::IntrinsicOp::MOP_HitObject_MakeNop: + ErrDiagID = diag::err_hlsl_ser_invalid_shader_kind; + break; + } + + if (!ValidEntryForHitObject) { + Diag(Loc, ErrDiagID) << ShaderModel::FullNameFromKind(EntrySK); + Diag(EntryFD->getLocation(), diag::note_hlsl_entry_defined_here); + } + + if (!getLangOpts().EnableShaderExecutionReordering) { + // Legal entry, but version not supported + Diag(Loc, diag::err_hlsl_ser_invalid_version) << SM->GetName(); + } +} + // Check HLSL member call constraints for used functions. // locallyVisited is true if this call has been visited already from any other // entry function. Used to avoid duplicate diagnostics when not dependent on @@ -11390,6 +11501,8 @@ void Sema::DiagnoseReachableHLSLCall(CallExpr *CE, const hlsl::ShaderModel *SM, if (!IsBuiltinTable(IntrinsicAttr->getGroup())) return; + DiagnoseShaderExecutionReordering(CE, EntrySK, EntryDecl, SM); + SourceLocation Loc = CE->getExprLoc(); hlsl::IntrinsicOp opCode = (IntrinsicOp)IntrinsicAttr->getOpcode(); switch (opCode) { diff --git a/tools/clang/lib/Sema/SemaHLSLDiagnoseTU.cpp b/tools/clang/lib/Sema/SemaHLSLDiagnoseTU.cpp index cf5d741541..c2a3e219a4 100644 --- a/tools/clang/lib/Sema/SemaHLSLDiagnoseTU.cpp +++ b/tools/clang/lib/Sema/SemaHLSLDiagnoseTU.cpp @@ -9,12 +9,14 @@ // // /////////////////////////////////////////////////////////////////////////////// +#include "dxc/DXIL/DxilFunctionProps.h" #include "dxc/DXIL/DxilShaderModel.h" #include "dxc/HlslIntrinsicOp.h" #include "dxc/Support/Global.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Attr.h" #include "clang/AST/Decl.h" +#include "clang/AST/HlslTypes.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/Sema/SemaDiagnostic.h" #include "clang/Sema/SemaHLSL.h" @@ -336,6 +338,30 @@ class HLSLCallDiagnoseVisitor llvm::SmallPtrSetImpl &DiagnosedCalls; }; +class HLSLNoSERDiagnoseVisitor + : public RecursiveASTVisitor { +public: + explicit HLSLNoSERDiagnoseVisitor(Sema &S, DXIL::ShaderKind EntrySK, + const FunctionDecl *EntryDecl) + : S(S), EntrySK(EntrySK), EntryDecl(EntryDecl) {} + + bool VisitTypeLoc(TypeLoc TL) { + if (!hlsl::IsHLSLHitObjectType(TL.getType())) + return true; + + S.Diag(TL.getLocStart(), diag::err_hlsl_ser_invalid_shader_kind) + << ShaderModel::FullNameFromKind(EntrySK); + S.Diag(EntryDecl->getLocation(), diag::note_hlsl_entry_defined_here); + return true; + } + +private: + clang::Sema &S; + DXIL::ShaderKind EntrySK; + const FunctionDecl *EntryDecl; + bool AllowHitObject; +}; + std::optional getFunctionInputPatchCount(const FunctionDecl *function) { for (const auto *param : function->params()) { @@ -537,6 +563,19 @@ void hlsl::DiagnoseTranslationUnit(clang::Sema *self) { NodeLaunchTy = DXIL::NodeLaunchType::Broadcasting; } } + + // Shader Execution Reordering + // ReorderThread(..) handled elsewhere. + const bool AllowHitObject = (EntrySK == DXIL::ShaderKind::ClosestHit || + EntrySK == DXIL::ShaderKind::Miss || + EntrySK == DXIL::ShaderKind::RayGeneration); + if (!AllowHitObject) { + HLSLNoSERDiagnoseVisitor Visitor(*self, EntrySK, FDecl); + for (FunctionDecl *FD : callGraph.GetVisitedFunctions()) { + Visitor.TraverseDecl(FD); + } + } + // Visit all visited functions in call graph to collect illegal intrinsic // calls. for (FunctionDecl *FD : callGraph.GetVisitedFunctions()) { diff --git a/tools/clang/test/SemaHLSL/hlsl/intrinsics/ser/hitobject-unused-id-pre-sm69.hlsl b/tools/clang/test/SemaHLSL/hlsl/intrinsics/ser/hitobject-unused-id-pre-sm69.hlsl new file mode 100644 index 0000000000..df0a38a1e1 --- /dev/null +++ b/tools/clang/test/SemaHLSL/hlsl/intrinsics/ser/hitobject-unused-id-pre-sm69.hlsl @@ -0,0 +1,9 @@ +// RUN: %dxc -T lib_6_6 %s -verify +// RUN: %dxc -T lib_6_8 %s -verify + +[shader("raygeneration")] +void main() +{ + // expected-error@+1{{use of undeclared identifier 'HitObject'}} + HitObject::MakeNop(); +} diff --git a/tools/clang/test/SemaHLSL/hlsl/intrinsics/ser/reorder-unclaimed-pre-sm69.hlsl b/tools/clang/test/SemaHLSL/hlsl/intrinsics/ser/reorder-unclaimed-pre-sm69.hlsl new file mode 100644 index 0000000000..a84cddf542 --- /dev/null +++ b/tools/clang/test/SemaHLSL/hlsl/intrinsics/ser/reorder-unclaimed-pre-sm69.hlsl @@ -0,0 +1,13 @@ +// RUN: %dxc -T lib_6_6 %s -verify +// RUN: %dxc -T lib_6_8 %s -verify + +// Check that intrinsic names of Shader Execution Reordering are unclaimed pre SM 6.9. +// expected-no-diagnostics + +void ReorderThread(uint CoherenceHint, uint NumCoherenceHintBitsFromLSB) { +} + +[shader("raygeneration")] +void main() { + ReorderThread(15u, 4u); +} diff --git a/tools/clang/test/SemaHLSL/hlsl/objects/HitObject/hitobject-entry-errors.hlsl b/tools/clang/test/SemaHLSL/hlsl/objects/HitObject/hitobject-entry-errors.hlsl new file mode 100644 index 0000000000..e0190651d5 --- /dev/null +++ b/tools/clang/test/SemaHLSL/hlsl/objects/HitObject/hitobject-entry-errors.hlsl @@ -0,0 +1,57 @@ +// RUN: %dxc -T lib_6_9 %s -verify + +struct [raypayload] Payload +{ + float elem + : write(caller,closesthit,anyhit,closesthit,miss) + : read(caller,closesthit,anyhit,closesthit,miss); +}; + +struct Attribs { float2 barys; }; + +void UseHitObject() { +// expected-error@+4{{Shader kind 'compute' incompatible with shader execution reordering (has to be raygeneration, closesthit or miss)}} +// expected-error@+3{{Shader kind 'intersection' incompatible with shader execution reordering (has to be raygeneration, closesthit or miss)}} +// expected-error@+2{{Shader kind 'anyhit' incompatible with shader execution reordering (has to be raygeneration, closesthit or miss)}} +// expected-error@+1{{Shader kind 'callable' incompatible with shader execution reordering (has to be raygeneration, closesthit or miss)}} + HitObject hit; +} + +// expected-note@+3{{entry function defined here}} +[shader("compute")] +[numthreads(4,4,4)] +void mainHitCS(uint ix : SV_GroupIndex, uint3 id : SV_GroupThreadID) { + UseHitObject(); +} + +[shader("raygeneration")] +void mainHitRG() { + UseHitObject(); +} + +// expected-note@+2{{entry function defined here}} +[shader("callable")] +void mainHitCALL(inout Attribs attrs) { + UseHitObject(); +} +// expected-note@+2{{entry function defined here}} +[shader("intersection")] +void mainHitIS() { + UseHitObject(); +} + +// expected-note@+2{{entry function defined here}} +[shader("anyhit")] +void mainHitAH(inout Payload pld, in Attribs attrs) { + UseHitObject(); +} + +[shader("closesthit")] +void mainHitCH(inout Payload pld, in Attribs attrs) { + UseHitObject(); +} + +[shader("miss")] +void mainHitMS(inout Payload pld) { + UseHitObject(); +} diff --git a/tools/clang/test/SemaHLSL/hlsl/objects/HitObject/hitobject-in-buffer.hlsl b/tools/clang/test/SemaHLSL/hlsl/objects/HitObject/hitobject-in-buffer.hlsl new file mode 100644 index 0000000000..3d19f3e850 --- /dev/null +++ b/tools/clang/test/SemaHLSL/hlsl/objects/HitObject/hitobject-in-buffer.hlsl @@ -0,0 +1,8 @@ +// RUN: %dxc -T lib_6_9 %s -verify + +// expected-error@+1{{'HitObject' is an object and cannot be used as a type parameter}} +RWStructuredBuffer InvalidBuffer; + +[shader("raygeneration")] void main() { + HitObject hit; +} diff --git a/tools/clang/test/SemaHLSL/hlsl/objects/HitObject/hitobject-target-profile-error.hlsl b/tools/clang/test/SemaHLSL/hlsl/objects/HitObject/hitobject-target-profile-error.hlsl new file mode 100644 index 0000000000..e1e223bc70 --- /dev/null +++ b/tools/clang/test/SemaHLSL/hlsl/objects/HitObject/hitobject-target-profile-error.hlsl @@ -0,0 +1,7 @@ +// RUN: not %dxc -T lib_6_8 %s 2>&1 | FileCheck %s + +[shader("raygeneration")] +void main() { +// CHECK: error: unknown type name 'HitObject' + HitObject hit; +} diff --git a/tools/clang/test/SemaHLSL/hlsl/objects/HitObject/hitobject-unclaimed-pre-sm69.hlsl b/tools/clang/test/SemaHLSL/hlsl/objects/HitObject/hitobject-unclaimed-pre-sm69.hlsl new file mode 100644 index 0000000000..08cbd50e0d --- /dev/null +++ b/tools/clang/test/SemaHLSL/hlsl/objects/HitObject/hitobject-unclaimed-pre-sm69.hlsl @@ -0,0 +1,18 @@ +// RUN: %dxc -T lib_6_8 %s -verify + +// Check that the HitObject type name of Shader Execution Reordering is unclaimed pre SM 6.9. +// expected-no-diagnostics + +struct HitObject { + int notTheSM69HitObject; + static HitObject MakeNop() { + HitObject hit; + hit.notTheSM69HitObject = 1; + return hit; + } +}; + +[shader("raygeneration")] +void main() { + HitObject hit = HitObject::MakeNop(); +} diff --git a/tools/clang/test/SemaHLSL/hlsl/objects/HitObject/hitobject-unsupported-vs.hlsl b/tools/clang/test/SemaHLSL/hlsl/objects/HitObject/hitobject-unsupported-vs.hlsl new file mode 100644 index 0000000000..358c6f0a4e --- /dev/null +++ b/tools/clang/test/SemaHLSL/hlsl/objects/HitObject/hitobject-unsupported-vs.hlsl @@ -0,0 +1,8 @@ +// RUN: %dxc -T vs_6_9 %s -verify + +// expected-note@+1{{entry function defined here}} +float main(RayDesc rayDesc: RAYDESC) : OUT { +// expected-error@+1{{Shader kind 'vertex' incompatible with shader execution reordering (has to be raygeneration, closesthit or miss)}} + HitObject hit; + return 0.f; +} diff --git a/tools/clang/tools/dxcompiler/dxcompilerobj.cpp b/tools/clang/tools/dxcompiler/dxcompilerobj.cpp index c1c844d4be..4909d06d8b 100644 --- a/tools/clang/tools/dxcompiler/dxcompilerobj.cpp +++ b/tools/clang/tools/dxcompiler/dxcompilerobj.cpp @@ -1438,6 +1438,8 @@ class DxcCompiler : public IDxcCompiler3, compiler.getLangOpts().EnablePayloadAccessQualifiers = Opts.EnablePayloadQualifiers; + compiler.getLangOpts().EnableShaderExecutionReordering = + Opts.EnableShaderExecutionReordering; compiler.getLangOpts().HLSLProfile = compiler.getCodeGenOpts().HLSLProfile = Opts.TargetProfile; @@ -1528,6 +1530,8 @@ class DxcCompiler : public IDxcCompiler3, Opts.EnableLifetimeMarkers; compiler.getCodeGenOpts().HLSLEnablePayloadAccessQualifiers = Opts.EnablePayloadQualifiers; + compiler.getCodeGenOpts().HLSLEnableShaderExecutionReordering = + Opts.EnableShaderExecutionReordering; // Translate signature packing options if (Opts.PackPrefixStable) diff --git a/tools/clang/unittests/HLSL/ExtensionTest.cpp b/tools/clang/unittests/HLSL/ExtensionTest.cpp index 51dda5533c..5edc1dab9a 100644 --- a/tools/clang/unittests/HLSL/ExtensionTest.cpp +++ b/tools/clang/unittests/HLSL/ExtensionTest.cpp @@ -204,79 +204,83 @@ Intrinsic Intrinsics[] = { {L"test_fn", DEFAULT_NAME, "r", - {1, false, true, false, -1, countof(TestFnArgs), TestFnArgs}}, + {1, false, true, false, false, -1, countof(TestFnArgs), TestFnArgs}}, {L"test_proc", DEFAULT_NAME, "r", - {2, false, false, false, -1, countof(TestProcArgs), TestProcArgs}}, + {2, false, false, false, false, -1, countof(TestProcArgs), TestProcArgs}}, {L"test_poly", "test_poly.$o", "r", - {3, false, true, false, -1, countof(TestFnCustomArgs), TestFnCustomArgs}}, + {3, false, true, false, false, -1, countof(TestFnCustomArgs), + TestFnCustomArgs}}, {L"test_int", "test_int", "r", - {4, false, true, false, -1, countof(TestFnIntArgs), TestFnIntArgs}}, + {4, false, true, false, false, -1, countof(TestFnIntArgs), TestFnIntArgs}}, {L"test_nolower", "test_nolower.$o", "n", - {5, false, true, false, -1, countof(TestFnNoLowerArgs), + {5, false, true, false, false, -1, countof(TestFnNoLowerArgs), TestFnNoLowerArgs}}, {L"test_pack_0", "test_pack_0.$o", "p", - {6, false, false, false, -1, countof(TestFnPack0), TestFnPack0}}, + {6, false, false, false, false, -1, countof(TestFnPack0), TestFnPack0}}, {L"test_pack_1", "test_pack_1.$o", "p", - {7, false, true, false, -1, countof(TestFnPack1), TestFnPack1}}, + {7, false, true, false, false, -1, countof(TestFnPack1), TestFnPack1}}, {L"test_pack_2", "test_pack_2.$o", "p", - {8, false, true, false, -1, countof(TestFnPack2), TestFnPack2}}, + {8, false, true, false, false, -1, countof(TestFnPack2), TestFnPack2}}, {L"test_pack_3", "test_pack_3.$o", "p", - {9, false, true, false, -1, countof(TestFnPack3), TestFnPack3}}, + {9, false, true, false, false, -1, countof(TestFnPack3), TestFnPack3}}, {L"test_pack_4", "test_pack_4.$o", "p", - {10, false, false, false, -1, countof(TestFnPack4), TestFnPack4}}, + {10, false, false, false, false, -1, countof(TestFnPack4), TestFnPack4}}, {L"test_rand", "test_rand", "r", - {11, false, false, false, -1, countof(TestRand), TestRand}}, + {11, false, false, false, false, -1, countof(TestRand), TestRand}}, {L"test_isinf", "test_isinf", "d", - {13, true, true, false, -1, countof(TestIsInf), TestIsInf}}, + {13, true, true, false, false, -1, countof(TestIsInf), TestIsInf}}, {L"test_ibfe", "test_ibfe", "d", - {14, true, true, false, -1, countof(TestIBFE), TestIBFE}}, + {14, true, true, false, false, -1, countof(TestIBFE), TestIBFE}}, // Make this intrinsic have the same opcode as an hlsl intrinsic with an // unsigned counterpart for testing purposes. {L"test_unsigned", "test_unsigned", "n", - {static_cast(hlsl::IntrinsicOp::IOP_min), false, true, false, -1, - countof(TestUnsigned), TestUnsigned}}, + {static_cast(hlsl::IntrinsicOp::IOP_min), false, true, false, + false, -1, countof(TestUnsigned), TestUnsigned}}, {L"wave_proc", DEFAULT_NAME, "r", - {16, false, true, true, -1, countof(WaveProcArgs), WaveProcArgs}}, + {16, false, true, true, false, -1, countof(WaveProcArgs), WaveProcArgs}}, {L"test_o_1", "test_o_1.$o:1", "r", - {18, false, true, true, -1, countof(TestOverloadArgs), TestOverloadArgs}}, + {18, false, true, true, false, -1, countof(TestOverloadArgs), + TestOverloadArgs}}, {L"test_o_2", "test_o_2.$o:2", "r", - {19, false, true, true, -1, countof(TestOverloadArgs), TestOverloadArgs}}, + {19, false, true, true, false, -1, countof(TestOverloadArgs), + TestOverloadArgs}}, {L"test_o_3", "test_o_3.$o:3", "r", - {20, false, true, true, -1, countof(TestOverloadArgs), TestOverloadArgs}}, + {20, false, true, true, false, -1, countof(TestOverloadArgs), + TestOverloadArgs}}, // custom lowering with both optional arguments and vector exploding. // Arg 0 = Opcode // Arg 1 = Pass as is @@ -286,16 +290,17 @@ Intrinsic Intrinsics[] = { {L"CustomLoadOp", "CustomLoadOp", "c:{\"default\" : \"0,1,2:?i1,3.0:?i32,3.1:?i32\"}", - {21, true, false, false, -1, countof(TestCustomLoadOp), TestCustomLoadOp}}, + {21, true, false, false, false, -1, countof(TestCustomLoadOp), + TestCustomLoadOp}}, {L"CustomLoadOp", "CustomLoadOp", "c:{\"default\" : \"0,1,2:?i1,3.0:?i32,3.1:?i32\"}", - {21, true, false, false, -1, countof(TestCustomLoadOpBool), + {21, true, false, false, false, -1, countof(TestCustomLoadOpBool), TestCustomLoadOpBool}}, {L"CustomLoadOp", "CustomLoadOp", "c:{\"default\" : \"0,1,2:?i1,3.0:?i32,3.1:?i32\"}", - {21, true, false, false, -1, countof(TestCustomLoadOpSubscript), + {21, true, false, false, false, -1, countof(TestCustomLoadOpSubscript), TestCustomLoadOpSubscript}}, }; @@ -303,7 +308,8 @@ Intrinsic BufferIntrinsics[] = { {L"MyBufferOp", "MyBufferOp", "m", - {12, false, true, false, -1, countof(TestMyBufferOp), TestMyBufferOp}}, + {12, false, true, false, false, -1, countof(TestMyBufferOp), + TestMyBufferOp}}, }; // Test adding a method to an object that normally has no methods (SamplerState @@ -312,7 +318,8 @@ Intrinsic SamplerIntrinsics[] = { {L"MySamplerOp", "MySamplerOp", "m", - {15, false, true, false, -1, countof(TestMySamplerOp), TestMySamplerOp}}, + {15, false, true, false, false, -1, countof(TestMySamplerOp), + TestMySamplerOp}}, }; // Define a lowering string to target a common dxil extension operation defined @@ -345,12 +352,12 @@ Intrinsic Texture1DIntrinsics[] = { {L"MyTextureOp", "MyTextureOp", MyTextureOp_LoweringInfo, - {17, false, true, false, -1, countof(TestMyTexture1DOp_0), + {17, false, true, false, false, -1, countof(TestMyTexture1DOp_0), TestMyTexture1DOp_0}}, {L"MyTextureOp", "MyTextureOp", MyTextureOp_LoweringInfo, - {17, false, true, false, -1, countof(TestMyTexture1DOp_1), + {17, false, true, false, false, -1, countof(TestMyTexture1DOp_1), TestMyTexture1DOp_1}}, }; @@ -358,7 +365,7 @@ Intrinsic Texture2DIntrinsics[] = { {L"MyTextureOp", "MyTextureOp", MyTextureOp_LoweringInfo, - {17, false, true, false, -1, countof(TestMyTexture2DOp), + {17, false, true, false, false, -1, countof(TestMyTexture2DOp), TestMyTexture2DOp}}, }; @@ -1497,8 +1504,8 @@ TEST_F(ExtensionTest, EvalAttributeCollision) { Intrinsic Intrinsic = {L"collide_proc", "collide_proc", "r", - {static_cast(op), true, false, false, -1, - countof(Args), Args}}; + {static_cast(op), true, false, false, + false, -1, countof(Args), Args}}; Compiler c(m_dllSupport); c.RegisterIntrinsicTable(new TestIntrinsicTable(&Intrinsic, 1)); c.Compile(R"( @@ -1532,10 +1539,11 @@ TEST_F(ExtensionTest, NoUnwind) { IA_C}, {"value", AR_QUAL_IN, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_NUMERIC, 1, IA_C}}; - Intrinsic Intrinsic = {L"test_proc", - "test_proc", - "r", - {1, false, false, false, -1, countof(Args), Args}}; + Intrinsic Intrinsic = { + L"test_proc", + "test_proc", + "r", + {1, false, false, false, false, -1, countof(Args), Args}}; Compiler c(m_dllSupport); c.RegisterIntrinsicTable(new TestIntrinsicTable(&Intrinsic, 1)); c.Compile(R"( @@ -1569,10 +1577,11 @@ TEST_F(ExtensionTest, DCE) { IA_C}, {"value", AR_QUAL_IN, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_NUMERIC, 1, IA_C}}; - Intrinsic Intrinsic = {L"test_proc", - "test_proc", - "r", - {1, true, true, false, -1, countof(Args), Args}}; + Intrinsic Intrinsic = { + L"test_proc", + "test_proc", + "r", + {1, true, true, false, false, -1, countof(Args), Args}}; Compiler c(m_dllSupport); c.RegisterIntrinsicTable(new TestIntrinsicTable(&Intrinsic, 1)); c.Compile(R"( diff --git a/utils/hct/gen_intrin_main.txt b/utils/hct/gen_intrin_main.txt index 7f7637b230..7f0c841887 100644 --- a/utils/hct/gen_intrin_main.txt +++ b/utils/hct/gen_intrin_main.txt @@ -34,8 +34,9 @@ // the size comes from the parse input. "<>" means any kind // of layout is acceptable. // -// Basic types are bool, int, uint, u64, float, sampler1d, sampler2d, -// sampler3d, sampler_cube, sampler_cmp, sampler, wave and void. +// Basic types are bool, int, uint, u64, float, hit_object, +// sampler1d, sampler2d, sampler3d, sampler_cube, sampler_cmp, +// sampler, wave and void. // There are meta-types too: any_int, uint_only, numeric and any. // // Along with a type and layout you can also give relations @@ -1089,6 +1090,10 @@ uint [[ro]] CommittedInstanceContributionToHitGroupIndex(); } namespace +namespace HitObjectMethods { + hit_object [[static,class_prefix]] MakeNop(); +} namespace + // Work Graphs objects and methods // EmptyNodeInput diff --git a/utils/hct/hctdb.py b/utils/hct/hctdb.py index 2f632aceee..1530310e36 100644 --- a/utils/hct/hctdb.py +++ b/utils/hct/hctdb.py @@ -8147,6 +8147,8 @@ def __init__( unsigned_op, overload_idx, hidden, + static_member, + class_prefix, ): self.name = name # Function name self.idx = idx # Unique number within namespace @@ -8162,7 +8164,11 @@ def __init__( self.name = "Vk" + self.name id_prefix = "IOP" # SPIR-V Change Ends - self.enum_name = "%s_%s" % (id_prefix, name) # enum name + if class_prefix: + class_name = ns[0 : -len("Methods")] + self.enum_name = "%s_%s_%s" % (id_prefix, class_name, name) + else: + self.enum_name = "%s_%s" % (id_prefix, name) self.readonly = ro # Only read memory self.readnone = rn # Not read memory self.argmemonly = amo # Only accesses memory through argument pointers @@ -8174,6 +8180,7 @@ def __init__( overload_idx # Parameter determines the overload type, -1 means ret type ) self.hidden = hidden # Internal high-level op, not exposed to HLSL + self.static_member = static_member # HLSL static member function self.key = ( ("%3d" % ns_idx) + "!" @@ -8269,6 +8276,8 @@ def __init__(self, intrinsic_defs): "resource": "LICOMPTYPE_RESOURCE", "ray_desc": "LICOMPTYPE_RAYDESC", "acceleration_struct": "LICOMPTYPE_ACCELERATION_STRUCT", + "ray_query": "LICOMPTYPE_RAY_QUERY", + "hit_object": "LICOMPTYPE_HIT_OBJECT", "udt": "LICOMPTYPE_USER_DEFINED_TYPE", "void": "LICOMPTYPE_VOID", "string": "LICOMPTYPE_STRING", @@ -8338,7 +8347,7 @@ def load_intrinsics(self, intrinsic_defs): r"""( sampler\w* | string | (?:RW)?(?:Texture\w*|ByteAddressBuffer) | - acceleration_struct | ray_desc | + acceleration_struct | ray_desc | ray_query | hit_object | Node\w* | RWNode\w* | EmptyNode\w* | AnyNodeOutput\w* | NodeOutputRecord\w* | GroupShared\w* $)""", @@ -8544,7 +8553,9 @@ def process_attr(attr): readonly = False # Only read memory readnone = False # Not read memory argmemonly = False # Only reads memory through pointer arguments + static_member = False # Static member function is_wave = False + class_prefix = False # Insert class name as enum_prefix # Is wave-sensitive unsigned_op = "" # Unsigned opcode if exist overload_param_index = ( @@ -8569,6 +8580,12 @@ def process_attr(attr): if a == "hidden": hidden = True continue + if a == "static": + static_member = True + continue + if a == "class_prefix": + class_prefix = True + continue assign = a.split("=") @@ -8593,6 +8610,8 @@ def process_attr(attr): unsigned_op, overload_param_index, hidden, + static_member, + class_prefix, ) current_namespace = None @@ -8640,6 +8659,8 @@ def process_attr(attr): unsigned_op, overload_param_index, hidden, + static_member, + class_prefix, ) = process_attr(attr) # Add an entry for this intrinsic. if bracket_cleanup_re.search(opts): @@ -8656,6 +8677,8 @@ def process_attr(attr): for in_arg in in_args: args.append(process_arg(in_arg, arg_idx, args, name)) arg_idx += 1 + if class_prefix: + assert current_namespace.endswith("Methods") # We have to process the return type description last # to match the compiler's handling of it and allow # the return type to match an input type. @@ -8678,6 +8701,8 @@ def process_attr(attr): unsigned_op, overload_param_index, hidden, + static_member, + class_prefix, ) ) num_entries += 1 diff --git a/utils/hct/hctdb_instrhelp.py b/utils/hct/hctdb_instrhelp.py index 17eefd4918..99082a421b 100644 --- a/utils/hct/hctdb_instrhelp.py +++ b/utils/hct/hctdb_instrhelp.py @@ -599,6 +599,7 @@ def print_opfunc_table(self): "noderecordhandle": "A(pNodeRecordHandle);", "nodeproperty": "A(nodeProperty);", "noderecordproperty": "A(nodeRecordProperty);", + "hit_object": "A(pHit);", } last_category = None for i in self.instrs: @@ -989,13 +990,13 @@ def get_hlsl_intrinsics(): result += "#ifdef ENABLE_SPIRV_CODEGEN\n\n" # SPIRV Change Ends arg_idx = 0 - ns_table += " {(UINT)%s::%s_%s, %s, %s, %s, %d, %d, g_%s_Args%s},\n" % ( + ns_table += " {(UINT)%s::%s, %s, %s, %s, %s, %d, %d, g_%s_Args%s},\n" % ( opcode_namespace, - id_prefix, - i.name, + i.enum_name, str(i.readonly).lower(), str(i.readnone).lower(), str(i.wave).lower(), + str(i.static_member).lower(), i.overload_param_index, len(i.params), last_ns, From 636e6c526e25b13217066574ac00093e2f9c52d9 Mon Sep 17 00:00:00 2001 From: Simon Moll Date: Wed, 29 Jan 2025 15:07:23 +0100 Subject: [PATCH 2/4] [ser][nfc] Remove unused AllowHitObject field to fix Clang Werror --- tools/clang/lib/Sema/SemaHLSLDiagnoseTU.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/clang/lib/Sema/SemaHLSLDiagnoseTU.cpp b/tools/clang/lib/Sema/SemaHLSLDiagnoseTU.cpp index c2a3e219a4..29cb47ba87 100644 --- a/tools/clang/lib/Sema/SemaHLSLDiagnoseTU.cpp +++ b/tools/clang/lib/Sema/SemaHLSLDiagnoseTU.cpp @@ -359,7 +359,6 @@ class HLSLNoSERDiagnoseVisitor clang::Sema &S; DXIL::ShaderKind EntrySK; const FunctionDecl *EntryDecl; - bool AllowHitObject; }; std::optional From 912c95730e367903156a36a2a79a0d1eabe2550a Mon Sep 17 00:00:00 2001 From: Simon Moll Date: Thu, 30 Jan 2025 12:59:32 +0100 Subject: [PATCH 3/4] [ser][nfc] WAR memleak observed in hitobject-entry-errors.hlsl When specifying more than four stages in a PAQ, the SmallVector in the PayloadAccessAnnotation starts to allocate memory. That memory is never free'd. The hitobject-entry-errors accidentally triggered this: struct [raypayload] Payload { float elem - : write(caller,closesthit,anyhit,closesthit,miss) - : read(caller,closesthit,anyhit,closesthit,miss); + : write(caller,anyhit,closesthit,miss) + : read(caller,anyhit,closesthit,miss); }; --- .../hlsl/objects/HitObject/hitobject-entry-errors.hlsl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/clang/test/SemaHLSL/hlsl/objects/HitObject/hitobject-entry-errors.hlsl b/tools/clang/test/SemaHLSL/hlsl/objects/HitObject/hitobject-entry-errors.hlsl index e0190651d5..2edbb9f190 100644 --- a/tools/clang/test/SemaHLSL/hlsl/objects/HitObject/hitobject-entry-errors.hlsl +++ b/tools/clang/test/SemaHLSL/hlsl/objects/HitObject/hitobject-entry-errors.hlsl @@ -3,8 +3,8 @@ struct [raypayload] Payload { float elem - : write(caller,closesthit,anyhit,closesthit,miss) - : read(caller,closesthit,anyhit,closesthit,miss); + : write(caller,anyhit,closesthit,miss) + : read(caller,anyhit,closesthit,miss); }; struct Attribs { float2 barys; }; From 57c861aab39debbbe5ba53dbb2a9bb4a7c40a822 Mon Sep 17 00:00:00 2001 From: Simon Moll Date: Mon, 3 Feb 2025 08:56:37 +0100 Subject: [PATCH 4/4] [ser][nfc] Simplified tests and fixed typo --- .../lib/CodeGen/CGHLSLMSFinishCodeGen.cpp | 2 +- .../HitObject/hitobject-entry-errors.hlsl | 19 ++++++++++--------- .../HitObject/hitobject-in-buffer.hlsl | 4 ---- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/tools/clang/lib/CodeGen/CGHLSLMSFinishCodeGen.cpp b/tools/clang/lib/CodeGen/CGHLSLMSFinishCodeGen.cpp index dbdebdccea..aad914143d 100644 --- a/tools/clang/lib/CodeGen/CGHLSLMSFinishCodeGen.cpp +++ b/tools/clang/lib/CodeGen/CGHLSLMSFinishCodeGen.cpp @@ -2812,7 +2812,7 @@ void TranslateHitObjectConstructor(HLModule &HLM) { "Wrong signature for apparent HitObject constructor"); DXASSERT(!HitObjectCtor, - "Multiple candidate functions that quality as HitObject " + "Multiple candidate functions that qualify as HitObject " "constructor when there must be at most one"); HitObjectCtor = &F; } diff --git a/tools/clang/test/SemaHLSL/hlsl/objects/HitObject/hitobject-entry-errors.hlsl b/tools/clang/test/SemaHLSL/hlsl/objects/HitObject/hitobject-entry-errors.hlsl index 2edbb9f190..5a45b62f7d 100644 --- a/tools/clang/test/SemaHLSL/hlsl/objects/HitObject/hitobject-entry-errors.hlsl +++ b/tools/clang/test/SemaHLSL/hlsl/objects/HitObject/hitobject-entry-errors.hlsl @@ -10,10 +10,6 @@ struct [raypayload] Payload struct Attribs { float2 barys; }; void UseHitObject() { -// expected-error@+4{{Shader kind 'compute' incompatible with shader execution reordering (has to be raygeneration, closesthit or miss)}} -// expected-error@+3{{Shader kind 'intersection' incompatible with shader execution reordering (has to be raygeneration, closesthit or miss)}} -// expected-error@+2{{Shader kind 'anyhit' incompatible with shader execution reordering (has to be raygeneration, closesthit or miss)}} -// expected-error@+1{{Shader kind 'callable' incompatible with shader execution reordering (has to be raygeneration, closesthit or miss)}} HitObject hit; } @@ -21,28 +17,33 @@ void UseHitObject() { [shader("compute")] [numthreads(4,4,4)] void mainHitCS(uint ix : SV_GroupIndex, uint3 id : SV_GroupThreadID) { - UseHitObject(); -} - -[shader("raygeneration")] -void mainHitRG() { +// expected-error@-7{{Shader kind 'compute' incompatible with shader execution reordering (has to be raygeneration, closesthit or miss)}} UseHitObject(); } // expected-note@+2{{entry function defined here}} [shader("callable")] void mainHitCALL(inout Attribs attrs) { +// expected-error@-14{{Shader kind 'callable' incompatible with shader execution reordering (has to be raygeneration, closesthit or miss)}} UseHitObject(); } + // expected-note@+2{{entry function defined here}} [shader("intersection")] void mainHitIS() { +// expected-error@-21{{Shader kind 'intersection' incompatible with shader execution reordering (has to be raygeneration, closesthit or miss)}} UseHitObject(); } // expected-note@+2{{entry function defined here}} [shader("anyhit")] void mainHitAH(inout Payload pld, in Attribs attrs) { +// expected-error@-28{{Shader kind 'anyhit' incompatible with shader execution reordering (has to be raygeneration, closesthit or miss)}} + UseHitObject(); +} + +[shader("raygeneration")] +void mainHitRG() { UseHitObject(); } diff --git a/tools/clang/test/SemaHLSL/hlsl/objects/HitObject/hitobject-in-buffer.hlsl b/tools/clang/test/SemaHLSL/hlsl/objects/HitObject/hitobject-in-buffer.hlsl index 3d19f3e850..e50c2515a6 100644 --- a/tools/clang/test/SemaHLSL/hlsl/objects/HitObject/hitobject-in-buffer.hlsl +++ b/tools/clang/test/SemaHLSL/hlsl/objects/HitObject/hitobject-in-buffer.hlsl @@ -2,7 +2,3 @@ // expected-error@+1{{'HitObject' is an object and cannot be used as a type parameter}} RWStructuredBuffer InvalidBuffer; - -[shader("raygeneration")] void main() { - HitObject hit; -}