llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang-codegen

Author: Nathan Gauër (Keenuts)

<details>
<summary>Changes</summary>

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 #<!-- -->152537

---
Full diff: https://github.com/llvm/llvm-project/pull/153224.diff


7 Files Affected:

- (modified) clang/lib/CodeGen/CGHLSLRuntime.cpp (+60-3) 
- (modified) clang/lib/CodeGen/CGHLSLRuntime.h (+4) 
- (added) clang/test/CodeGenHLSL/semantics/semantic-struct-1.hlsl (+23) 
- (added) clang/test/CodeGenHLSL/semantics/semantic-struct-2.hlsl (+25) 
- (added) clang/test/CodeGenHLSL/semantics/semantic-struct-nested-inherit.hlsl 
(+30) 
- (added) clang/test/CodeGenHLSL/semantics/semantic-struct-nested-shadow.hlsl 
(+30) 
- (added) clang/test/CodeGenHLSL/semantics/semantic-struct-nested.hlsl (+30) 


``````````diff
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp 
b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index 60ad3eb75afea..f17e9b1d908e9 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -619,11 +619,51 @@ CGHLSLRuntime::handleScalarSemanticLoad(IRBuilder<> &B, 
llvm::Type *Type,
   return emitSystemSemanticLoad(B, Type, Decl, ActiveSemantic);
 }
 
+llvm::Value *
+CGHLSLRuntime::handleStructSemanticLoad(IRBuilder<> &B, llvm::Type *Type,
+                                        const clang::DeclaratorDecl *Decl,
+                                        SemanticInfo &ActiveSemantic) {
+  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());
+
+  if (!ActiveSemantic.Semantic) {
+    ActiveSemantic.Semantic = Decl->getAttr<HLSLSemanticAttr>();
+    ActiveSemantic.Index = ActiveSemantic.Semantic
+                               ? ActiveSemantic.Semantic->getSemanticIndex()
+                               : 0;
+  }
+
+  llvm::Value *Aggregate = llvm::PoisonValue::get(Type);
+  auto FieldDecl = RD->field_begin();
+  for (unsigned I = 0; I < ST->getNumElements(); ++I) {
+    SemanticInfo Info = ActiveSemantic;
+    llvm::Value *ChildValue =
+        handleSemanticLoad(B, ST->getElementType(I), *FieldDecl, Info);
+    if (!ChildValue) {
+      CGM.getDiags().Report(Decl->getInnerLocStart(),
+                            diag::note_hlsl_semantic_used_here)
+          << Decl;
+      return nullptr;
+    }
+    if (ActiveSemantic.Semantic)
+      ActiveSemantic = Info;
+
+    Aggregate = B.CreateInsertValue(Aggregate, ChildValue, I);
+    ++FieldDecl;
+  }
+
+  return Aggregate;
+}
+
 llvm::Value *
 CGHLSLRuntime::handleSemanticLoad(IRBuilder<> &B, llvm::Type *Type,
                                   const clang::DeclaratorDecl *Decl,
                                   SemanticInfo &ActiveSemantic) {
-  assert(!Type->isStructTy());
+  if (Type->isStructTy())
+    return handleStructSemanticLoad(B, Type, Decl, ActiveSemantic);
   return handleScalarSemanticLoad(B, Type, Decl, ActiveSemantic);
 }
 
@@ -671,8 +711,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 (HLSLParamModifierAttr *MA = PD->getAttr<HLSLParamModifierAttr>()) {
+      llvm_unreachable("Not handled yet");
+    } else {
+      llvm::Type *ParamType =
+          Param.hasByValAttr() ? Param.getParamByValType() : Param.getType();
+      SemanticInfo ActiveSemantic = {nullptr, 0};
+      SemanticValue = handleSemanticLoad(B, ParamType, PD, ActiveSemantic);
+      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 25d4c65426b0d..5d28994a5277b 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -156,6 +156,10 @@ class CGHLSLRuntime {
                                         const clang::DeclaratorDecl *Decl,
                                         SemanticInfo &ActiveSemantic);
 
+  llvm::Value *handleStructSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type,
+                                        const clang::DeclaratorDecl *Decl,
+                                        SemanticInfo &ActiveSemantic);
+
   llvm::Value *handleSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type,
                                   const clang::DeclaratorDecl *Decl,
                                   SemanticInfo &ActiveSemantic);
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.[[TARGET]].group.id(i32 0)
+// CHECK-SPIRV:%[[#GID:]] = call i32 @llvm.[[TARGET]].group.id.i32(i32 0)
+// CHECK:     %[[#TMP2:]] = insertvalue %struct.Input %[[#TMP1]], i32 
%[[#GID]], 1
+// CHECK:      %[[#VAR:]] = alloca %struct.Input, align 8
+// CHECK:                   store %struct.Input %[[#TMP2]], 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-nested-inherit.hlsl 
b/clang/test/CodeGenHLSL/semantics/semantic-struct-nested-inherit.hlsl
new file mode 100644
index 0000000000000..f4c4d86933ca1
--- /dev/null
+++ b/clang/test/CodeGenHLSL/semantics/semantic-struct-nested-inherit.hlsl
@@ -0,0 +1,30 @@
+// 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 Inner {
+  uint Gid;
+};
+
+struct Input {
+  uint Idx : SV_DispatchThreadID;
+  Inner inner : SV_GroupIndex;
+};
+
+// 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.dx.flattened.thread.id.in.group()
+// CHECK-SPIRV:%[[#GID:]] = call i32 @llvm.spv.flattened.thread.id.in.group()
+// CHECK:     %[[#TMP2:]] = insertvalue %struct.Inner poison, i32 %[[#GID]], 0
+// CHECK:     %[[#TMP3:]] = insertvalue %struct.Input %[[#TMP1]], 
%struct.Inner %[[#TMP2]], 1
+// CHECK:      %[[#VAR:]] = alloca %struct.Input, align 8
+// CHECK:                   store %struct.Input %[[#TMP3]], 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-nested-shadow.hlsl 
b/clang/test/CodeGenHLSL/semantics/semantic-struct-nested-shadow.hlsl
new file mode 100644
index 0000000000000..e1344dd87a6ed
--- /dev/null
+++ b/clang/test/CodeGenHLSL/semantics/semantic-struct-nested-shadow.hlsl
@@ -0,0 +1,30 @@
+// 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 Inner {
+  uint Gid : SV_GroupID;
+};
+
+struct Input {
+  uint Idx : SV_DispatchThreadID;
+  Inner inner : SV_GroupIndex;
+};
+
+// 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.dx.flattened.thread.id.in.group()
+// CHECK-SPIRV:%[[#GID:]] = call i32 @llvm.spv.flattened.thread.id.in.group()
+// CHECK:     %[[#TMP2:]] = insertvalue %struct.Inner poison, i32 %[[#GID]], 0
+// CHECK:     %[[#TMP3:]] = insertvalue %struct.Input %[[#TMP1]], 
%struct.Inner %[[#TMP2]], 1
+// CHECK:      %[[#VAR:]] = alloca %struct.Input, align 8
+// CHECK:                   store %struct.Input %[[#TMP3]], 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-nested.hlsl 
b/clang/test/CodeGenHLSL/semantics/semantic-struct-nested.hlsl
new file mode 100644
index 0000000000000..cd6f9460bc617
--- /dev/null
+++ b/clang/test/CodeGenHLSL/semantics/semantic-struct-nested.hlsl
@@ -0,0 +1,30 @@
+// 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 Inner {
+  uint Gid : SV_GroupID;
+};
+
+struct Input {
+  uint Idx : SV_DispatchThreadID;
+  Inner inner;
+};
+
+// 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.[[TARGET]].group.id(i32 0)
+// CHECK-SPIRV:%[[#GID:]] = call i32 @llvm.[[TARGET]].group.id.i32(i32 0)
+// CHECK:     %[[#TMP2:]] = insertvalue %struct.Inner poison, i32 %[[#GID]], 0
+// CHECK:     %[[#TMP3:]] = insertvalue %struct.Input %[[#TMP1]], 
%struct.Inner %[[#TMP2]], 1
+// CHECK:      %[[#VAR:]] = alloca %struct.Input, align 8
+// CHECK:                   store %struct.Input %[[#TMP3]], 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) {}

``````````

</details>


https://github.com/llvm/llvm-project/pull/153224
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to