https://github.com/tcorringham updated https://github.com/llvm/llvm-project/pull/211256
>From 9df964e1090328a8585ca87a24c41bf90f640ee5 Mon Sep 17 00:00:00 2001 From: Tim Corringham <[email protected]> Date: Wed, 22 Jul 2026 11:08:50 +0100 Subject: [PATCH 1/3] [HLSL][SPIRV] Add IntrConvergent to convergent intrinsics A number of spirv intrinsics need to run in convergent code flow but LLVM -O3 could sometimes lower these into divergent control flow as they were missing the IntrConvergent attribute. This change adds the IntrConvergent attribute to these intrinsics, and switches the builtin emission from `Builder.CreateIntrinsic` to `EmitRuntimeCall` (via a helper function) so that the attribute is preserved through codegen. Tests check that the Convergent attribute is added where expected, and that it survives a llvm-as/llvm-dis round-trip. Assisted by Cursor Fixes #211253 --- clang/lib/CodeGen/CGHLSLBuiltins.cpp | 40 +++++++++++++------ llvm/include/llvm/IR/IntrinsicsSPIRV.td | 12 +++--- .../spirv-resource-intrinsic-attributes.ll | 29 ++++++++++++++ llvm/unittests/IR/IntrinsicsTest.cpp | 26 +++++++++++- 4 files changed, 87 insertions(+), 20 deletions(-) create mode 100644 llvm/test/Assembler/spirv-resource-intrinsic-attributes.ll diff --git a/clang/lib/CodeGen/CGHLSLBuiltins.cpp b/clang/lib/CodeGen/CGHLSLBuiltins.cpp index 1bda113143e07..9cdf650f1d560 100644 --- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp +++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp @@ -533,6 +533,19 @@ static Value *emitHlslClamp(CodeGenFunction &CGF, const CallExpr *E, return Clamp; } +static CallInst *emitConvergentResourceIntrinsicCall(CodeGenFunction &CGF, + llvm::Type *RetTy, + Intrinsic::ID ID, + ArrayRef<Value *> Args) { + SmallVector<llvm::Type *> ArgTys; + ArgTys.reserve(Args.size()); + for (Value *Arg : Args) + ArgTys.push_back(Arg->getType()); + Function *IntrFn = Intrinsic::getOrInsertDeclaration( + &CGF.CGM.getModule(), ID, RetTy, ArgTys); + return CGF.EmitRuntimeCall(IntrFn, Args); +} + static Value *emitGetDimensions(CodeGenFunction &CGF, const CallExpr *E, unsigned IntrinsicID, unsigned NumRetComps, bool HasLod) { @@ -667,13 +680,13 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID, llvm::Type *RetTy = ConvertType(E->getType()); if (E->getNumArgs() <= 4) { - return Builder.CreateIntrinsic( - RetTy, CGM.getHLSLRuntime().getSampleIntrinsic(), Args); + return emitConvergentResourceIntrinsicCall( + *this, RetTy, CGM.getHLSLRuntime().getSampleIntrinsic(), Args); } Args.push_back(emitHlslClamp(*this, E, 4)); - return Builder.CreateIntrinsic( - RetTy, CGM.getHLSLRuntime().getSampleClampIntrinsic(), Args); + return emitConvergentResourceIntrinsicCall( + *this, RetTy, CGM.getHLSLRuntime().getSampleClampIntrinsic(), Args); } case Builtin::BI__builtin_hlsl_resource_sample_bias: { Value *HandleOp = EmitScalarExpr(E->getArg(0)); @@ -692,13 +705,14 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID, Args.push_back(emitHlslOffset(*this, E, 4, getOffsetType(CGM, RT))); llvm::Type *RetTy = ConvertType(E->getType()); - if (E->getNumArgs() <= 5) - return Builder.CreateIntrinsic( - RetTy, CGM.getHLSLRuntime().getSampleBiasIntrinsic(), Args); + if (E->getNumArgs() <= 5) { + return emitConvergentResourceIntrinsicCall( + *this, RetTy, CGM.getHLSLRuntime().getSampleBiasIntrinsic(), Args); + } Args.push_back(emitHlslClamp(*this, E, 5)); - return Builder.CreateIntrinsic( - RetTy, CGM.getHLSLRuntime().getSampleBiasClampIntrinsic(), Args); + return emitConvergentResourceIntrinsicCall( + *this, RetTy, CGM.getHLSLRuntime().getSampleBiasClampIntrinsic(), Args); } case Builtin::BI__builtin_hlsl_resource_sample_grad: { Value *HandleOp = EmitScalarExpr(E->getArg(0)); @@ -827,8 +841,8 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID, Value *SamplerOp = EmitScalarExpr(E->getArg(1)); Value *CoordOp = EmitScalarExpr(E->getArg(2)); - return Builder.CreateIntrinsic( - ConvertType(E->getType()), + return emitConvergentResourceIntrinsicCall( + *this, ConvertType(E->getType()), CGM.getHLSLRuntime().getCalculateLodIntrinsic(), {HandleOp, SamplerOp, CoordOp}); } @@ -837,8 +851,8 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID, Value *SamplerOp = EmitScalarExpr(E->getArg(1)); Value *CoordOp = EmitScalarExpr(E->getArg(2)); - return Builder.CreateIntrinsic( - ConvertType(E->getType()), + return emitConvergentResourceIntrinsicCall( + *this, ConvertType(E->getType()), CGM.getHLSLRuntime().getCalculateLodUnclampedIntrinsic(), {HandleOp, SamplerOp, CoordOp}); } diff --git a/llvm/include/llvm/IR/IntrinsicsSPIRV.td b/llvm/include/llvm/IR/IntrinsicsSPIRV.td index d948ef78b9584..b6debb2a0b74a 100644 --- a/llvm/include/llvm/IR/IntrinsicsSPIRV.td +++ b/llvm/include/llvm/IR/IntrinsicsSPIRV.td @@ -245,25 +245,25 @@ def int_spv_rsqrt : DefaultAttrsIntrinsic<[LLVMMatchType<0>], [llvm_anyfloat_ty] def int_spv_resource_sample : DefaultAttrsIntrinsic< [llvm_any_ty], [llvm_any_ty, llvm_any_ty, llvm_any_ty, llvm_any_ty], - [IntrReadMem]>; + [IntrReadMem, IntrConvergent]>; def int_spv_resource_sample_clamp : DefaultAttrsIntrinsic<[llvm_any_ty], [llvm_any_ty, llvm_any_ty, llvm_any_ty, llvm_any_ty, llvm_float_ty], - [IntrReadMem]>; + [IntrReadMem, IntrConvergent]>; def int_spv_resource_samplebias : DefaultAttrsIntrinsic<[llvm_any_ty], [llvm_any_ty, llvm_any_ty, llvm_any_ty, llvm_float_ty, llvm_any_ty], - [IntrReadMem]>; + [IntrReadMem, IntrConvergent]>; def int_spv_resource_samplebias_clamp : DefaultAttrsIntrinsic<[llvm_any_ty], [llvm_any_ty, llvm_any_ty, llvm_any_ty, llvm_float_ty, llvm_any_ty, llvm_float_ty], - [IntrReadMem]>; + [IntrReadMem, IntrConvergent]>; def int_spv_resource_samplegrad : DefaultAttrsIntrinsic<[llvm_any_ty], @@ -311,12 +311,12 @@ def int_spv_rsqrt : DefaultAttrsIntrinsic<[LLVMMatchType<0>], [llvm_anyfloat_ty] def int_spv_resource_calculate_lod : DefaultAttrsIntrinsic<[llvm_any_ty], [llvm_any_ty, llvm_any_ty, llvm_any_ty], - [IntrReadMem]>; + [IntrReadMem, IntrConvergent]>; def int_spv_resource_calculate_lod_unclamped : DefaultAttrsIntrinsic<[llvm_any_ty], [llvm_any_ty, llvm_any_ty, llvm_any_ty], - [IntrReadMem]>; + [IntrReadMem, IntrConvergent]>; def int_spv_resource_gather : DefaultAttrsIntrinsic<[llvm_any_ty], diff --git a/llvm/test/Assembler/spirv-resource-intrinsic-attributes.ll b/llvm/test/Assembler/spirv-resource-intrinsic-attributes.ll new file mode 100644 index 0000000000000..6cb690411d8b0 --- /dev/null +++ b/llvm/test/Assembler/spirv-resource-intrinsic-attributes.ll @@ -0,0 +1,29 @@ +; RUN: llvm-as < %s | llvm-dis | FileCheck %s + +; Verify SPIR-V resource intrinsics that use implicit derivatives are marked +; convergent so LLVM does not sink them into divergent control flow. + +; CHECK: declare float @llvm.spv.resource.calculate.lod.f32.{{.*}} [[CONVERGENT:#[0-9]+]] +declare float @llvm.spv.resource.calculate.lod.f32.tspirv.Image_f32_1_2_0_0_1_0t.tspirv.Samplert.v2f32(target("spirv.Image", float, 1, 2, 0, 0, 1, 0), target("spirv.Sampler"), <2 x float>) + +; CHECK: declare float @llvm.spv.resource.calculate.lod.unclamped.f32.{{.*}} [[CONVERGENT]] +declare float @llvm.spv.resource.calculate.lod.unclamped.f32.tspirv.Image_f32_1_2_0_0_1_0t.tspirv.Samplert.v2f32(target("spirv.Image", float, 1, 2, 0, 0, 1, 0), target("spirv.Sampler"), <2 x float>) + +; CHECK: declare <4 x float> @llvm.spv.resource.sample.v4f32.{{.*}} [[CONVERGENT]] +declare <4 x float> @llvm.spv.resource.sample.v4f32.tspirv.Image_f32_1_2_0_0_1_0t.tspirv.Samplert.v2f32.v2i32(target("spirv.Image", float, 1, 2, 0, 0, 1, 0), target("spirv.Sampler"), <2 x float>, <2 x i32>) + +; CHECK: declare <4 x float> @llvm.spv.resource.sample.clamp.v4f32.{{.*}} [[CONVERGENT]] +declare <4 x float> @llvm.spv.resource.sample.clamp.v4f32.tspirv.Image_f32_1_2_0_0_1_0t.tspirv.Samplert.v2f32.v2i32(target("spirv.Image", float, 1, 2, 0, 0, 1, 0), target("spirv.Sampler"), <2 x float>, <2 x i32>, float) + +; CHECK: declare <4 x float> @llvm.spv.resource.samplebias.v4f32.{{.*}} [[CONVERGENT]] +declare <4 x float> @llvm.spv.resource.samplebias.v4f32.tspirv.Image_f32_1_2_0_0_1_0t.tspirv.Samplert.v2f32.v2i32(target("spirv.Image", float, 1, 2, 0, 0, 1, 0), target("spirv.Sampler"), <2 x float>, float, <2 x i32>) + +; CHECK: declare <4 x float> @llvm.spv.resource.samplebias.clamp.v4f32.{{.*}} [[CONVERGENT]] +declare <4 x float> @llvm.spv.resource.samplebias.clamp.v4f32.tspirv.Image_f32_1_2_0_0_1_0t.tspirv.Samplert.v2f32.v2i32(target("spirv.Image", float, 1, 2, 0, 0, 1, 0), target("spirv.Sampler"), <2 x float>, float, <2 x i32>, float) + +; Explicit-derivative sampling should remain non-convergent. +; CHECK: declare <4 x float> @llvm.spv.resource.samplegrad.v4f32.{{.*}} [[NON_CONVERGENT:#[0-9]+]] +declare <4 x float> @llvm.spv.resource.samplegrad.v4f32.tspirv.Image_f32_1_2_0_0_1_0t.tspirv.Samplert.v3f32.v2f32.v2f32.v2i32(target("spirv.Image", float, 1, 2, 0, 0, 1, 0), target("spirv.Sampler"), <3 x float>, <2 x float>, <2 x float>, <2 x i32>) + +; CHECK: attributes [[CONVERGENT]] = { convergent nocallback nofree nosync nounwind willreturn memory(read) } +; CHECK: attributes [[NON_CONVERGENT]] = { nocallback nofree nosync nounwind willreturn memory(read) } diff --git a/llvm/unittests/IR/IntrinsicsTest.cpp b/llvm/unittests/IR/IntrinsicsTest.cpp index d502bf591b7fa..c2a9fc5316fff 100644 --- a/llvm/unittests/IR/IntrinsicsTest.cpp +++ b/llvm/unittests/IR/IntrinsicsTest.cpp @@ -23,6 +23,7 @@ #include "llvm/IR/IntrinsicsPowerPC.h" #include "llvm/IR/IntrinsicsRISCV.h" #include "llvm/IR/IntrinsicsS390.h" +#include "llvm/IR/IntrinsicsSPIRV.h" #include "llvm/IR/IntrinsicsX86.h" #include "llvm/IR/Module.h" #include "gtest/gtest.h" @@ -189,8 +190,31 @@ TEST_F(IntrinsicsTest, InstrProfInheritance) { } } +TEST(IntrinsicAttributes, SPIRVResourceImplicitDerivativeIntrinsicsAreConvergent) { + using namespace Intrinsic; + LLVMContext Context; + static constexpr ID ConvergentResourceIntrinsics[] = { + spv_resource_sample, + spv_resource_sample_clamp, + spv_resource_samplebias, + spv_resource_samplebias_clamp, + spv_resource_calculate_lod, + spv_resource_calculate_lod_unclamped, + }; + for (ID IntrID : ConvergentResourceIntrinsics) { + AttributeSet AS = getFnAttributes(Context, IntrID); + EXPECT_TRUE(AS.hasAttribute(Attribute::Convergent)) + << "Intrinsic " << getName(IntrID) << " should be convergent"; + } + + AttributeSet SampleGradAttrs = getFnAttributes(Context, spv_resource_samplegrad); + EXPECT_FALSE(SampleGradAttrs.hasAttribute(Attribute::Convergent)) + << "Intrinsic " << getName(spv_resource_samplegrad) + << " should not be convergent"; +} + // Check that getFnAttributes for intrinsics that do not have any function -// attributes correcty returns an empty set. +// attributes correctly returns an empty set. TEST(IntrinsicAttributes, TestGetFnAttributesBug) { using namespace Intrinsic; LLVMContext Context; >From 19e3b539dde0ff0c49b1bf5a3c0a51de1f35d464 Mon Sep 17 00:00:00 2001 From: Tim Corringham <[email protected]> Date: Wed, 22 Jul 2026 14:54:59 +0100 Subject: [PATCH 2/3] Fix clang-format errors Tidy up formatting errors - no functional change. --- clang/lib/CodeGen/CGHLSLBuiltins.cpp | 4 ++-- llvm/unittests/IR/IntrinsicsTest.cpp | 15 +++++++-------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/clang/lib/CodeGen/CGHLSLBuiltins.cpp b/clang/lib/CodeGen/CGHLSLBuiltins.cpp index 9cdf650f1d560..2187f9de315f2 100644 --- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp +++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp @@ -541,8 +541,8 @@ static CallInst *emitConvergentResourceIntrinsicCall(CodeGenFunction &CGF, ArgTys.reserve(Args.size()); for (Value *Arg : Args) ArgTys.push_back(Arg->getType()); - Function *IntrFn = Intrinsic::getOrInsertDeclaration( - &CGF.CGM.getModule(), ID, RetTy, ArgTys); + Function *IntrFn = Intrinsic::getOrInsertDeclaration(&CGF.CGM.getModule(), ID, + RetTy, ArgTys); return CGF.EmitRuntimeCall(IntrFn, Args); } diff --git a/llvm/unittests/IR/IntrinsicsTest.cpp b/llvm/unittests/IR/IntrinsicsTest.cpp index c2a9fc5316fff..003b9fd61ceaf 100644 --- a/llvm/unittests/IR/IntrinsicsTest.cpp +++ b/llvm/unittests/IR/IntrinsicsTest.cpp @@ -190,16 +190,14 @@ TEST_F(IntrinsicsTest, InstrProfInheritance) { } } -TEST(IntrinsicAttributes, SPIRVResourceImplicitDerivativeIntrinsicsAreConvergent) { +TEST(IntrinsicAttributes, + SPIRVResourceImplicitDerivativeIntrinsicsAreConvergent) { using namespace Intrinsic; LLVMContext Context; static constexpr ID ConvergentResourceIntrinsics[] = { - spv_resource_sample, - spv_resource_sample_clamp, - spv_resource_samplebias, - spv_resource_samplebias_clamp, - spv_resource_calculate_lod, - spv_resource_calculate_lod_unclamped, + spv_resource_sample, spv_resource_sample_clamp, + spv_resource_samplebias, spv_resource_samplebias_clamp, + spv_resource_calculate_lod, spv_resource_calculate_lod_unclamped, }; for (ID IntrID : ConvergentResourceIntrinsics) { AttributeSet AS = getFnAttributes(Context, IntrID); @@ -207,7 +205,8 @@ TEST(IntrinsicAttributes, SPIRVResourceImplicitDerivativeIntrinsicsAreConvergent << "Intrinsic " << getName(IntrID) << " should be convergent"; } - AttributeSet SampleGradAttrs = getFnAttributes(Context, spv_resource_samplegrad); + AttributeSet SampleGradAttrs = + getFnAttributes(Context, spv_resource_samplegrad); EXPECT_FALSE(SampleGradAttrs.hasAttribute(Attribute::Convergent)) << "Intrinsic " << getName(spv_resource_samplegrad) << " should not be convergent"; >From c092b71b89a30c4c4fb847ed3b60cbbea072edf6 Mon Sep 17 00:00:00 2001 From: Tim Corringham <[email protected]> Date: Mon, 27 Jul 2026 19:10:07 +0100 Subject: [PATCH 3/3] Add IntrConvergent to DirectX resource intrinsics Added IntrConvergent property to the DirextX intrinsics, and adjusted the test case accordingly. Renamed the helper function - a wider cleanup is debatable, and is left as a separate exercise. --- clang/lib/CodeGen/CGHLSLBuiltins.cpp | 19 +++--- llvm/include/llvm/IR/IntrinsicsDirectX.td | 12 ++-- .../resource-intrinsic-attributes.ll | 59 +++++++++++++++++++ .../spirv-resource-intrinsic-attributes.ll | 29 --------- 4 files changed, 74 insertions(+), 45 deletions(-) create mode 100644 llvm/test/Assembler/resource-intrinsic-attributes.ll delete mode 100644 llvm/test/Assembler/spirv-resource-intrinsic-attributes.ll diff --git a/clang/lib/CodeGen/CGHLSLBuiltins.cpp b/clang/lib/CodeGen/CGHLSLBuiltins.cpp index 2187f9de315f2..d6df16d65e550 100644 --- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp +++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp @@ -533,10 +533,9 @@ static Value *emitHlslClamp(CodeGenFunction &CGF, const CallExpr *E, return Clamp; } -static CallInst *emitConvergentResourceIntrinsicCall(CodeGenFunction &CGF, - llvm::Type *RetTy, - Intrinsic::ID ID, - ArrayRef<Value *> Args) { +static CallInst *emitResourceIntrinsic(CodeGenFunction &CGF, llvm::Type *RetTy, + Intrinsic::ID ID, + ArrayRef<Value *> Args) { SmallVector<llvm::Type *> ArgTys; ArgTys.reserve(Args.size()); for (Value *Arg : Args) @@ -680,12 +679,12 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID, llvm::Type *RetTy = ConvertType(E->getType()); if (E->getNumArgs() <= 4) { - return emitConvergentResourceIntrinsicCall( + return emitResourceIntrinsic( *this, RetTy, CGM.getHLSLRuntime().getSampleIntrinsic(), Args); } Args.push_back(emitHlslClamp(*this, E, 4)); - return emitConvergentResourceIntrinsicCall( + return emitResourceIntrinsic( *this, RetTy, CGM.getHLSLRuntime().getSampleClampIntrinsic(), Args); } case Builtin::BI__builtin_hlsl_resource_sample_bias: { @@ -706,12 +705,12 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID, llvm::Type *RetTy = ConvertType(E->getType()); if (E->getNumArgs() <= 5) { - return emitConvergentResourceIntrinsicCall( + return emitResourceIntrinsic( *this, RetTy, CGM.getHLSLRuntime().getSampleBiasIntrinsic(), Args); } Args.push_back(emitHlslClamp(*this, E, 5)); - return emitConvergentResourceIntrinsicCall( + return emitResourceIntrinsic( *this, RetTy, CGM.getHLSLRuntime().getSampleBiasClampIntrinsic(), Args); } case Builtin::BI__builtin_hlsl_resource_sample_grad: { @@ -841,7 +840,7 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID, Value *SamplerOp = EmitScalarExpr(E->getArg(1)); Value *CoordOp = EmitScalarExpr(E->getArg(2)); - return emitConvergentResourceIntrinsicCall( + return emitResourceIntrinsic( *this, ConvertType(E->getType()), CGM.getHLSLRuntime().getCalculateLodIntrinsic(), {HandleOp, SamplerOp, CoordOp}); @@ -851,7 +850,7 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID, Value *SamplerOp = EmitScalarExpr(E->getArg(1)); Value *CoordOp = EmitScalarExpr(E->getArg(2)); - return emitConvergentResourceIntrinsicCall( + return emitResourceIntrinsic( *this, ConvertType(E->getType()), CGM.getHLSLRuntime().getCalculateLodUnclampedIntrinsic(), {HandleOp, SamplerOp, CoordOp}); diff --git a/llvm/include/llvm/IR/IntrinsicsDirectX.td b/llvm/include/llvm/IR/IntrinsicsDirectX.td index 4dd86270f0d01..2b155701564f7 100644 --- a/llvm/include/llvm/IR/IntrinsicsDirectX.td +++ b/llvm/include/llvm/IR/IntrinsicsDirectX.td @@ -91,24 +91,24 @@ def int_dx_resource_getdimensions_levels_xy def int_dx_resource_sample : DefaultAttrsIntrinsic< [llvm_any_ty], [llvm_any_ty, llvm_any_ty, llvm_any_ty, llvm_any_ty], - [IntrReadMem]>; + [IntrReadMem, IntrConvergent]>; def int_dx_resource_sample_clamp : DefaultAttrsIntrinsic<[llvm_any_ty], [llvm_any_ty, llvm_any_ty, llvm_any_ty, llvm_any_ty, llvm_float_ty], - [IntrReadMem]>; + [IntrReadMem, IntrConvergent]>; def int_dx_resource_samplebias : DefaultAttrsIntrinsic<[llvm_any_ty], [llvm_any_ty, llvm_any_ty, llvm_any_ty, llvm_float_ty, llvm_any_ty], - [IntrReadMem]>; + [IntrReadMem, IntrConvergent]>; def int_dx_resource_samplebias_clamp : DefaultAttrsIntrinsic<[llvm_any_ty], [llvm_any_ty, llvm_any_ty, llvm_any_ty, llvm_float_ty, llvm_any_ty, llvm_float_ty], - [IntrReadMem]>; + [IntrReadMem, IntrConvergent]>; def int_dx_resource_samplegrad : DefaultAttrsIntrinsic<[llvm_any_ty], @@ -137,12 +137,12 @@ def int_dx_resource_load_level def int_dx_resource_calculate_lod : DefaultAttrsIntrinsic<[llvm_float_ty], [llvm_any_ty, llvm_any_ty, llvm_any_ty], - [IntrReadMem]>; + [IntrReadMem, IntrConvergent]>; def int_dx_resource_calculate_lod_unclamped : DefaultAttrsIntrinsic<[llvm_float_ty], [llvm_any_ty, llvm_any_ty, llvm_any_ty], - [IntrReadMem]>; + [IntrReadMem, IntrConvergent]>; def int_dx_resource_samplecmp : DefaultAttrsIntrinsic<[llvm_any_ty], diff --git a/llvm/test/Assembler/resource-intrinsic-attributes.ll b/llvm/test/Assembler/resource-intrinsic-attributes.ll new file mode 100644 index 0000000000000..6bb1fac70e4c5 --- /dev/null +++ b/llvm/test/Assembler/resource-intrinsic-attributes.ll @@ -0,0 +1,59 @@ +; RUN: llvm-as < %s | llvm-dis | FileCheck %s + +; Verify both DirectX and SPIR-V resource intrinsics that use implicit +; derivatives are marked convergent so LLVM does not sink them into +; divergent control flow. + +; CHECK: declare float @llvm.dx.resource.calculate.lod.{{.*}} [[CONVERGENT:#[0-9]+]] +declare float @llvm.dx.resource.calculate.lod.tdx.Texture_v4f32_0_0_0_2t.tdx.Sampler_0t.v2f32(target("dx.Texture", <4 x float>, 0, 0, 0, 2), target("dx.Sampler", 0), <2 x float>) + +; CHECK: declare float @llvm.dx.resource.calculate.lod.unclamped.{{.*}} [[CONVERGENT]] +declare float @llvm.dx.resource.calculate.lod.unclamped.tdx.Texture_v4f32_0_0_0_2t.tdx.Sampler_0t.v2f32(target("dx.Texture", <4 x float>, 0, 0, 0, 2), target("dx.Sampler", 0), <2 x float>) + +; CHECK: declare ptr @llvm.dx.resource.getpointer.p0.{{.*}} [[CONVERGENT_NO_MEM:#[0-9]+]] +declare ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i32_1_0t.i32(target("dx.RawBuffer", i32, 1, 0), i32) + +; CHECK: declare ptr @llvm.dx.resource.getbasepointer.p0.{{.*}} [[CONVERGENT_NO_MEM]] +declare ptr @llvm.dx.resource.getbasepointer.p0.tdx.RawBuffer_i32_1_0t(target("dx.RawBuffer", i32, 1, 0)) + +; CHECK: declare <4 x float> @llvm.dx.resource.sample.v4f32.{{.*}} [[CONVERGENT]] +declare <4 x float> @llvm.dx.resource.sample.v4f32.tdx.Texture_v4f32_0_0_0_2t.tdx.Sampler_0t.v2f32.v2i32(target("dx.Texture", <4 x float>, 0, 0, 0, 2), target("dx.Sampler", 0), <2 x float>, <2 x i32>) + +; CHECK: declare <4 x float> @llvm.dx.resource.sample.clamp.v4f32.{{.*}} [[CONVERGENT]] +declare <4 x float> @llvm.dx.resource.sample.clamp.v4f32.tdx.Texture_v4f32_0_0_0_2t.tdx.Sampler_0t.v2f32.v2i32(target("dx.Texture", <4 x float>, 0, 0, 0, 2), target("dx.Sampler", 0), <2 x float>, <2 x i32>, float) + +; CHECK: declare <4 x float> @llvm.dx.resource.samplebias.v4f32.{{.*}} [[CONVERGENT]] +declare <4 x float> @llvm.dx.resource.samplebias.v4f32.tdx.Texture_v4f32_0_0_0_2t.tdx.Sampler_0t.v2f32.v2i32(target("dx.Texture", <4 x float>, 0, 0, 0, 2), target("dx.Sampler", 0), <2 x float>, float, <2 x i32>) + +; CHECK: declare <4 x float> @llvm.dx.resource.samplebias.clamp.v4f32.{{.*}} [[CONVERGENT]] +declare <4 x float> @llvm.dx.resource.samplebias.clamp.v4f32.tdx.Texture_v4f32_0_0_0_2t.tdx.Sampler_0t.v2f32.v2i32(target("dx.Texture", <4 x float>, 0, 0, 0, 2), target("dx.Sampler", 0), <2 x float>, float, <2 x i32>, float) + +; Explicit-derivative sampling should remain non-convergent. +; CHECK: declare <4 x float> @llvm.dx.resource.samplegrad.v4f32.{{.*}} [[NON_CONVERGENT:#[0-9]+]] +declare <4 x float> @llvm.dx.resource.samplegrad.v4f32.tdx.Texture_v4f32_0_0_0_2t.tdx.Sampler_0t.v2f32.v2f32.v2f32.v2i32(target("dx.Texture", <4 x float>, 0, 0, 0, 2), target("dx.Sampler", 0), <2 x float>, <2 x float>, <2 x float>, <2 x i32>) + +; CHECK: declare float @llvm.spv.resource.calculate.lod.f32.{{.*}} [[CONVERGENT]] +declare float @llvm.spv.resource.calculate.lod.f32.tspirv.Image_f32_1_2_0_0_1_0t.tspirv.Samplert.v2f32(target("spirv.Image", float, 1, 2, 0, 0, 1, 0), target("spirv.Sampler"), <2 x float>) + +; CHECK: declare float @llvm.spv.resource.calculate.lod.unclamped.f32.{{.*}} [[CONVERGENT]] +declare float @llvm.spv.resource.calculate.lod.unclamped.f32.tspirv.Image_f32_1_2_0_0_1_0t.tspirv.Samplert.v2f32(target("spirv.Image", float, 1, 2, 0, 0, 1, 0), target("spirv.Sampler"), <2 x float>) + +; CHECK: declare <4 x float> @llvm.spv.resource.sample.v4f32.{{.*}} [[CONVERGENT]] +declare <4 x float> @llvm.spv.resource.sample.v4f32.tspirv.Image_f32_1_2_0_0_1_0t.tspirv.Samplert.v2f32.v2i32(target("spirv.Image", float, 1, 2, 0, 0, 1, 0), target("spirv.Sampler"), <2 x float>, <2 x i32>) + +; CHECK: declare <4 x float> @llvm.spv.resource.sample.clamp.v4f32.{{.*}} [[CONVERGENT]] +declare <4 x float> @llvm.spv.resource.sample.clamp.v4f32.tspirv.Image_f32_1_2_0_0_1_0t.tspirv.Samplert.v2f32.v2i32(target("spirv.Image", float, 1, 2, 0, 0, 1, 0), target("spirv.Sampler"), <2 x float>, <2 x i32>, float) + +; CHECK: declare <4 x float> @llvm.spv.resource.samplebias.v4f32.{{.*}} [[CONVERGENT]] +declare <4 x float> @llvm.spv.resource.samplebias.v4f32.tspirv.Image_f32_1_2_0_0_1_0t.tspirv.Samplert.v2f32.v2i32(target("spirv.Image", float, 1, 2, 0, 0, 1, 0), target("spirv.Sampler"), <2 x float>, float, <2 x i32>) + +; CHECK: declare <4 x float> @llvm.spv.resource.samplebias.clamp.v4f32.{{.*}} [[CONVERGENT]] +declare <4 x float> @llvm.spv.resource.samplebias.clamp.v4f32.tspirv.Image_f32_1_2_0_0_1_0t.tspirv.Samplert.v2f32.v2i32(target("spirv.Image", float, 1, 2, 0, 0, 1, 0), target("spirv.Sampler"), <2 x float>, float, <2 x i32>, float) + +; Explicit-derivative sampling should remain non-convergent. +; CHECK: declare <4 x float> @llvm.spv.resource.samplegrad.v4f32.{{.*}} [[NON_CONVERGENT]] +declare <4 x float> @llvm.spv.resource.samplegrad.v4f32.tspirv.Image_f32_1_2_0_0_1_0t.tspirv.Samplert.v3f32.v2f32.v2f32.v2i32(target("spirv.Image", float, 1, 2, 0, 0, 1, 0), target("spirv.Sampler"), <3 x float>, <2 x float>, <2 x float>, <2 x i32>) + +; CHECK: attributes [[CONVERGENT]] = { convergent nocallback nofree nosync nounwind willreturn memory(read) } +; CHECK: attributes [[CONVERGENT_NO_MEM]] = { convergent nocallback nofree nosync nounwind willreturn memory(none) } +; CHECK: attributes [[NON_CONVERGENT]] = { nocallback nofree nosync nounwind willreturn memory(read) } diff --git a/llvm/test/Assembler/spirv-resource-intrinsic-attributes.ll b/llvm/test/Assembler/spirv-resource-intrinsic-attributes.ll deleted file mode 100644 index 6cb690411d8b0..0000000000000 --- a/llvm/test/Assembler/spirv-resource-intrinsic-attributes.ll +++ /dev/null @@ -1,29 +0,0 @@ -; RUN: llvm-as < %s | llvm-dis | FileCheck %s - -; Verify SPIR-V resource intrinsics that use implicit derivatives are marked -; convergent so LLVM does not sink them into divergent control flow. - -; CHECK: declare float @llvm.spv.resource.calculate.lod.f32.{{.*}} [[CONVERGENT:#[0-9]+]] -declare float @llvm.spv.resource.calculate.lod.f32.tspirv.Image_f32_1_2_0_0_1_0t.tspirv.Samplert.v2f32(target("spirv.Image", float, 1, 2, 0, 0, 1, 0), target("spirv.Sampler"), <2 x float>) - -; CHECK: declare float @llvm.spv.resource.calculate.lod.unclamped.f32.{{.*}} [[CONVERGENT]] -declare float @llvm.spv.resource.calculate.lod.unclamped.f32.tspirv.Image_f32_1_2_0_0_1_0t.tspirv.Samplert.v2f32(target("spirv.Image", float, 1, 2, 0, 0, 1, 0), target("spirv.Sampler"), <2 x float>) - -; CHECK: declare <4 x float> @llvm.spv.resource.sample.v4f32.{{.*}} [[CONVERGENT]] -declare <4 x float> @llvm.spv.resource.sample.v4f32.tspirv.Image_f32_1_2_0_0_1_0t.tspirv.Samplert.v2f32.v2i32(target("spirv.Image", float, 1, 2, 0, 0, 1, 0), target("spirv.Sampler"), <2 x float>, <2 x i32>) - -; CHECK: declare <4 x float> @llvm.spv.resource.sample.clamp.v4f32.{{.*}} [[CONVERGENT]] -declare <4 x float> @llvm.spv.resource.sample.clamp.v4f32.tspirv.Image_f32_1_2_0_0_1_0t.tspirv.Samplert.v2f32.v2i32(target("spirv.Image", float, 1, 2, 0, 0, 1, 0), target("spirv.Sampler"), <2 x float>, <2 x i32>, float) - -; CHECK: declare <4 x float> @llvm.spv.resource.samplebias.v4f32.{{.*}} [[CONVERGENT]] -declare <4 x float> @llvm.spv.resource.samplebias.v4f32.tspirv.Image_f32_1_2_0_0_1_0t.tspirv.Samplert.v2f32.v2i32(target("spirv.Image", float, 1, 2, 0, 0, 1, 0), target("spirv.Sampler"), <2 x float>, float, <2 x i32>) - -; CHECK: declare <4 x float> @llvm.spv.resource.samplebias.clamp.v4f32.{{.*}} [[CONVERGENT]] -declare <4 x float> @llvm.spv.resource.samplebias.clamp.v4f32.tspirv.Image_f32_1_2_0_0_1_0t.tspirv.Samplert.v2f32.v2i32(target("spirv.Image", float, 1, 2, 0, 0, 1, 0), target("spirv.Sampler"), <2 x float>, float, <2 x i32>, float) - -; Explicit-derivative sampling should remain non-convergent. -; CHECK: declare <4 x float> @llvm.spv.resource.samplegrad.v4f32.{{.*}} [[NON_CONVERGENT:#[0-9]+]] -declare <4 x float> @llvm.spv.resource.samplegrad.v4f32.tspirv.Image_f32_1_2_0_0_1_0t.tspirv.Samplert.v3f32.v2f32.v2f32.v2i32(target("spirv.Image", float, 1, 2, 0, 0, 1, 0), target("spirv.Sampler"), <3 x float>, <2 x float>, <2 x float>, <2 x i32>) - -; CHECK: attributes [[CONVERGENT]] = { convergent nocallback nofree nosync nounwind willreturn memory(read) } -; CHECK: attributes [[NON_CONVERGENT]] = { nocallback nofree nosync nounwind willreturn memory(read) } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
