diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -4031,6 +4031,13 @@ let Documentation = [HLSLSV_GroupIndexDocs]; } +def HLSLSV_DispatchThreadID: HLSLAnnotationAttr { + let Spellings = [HLSLSemantic<"SV_DispatchThreadID">]; + let Subjects = SubjectList<[ParmVar, GlobalVar]>; + let LangOpts = [HLSL]; + let Documentation = [HLSLSV_DispatchThreadIDDocs]; +} + def HLSLShader : InheritableAttr { let Spellings = [Microsoft<"shader">]; let Subjects = SubjectList<[HLSLEntry]>; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -6567,6 +6567,17 @@ }]; } +def HLSLSV_DispatchThreadIDDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +The ``SV_DispatchThreadID`` semantic, when applied to an input parameter, specifies a +data binding to map global thread offset within the Dispatch call(per dimension of the group) to the specified parameter. +This attribute is only supported in compute shaders. + +The full documentation is available here: https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/sv-dispatchthreadid + }]; +} + def AnnotateTypeDocs : Documentation { let Category = DocCatType; let Heading = "annotate_type"; diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -39,7 +39,8 @@ uint32_t ResourceCounters[static_cast( hlsl::ResourceClass::NumClasses)] = {0}; - llvm::Value *emitInputSemantic(llvm::IRBuilder<> &B, const ParmVarDecl &D); + llvm::Value *emitInputSemantic(llvm::IRBuilder<> &B, const ParmVarDecl &D, + llvm::Type *Ty); public: CGHLSLRuntime(CodeGenModule &CGM) : CGM(CGM) {} diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp --- a/clang/lib/CodeGen/CGHLSLRuntime.cpp +++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp @@ -109,14 +109,32 @@ ShaderAttr->ConvertShaderTypeToStr(ShaderAttr->getType())); } +static Value *buildVectorInput(IRBuilder<> &B, Function *F, llvm::Type *Ty) { + if (FixedVectorType *VT = dyn_cast(Ty)) { + Value *Result = PoisonValue::get(Ty); + for (unsigned I = 0; I < VT->getNumElements(); ++I) { + Value *Elt = B.CreateCall(F, {B.getInt32(I)}); + Result = B.CreateInsertElement(Result, Elt, I); + } + return Result; + } else + return B.CreateCall(F, {B.getInt32(0)}); +} + llvm::Value *CGHLSLRuntime::emitInputSemantic(IRBuilder<> &B, - const ParmVarDecl &D) { + const ParmVarDecl &D, + llvm::Type *Ty) { assert(D.hasAttrs() && "Entry parameter missing annotation attribute!"); if (D.hasAttr()) { llvm::Function *DxGroupIndex = CGM.getIntrinsic(Intrinsic::dx_flattened_thread_id_in_group); return B.CreateCall(FunctionCallee(DxGroupIndex)); } + if (D.hasAttr()) { + llvm::Function *DxThreadID = CGM.getIntrinsic(Intrinsic::dx_thread_id); + // dx_thread_id + return buildVectorInput(B, DxThreadID, Ty); + } assert(false && "Unhandled parameter attribute"); return nullptr; } @@ -143,8 +161,15 @@ IRBuilder<> B(BB); llvm::SmallVector Args; // FIXME: support struct parameters where semantics are on members. - for (const auto *Param : FD->parameters()) { - Args.push_back(emitInputSemantic(B, *Param)); + unsigned SRetOffset = 0; + for (const auto &Param : Fn->args()) { + if (Param.hasStructRetAttr()) { + // FIXME: support output. + SRetOffset = 1; + continue; + } + const ParmVarDecl *PD = FD->getParamDecl(Param.getArgNo() - SRetOffset); + Args.push_back(emitInputSemantic(B, *PD, Param.getType())); } CallInst *CI = B.CreateCall(FunctionCallee(Fn), Args); diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -6907,6 +6907,25 @@ D->addAttr(::new (S.Context) HLSLSV_GroupIndexAttr(S.Context, AL)); } +static void handleHLSLSV_DispatchThreadIDAttr(Sema &S, Decl *D, + const ParsedAttr &AL) { + using llvm::Triple; + Triple Target = S.Context.getTargetInfo().getTriple(); + // FIXME: it is OK for a compute shader entry and pixiel shader entry live in + // same HLSL file. + if (Target.getEnvironment() != Triple::Compute && + Target.getEnvironment() != Triple::Library) { + uint32_t Pipeline = + (uint32_t)S.Context.getTargetInfo().getTriple().getEnvironment() - + (uint32_t)llvm::Triple::Pixel; + S.Diag(AL.getLoc(), diag::err_hlsl_attr_unsupported_in_stage) + << AL << Pipeline << "Compute"; + return; + } + + D->addAttr(::new (S.Context) HLSLSV_DispatchThreadIDAttr(S.Context, AL)); +} + static void handleHLSLShaderAttr(Sema &S, Decl *D, const ParsedAttr &AL) { StringRef Str; SourceLocation ArgLoc; @@ -8920,6 +8939,9 @@ case ParsedAttr::AT_HLSLSV_GroupIndex: handleHLSLSVGroupIndexAttr(S, D, AL); break; + case ParsedAttr::AT_HLSLSV_DispatchThreadID: + handleHLSLSV_DispatchThreadIDAttr(S, D, AL); + break; case ParsedAttr::AT_HLSLShader: handleHLSLShaderAttr(S, D, AL); break; diff --git a/clang/test/CodeGenHLSL/semantics/DispatchThreadID.hlsl b/clang/test/CodeGenHLSL/semantics/DispatchThreadID.hlsl new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenHLSL/semantics/DispatchThreadID.hlsl @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s + +// Make sure SV_DispatchThreadID translated into dx.thread.id. + +const RWBuffer In; +RWBuffer Out; + +// CHECK: define void @foo() +// CHECK: call i32 @llvm.dx.thread.id(i32 0) +// CHECK: call void @"?foo@@YAXH@Z"(i32 %{{.*}}) +[shader("compute")] +[numthreads(8,8,1)] +void foo(int Idx : SV_DispatchThreadID) { + Out[Idx] = In[Idx]; +} + +// CHECK: define void @bar() +// CHECK: call i32 @llvm.dx.thread.id(i32 0) +// CHECK: call i32 @llvm.dx.thread.id(i32 1) +// CHECK: call void @"?bar@@YAXT?$__vector@H$01@__clang@@@Z"(<2 x i32> %{{.*}}) +[shader("compute")] +[numthreads(8,8,1)] +void bar(int2 Idx : SV_DispatchThreadID) { + Out[Idx.y] = In[Idx.x]; +} +