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 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(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 Index) { + // DXIL packing rules etc shall be handled here. + // FIXME: generate proper sigpoint, index, col, row values. + SmallVector 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 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 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 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 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 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> 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 +CGHLSLRuntime::handleStructSemanticStore( + IRBuilder<> &B, const FunctionDecl *FD, llvm::Value *Source, + const clang::DeclaratorDecl *Decl, + specific_attr_iterator AttrBegin, + specific_attr_iterator AttrEnd) { + + const llvm::StructType *ST = cast(Source->getType()); + + const clang::RecordDecl *RD = nullptr; + if (const FunctionDecl *FD = dyn_cast(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> CGHLSLRuntime::handleSemanticLoad( IRBuilder<> &B, const FunctionDecl *FD, llvm::Type *Type, @@ -721,6 +848,22 @@ CGHLSLRuntime::handleSemanticLoad( AttrBegin); } +specific_attr_iterator +CGHLSLRuntime::handleSemanticStore( + IRBuilder<> &B, const FunctionDecl *FD, llvm::Value *Source, + const clang::DeclaratorDecl *Decl, + specific_attr_iterator AttrBegin, + specific_attr_iterator 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 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()) { 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(Source); + llvm::Value *SourceValue = + AI ? B.CreateLoad(AI->getAllocatedType(), Source) : Source; + + auto AttrBegin = Decl->specific_attr_begin(); + auto AttrEnd = Decl->specific_attr_end(); + 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 Index); + void emitSystemSemanticStore(llvm::IRBuilder<> &B, llvm::Value *Source, + const clang::DeclaratorDecl *Decl, + HLSLAppliedSemanticAttr *Semantic, + std::optional 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> handleStructSemanticLoad( llvm::IRBuilder<> &B, const FunctionDecl *FD, llvm::Type *Type, @@ -189,12 +199,24 @@ class CGHLSLRuntime { specific_attr_iterator begin, specific_attr_iterator end); + specific_attr_iterator handleStructSemanticStore( + llvm::IRBuilder<> &B, const FunctionDecl *FD, llvm::Value *Source, + const clang::DeclaratorDecl *Decl, + specific_attr_iterator AttrBegin, + specific_attr_iterator AttrEnd); + std::pair> handleSemanticLoad(llvm::IRBuilder<> &B, const FunctionDecl *FD, llvm::Type *Type, const clang::DeclaratorDecl *Decl, specific_attr_iterator begin, specific_attr_iterator end); + specific_attr_iterator + handleSemanticStore(llvm::IRBuilder<> &B, const FunctionDecl *FD, + llvm::Value *Source, const clang::DeclaratorDecl *Decl, + specific_attr_iterator AttrBegin, + specific_attr_iterator AttrEnd); + public: CGHLSLRuntime(CodeGenModule &CGM) : CGM(CGM) {} virtual ~CGHLSLRuntime() {} @@ -249,10 +271,22 @@ class CGHLSLRuntime { HLSLAppliedSemanticAttr *Semantic, std::optional Index); + void emitSPIRVUserSemanticStore(llvm::IRBuilder<> &B, llvm::Value *Source, + HLSLAppliedSemanticAttr *Semantic, + std::optional Index); + void emitDXILUserSemanticStore(llvm::IRBuilder<> &B, llvm::Value *Source, + HLSLAppliedSemanticAttr *Semantic, + std::optional Index); + void emitUserSemanticStore(llvm::IRBuilder<> &B, llvm::Value *Source, + const clang::DeclaratorDecl *Decl, + HLSLAppliedSemanticAttr *Semantic, + std::optional Index); + llvm::Triple::ArchType getArch(); llvm::DenseMap 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..81e49977b0551 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(); 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(); @@ -816,26 +816,29 @@ bool SemaHLSL::determineActiveSemanticOnScalar( return true; } -bool SemaHLSL::determineActiveSemantic( - FunctionDecl *FD, DeclaratorDecl *OutputDecl, DeclaratorDecl *D, - SemanticInfo &ActiveSemantic, llvm::StringSet<> &ActiveInputSemantics) { +bool SemaHLSL::determineActiveSemantic(FunctionDecl *FD, + DeclaratorDecl *OutputDecl, + DeclaratorDecl *D, + SemanticInfo &ActiveSemantic, + llvm::StringSet<> &UsedSemantics) { if (ActiveSemantic.Semantic == nullptr) { ActiveSemantic.Semantic = D->getAttr(); if (ActiveSemantic.Semantic) 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(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)) { + if (!determineActiveSemantic(FD, OutputDecl, Field, Info, UsedSemantics)) { Diag(Field->getLocation(), diag::note_hlsl_semantic_used_here) << Field; return false; } @@ -915,13 +918,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(); + 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/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..d75f4e0ca8338 --- /dev/null +++ b/clang/test/CodeGenHLSL/semantics/semantic.array.output.hlsl @@ -0,0 +1,37 @@ +// 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; +}; + +// 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 { +// 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; +} + +// 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 new file mode 100644 index 0000000000000..0f2444d21724a --- /dev/null +++ b/clang/test/CodeGenHLSL/semantics/semantic.struct.output.hlsl @@ -0,0 +1,56 @@ +// 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 { + // FIXME: change this once we have a valid system semantic as input for VS. + float Idx : B2; +}; + +struct Output { + float a : A4; + float b : A2; +}; + +// 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 + +// 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" 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(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/missing-vs.hlsl b/clang/test/SemaHLSL/Semantics/missing-vs.hlsl new file mode 100644 index 0000000000000..41be9c0ab730c --- /dev/null +++ b/clang/test/SemaHLSL/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/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' +// CHECK-NEXT: ParmVarDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:20 used a 'float4':'vector' // CHECK-NEXT: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} "SV_Position" 2 // CHECK-NEXT: HLSLAppliedSemanticAttr 0x{{[0-9a-f]+}} "SV_Position" 2 + +// CHECK: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} "A" 0 +// CHECK: HLSLAppliedSemanticAttr 0x{{[0-9a-f]+}} "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' // CHECK-NEXT: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} "SV_Position" 0 float4 f1 : SV_Position3; -// CHECK: FieldDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:10 f1 'float4':'vector' +// CHECK: FieldDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:10 referenced f1 'float4':'vector' // CHECK-NEXT: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} "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]+}} "SV_Position" 0 // CHECK-NEXT: HLSLAppliedSemanticAttr 0x{{[0-9a-f]+}} "SV_Position" 3 + +// CHECK: HLSLAppliedSemanticAttr 0x{{[0-9a-f]+}} "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' +// CHECK: FieldDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:10 referenced x 'float4':'vector' // CHECK-NEXT: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} "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]+}} "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]+}} "D" 0 // CHECK-NEXT: HLSLAppliedSemanticAttr 0x{{[0-9a-f]+}} "D" 0 // CHECK-NEXT: HLSLAppliedSemanticAttr 0x{{[0-9a-f]+}} "D" 1 + +// CHECK: HLSLAppliedSemanticAttr 0x{{[0-9a-f]+}} "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]+}} Compute +// CHECK:HLSLShaderAttr 0x{{[0-9a-fA-F]+}} Compute // CHECK:HLSLNumThreadsAttr 0x{{[0-9a-fA-F]+}} 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]+}} Compute +// CHECK:HLSLShaderAttr 0x{{[0-9a-fA-F]+}} Compute // CHECK:HLSLNumThreadsAttr 0x{{[0-9a-fA-F]+}} 8 1 1 -int secondFn(); +void secondFn(); [shader("compute")][numthreads(8,1,1)] -// CHECK:HLSLShaderAttr 0x{{[0-9a-fA-F]+}} Compute +// CHECK:HLSLShaderAttr 0x{{[0-9a-fA-F]+}} Compute // CHECK:HLSLNumThreadsAttr 0x{{[0-9a-fA-F]+}} 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]>; }