https://github.com/Keenuts updated 
https://github.com/llvm/llvm-project/pull/168095

From f0313c98fed2ae77713604420cee7938c82b9f92 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= <[email protected]>
Date: Fri, 14 Nov 2025 11:13:42 +0100
Subject: [PATCH 1/5] [HLSL] Add initial support for output semantics

This commits adds the first part of the output semantics. It only
considers return values (and sret), but does not handle `inout` or `out`
parameters yet.
Those missing bits will reuse the same code, but will require additional
testing & some fixups, so planning on adding them separately.
---
 clang/lib/CodeGen/CGHLSLRuntime.cpp           | 171 +++++++++++++++++-
 clang/lib/CodeGen/CGHLSLRuntime.h             |  34 ++++
 clang/lib/Sema/SemaHLSL.cpp                   |  14 +-
 .../CodeGenHLSL/semantics/SV_Position.ps.hlsl |   3 +-
 .../CodeGenHLSL/semantics/missing-vs.hlsl     |   6 +
 .../semantics/semantic-struct-2-output.hlsl   |  35 ++++
 .../semantics/semantic.array.output.hlsl      |  31 ++++
 .../semantics/semantic.struct.output.hlsl     |  27 +++
 clang/test/CodeGenHLSL/sret_output.hlsl       |  32 +++-
 .../attr-availability-compute.hlsl            |   4 +-
 .../Availability/attr-availability-mesh.hlsl  |   4 +-
 .../Availability/attr-availability-pixel.hlsl |   2 +-
 .../avail-diag-default-compute.hlsl           |   3 +-
 .../Availability/avail-diag-default-lib.hlsl  |   5 +-
 .../avail-diag-relaxed-compute.hlsl           |   3 +-
 .../Availability/avail-diag-relaxed-lib.hlsl  |   5 +-
 .../avail-diag-strict-compute.hlsl            |   3 +-
 .../Availability/avail-diag-strict-lib.hlsl   |   3 +-
 .../test/SemaHLSL/Semantics/position.ps.hlsl  |  10 +-
 .../Semantics/position.ps.struct.hlsl         |   9 +-
 .../Semantics/position.ps.struct.reuse.hlsl   |  11 +-
 .../test/SemaHLSL/Semantics/position.vs.hlsl  |   2 +-
 .../SemaHLSL/WaveBuiltinAvailability.hlsl     |   4 +-
 clang/test/SemaHLSL/num_threads.hlsl          |   2 +-
 clang/test/SemaHLSL/shader_type_attr.hlsl     |  21 +--
 llvm/include/llvm/IR/IntrinsicsDirectX.td     |   6 +
 26 files changed, 383 insertions(+), 67 deletions(-)
 create mode 100644 clang/test/CodeGenHLSL/semantics/missing-vs.hlsl
 create mode 100644 
clang/test/CodeGenHLSL/semantics/semantic-struct-2-output.hlsl
 create mode 100644 clang/test/CodeGenHLSL/semantics/semantic.array.output.hlsl
 create mode 100644 clang/test/CodeGenHLSL/semantics/semantic.struct.output.hlsl

diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp 
b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index ec02096787c7a..741e60e9865cd 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -589,6 +589,36 @@ CGHLSLRuntime::emitSPIRVUserSemanticLoad(llvm::IRBuilder<> 
&B, llvm::Type *Type,
                                  VariableName.str());
 }
 
+static void createSPIRVLocationStore(IRBuilder<> &B, llvm::Module &M,
+                                     llvm::Value *Source, unsigned Location,
+                                     StringRef Name) {
+  auto *GV = new llvm::GlobalVariable(
+      M, Source->getType(), /* isConstant= */ false,
+      llvm::GlobalValue::ExternalLinkage,
+      /* Initializer= */ nullptr, /* Name= */ Name, /* insertBefore= */ 
nullptr,
+      llvm::GlobalVariable::GeneralDynamicTLSModel,
+      /* AddressSpace */ 8, /* isExternallyInitialized= */ false);
+  GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
+  addLocationDecoration(GV, Location);
+  B.CreateStore(Source, GV);
+}
+
+void CGHLSLRuntime::emitSPIRVUserSemanticStore(
+    llvm::IRBuilder<> &B, llvm::Value *Source,
+    HLSLAppliedSemanticAttr *Semantic, std::optional<unsigned> Index) {
+  Twine BaseName = Twine(Semantic->getAttrName()->getName());
+  Twine VariableName = BaseName.concat(Twine(Index.value_or(0)));
+  unsigned Location = SPIRVLastAssignedOutputSemanticLocation;
+
+  // DXC completely ignores the semantic/index pair. Location are assigned from
+  // the first semantic to the last.
+  llvm::ArrayType *AT = dyn_cast<llvm::ArrayType>(Source->getType());
+  unsigned ElementCount = AT ? AT->getNumElements() : 1;
+  SPIRVLastAssignedOutputSemanticLocation += ElementCount;
+  createSPIRVLocationStore(B, CGM.getModule(), Source, Location,
+                           VariableName.str());
+}
+
 llvm::Value *
 CGHLSLRuntime::emitDXILUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type,
                                         HLSLAppliedSemanticAttr *Semantic,
@@ -609,6 +639,23 @@ CGHLSLRuntime::emitDXILUserSemanticLoad(llvm::IRBuilder<> 
&B, llvm::Type *Type,
   return Value;
 }
 
+void CGHLSLRuntime::emitDXILUserSemanticStore(llvm::IRBuilder<> &B,
+                                              llvm::Value *Source,
+                                              HLSLAppliedSemanticAttr 
*Semantic,
+                                              std::optional<unsigned> Index) {
+  // DXIL packing rules etc shall be handled here.
+  // FIXME: generate proper sigpoint, index, col, row values.
+  SmallVector<Value *> Args{B.getInt32(4),
+                            B.getInt32(0),
+                            B.getInt32(0),
+                            B.getInt8(0),
+                            llvm::PoisonValue::get(B.getInt32Ty()),
+                            Source};
+
+  llvm::Intrinsic::ID IntrinsicID = llvm::Intrinsic::dx_store_output;
+  B.CreateIntrinsic(/*ReturnType=*/CGM.VoidTy, IntrinsicID, Args, nullptr);
+}
+
 llvm::Value *CGHLSLRuntime::emitUserSemanticLoad(
     IRBuilder<> &B, llvm::Type *Type, const clang::DeclaratorDecl *Decl,
     HLSLAppliedSemanticAttr *Semantic, std::optional<unsigned> Index) {
@@ -621,6 +668,19 @@ llvm::Value *CGHLSLRuntime::emitUserSemanticLoad(
   llvm_unreachable("Unsupported target for user-semantic load.");
 }
 
+void CGHLSLRuntime::emitUserSemanticStore(IRBuilder<> &B, llvm::Value *Source,
+                                          const clang::DeclaratorDecl *Decl,
+                                          HLSLAppliedSemanticAttr *Semantic,
+                                          std::optional<unsigned> Index) {
+  if (CGM.getTarget().getTriple().isSPIRV())
+    return emitSPIRVUserSemanticStore(B, Source, Semantic, Index);
+
+  if (CGM.getTarget().getTriple().isDXIL())
+    return emitDXILUserSemanticStore(B, Source, Semantic, Index);
+
+  llvm_unreachable("Unsupported target for user-semantic load.");
+}
+
 llvm::Value *CGHLSLRuntime::emitSystemSemanticLoad(
     IRBuilder<> &B, llvm::Type *Type, const clang::DeclaratorDecl *Decl,
     HLSLAppliedSemanticAttr *Semantic, std::optional<unsigned> Index) {
@@ -669,6 +729,34 @@ llvm::Value *CGHLSLRuntime::emitSystemSemanticLoad(
   llvm_unreachable("non-handled system semantic. FIXME.");
 }
 
+static void createSPIRVBuiltinStore(IRBuilder<> &B, llvm::Module &M,
+                                    llvm::Value *Source, const Twine &Name,
+                                    unsigned BuiltInID) {
+  auto *GV = new llvm::GlobalVariable(
+      M, Source->getType(), /* isConstant= */ false,
+      llvm::GlobalValue::ExternalLinkage,
+      /* Initializer= */ nullptr, Name, /* insertBefore= */ nullptr,
+      llvm::GlobalVariable::GeneralDynamicTLSModel,
+      /* AddressSpace */ 8, /* isExternallyInitialized= */ false);
+  addSPIRVBuiltinDecoration(GV, BuiltInID);
+  GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
+  B.CreateStore(Source, GV);
+}
+
+void CGHLSLRuntime::emitSystemSemanticStore(IRBuilder<> &B, llvm::Value 
*Source,
+                                            const clang::DeclaratorDecl *Decl,
+                                            HLSLAppliedSemanticAttr *Semantic,
+                                            std::optional<unsigned> Index) {
+
+  std::string SemanticName = Semantic->getAttrName()->getName().upper();
+  if (SemanticName == "SV_POSITION")
+    createSPIRVBuiltinStore(B, CGM.getModule(), Source,
+                            Semantic->getAttrName()->getName(),
+                            /* BuiltIn::Position */ 0);
+  else
+    llvm_unreachable("non-handled system semantic. FIXME.");
+}
+
 llvm::Value *CGHLSLRuntime::handleScalarSemanticLoad(
     IRBuilder<> &B, const FunctionDecl *FD, llvm::Type *Type,
     const clang::DeclaratorDecl *Decl, HLSLAppliedSemanticAttr *Semantic) {
@@ -679,6 +767,16 @@ llvm::Value *CGHLSLRuntime::handleScalarSemanticLoad(
   return emitUserSemanticLoad(B, Type, Decl, Semantic, Index);
 }
 
+void CGHLSLRuntime::handleScalarSemanticStore(
+    IRBuilder<> &B, const FunctionDecl *FD, llvm::Value *Source,
+    const clang::DeclaratorDecl *Decl, HLSLAppliedSemanticAttr *Semantic) {
+  std::optional<unsigned> Index = Semantic->getSemanticIndex();
+  if (Semantic->getAttrName()->getName().starts_with_insensitive("SV_"))
+    emitSystemSemanticStore(B, Source, Decl, Semantic, Index);
+  else
+    emitUserSemanticStore(B, Source, Decl, Semantic, Index);
+}
+
 std::pair<llvm::Value *, specific_attr_iterator<HLSLAppliedSemanticAttr>>
 CGHLSLRuntime::handleStructSemanticLoad(
     IRBuilder<> &B, const FunctionDecl *FD, llvm::Type *Type,
@@ -705,6 +803,35 @@ CGHLSLRuntime::handleStructSemanticLoad(
   return std::make_pair(Aggregate, AttrBegin);
 }
 
+specific_attr_iterator<HLSLAppliedSemanticAttr>
+CGHLSLRuntime::handleStructSemanticStore(
+    IRBuilder<> &B, const FunctionDecl *FD, llvm::Value *Source,
+    const clang::DeclaratorDecl *Decl,
+    specific_attr_iterator<HLSLAppliedSemanticAttr> AttrBegin,
+    specific_attr_iterator<HLSLAppliedSemanticAttr> AttrEnd) {
+
+  const llvm::StructType *ST = cast<StructType>(Source->getType());
+
+  const clang::RecordDecl *RD = nullptr;
+  if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(Decl))
+    RD = FD->getDeclaredReturnType()->getAsRecordDecl();
+  else
+    RD = Decl->getType()->getAsRecordDecl();
+  assert(RD);
+
+  assert(std::distance(RD->field_begin(), RD->field_end()) ==
+         ST->getNumElements());
+
+  auto FieldDecl = RD->field_begin();
+  for (unsigned I = 0; I < ST->getNumElements(); ++I) {
+    llvm::Value *Extract = B.CreateExtractValue(Source, I);
+    AttrBegin =
+        handleSemanticStore(B, FD, Extract, *FieldDecl, AttrBegin, AttrEnd);
+  }
+
+  return AttrBegin;
+}
+
 std::pair<llvm::Value *, specific_attr_iterator<HLSLAppliedSemanticAttr>>
 CGHLSLRuntime::handleSemanticLoad(
     IRBuilder<> &B, const FunctionDecl *FD, llvm::Type *Type,
@@ -721,6 +848,22 @@ CGHLSLRuntime::handleSemanticLoad(
                         AttrBegin);
 }
 
+specific_attr_iterator<HLSLAppliedSemanticAttr>
+CGHLSLRuntime::handleSemanticStore(
+    IRBuilder<> &B, const FunctionDecl *FD, llvm::Value *Source,
+    const clang::DeclaratorDecl *Decl,
+    specific_attr_iterator<HLSLAppliedSemanticAttr> AttrBegin,
+    specific_attr_iterator<HLSLAppliedSemanticAttr> AttrEnd) {
+  assert(AttrBegin != AttrEnd);
+  if (Source->getType()->isStructTy())
+    return handleStructSemanticStore(B, FD, Source, Decl, AttrBegin, AttrEnd);
+
+  HLSLAppliedSemanticAttr *Attr = *AttrBegin;
+  ++AttrBegin;
+  handleScalarSemanticStore(B, FD, Source, Decl, Attr);
+  return AttrBegin;
+}
+
 void CGHLSLRuntime::emitEntryFunction(const FunctionDecl *FD,
                                       llvm::Function *Fn) {
   llvm::Module &M = CGM.getModule();
@@ -752,20 +895,22 @@ void CGHLSLRuntime::emitEntryFunction(const FunctionDecl 
*FD,
     OB.emplace_back("convergencectrl", bundleArgs);
   }
 
-  // FIXME: support struct parameters where semantics are on members.
-  // See: https://github.com/llvm/llvm-project/issues/57874
+  std::unordered_map<const DeclaratorDecl *, llvm::Value *> OutputSemantic;
+
   unsigned SRetOffset = 0;
   for (const auto &Param : Fn->args()) {
     if (Param.hasStructRetAttr()) {
-      // FIXME: support output.
-      // See: https://github.com/llvm/llvm-project/issues/57874
       SRetOffset = 1;
-      Args.emplace_back(PoisonValue::get(Param.getType()));
+      llvm::Type *VarType = Param.getParamStructRetType();
+      llvm::Value *Var = B.CreateAlloca(VarType);
+      OutputSemantic.emplace(FD, Var);
+      Args.push_back(Var);
       continue;
     }
 
     const ParmVarDecl *PD = FD->getParamDecl(Param.getArgNo() - SRetOffset);
     llvm::Value *SemanticValue = nullptr;
+    // FIXME: support inout/out parameters for semantics.
     if ([[maybe_unused]] HLSLParamModifierAttr *MA =
             PD->getAttr<HLSLParamModifierAttr>()) {
       llvm_unreachable("Not handled yet");
@@ -792,8 +937,20 @@ void CGHLSLRuntime::emitEntryFunction(const FunctionDecl 
*FD,
 
   CallInst *CI = B.CreateCall(FunctionCallee(Fn), Args, OB);
   CI->setCallingConv(Fn->getCallingConv());
-  // FIXME: Handle codegen for return type semantics.
-  // See: https://github.com/llvm/llvm-project/issues/57875
+
+  if (Fn->getReturnType() != CGM.VoidTy)
+    OutputSemantic.emplace(FD, CI);
+
+  for (auto &[Decl, Source] : OutputSemantic) {
+    AllocaInst *AI = dyn_cast<AllocaInst>(Source);
+    llvm::Value *SourceValue =
+        AI ? B.CreateLoad(AI->getAllocatedType(), Source) : Source;
+
+    auto AttrBegin = Decl->specific_attr_begin<HLSLAppliedSemanticAttr>();
+    auto AttrEnd = Decl->specific_attr_end<HLSLAppliedSemanticAttr>();
+    handleSemanticStore(B, FD, SourceValue, Decl, AttrBegin, AttrEnd);
+  }
+
   B.CreateRetVoid();
 
   // Add and identify root signature to function, if applicable
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h 
b/clang/lib/CodeGen/CGHLSLRuntime.h
index 48935584f28a2..d9f7b3db1bb79 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -176,12 +176,22 @@ class CGHLSLRuntime {
                                       HLSLAppliedSemanticAttr *Semantic,
                                       std::optional<unsigned> Index);
 
+  void emitSystemSemanticStore(llvm::IRBuilder<> &B, llvm::Value *Source,
+                               const clang::DeclaratorDecl *Decl,
+                               HLSLAppliedSemanticAttr *Semantic,
+                               std::optional<unsigned> Index);
+
   llvm::Value *handleScalarSemanticLoad(llvm::IRBuilder<> &B,
                                         const FunctionDecl *FD,
                                         llvm::Type *Type,
                                         const clang::DeclaratorDecl *Decl,
                                         HLSLAppliedSemanticAttr *Semantic);
 
+  void handleScalarSemanticStore(llvm::IRBuilder<> &B, const FunctionDecl *FD,
+                                 llvm::Value *Source,
+                                 const clang::DeclaratorDecl *Decl,
+                                 HLSLAppliedSemanticAttr *Semantic);
+
   std::pair<llvm::Value *, specific_attr_iterator<HLSLAppliedSemanticAttr>>
   handleStructSemanticLoad(
       llvm::IRBuilder<> &B, const FunctionDecl *FD, llvm::Type *Type,
@@ -189,12 +199,24 @@ class CGHLSLRuntime {
       specific_attr_iterator<HLSLAppliedSemanticAttr> begin,
       specific_attr_iterator<HLSLAppliedSemanticAttr> end);
 
+  specific_attr_iterator<HLSLAppliedSemanticAttr> handleStructSemanticStore(
+      llvm::IRBuilder<> &B, const FunctionDecl *FD, llvm::Value *Source,
+      const clang::DeclaratorDecl *Decl,
+      specific_attr_iterator<HLSLAppliedSemanticAttr> AttrBegin,
+      specific_attr_iterator<HLSLAppliedSemanticAttr> AttrEnd);
+
   std::pair<llvm::Value *, specific_attr_iterator<HLSLAppliedSemanticAttr>>
   handleSemanticLoad(llvm::IRBuilder<> &B, const FunctionDecl *FD,
                      llvm::Type *Type, const clang::DeclaratorDecl *Decl,
                      specific_attr_iterator<HLSLAppliedSemanticAttr> begin,
                      specific_attr_iterator<HLSLAppliedSemanticAttr> end);
 
+  specific_attr_iterator<HLSLAppliedSemanticAttr>
+  handleSemanticStore(llvm::IRBuilder<> &B, const FunctionDecl *FD,
+                      llvm::Value *Source, const clang::DeclaratorDecl *Decl,
+                      specific_attr_iterator<HLSLAppliedSemanticAttr> 
AttrBegin,
+                      specific_attr_iterator<HLSLAppliedSemanticAttr> AttrEnd);
+
 public:
   CGHLSLRuntime(CodeGenModule &CGM) : CGM(CGM) {}
   virtual ~CGHLSLRuntime() {}
@@ -249,10 +271,22 @@ class CGHLSLRuntime {
                                     HLSLAppliedSemanticAttr *Semantic,
                                     std::optional<unsigned> Index);
 
+  void emitSPIRVUserSemanticStore(llvm::IRBuilder<> &B, llvm::Value *Source,
+                                  HLSLAppliedSemanticAttr *Semantic,
+                                  std::optional<unsigned> Index);
+  void emitDXILUserSemanticStore(llvm::IRBuilder<> &B, llvm::Value *Source,
+                                 HLSLAppliedSemanticAttr *Semantic,
+                                 std::optional<unsigned> Index);
+  void emitUserSemanticStore(llvm::IRBuilder<> &B, llvm::Value *Source,
+                             const clang::DeclaratorDecl *Decl,
+                             HLSLAppliedSemanticAttr *Semantic,
+                             std::optional<unsigned> Index);
+
   llvm::Triple::ArchType getArch();
 
   llvm::DenseMap<const clang::RecordType *, llvm::TargetExtType *> LayoutTypes;
   unsigned SPIRVLastAssignedInputSemanticLocation = 0;
+  unsigned SPIRVLastAssignedOutputSemanticLocation = 0;
 };
 
 } // namespace CodeGen
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 2b9b3abbd5360..dd8122c11e696 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -825,7 +825,9 @@ bool SemaHLSL::determineActiveSemantic(
       ActiveSemantic.Index = ActiveSemantic.Semantic->getSemanticIndex();
   }
 
-  const Type *T = D->getType()->getUnqualifiedDesugaredType();
+  const Type *T = D == FD ? &*FD->getReturnType() : &*D->getType();
+  T = T->getUnqualifiedDesugaredType();
+
   const RecordType *RT = dyn_cast<RecordType>(T);
   if (!RT)
     return determineActiveSemanticOnScalar(FD, OutputDecl, D, ActiveSemantic,
@@ -915,13 +917,21 @@ void SemaHLSL::CheckEntryPoint(FunctionDecl *FD) {
     if (ActiveSemantic.Semantic)
       ActiveSemantic.Index = ActiveSemantic.Semantic->getSemanticIndex();
 
+    // FIXME: Verify output semantics in parameters.
     if (!determineActiveSemantic(FD, Param, Param, ActiveSemantic,
                                  ActiveInputSemantics)) {
       Diag(Param->getLocation(), diag::note_previous_decl) << Param;
       FD->setInvalidDecl();
     }
   }
-  // FIXME: Verify return type semantic annotation.
+
+  SemanticInfo ActiveSemantic;
+  llvm::StringSet<> ActiveOutputSemantics;
+  ActiveSemantic.Semantic = FD->getAttr<HLSLParsedSemanticAttr>();
+  if (ActiveSemantic.Semantic)
+    ActiveSemantic.Index = ActiveSemantic.Semantic->getSemanticIndex();
+  if (!FD->getReturnType()->isVoidType())
+    determineActiveSemantic(FD, FD, FD, ActiveSemantic, ActiveOutputSemantics);
 }
 
 void SemaHLSL::checkSemanticAnnotation(
diff --git a/clang/test/CodeGenHLSL/semantics/SV_Position.ps.hlsl 
b/clang/test/CodeGenHLSL/semantics/SV_Position.ps.hlsl
index 1bba87ea07141..be30e79438831 100644
--- a/clang/test/CodeGenHLSL/semantics/SV_Position.ps.hlsl
+++ b/clang/test/CodeGenHLSL/semantics/SV_Position.ps.hlsl
@@ -3,8 +3,9 @@
 // CHECK: @SV_Position = external hidden thread_local addrspace(7) 
externally_initialized constant <4 x float>, !spirv.Decorations !0
 
 // CHECK: define void @main() {{.*}} {
-float4 main(float4 p : SV_Position) {
+float4 main(float4 p : SV_Position) : A {
   // CHECK: %[[#P:]] = load <4 x float>, ptr addrspace(7) @SV_Position, align 
16
   // CHECK: %[[#R:]] = call spir_func <4 x float> @_Z4mainDv4_f(<4 x float> 
%[[#P]])
+  // CHECK:            store <4 x float> %[[#R]], ptr addrspace(8) @A0, align 
16
   return p;
 }
diff --git a/clang/test/CodeGenHLSL/semantics/missing-vs.hlsl 
b/clang/test/CodeGenHLSL/semantics/missing-vs.hlsl
new file mode 100644
index 0000000000000..41be9c0ab730c
--- /dev/null
+++ b/clang/test/CodeGenHLSL/semantics/missing-vs.hlsl
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-vertex -x hlsl -emit-llvm 
-disable-llvm-passes -o - -hlsl-entry main %s -verify 
-verify-ignore-unexpected=note
+// RUN: %clang_cc1 -triple spirv-unknown-vulkan-vertex -x hlsl -emit-llvm 
-disable-llvm-passes -o - -hlsl-entry main %s -verify 
-verify-ignore-unexpected=note
+
+float main(unsigned GI : A) {
+  // expected-error@-1 {{semantic annotations must be present for all 
parameters of an entry function or patch constant function}}
+}
diff --git a/clang/test/CodeGenHLSL/semantics/semantic-struct-2-output.hlsl 
b/clang/test/CodeGenHLSL/semantics/semantic-struct-2-output.hlsl
new file mode 100644
index 0000000000000..2f8dc97ef762e
--- /dev/null
+++ b/clang/test/CodeGenHLSL/semantics/semantic-struct-2-output.hlsl
@@ -0,0 +1,35 @@
+// 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-DX,CHECK
+// 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-VK,CHECK
+
+
+struct Input {
+  float Idx : SV_Position0;
+  float Gid : SV_Position1;
+};
+
+struct Output {
+  float a : A;
+  float b : B;
+};
+
+// Make sure SV_DispatchThreadID translated into dx.thread.id.
+
+// CHECK-DX: define hidden void @_Z3foo5Input(ptr dead_on_unwind noalias 
writable sret(%struct.Output) align 1 %agg.result, ptr noundef 
byval(%struct.Input) align 1 %input)
+// CHECK-VK: define hidden spir_func void @_Z3foo5Input(ptr dead_on_unwind 
noalias writable sret(%struct.Output) align 1 %agg.result, ptr noundef 
byval(%struct.Input) align 1 %input)
+
+// CHECK: %Idx = getelementptr inbounds nuw %struct.Input, ptr %input, i32 0, 
i32 0
+// CHECK: %[[#tmp:]] = load float, ptr %Idx, align 1
+// CHECK: %a = getelementptr inbounds nuw %struct.Output, ptr %agg.result, i32 
0, i32 0
+// CHECK: store float %[[#tmp]], ptr %a, align 1
+// CHECK: %Gid = getelementptr inbounds nuw %struct.Input, ptr %input, i32 0, 
i32 1
+// CHECK: %[[#tmp:]] = load float, ptr %Gid, align 1
+// CHECK: %b = getelementptr inbounds nuw %struct.Output, ptr %agg.result, i32 
0, i32 1
+// CHECK: store float %[[#tmp]], ptr %b, align 1
+
+Output foo(Input input) {
+  Output o;
+  o.a = input.Idx;
+  o.b = input.Gid;
+  return o;
+}
+
diff --git a/clang/test/CodeGenHLSL/semantics/semantic.array.output.hlsl 
b/clang/test/CodeGenHLSL/semantics/semantic.array.output.hlsl
new file mode 100644
index 0000000000000..2ff0e3835672c
--- /dev/null
+++ b/clang/test/CodeGenHLSL/semantics/semantic.array.output.hlsl
@@ -0,0 +1,31 @@
+// 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
+// RUN: %clang_cc1 -triple dxil-px-shadermodel6.3-library -x hlsl -emit-llvm 
-finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s 
--check-prefixes=CHECK,CHECK-DXIL -DTARGET=dx
+
+struct S0 {
+  float4 position[2];
+  float4 color;
+};
+
+
+[shader("pixel")]
+S0 main1(float4 input : A) : B {
+// CHECK:         %[[#ARG:]] = alloca %struct.S0, align 16
+// CHECK-SPIRV: %[[#INPUT:]] = load <4 x float>, ptr addrspace(7) @A0, align 16
+// CHECK-DXIL:           %A0 = call <4 x float> @llvm.dx.load.input.v4f32(i32 
4, i32 0, i32 0, i8 0, i32 poison)
+// CHECK-DXIL:                 call void @{{.*}}main1{{.*}}(ptr %[[#ARG]], <4 
x float> %A0)
+// CHECK-SPIRV:                call spir_func void @{{.*}}main1{{.*}}(ptr 
%[[#ARG]], <4 x float> %[[#INPUT]])
+
+  // CHECK:        %[[#ST:]] = load %struct.S0, ptr %[[#ARG]], align 16
+  // CHECK:       %[[#TMP:]] = extractvalue %struct.S0 %[[#ST]], 0
+  // CHECK-SPIRV:              store [2 x <4 x float>] %[[#TMP]], ptr 
addrspace(8) @B0, align 16
+  // CHECK-DXIL:               call void @llvm.dx.store.output.a2v4f32(i32 4, 
i32 0, i32 0, i8 0, i32 poison, [2 x <4 x float>] %[[#TMP]])
+  // CHECK:       %[[#TMP:]] = extractvalue %struct.S0 %[[#ST]], 1
+  // CHECK-SPIRV:              store <4 x float> %[[#TMP]], ptr addrspace(8) 
@B2, align 16
+  // CHECK-DXIL:               call void @llvm.dx.store.output.v4f32(i32 4, 
i32 0, i32 0, i8 0, i32 poison, <4 x float> %[[#TMP]])
+
+  S0 output;
+  output.position[0] = input;
+  output.position[1] = input;
+  output.color = input;
+  return output;
+}
diff --git a/clang/test/CodeGenHLSL/semantics/semantic.struct.output.hlsl 
b/clang/test/CodeGenHLSL/semantics/semantic.struct.output.hlsl
new file mode 100644
index 0000000000000..3b9832afa3f56
--- /dev/null
+++ b/clang/test/CodeGenHLSL/semantics/semantic.struct.output.hlsl
@@ -0,0 +1,27 @@
+// 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-DX,CHECK
+// 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-VK,CHECK
+
+
+struct Input {
+  float Idx : SV_Position0;
+};
+
+struct Output {
+  float a : A;
+};
+
+// Make sure SV_DispatchThreadID translated into dx.thread.id.
+
+// CHECK-DX: define hidden void @_Z3foo5Input(ptr dead_on_unwind noalias 
writable sret(%struct.Output) align 1 %agg.result, ptr noundef 
byval(%struct.Input) align 1 %input)
+// CHECK-VK: define hidden spir_func void @_Z3foo5Input(ptr dead_on_unwind 
noalias writable sret(%struct.Output) align 1 %agg.result, ptr noundef 
byval(%struct.Input) align 1 %input)
+
+// CHECK: %Idx = getelementptr inbounds nuw %struct.Input, ptr %input, i32 0, 
i32 0
+// CHECK: %[[#tmp:]] = load float, ptr %Idx, align 1
+// CHECK: %a = getelementptr inbounds nuw %struct.Output, ptr %agg.result, i32 
0, i32 0
+// CHECK: store float %[[#tmp]], ptr %a, align 1
+
+Output foo(Input input) {
+  Output o;
+  o.a = input.Idx;
+  return o;
+}
diff --git a/clang/test/CodeGenHLSL/sret_output.hlsl 
b/clang/test/CodeGenHLSL/sret_output.hlsl
index eefc9dabab517..e1aa0973fe5db 100644
--- a/clang/test/CodeGenHLSL/sret_output.hlsl
+++ b/clang/test/CodeGenHLSL/sret_output.hlsl
@@ -1,21 +1,33 @@
 // RUN: %clang_cc1 -std=hlsl2021 -finclude-default-header -triple 
dxil-pc-shadermodel6.3-library %s  \
-// RUN:   -emit-llvm -disable-llvm-passes -o - | FileCheck %s
+// RUN:   -emit-llvm -disable-llvm-passes -o - | FileCheck %s 
--check-prefixes=CHECK-DX,CHECK
+// RUN: %clang_cc1 -std=hlsl2021 -finclude-default-header -triple 
spirv-pc-vulkan-library %s  \
+// RUN:   -emit-llvm -disable-llvm-passes -o - | FileCheck %s 
--check-prefixes=CHECK-VK,CHECK
 
-// FIXME: add semantic to a.
-// See https://github.com/llvm/llvm-project/issues/57874
 struct S {
-  float a;
+  float a : A4;
 };
 
+// CHECK-VK: @A4 = external hidden thread_local addrspace(8) global float, 
!spirv.Decorations ![[#ATTR0:]]
 
 // Make sure sret parameter is generated.
-// CHECK:define internal void @_Z7ps_mainv(ptr dead_on_unwind noalias writable 
sret(%struct.S) align 1 %agg.result)
-// FIXME: change it to real value instead of poison value once semantic is add 
to a.
-// Make sure the function with sret is called.
-// CHECK:call void @_Z7ps_mainv(ptr poison)
-[shader("pixel")]
-S ps_main() {
+// CHECK-DX: define internal void @_Z7vs_mainv(ptr dead_on_unwind noalias 
writable sret(%struct.S) align 1 %agg.result)
+// CHECK-VK: define internal spir_func void @_Z7vs_mainv(ptr dead_on_unwind 
noalias writable sret(%struct.S) align 1 %agg.result)
+
+[shader("vertex")]
+S vs_main() {
   S s;
   s.a = 0;
   return s;
 };
+
+// CHECK: %[[#alloca:]] = alloca %struct.S, align 8
+// CHECK-DX:              call void @_Z7vs_mainv(ptr %[[#alloca]])
+// CHECK-VK:              call spir_func void @_Z7vs_mainv(ptr %[[#alloca]])
+// CHECK: %[[#a:]] = load %struct.S, ptr %[[#alloca]], align 4
+// CHECK: %[[#b:]] = extractvalue %struct.S %[[#a]], 0
+// CHECK-DX:         call void @llvm.dx.store.output.f32(i32 4, i32 0, i32 0, 
i8 0, i32 poison, float %[[#b]])
+// CHECK-VK:         store float %3, ptr addrspace(8) @A4, align 4
+// CHECK:            ret void
+
+// CHECK-VK: ![[#ATTR0]] = !{![[#ATTR1:]]}
+// CHECK-VK: ![[#ATTR1]] = !{i32 30, i32 0}
diff --git a/clang/test/SemaHLSL/Availability/attr-availability-compute.hlsl 
b/clang/test/SemaHLSL/Availability/attr-availability-compute.hlsl
index 2f488a8d7c357..e5e399cf490ba 100644
--- a/clang/test/SemaHLSL/Availability/attr-availability-compute.hlsl
+++ b/clang/test/SemaHLSL/Availability/attr-availability-compute.hlsl
@@ -37,7 +37,7 @@ __attribute__((availability(shadermodel, introduced = 6.0, 
environment = mesh)))
 unsigned f8();
 
 [numthreads(4,1,1)]
-int main() {
+void main() {
     // expected-error@#f1_call {{'f1' is only available on Shader Model 6.0 or 
newer}}
     // expected-note@#f1 {{'f1' has been marked as being introduced in Shader 
Model 6.0 here, but the deployment target is Shader Model 5.0}}
     unsigned A = f1(); // #f1_call
@@ -63,6 +63,4 @@ int main() {
     unsigned G = f7(); // #f7_call
 
     unsigned H = f8();
-
-    return 0;
 }
diff --git a/clang/test/SemaHLSL/Availability/attr-availability-mesh.hlsl 
b/clang/test/SemaHLSL/Availability/attr-availability-mesh.hlsl
index 07da116d403ce..eddba54d5ca9e 100644
--- a/clang/test/SemaHLSL/Availability/attr-availability-mesh.hlsl
+++ b/clang/test/SemaHLSL/Availability/attr-availability-mesh.hlsl
@@ -37,7 +37,7 @@ __attribute__((availability(shadermodel, introduced = 6.0, 
environment = mesh)))
 unsigned f8(); // #f8
 
 [numthreads(4,1,1)]
-int main() {
+void main() {
     // expected-error@#f1_call {{'f1' is only available on Shader Model 6.0 or 
newer}}
     // expected-note@#f1 {{'f1' has been marked as being introduced in Shader 
Model 6.0 here, but the deployment target is Shader Model 5.0}}
     unsigned A = f1(); // #f1_call
@@ -63,6 +63,4 @@ int main() {
     // expected-error@#f8_call {{'f8' is only available in mesh environment on 
Shader Model 6.0 or newer}}
     // expected-note@#f8 {{'f8' has been marked as being introduced in Shader 
Model 6.0 in mesh environment here, but the deployment target is Shader Model 
5.0 mesh environment}}
     unsigned H = f8(); // #f8_call
-
-    return 0;
 }
diff --git a/clang/test/SemaHLSL/Availability/attr-availability-pixel.hlsl 
b/clang/test/SemaHLSL/Availability/attr-availability-pixel.hlsl
index 7cd13e653ed5a..83c49738f8810 100644
--- a/clang/test/SemaHLSL/Availability/attr-availability-pixel.hlsl
+++ b/clang/test/SemaHLSL/Availability/attr-availability-pixel.hlsl
@@ -36,7 +36,7 @@ __attribute__((availability(shadermodel, introduced = 5.0, 
environment = compute
 __attribute__((availability(shadermodel, introduced = 6.0, environment = 
mesh)))
 unsigned f8();
 
-int main() {
+int main() : A {
     // expected-error@#f1_call {{'f1' is only available on Shader Model 6.0 or 
newer}}
     // expected-note@#f1 {{'f1' has been marked as being introduced in Shader 
Model 6.0 here, but the deployment target is Shader Model 5.0}}
     unsigned A = f1(); // #f1_call
diff --git a/clang/test/SemaHLSL/Availability/avail-diag-default-compute.hlsl 
b/clang/test/SemaHLSL/Availability/avail-diag-default-compute.hlsl
index b60fba62bdb00..1424fe63242ae 100644
--- a/clang/test/SemaHLSL/Availability/avail-diag-default-compute.hlsl
+++ b/clang/test/SemaHLSL/Availability/avail-diag-default-compute.hlsl
@@ -107,7 +107,7 @@ class MyClass
 };
 
 [numthreads(4,1,1)]
-float main() {
+void main() {
   float f = 3;
   MyClass C = { 1.0f };
   float a = alive(f);
@@ -115,5 +115,4 @@ float main() {
   float c = C.makeF();
   float d = test((float)1.0);
   float e = test((half)1.0);
-  return a * b * c;
 }
diff --git a/clang/test/SemaHLSL/Availability/avail-diag-default-lib.hlsl 
b/clang/test/SemaHLSL/Availability/avail-diag-default-lib.hlsl
index 35b7c384f26cd..0c997d28ecdfc 100644
--- a/clang/test/SemaHLSL/Availability/avail-diag-default-lib.hlsl
+++ b/clang/test/SemaHLSL/Availability/avail-diag-default-lib.hlsl
@@ -162,12 +162,12 @@ namespace A {
 // Shader entry point without body
 [shader("compute")]
 [numthreads(4,1,1)]
-float main();
+void main();
 
 // Shader entry point with body
 [shader("compute")]
 [numthreads(4,1,1)]
-float main() {
+void main() {
   float f = 3;
   MyClass C = { 1.0f };
   float a = alive(f);
@@ -176,5 +176,4 @@ float main() {
   float d = test((float)1.0);
   float e = test((half)1.0);
   exportedFunctionUsed(1.0f);
-  return a * b * c;
 }
diff --git a/clang/test/SemaHLSL/Availability/avail-diag-relaxed-compute.hlsl 
b/clang/test/SemaHLSL/Availability/avail-diag-relaxed-compute.hlsl
index 4068798383930..2474a8ae2e02a 100644
--- a/clang/test/SemaHLSL/Availability/avail-diag-relaxed-compute.hlsl
+++ b/clang/test/SemaHLSL/Availability/avail-diag-relaxed-compute.hlsl
@@ -107,7 +107,7 @@ class MyClass
 };
 
 [numthreads(4,1,1)]
-float main() {
+void main() {
   float f = 3;
   MyClass C = { 1.0f };
   float a = alive(f);
@@ -115,5 +115,4 @@ float main() {
   float c = C.makeF();
   float d = test((float)1.0);
   float e = test((half)1.0);
-  return a * b * c;
 }
diff --git a/clang/test/SemaHLSL/Availability/avail-diag-relaxed-lib.hlsl 
b/clang/test/SemaHLSL/Availability/avail-diag-relaxed-lib.hlsl
index a23e91a546b16..e598bc99a4e6a 100644
--- a/clang/test/SemaHLSL/Availability/avail-diag-relaxed-lib.hlsl
+++ b/clang/test/SemaHLSL/Availability/avail-diag-relaxed-lib.hlsl
@@ -144,12 +144,12 @@ export void exportedFunctionUsed(float f) {
 // Shader entry point without body
 [shader("compute")]
 [numthreads(4,1,1)]
-float main();
+void main();
 
 // Shader entry point with body
 [shader("compute")]
 [numthreads(4,1,1)]
-float main() {
+void main() {
   float f = 3;
   MyClass C = { 1.0f };
   float a = alive(f);
@@ -158,5 +158,4 @@ float main() {
   float d = test((float)1.0);
   float e = test((half)1.0);
   exportedFunctionUsed(1.0f);
-  return a * b * c;
 }
diff --git a/clang/test/SemaHLSL/Availability/avail-diag-strict-compute.hlsl 
b/clang/test/SemaHLSL/Availability/avail-diag-strict-compute.hlsl
index c5d14c024d540..9cb9a32e11c73 100644
--- a/clang/test/SemaHLSL/Availability/avail-diag-strict-compute.hlsl
+++ b/clang/test/SemaHLSL/Availability/avail-diag-strict-compute.hlsl
@@ -117,7 +117,7 @@ class MyClass
 };
 
 [numthreads(4,1,1)]
-float main() {
+void main() {
   float f = 3;
   MyClass C = { 1.0f };
   float a = alive(f);
@@ -125,5 +125,4 @@ float main() {
   float c = C.makeF();
   float d = test((float)1.0);
   float e = test((half)1.0);
-  return a * b * c;
 }
diff --git a/clang/test/SemaHLSL/Availability/avail-diag-strict-lib.hlsl 
b/clang/test/SemaHLSL/Availability/avail-diag-strict-lib.hlsl
index 0fffbc96dac19..3a7efc3af80a0 100644
--- a/clang/test/SemaHLSL/Availability/avail-diag-strict-lib.hlsl
+++ b/clang/test/SemaHLSL/Availability/avail-diag-strict-lib.hlsl
@@ -180,7 +180,7 @@ namespace A {
 
 [shader("compute")]
 [numthreads(4,1,1)]
-float main() {
+void main() {
   float f = 3;
   MyClass C = { 1.0f };
   float a = alive(f);float b = aliveTemp<float>(f); // #aliveTemp_inst
@@ -188,5 +188,4 @@ float main() {
   float d = test((float)1.0);
   float e = test((half)1.0);
   exportedFunctionUsed(1.0f);
-  return a * b * c;
 }
diff --git a/clang/test/SemaHLSL/Semantics/position.ps.hlsl 
b/clang/test/SemaHLSL/Semantics/position.ps.hlsl
index 7adf2a51f01c8..2d02384821d90 100644
--- a/clang/test/SemaHLSL/Semantics/position.ps.hlsl
+++ b/clang/test/SemaHLSL/Semantics/position.ps.hlsl
@@ -1,9 +1,13 @@
 // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-pixel -x hlsl 
-finclude-default-header -o - %s -ast-dump | FileCheck %s
 
-// FIXME(Keenuts): add mandatory output semantic once those are implemented.
-float4 main(float4 a : SV_Position2) {
+// FIXME(Keenuts): change output semantic to something valid for pixels shaders
+float4 main(float4 a : SV_Position2) : A {
 // CHECK: FunctionDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> line:[[@LINE-1]]:8 main 
'float4 (float4)'
-// CHECK-NEXT: ParmVarDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:20 a 
'float4':'vector<float, 4>'
+// CHECK-NEXT: ParmVarDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:20 used a 
'float4':'vector<float, 4>'
 // CHECK-NEXT:  HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} <col:24> "SV_Position" 2
 // CHECK-NEXT:  HLSLAppliedSemanticAttr 0x{{[0-9a-f]+}} <col:24> "SV_Position" 
2
+
+// CHECK:       HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} <line:4:40> "A" 0
+// CHECK:       HLSLAppliedSemanticAttr 0x{{[0-9a-f]+}} <col:40> "A" 0
+  return a;
 }
diff --git a/clang/test/SemaHLSL/Semantics/position.ps.struct.hlsl 
b/clang/test/SemaHLSL/Semantics/position.ps.struct.hlsl
index 3186aadf19946..213a53e30155b 100644
--- a/clang/test/SemaHLSL/Semantics/position.ps.struct.hlsl
+++ b/clang/test/SemaHLSL/Semantics/position.ps.struct.hlsl
@@ -5,14 +5,17 @@ struct S {
 // CHECK: FieldDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:10 f0 
'float4':'vector<float, 4>'
 // CHECK-NEXT:  HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} <col:15> "SV_Position" 0
   float4 f1 : SV_Position3;
-// CHECK: FieldDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:10 f1 
'float4':'vector<float, 4>'
+// CHECK: FieldDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:10 referenced f1 
'float4':'vector<float, 4>'
 // CHECK-NEXT:  HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} <col:15> "SV_Position" 3
 };
 
 // FIXME(Keenuts): add mandatory output semantic once those are implemented.
-float4 main(S s) {
+float4 main(S s) : B {
 // CHECK: FunctionDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> line:[[@LINE-1]]:8 main 
'float4 (S)'
-// CHECK-NEXT: ParmVarDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:15 s 'S'
+// CHECK-NEXT: ParmVarDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:15 used s 'S'
 // CHECK-NEXT:  HLSLAppliedSemanticAttr 0x{{[0-9a-f]+}} <line:4:15> 
"SV_Position" 0
 // CHECK-NEXT:  HLSLAppliedSemanticAttr 0x{{[0-9a-f]+}} <line:7:15> 
"SV_Position" 3
+
+// CHECK:       HLSLAppliedSemanticAttr 0x{{[0-9a-f]+}} <col:20> "B" 0
+  return s.f1;
 }
diff --git a/clang/test/SemaHLSL/Semantics/position.ps.struct.reuse.hlsl 
b/clang/test/SemaHLSL/Semantics/position.ps.struct.reuse.hlsl
index f12ac4df0c450..d10c817d53af2 100644
--- a/clang/test/SemaHLSL/Semantics/position.ps.struct.reuse.hlsl
+++ b/clang/test/SemaHLSL/Semantics/position.ps.struct.reuse.hlsl
@@ -2,13 +2,13 @@
 
 struct A {
   float4 x : A;
-// CHECK: FieldDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:10 x 
'float4':'vector<float, 4>'
+// CHECK: FieldDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:10 referenced x 
'float4':'vector<float, 4>'
 // CHECK-NEXT:  HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} <col:14> "A" 0
 };
 
 struct Top {
   A f0 : B;
-// CHECK: FieldDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:5 f0 'A'
+// CHECK: FieldDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:5 referenced f0 'A'
 // CHECK-NEXT:  HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} <col:10> "B" 0
   A f1 : C;
 // CHECK: FieldDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:5 f1 'A'
@@ -17,10 +17,13 @@ struct Top {
 
 
 // FIXME(Keenuts): add mandatory output semantic once those are implemented.
-float4 main(Top s : D) {
+float4 main(Top s : D) : F4 {
 // CHECK: FunctionDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> line:[[@LINE-1]]:8 main 
'float4 (Top)'
-// CHECK-NEXT: ParmVarDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:17 s 'Top'
+// CHECK-NEXT: ParmVarDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:17 used s 'Top'
 // CHECK-NEXT:  HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} <col:21> "D" 0
 // CHECK-NEXT:  HLSLAppliedSemanticAttr 0x{{[0-9a-f]+}} <col:21> "D" 0
 // CHECK-NEXT:  HLSLAppliedSemanticAttr 0x{{[0-9a-f]+}} <col:21> "D" 1
+
+// CHECK:       HLSLAppliedSemanticAttr 0x{{[0-9a-f]+}} <col:26> "F" 4
+  return s.f0.x;
 }
diff --git a/clang/test/SemaHLSL/Semantics/position.vs.hlsl 
b/clang/test/SemaHLSL/Semantics/position.vs.hlsl
index 19f781fa3757c..9d0ff285ce055 100644
--- a/clang/test/SemaHLSL/Semantics/position.vs.hlsl
+++ b/clang/test/SemaHLSL/Semantics/position.vs.hlsl
@@ -1,6 +1,6 @@
 // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-vertex -x hlsl 
-finclude-default-header -o - %s -verify
 
 // expected-error@+1 {{attribute 'SV_Position' is unsupported in 'vertex' 
shaders, requires pixel}}
-float4 main(float4 a : SV_Position) {
+float4 main(float4 a : SV_Position) : A {
   return a;
 }
diff --git a/clang/test/SemaHLSL/WaveBuiltinAvailability.hlsl 
b/clang/test/SemaHLSL/WaveBuiltinAvailability.hlsl
index a5645d1400da7..e7cb59bea8cf5 100644
--- a/clang/test/SemaHLSL/WaveBuiltinAvailability.hlsl
+++ b/clang/test/SemaHLSL/WaveBuiltinAvailability.hlsl
@@ -3,8 +3,8 @@
 
 [shader("compute")]
 [numthreads(8,8,1)]
-unsigned foo() {
+void foo() {
     // expected-error@#site {{'WaveActiveCountBits' is only available on 
Shader Model 6.0 or newer}}
     // expected-note@hlsl/hlsl_alias_intrinsics.h:* {{'WaveActiveCountBits' 
has been marked as being introduced in Shader Model 6.0 here, but the 
deployment target is Shader Model 5.0}}
-    return hlsl::WaveActiveCountBits(1); // #site
+    unsigned tmp = hlsl::WaveActiveCountBits(1); // #site
 }
diff --git a/clang/test/SemaHLSL/num_threads.hlsl 
b/clang/test/SemaHLSL/num_threads.hlsl
index 96200312bbf69..073f9bcfbe2ae 100644
--- a/clang/test/SemaHLSL/num_threads.hlsl
+++ b/clang/test/SemaHLSL/num_threads.hlsl
@@ -117,7 +117,7 @@ int largeZ();
 #else // Vertex and Pixel only beyond here
 // expected-error-re@+1 {{attribute 'numthreads' is unsupported in 
'{{[A-Za-z]+}}' shaders, requires one of the following: compute, amplification, 
mesh}}
 [numthreads(1,1,1)]
-int main() {
+int main() : A {
  return 1;
 }
 
diff --git a/clang/test/SemaHLSL/shader_type_attr.hlsl 
b/clang/test/SemaHLSL/shader_type_attr.hlsl
index 52d3b1c9d012f..5f30a520b7255 100644
--- a/clang/test/SemaHLSL/shader_type_attr.hlsl
+++ b/clang/test/SemaHLSL/shader_type_attr.hlsl
@@ -31,18 +31,17 @@ static void oops() {}
 [shader("pixel")]
 // expected-note@+1 {{conflicting attribute is here}}
 [shader("vertex")]
-int doubledUp() {
+int doubledUp() : A {
   return 1;
 }
 
 // expected-note@+1 {{conflicting attribute is here}}
 [shader("vertex")]
-int forwardDecl();
+void forwardDecl();
 
 // expected-error@+1 {{'shader' attribute parameters do not match the previous 
declaration}}
 [shader("compute")][numthreads(8,1,1)]
-int forwardDecl() {
-  return 1;
+void forwardDecl() {
 }
 
 // expected-error@+1 {{'shader' attribute takes one argument}}
@@ -57,22 +56,20 @@ int forwardDecl() {
 [shader("library")]
 #endif // END of FAIL
 
-// CHECK:HLSLShaderAttr 0x{{[0-9a-fA-F]+}} <line:62:2, col:18> Compute
+// CHECK:HLSLShaderAttr 0x{{[0-9a-fA-F]+}} <line:61:2, col:18> Compute
 // CHECK:HLSLNumThreadsAttr 0x{{[0-9a-fA-F]+}} <col:21, col:37> 8 1 1
 [shader("compute")][numthreads(8,1,1)]
-int entry() {
-  return 1;
+void entry() {
 }
 
 // Because these two attributes match, they should both appear in the AST
 [shader("compute")][numthreads(8,1,1)]
-// CHECK:HLSLShaderAttr 0x{{[0-9a-fA-F]+}} <line:68:2, col:18> Compute
+// CHECK:HLSLShaderAttr 0x{{[0-9a-fA-F]+}} <line:66:2, col:18> Compute
 // CHECK:HLSLNumThreadsAttr 0x{{[0-9a-fA-F]+}} <col:21, col:37> 8 1 1
-int secondFn();
+void secondFn();
 
 [shader("compute")][numthreads(8,1,1)]
-// CHECK:HLSLShaderAttr 0x{{[0-9a-fA-F]+}} <line:73:2, col:18> Compute
+// CHECK:HLSLShaderAttr 0x{{[0-9a-fA-F]+}} <line:71:2, col:18> Compute
 // CHECK:HLSLNumThreadsAttr 0x{{[0-9a-fA-F]+}} <col:21, col:37> 8 1 1
-int secondFn() {
-  return 1;
+void secondFn() {
 }
diff --git a/llvm/include/llvm/IR/IntrinsicsDirectX.td 
b/llvm/include/llvm/IR/IntrinsicsDirectX.td
index d7db935ee07f1..b8fd81cf16e4a 100644
--- a/llvm/include/llvm/IR/IntrinsicsDirectX.td
+++ b/llvm/include/llvm/IR/IntrinsicsDirectX.td
@@ -182,4 +182,10 @@ def int_dx_load_input
                             [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty, llvm_i8_ty,
                              llvm_i32_ty],
                             [IntrConvergent]>;
+
+def int_dx_store_output
+    : DefaultAttrsIntrinsic<[],
+                            [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty, llvm_i8_ty,
+                             llvm_i32_ty, llvm_any_ty],
+                            [IntrConvergent]>;
 }

From ac17bee3ad403ce2a73689d3cbc8c0f348179e53 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= <[email protected]>
Date: Tue, 18 Nov 2025 16:18:05 +0100
Subject: [PATCH 2/5] rename parameter to UsedSemantics

---
 clang/lib/Sema/SemaHLSL.cpp | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index dd8122c11e696..29beb07edaca8 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -773,7 +773,7 @@ void SemaHLSL::ActOnTopLevelFunction(FunctionDecl *FD) {
 
 bool SemaHLSL::determineActiveSemanticOnScalar(
     FunctionDecl *FD, DeclaratorDecl *OutputDecl, DeclaratorDecl *D,
-    SemanticInfo &ActiveSemantic, llvm::StringSet<> &ActiveInputSemantics) {
+    SemanticInfo &ActiveSemantic, llvm::StringSet<> &UsedSemantics) {
   if (ActiveSemantic.Semantic == nullptr) {
     ActiveSemantic.Semantic = D->getAttr<HLSLParsedSemanticAttr>();
     if (ActiveSemantic.Semantic)
@@ -805,7 +805,7 @@ bool SemaHLSL::determineActiveSemanticOnScalar(
   for (unsigned I = 0; I < ElementCount; ++I) {
     Twine VariableName = BaseName.concat(Twine(Location + I));
 
-    auto [_, Inserted] = ActiveInputSemantics.insert(VariableName.str());
+    auto [_, Inserted] = UsedSemantics.insert(VariableName.str());
     if (!Inserted) {
       Diag(D->getLocation(), diag::err_hlsl_semantic_index_overlap)
           << VariableName.str();
@@ -818,7 +818,7 @@ bool SemaHLSL::determineActiveSemanticOnScalar(
 
 bool SemaHLSL::determineActiveSemantic(
     FunctionDecl *FD, DeclaratorDecl *OutputDecl, DeclaratorDecl *D,
-    SemanticInfo &ActiveSemantic, llvm::StringSet<> &ActiveInputSemantics) {
+    SemanticInfo &ActiveSemantic, llvm::StringSet<> &UsedSemantics) {
   if (ActiveSemantic.Semantic == nullptr) {
     ActiveSemantic.Semantic = D->getAttr<HLSLParsedSemanticAttr>();
     if (ActiveSemantic.Semantic)
@@ -831,13 +831,13 @@ bool SemaHLSL::determineActiveSemantic(
   const RecordType *RT = dyn_cast<RecordType>(T);
   if (!RT)
     return determineActiveSemanticOnScalar(FD, OutputDecl, D, ActiveSemantic,
-                                           ActiveInputSemantics);
+                                           UsedSemantics);
 
   const RecordDecl *RD = RT->getDecl();
   for (FieldDecl *Field : RD->fields()) {
     SemanticInfo Info = ActiveSemantic;
     if (!determineActiveSemantic(FD, OutputDecl, Field, Info,
-                                 ActiveInputSemantics)) {
+                                 UsedSemantics)) {
       Diag(Field->getLocation(), diag::note_hlsl_semantic_used_here) << Field;
       return false;
     }

From 53915ec7b57bdd1594fd26745826a175adba255a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= <[email protected]>
Date: Tue, 18 Nov 2025 16:23:19 +0100
Subject: [PATCH 3/5] move test to sema

---
 .../{CodeGenHLSL/semantics => SemaHLSL/Semantics}/missing-vs.hlsl | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename clang/test/{CodeGenHLSL/semantics => 
SemaHLSL/Semantics}/missing-vs.hlsl (100%)

diff --git a/clang/test/CodeGenHLSL/semantics/missing-vs.hlsl 
b/clang/test/SemaHLSL/Semantics/missing-vs.hlsl
similarity index 100%
rename from clang/test/CodeGenHLSL/semantics/missing-vs.hlsl
rename to clang/test/SemaHLSL/Semantics/missing-vs.hlsl

From 1338e440210cbf99c65d2a7285b0dfe40637160a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= <[email protected]>
Date: Tue, 18 Nov 2025 16:39:12 +0100
Subject: [PATCH 4/5] add metadata testing

---
 .../semantics/semantic.array.output.hlsl      |  6 +++
 .../semantics/semantic.struct.output.hlsl     | 47 +++++++++++++++----
 2 files changed, 44 insertions(+), 9 deletions(-)

diff --git a/clang/test/CodeGenHLSL/semantics/semantic.array.output.hlsl 
b/clang/test/CodeGenHLSL/semantics/semantic.array.output.hlsl
index 2ff0e3835672c..d75f4e0ca8338 100644
--- a/clang/test/CodeGenHLSL/semantics/semantic.array.output.hlsl
+++ b/clang/test/CodeGenHLSL/semantics/semantic.array.output.hlsl
@@ -6,6 +6,7 @@ struct S0 {
   float4 color;
 };
 
+// CHECK-SPIRV-DAG:    @A0 = external hidden thread_local addrspace(7) 
externally_initialized constant <4 x float>, !spirv.Decorations 
![[#METADATA_0:]]
 
 [shader("pixel")]
 S0 main1(float4 input : A) : B {
@@ -29,3 +30,8 @@ S0 main1(float4 input : A) : B {
   output.color = input;
   return output;
 }
+
+// CHECK-SPIRV-DAG: ![[#METADATA_0]] = !{![[#METADATA_1:]]}
+// CHECK-SPIRV-DAG: ![[#METADATA_1]] = !{i32 30, i32 0}
+//                                            |      `- Location index
+//                                            `-> Decoration "Location"
diff --git a/clang/test/CodeGenHLSL/semantics/semantic.struct.output.hlsl 
b/clang/test/CodeGenHLSL/semantics/semantic.struct.output.hlsl
index 3b9832afa3f56..0f2444d21724a 100644
--- a/clang/test/CodeGenHLSL/semantics/semantic.struct.output.hlsl
+++ b/clang/test/CodeGenHLSL/semantics/semantic.struct.output.hlsl
@@ -1,27 +1,56 @@
-// 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-DX,CHECK
-// 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-VK,CHECK
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-vertex -x hlsl -emit-llvm 
-finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s 
--check-prefixes=CHECK-DXIL,CHECK
+// RUN: %clang_cc1 -triple spirv-linux-vulkan-vertex -x hlsl -emit-llvm 
-finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s 
--check-prefixes=CHECK-SPIRV,CHECK
 
 
 struct Input {
-  float Idx : SV_Position0;
+  // FIXME: change this once we have a valid system semantic as input for VS.
+  float Idx : B2;
 };
 
 struct Output {
-  float a : A;
+  float a : A4;
+  float b : A2;
 };
 
-// Make sure SV_DispatchThreadID translated into dx.thread.id.
-
-// CHECK-DX: define hidden void @_Z3foo5Input(ptr dead_on_unwind noalias 
writable sret(%struct.Output) align 1 %agg.result, ptr noundef 
byval(%struct.Input) align 1 %input)
-// CHECK-VK: define hidden spir_func void @_Z3foo5Input(ptr dead_on_unwind 
noalias writable sret(%struct.Output) align 1 %agg.result, ptr noundef 
byval(%struct.Input) align 1 %input)
+// CHECK-SPIRV-DAG:    @B2 = external hidden thread_local addrspace(7) 
externally_initialized constant float, !spirv.Decorations ![[#METADATA_0:]]
+// CHECK-SPIRV-DAG:    @A4 = external hidden thread_local addrspace(8) global 
float, !spirv.Decorations ![[#METADATA_0:]]
+// CHECK-SPIRV-DAG:    @A2 = external hidden thread_local addrspace(8) global 
float, !spirv.Decorations ![[#METADATA_2:]]
 
 // CHECK: %Idx = getelementptr inbounds nuw %struct.Input, ptr %input, i32 0, 
i32 0
 // CHECK: %[[#tmp:]] = load float, ptr %Idx, align 1
 // CHECK: %a = getelementptr inbounds nuw %struct.Output, ptr %agg.result, i32 
0, i32 0
 // CHECK: store float %[[#tmp]], ptr %a, align 1
 
-Output foo(Input input) {
+// CHECK: %Idx1 = getelementptr inbounds nuw %struct.Input, ptr %input, i32 0, 
i32 0
+// CHECK: %[[#tmp:]] = load float, ptr %Idx1, align 1
+// CHECK: %b = getelementptr inbounds nuw %struct.Output, ptr %agg.result, i32 
0, i32 1
+// CHECK: store float %[[#tmp]], ptr %b, align 1
+
+Output main(Input input) {
   Output o;
   o.a = input.Idx;
+  o.b = input.Idx;
   return o;
 }
+
+// Code generated in the entrypoint wrapper:
+
+// CHECK: %[[#OUTPUT:]] = alloca %struct.Output, align 8
+
+// CHECK-SPIRV: call spir_func void @_Z4main5Input(ptr %[[#OUTPUT]], ptr 
%[[#]])
+// CHECK-DXIL:  call void @_Z4main5Input(ptr %[[#OUTPUT]], ptr %[[#]])
+
+// CHECK: %[[#TMP:]] = load %struct.Output, ptr %[[#OUTPUT]], align 4
+// CHECK: %[[#VAL:]] = extractvalue %struct.Output %[[#TMP]], 0
+// CHECK-SPIRV:        store float %[[#VAL]], ptr addrspace(8) @A4, align 4
+// CHECK-DXIL:         call void @llvm.dx.store.output.f32(i32 4, i32 0, i32 
0, i8 0, i32 poison, float %[[#VAL]])
+// CHECK: %[[#VAL:]] = extractvalue %struct.Output %[[#TMP]], 1
+// CHECK-SPIRV:        store float %[[#VAL]], ptr addrspace(8) @A2, align 4
+// CHECK-DXIL:         call void @llvm.dx.store.output.f32(i32 4, i32 0, i32 
0, i8 0, i32 poison, float %[[#VAL]])
+
+// CHECK-SPIRV-DAG: ![[#METADATA_0]] = !{![[#METADATA_1:]]}
+// CHECK-SPIRV-DAG: ![[#METADATA_2]] = !{![[#METADATA_3:]]}
+// CHECK-SPIRV-DAG: ![[#METADATA_1]] = !{i32 30, i32 0}
+// CHECK-SPIRV-DAG: ![[#METADATA_3]] = !{i32 30, i32 1}
+//                                            |      `- Location index
+//                                            `-> Decoration "Location"

From 4b23dc44c268d9a399d032a10119d55835d0df6f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= <[email protected]>
Date: Tue, 18 Nov 2025 16:40:33 +0100
Subject: [PATCH 5/5] clang-format

---
 clang/lib/Sema/SemaHLSL.cpp | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 29beb07edaca8..81e49977b0551 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -816,9 +816,11 @@ bool SemaHLSL::determineActiveSemanticOnScalar(
   return true;
 }
 
-bool SemaHLSL::determineActiveSemantic(
-    FunctionDecl *FD, DeclaratorDecl *OutputDecl, DeclaratorDecl *D,
-    SemanticInfo &ActiveSemantic, llvm::StringSet<> &UsedSemantics) {
+bool SemaHLSL::determineActiveSemantic(FunctionDecl *FD,
+                                       DeclaratorDecl *OutputDecl,
+                                       DeclaratorDecl *D,
+                                       SemanticInfo &ActiveSemantic,
+                                       llvm::StringSet<> &UsedSemantics) {
   if (ActiveSemantic.Semantic == nullptr) {
     ActiveSemantic.Semantic = D->getAttr<HLSLParsedSemanticAttr>();
     if (ActiveSemantic.Semantic)
@@ -836,8 +838,7 @@ bool SemaHLSL::determineActiveSemantic(
   const RecordDecl *RD = RT->getDecl();
   for (FieldDecl *Field : RD->fields()) {
     SemanticInfo Info = ActiveSemantic;
-    if (!determineActiveSemantic(FD, OutputDecl, Field, Info,
-                                 UsedSemantics)) {
+    if (!determineActiveSemantic(FD, OutputDecl, Field, Info, UsedSemantics)) {
       Diag(Field->getLocation(), diag::note_hlsl_semantic_used_here) << Field;
       return false;
     }

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to