-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[HLSL] Allow input semantics on structs #159047
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
This commit adds the support for semantics annotations on structs, but only for inputs. Due to the current semantics implemented, we cannot test much more than nesting/shadowing. Once user semantics are implemented, we'll be able to test arrays in structs and more complex cases. As-is, this commit has one weakness vs DXC: semantics type validation is not looking at the inner-most type, but the outermost type: ```hlsl struct Inner { uint tid; }; Inner inner : SV_GroupID ``` This sample would fail today because `SV_GroupID` require the type to be an integer. This works in DXC as the inner type is a integer. Because GroupIndex is not correctly validated, I uses this semantic to test the inheritance/shadowing. But this will need to be fixed in a later commit. Requires llvm#152537
@llvm/pr-subscribers-clang-codegen @llvm/pr-subscribers-clang Author: Nathan Gauër (Keenuts) ChangesThis PR is an incremental improvement regarding semantics I/O in HLSL. This PR allows The next step will be to enable user semantics, which will bring the need to properly determine semantic indices depending on context. This is not yet a solid semantic implementation, but increases the test coverage and improves the status from where we are now. Patch is 25.93 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/159047.diff 12 Files Affected:
diff --git a/clang/include/clang/AST/Attr.h b/clang/include/clang/AST/Attr.h
index fe388b9fa045e..00d4a0035fccf 100644
--- a/clang/include/clang/AST/Attr.h
+++ b/clang/include/clang/AST/Attr.h
@@ -259,6 +259,8 @@ class HLSLSemanticAttr : public HLSLAnnotationAttr {
unsigned getSemanticIndex() const { return SemanticIndex; }
+ bool isSemanticIndexExplicit() const { return SemanticExplicitIndex; }
+
// Implement isa/cast/dyncast/etc.
static bool classof(const Attr *A) {
return A->getKind() >= attr::FirstHLSLSemanticAttr &&
diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
index 2fd2ae434d7c5..15447558cf952 100644
--- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -400,10 +400,6 @@ def warn_hlsl_langstd_minimal :
"recommend using %1 instead">,
InGroup<HLSLDXCCompat>;
-def err_hlsl_semantic_missing : Error<"semantic annotations must be present "
- "for all input and outputs of an entry "
- "function or patch constant function">;
-
// ClangIR frontend errors
def err_cir_to_cir_transform_failed : Error<
"CIR-to-CIR transformation failed">, DefaultFatal;
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 757404a3f5eac..6950fdd994b3d 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -13123,6 +13123,7 @@ def err_hlsl_duplicate_parameter_modifier : Error<"duplicate parameter modifier
def err_hlsl_missing_semantic_annotation : Error<
"semantic annotations must be present for all parameters of an entry "
"function or patch constant function">;
+def note_hlsl_semantic_used_here : Note<"%0 used here">;
def err_hlsl_unknown_semantic : Error<"unknown HLSL semantic %0">;
def err_hlsl_semantic_output_not_supported
: Error<"semantic %0 does not support output">;
diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h
index b5ddca0fe2ca5..f0a940353515c 100644
--- a/clang/include/clang/Sema/SemaHLSL.h
+++ b/clang/include/clang/Sema/SemaHLSL.h
@@ -130,9 +130,6 @@ class SemaHLSL : public SemaBase {
bool ActOnUninitializedVarDecl(VarDecl *D);
void ActOnEndOfTranslationUnit(TranslationUnitDecl *TU);
void CheckEntryPoint(FunctionDecl *FD);
- bool isSemanticValid(FunctionDecl *FD, DeclaratorDecl *D);
- void CheckSemanticAnnotation(FunctionDecl *EntryPoint, const Decl *Param,
- const HLSLAnnotationAttr *AnnotationAttr);
void DiagnoseAttrStageMismatch(
const Attr *A, llvm::Triple::EnvironmentType Stage,
std::initializer_list<llvm::Triple::EnvironmentType> AllowedStages);
@@ -177,9 +174,9 @@ class SemaHLSL : public SemaBase {
bool handleResourceTypeAttr(QualType T, const ParsedAttr &AL);
template <typename T>
- T *createSemanticAttr(const ParsedAttr &AL,
+ T *createSemanticAttr(const AttributeCommonInfo &ACI,
std::optional<unsigned> Location) {
- T *Attr = ::new (getASTContext()) T(getASTContext(), AL);
+ T *Attr = ::new (getASTContext()) T(getASTContext(), ACI);
if (Attr->isSemanticIndexable())
Attr->setSemanticIndex(Location ? *Location : 0);
else if (Location.has_value()) {
@@ -246,10 +243,24 @@ class SemaHLSL : public SemaBase {
IdentifierInfo *RootSigOverrideIdent = nullptr;
+ struct SemanticInfo {
+ HLSLSemanticAttr *Semantic;
+ std::optional<uint32_t> Index;
+ };
+
private:
void collectResourceBindingsOnVarDecl(VarDecl *D);
void collectResourceBindingsOnUserRecordDecl(const VarDecl *VD,
const RecordType *RT);
+
+ void checkSemanticAnnotation(FunctionDecl *EntryPoint, const Decl *Param,
+ const HLSLSemanticAttr *SemanticAttr);
+ HLSLSemanticAttr *createSemantic(const SemanticInfo &Semantic);
+ bool isSemanticOnScalarValid(FunctionDecl *FD, DeclaratorDecl *D,
+ SemanticInfo &ActiveSemantic);
+ bool isSemanticValid(FunctionDecl *FD, DeclaratorDecl *D,
+ SemanticInfo &ActiveSemantic);
+
void processExplicitBindingsOnDecl(VarDecl *D);
void diagnoseAvailabilityViolations(TranslationUnitDecl *TU);
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index afee1198e0988..c68d85ac837f3 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -566,17 +566,16 @@ static llvm::Value *createSPIRVBuiltinLoad(IRBuilder<> &B, llvm::Module &M,
return B.CreateLoad(Ty, GV);
}
-llvm::Value *
-CGHLSLRuntime::emitSystemSemanticLoad(IRBuilder<> &B, llvm::Type *Type,
- const clang::DeclaratorDecl *Decl,
- SemanticInfo &ActiveSemantic) {
- if (isa<HLSLSV_GroupIndexAttr>(ActiveSemantic.Semantic)) {
+llvm::Value *CGHLSLRuntime::emitSystemSemanticLoad(
+ IRBuilder<> &B, llvm::Type *Type, const clang::DeclaratorDecl *Decl,
+ Attr *Semantic, std::optional<unsigned> Index) {
+ if (isa<HLSLSV_GroupIndexAttr>(Semantic)) {
llvm::Function *GroupIndex =
CGM.getIntrinsic(getFlattenedThreadIdInGroupIntrinsic());
return B.CreateCall(FunctionCallee(GroupIndex));
}
- if (isa<HLSLSV_DispatchThreadIDAttr>(ActiveSemantic.Semantic)) {
+ if (isa<HLSLSV_DispatchThreadIDAttr>(Semantic)) {
llvm::Intrinsic::ID IntrinID = getThreadIdIntrinsic();
llvm::Function *ThreadIDIntrinsic =
llvm::Intrinsic::isOverloaded(IntrinID)
@@ -585,7 +584,7 @@ CGHLSLRuntime::emitSystemSemanticLoad(IRBuilder<> &B, llvm::Type *Type,
return buildVectorInput(B, ThreadIDIntrinsic, Type);
}
- if (isa<HLSLSV_GroupThreadIDAttr>(ActiveSemantic.Semantic)) {
+ if (isa<HLSLSV_GroupThreadIDAttr>(Semantic)) {
llvm::Intrinsic::ID IntrinID = getGroupThreadIdIntrinsic();
llvm::Function *GroupThreadIDIntrinsic =
llvm::Intrinsic::isOverloaded(IntrinID)
@@ -594,7 +593,7 @@ CGHLSLRuntime::emitSystemSemanticLoad(IRBuilder<> &B, llvm::Type *Type,
return buildVectorInput(B, GroupThreadIDIntrinsic, Type);
}
- if (isa<HLSLSV_GroupIDAttr>(ActiveSemantic.Semantic)) {
+ if (isa<HLSLSV_GroupIDAttr>(Semantic)) {
llvm::Intrinsic::ID IntrinID = getGroupIdIntrinsic();
llvm::Function *GroupIDIntrinsic =
llvm::Intrinsic::isOverloaded(IntrinID)
@@ -603,8 +602,7 @@ CGHLSLRuntime::emitSystemSemanticLoad(IRBuilder<> &B, llvm::Type *Type,
return buildVectorInput(B, GroupIDIntrinsic, Type);
}
- if (HLSLSV_PositionAttr *S =
- dyn_cast<HLSLSV_PositionAttr>(ActiveSemantic.Semantic)) {
+ if (HLSLSV_PositionAttr *S = dyn_cast<HLSLSV_PositionAttr>(Semantic)) {
if (CGM.getTriple().getEnvironment() == Triple::EnvironmentType::Pixel)
return createSPIRVBuiltinLoad(B, CGM.getModule(), Type,
S->getAttrName()->getName(),
@@ -616,28 +614,45 @@ CGHLSLRuntime::emitSystemSemanticLoad(IRBuilder<> &B, llvm::Type *Type,
llvm::Value *
CGHLSLRuntime::handleScalarSemanticLoad(IRBuilder<> &B, llvm::Type *Type,
- const clang::DeclaratorDecl *Decl,
- SemanticInfo &ActiveSemantic) {
-
- if (!ActiveSemantic.Semantic) {
- ActiveSemantic.Semantic = Decl->getAttr<HLSLSemanticAttr>();
- if (!ActiveSemantic.Semantic) {
- CGM.getDiags().Report(Decl->getInnerLocStart(),
- diag::err_hlsl_semantic_missing);
- return nullptr;
- }
- ActiveSemantic.Index = ActiveSemantic.Semantic->getSemanticIndex();
+ const clang::DeclaratorDecl *Decl) {
+ HLSLSemanticAttr *Semantic = Decl->getAttr<HLSLSemanticAttr>();
+ // Sema either attached a semantic to each field/param, or raised an error.
+ assert(Semantic);
+
+ std::optional<unsigned> Index = std::nullopt;
+ if (Semantic->isSemanticIndexExplicit())
+ Index = Semantic->getSemanticIndex();
+ return emitSystemSemanticLoad(B, Type, Decl, Semantic, Index);
+}
+
+llvm::Value *
+CGHLSLRuntime::handleStructSemanticLoad(IRBuilder<> &B, llvm::Type *Type,
+ const clang::DeclaratorDecl *Decl) {
+ const llvm::StructType *ST = cast<StructType>(Type);
+ const clang::RecordDecl *RD = Decl->getType()->getAsRecordDecl();
+
+ assert(std::distance(RD->field_begin(), RD->field_end()) ==
+ ST->getNumElements());
+
+ llvm::Value *Aggregate = llvm::PoisonValue::get(Type);
+ auto FieldDecl = RD->field_begin();
+ for (unsigned I = 0; I < ST->getNumElements(); ++I) {
+ llvm::Value *ChildValue =
+ handleSemanticLoad(B, ST->getElementType(I), *FieldDecl);
+ assert(ChildValue);
+ Aggregate = B.CreateInsertValue(Aggregate, ChildValue, I);
+ ++FieldDecl;
}
- return emitSystemSemanticLoad(B, Type, Decl, ActiveSemantic);
+ return Aggregate;
}
llvm::Value *
CGHLSLRuntime::handleSemanticLoad(IRBuilder<> &B, llvm::Type *Type,
- const clang::DeclaratorDecl *Decl,
- SemanticInfo &ActiveSemantic) {
- assert(!Type->isStructTy());
- return handleScalarSemanticLoad(B, Type, Decl, ActiveSemantic);
+ const clang::DeclaratorDecl *Decl) {
+ if (Type->isStructTy())
+ return handleStructSemanticLoad(B, Type, Decl);
+ return handleScalarSemanticLoad(B, Type, Decl);
}
void CGHLSLRuntime::emitEntryFunction(const FunctionDecl *FD,
@@ -684,8 +699,25 @@ void CGHLSLRuntime::emitEntryFunction(const FunctionDecl *FD,
}
const ParmVarDecl *PD = FD->getParamDecl(Param.getArgNo() - SRetOffset);
- SemanticInfo ActiveSemantic = {nullptr, 0};
- Args.push_back(handleSemanticLoad(B, Param.getType(), PD, ActiveSemantic));
+ llvm::Value *SemanticValue = nullptr;
+ if ([[maybe_unused]] HLSLParamModifierAttr *MA =
+ PD->getAttr<HLSLParamModifierAttr>()) {
+ llvm_unreachable("Not handled yet");
+ } else {
+ llvm::Type *ParamType =
+ Param.hasByValAttr() ? Param.getParamByValType() : Param.getType();
+ SemanticValue = handleSemanticLoad(B, ParamType, PD);
+ if (!SemanticValue)
+ return;
+ if (Param.hasByValAttr()) {
+ llvm::Value *Var = B.CreateAlloca(Param.getParamByValType());
+ B.CreateStore(SemanticValue, Var);
+ SemanticValue = Var;
+ }
+ }
+
+ assert(SemanticValue);
+ Args.push_back(SemanticValue);
}
CallInst *CI = B.CreateCall(FunctionCallee(Fn), Args, OB);
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h
index 370f3d5c5d30d..039b881d2c9ee 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -144,22 +144,19 @@ class CGHLSLRuntime {
llvm::Type *Type,
SmallVectorImpl<llvm::Value *> &Inputs);
- struct SemanticInfo {
- clang::HLSLSemanticAttr *Semantic;
- uint32_t Index;
- };
-
llvm::Value *emitSystemSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type,
const clang::DeclaratorDecl *Decl,
- SemanticInfo &ActiveSemantic);
+ Attr *Semantic,
+ std::optional<unsigned> Index);
llvm::Value *handleScalarSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type,
- const clang::DeclaratorDecl *Decl,
- SemanticInfo &ActiveSemantic);
+ const clang::DeclaratorDecl *Decl);
+
+ llvm::Value *handleStructSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type,
+ const clang::DeclaratorDecl *Decl);
llvm::Value *handleSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type,
- const clang::DeclaratorDecl *Decl,
- SemanticInfo &ActiveSemantic);
+ const clang::DeclaratorDecl *Decl);
public:
CGHLSLRuntime(CodeGenModule &CGM) : CGM(CGM) {}
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 0af38472b0fec..ee4088d528c98 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -769,23 +769,78 @@ void SemaHLSL::ActOnTopLevelFunction(FunctionDecl *FD) {
}
}
-bool SemaHLSL::isSemanticValid(FunctionDecl *FD, DeclaratorDecl *D) {
- const auto *AnnotationAttr = D->getAttr<HLSLAnnotationAttr>();
- if (AnnotationAttr) {
- CheckSemanticAnnotation(FD, D, AnnotationAttr);
- return true;
+HLSLSemanticAttr *SemaHLSL::createSemantic(const SemanticInfo &Info) {
+ std::string SemanticName = Info.Semantic->getAttrName()->getName().upper();
+
+ if (SemanticName == "SV_DISPATCHTHREADID") {
+ return createSemanticAttr<HLSLSV_DispatchThreadIDAttr>(*Info.Semantic,
+ Info.Index);
+ } else if (SemanticName == "SV_GROUPINDEX") {
+ return createSemanticAttr<HLSLSV_GroupIndexAttr>(*Info.Semantic,
+ Info.Index);
+ } else if (SemanticName == "SV_GROUPTHREADID") {
+ return createSemanticAttr<HLSLSV_GroupThreadIDAttr>(*Info.Semantic,
+ Info.Index);
+ } else if (SemanticName == "SV_GROUPID") {
+ return createSemanticAttr<HLSLSV_GroupIDAttr>(*Info.Semantic, Info.Index);
+ } else if (SemanticName == "SV_POSITION") {
+ return createSemanticAttr<HLSLSV_PositionAttr>(*Info.Semantic, Info.Index);
+ } else
+ Diag(Info.Semantic->getLoc(), diag::err_hlsl_unknown_semantic)
+ << *Info.Semantic;
+
+ return nullptr;
+}
+
+bool SemaHLSL::isSemanticOnScalarValid(FunctionDecl *FD, DeclaratorDecl *D,
+ SemanticInfo &ActiveSemantic) {
+ if (ActiveSemantic.Semantic == nullptr) {
+ ActiveSemantic.Semantic = D->getAttr<HLSLSemanticAttr>();
+ if (ActiveSemantic.Semantic &&
+ ActiveSemantic.Semantic->isSemanticIndexExplicit())
+ ActiveSemantic.Index = ActiveSemantic.Semantic->getSemanticIndex();
+ }
+
+ if (!ActiveSemantic.Semantic) {
+ Diag(D->getLocation(), diag::err_hlsl_missing_semantic_annotation);
+ return false;
+ }
+
+ auto *A = createSemantic(ActiveSemantic);
+ if (!A)
+ return false;
+
+ checkSemanticAnnotation(FD, D, A);
+ D->dropAttrs<HLSLSemanticAttr>();
+ D->addAttr(A);
+ return true;
+}
+
+bool SemaHLSL::isSemanticValid(FunctionDecl *FD, DeclaratorDecl *D,
+ SemanticInfo &ActiveSemantic) {
+ if (ActiveSemantic.Semantic == nullptr) {
+ ActiveSemantic.Semantic = D->getAttr<HLSLSemanticAttr>();
+ if (ActiveSemantic.Semantic &&
+ ActiveSemantic.Semantic->isSemanticIndexExplicit())
+ ActiveSemantic.Index = ActiveSemantic.Semantic->getSemanticIndex();
}
const Type *T = D->getType()->getUnqualifiedDesugaredType();
const RecordType *RT = dyn_cast<RecordType>(T);
if (!RT)
- return false;
+ return isSemanticOnScalarValid(FD, D, ActiveSemantic);
const RecordDecl *RD = RT->getOriginalDecl();
for (FieldDecl *Field : RD->fields()) {
- if (!isSemanticValid(FD, Field))
+ SemanticInfo Info = ActiveSemantic;
+ if (!isSemanticValid(FD, Field, Info)) {
+ Diag(Field->getLocation(), diag::note_hlsl_semantic_used_here) << Field;
return false;
+ }
+ if (ActiveSemantic.Semantic)
+ ActiveSemantic = Info;
}
+
return true;
}
@@ -852,8 +907,11 @@ void SemaHLSL::CheckEntryPoint(FunctionDecl *FD) {
}
for (ParmVarDecl *Param : FD->parameters()) {
- if (!isSemanticValid(FD, Param)) {
- Diag(FD->getLocation(), diag::err_hlsl_missing_semantic_annotation);
+ SemanticInfo ActiveSemantic;
+ ActiveSemantic.Semantic = nullptr;
+ ActiveSemantic.Index = std::nullopt;
+
+ if (!isSemanticValid(FD, Param, ActiveSemantic)) {
Diag(Param->getLocation(), diag::note_previous_decl) << Param;
FD->setInvalidDecl();
}
@@ -861,31 +919,31 @@ void SemaHLSL::CheckEntryPoint(FunctionDecl *FD) {
// FIXME: Verify return type semantic annotation.
}
-void SemaHLSL::CheckSemanticAnnotation(
- FunctionDecl *EntryPoint, const Decl *Param,
- const HLSLAnnotationAttr *AnnotationAttr) {
+void SemaHLSL::checkSemanticAnnotation(FunctionDecl *EntryPoint,
+ const Decl *Param,
+ const HLSLSemanticAttr *SemanticAttr) {
auto *ShaderAttr = EntryPoint->getAttr<HLSLShaderAttr>();
assert(ShaderAttr && "Entry point has no shader attribute");
llvm::Triple::EnvironmentType ST = ShaderAttr->getType();
- switch (AnnotationAttr->getKind()) {
+ switch (SemanticAttr->getKind()) {
case attr::HLSLSV_DispatchThreadID:
case attr::HLSLSV_GroupIndex:
case attr::HLSLSV_GroupThreadID:
case attr::HLSLSV_GroupID:
if (ST == llvm::Triple::Compute)
return;
- DiagnoseAttrStageMismatch(AnnotationAttr, ST, {llvm::Triple::Compute});
+ DiagnoseAttrStageMismatch(SemanticAttr, ST, {llvm::Triple::Compute});
break;
case attr::HLSLSV_Position:
// TODO(#143523): allow use on other shader types & output once the overall
// semantic logic is implemented.
if (ST == llvm::Triple::Pixel)
return;
- DiagnoseAttrStageMismatch(AnnotationAttr, ST, {llvm::Triple::Pixel});
+ DiagnoseAttrStageMismatch(SemanticAttr, ST, {llvm::Triple::Pixel});
break;
default:
- llvm_unreachable("Unknown HLSLAnnotationAttr");
+ llvm_unreachable("Unknown SemanticAttr");
}
}
diff --git a/clang/test/CodeGenHLSL/semantics/semantic-struct-1.hlsl b/clang/test/CodeGenHLSL/semantics/semantic-struct-1.hlsl
new file mode 100644
index 0000000000000..ddd0baed41f37
--- /dev/null
+++ b/clang/test/CodeGenHLSL/semantics/semantic-struct-1.hlsl
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-DXIL -DTARGET=dx
+// RUN: %clang_cc1 -triple spirv-linux-vulkan-library -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-SPIRV -DTARGET=spv
+
+
+struct Input {
+ uint Idx : SV_DispatchThreadID;
+
+};
+
+// Make sure SV_DispatchThreadID translated into dx.thread.id.
+
+// CHECK: define void @foo()
+// CHECK-DXIL: %[[#ID:]] = call i32 @llvm.[[TARGET]].thread.id(i32 0)
+// CHECK-SPIRV: %[[#ID:]] = call i32 @llvm.[[TARGET]].thread.id.i32(i32 0)
+// CHECK: %[[#TMP:]] = insertvalue %struct.Input poison, i32 %[[#ID]], 0
+// CHECK: %[[#VAR:]] = alloca %struct.Input, align 8
+// CHECK: store %struct.Input %[[#TMP]], ptr %[[#VAR]], align 4
+// CHECK-DXIL: call void @{{.*}}foo{{.*}}(ptr %[[#VAR]])
+// CHECK-SPIRV: call spir_func void @{{.*}}foo{{.*}}(ptr %[[#VAR]])
+[shader("compute")]
+[numthreads(8,8,1)]
+void foo(Input input) {}
+
diff --git a/clang/test/CodeGenHLSL/semantics/semantic-struct-2.hlsl b/clang/test/CodeGenHLSL/semantics/semantic-struct-2.hlsl
new file mode 100644
index 0000000000000..0d9c91e746454
--- /dev/null
+++ b/clang/test/CodeGenHLSL/semantics/semantic-struct-2.hlsl
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-DXIL -DTARGET=dx
+// RUN: %clang_cc1 -triple spirv-linux-vulkan-library -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-SPIRV -DTARGET=spv
+
+
+struct Input {
+ uint Idx : SV_DispatchThreadID;
+ uint Gid : SV_GroupID;
+};
+
+// Make sure SV_DispatchThreadID translated into dx.thread.id.
+
+// CHECK: define void @foo()
+// CHECK-DXIL: %[[#ID:]] = call i32 @llvm.[[TARGET]].thread.id(i32 0)
+// CHECK-SPIRV: %[[#ID:]] = call i32 @llvm.[[TARGET]].thread.id.i32(i32 0)
+// CHECK: %[[#TMP1:]] = insertvalue %struct.Input poison, i32 %[[#ID]], 0
+// CHECK-DXIL: %[[#GID:]] = call i32 @llvm...
[truncated]
|
The previous solution had a major drawback: if a stuct was used by multiple entrypoints, we had conflicting attribute. This commit moves the attribute to the function declaration: - each field with an active semantic will have a related attribute attached to the corresponding entrypoint. This means the semantic list is per-entrypoint.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should have some AST test to make sure the attribute is correctly added to the entry point. I tried looking at an example, and the connection between the attribute on the function parameter does not seem obvious. That might need to be better designed.
EDIT: I was looking at the ast-dump, which was showing an attribute without any parameters. Looking closer, I saw that you add the decl to the attribute. That creates an obvious link. We just need to make sure the ast-dump reflects that.
if (!A) | ||
return false; | ||
|
||
checkSemanticAnnotation(FD, D, A); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does not have to be fixed in this PR, but should this function return false if the check fails?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could yes, but still emitting a diagnostic will make the compilation fail, so here we add an attribute to something we are going to discard anyway.
4bacbbe
to
bf3a90c
Compare
Modified the code so ast-dump shows this correctly. We already have some AST checks but expanded them to check the newly generated attributes on the entrypoint |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This LGTM, but there are others will have to approve.
// The generator puts the arguments for each attribute in the child class, | ||
// even if those are set in the inherited attribute class (in the TD | ||
// file). This means I cannot access those from the parent class, and have | ||
// to do this weirdness. Maybe the generator should be changed to | ||
// arguments are put in the class they are declared in inside the TD file? | ||
if (HLSLSemantic) { | ||
OS << " if (SemanticExplicitIndex)\n"; | ||
OS << " setSemanticIndex(SemanticIndex);\n"; | ||
OS << " setTargetDecl(Target);\n"; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Someone with more knowledge will have to comment on the best way to do this.
This PR is an incremental improvement regarding semantics I/O in HLSL. This PR allows
system semantics to be used on struct type in addition to parameters (state today).
This PR doesn't consider implicit indexing increment that happens when placing a semantic on an aggregate/array as implemented system semantics don't allow such use yet.
The next step will be to enable user semantics, which will bring the need to properly determine semantic indices depending on context.
This PR diverge from the initial wg-hlsl proposal as all diagnostics are done in Sema (initial proposal suggested running diags in codegen).
This is not yet a solid semantic implementation, but increases the test coverage and improves the status from where we are now.