[clang] [llvm] [HLSL] Add initial support for output semantics (PR #168095)
Nathan Gauër via llvm-commits
llvm-commits at lists.llvm.org
Tue Nov 18 07:42:41 PST 2025
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?= <brioche at google.com>
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 at -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 at +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 at 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 at +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 at +1 {{conflicting attribute is here}}
[shader("vertex")]
-int doubledUp() {
+int doubledUp() : A {
return 1;
}
// expected-note at +1 {{conflicting attribute is here}}
[shader("vertex")]
-int forwardDecl();
+void forwardDecl();
// expected-error at +1 {{'shader' attribute parameters do not match the previous declaration}}
[shader("compute")][numthreads(8,1,1)]
-int forwardDecl() {
- return 1;
+void forwardDecl() {
}
// expected-error at +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?= <brioche at google.com>
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?= <brioche at google.com>
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?= <brioche at google.com>
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?= <brioche at google.com>
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;
}
More information about the llvm-commits
mailing list