[clang] [llvm] [IR] Mark convergence intrins as has-side-effect (PR #134844)
Nathan Gauër via llvm-commits
llvm-commits at lists.llvm.org
Tue Apr 8 04:46:23 PDT 2025
https://github.com/Keenuts created https://github.com/llvm/llvm-project/pull/134844
When a callee is marked as `convergent`, some targets like HLSL/SPIR-V add a convergent token to the call.
This is valid if both functions are marked as `convergent`.
ADCE/BDCE and other DCE passes were allowed to remove convergence intrinsics when their token were unused.
This meant a leaf function could lose all its convergence intrinsics. This would allow further optimization to remove the `convergent` attribute from the callee.
Issue was the caller was not updated, and we now had a convergence token attached to a call function calling a non-convergent function.
This can be solved in different ways:
- modify DCE passes to keep calls marked as convergent.
- add a 'hasSideEffect' to the intrinsics definition, preventing DCE to remove the intrinsic.
- fix optimization passed removing the attribute by also removing the tokens from the call.
I picked the second option: mark those as `hasSideEffects`, because convergence intrinsics presence impact the divergence/reconvergence location of the IR, hence their simple presence has an implicit meaning. This is particularly important for SPIR-V as the control flow shape will depend on the presence of those intrinsics.
An alternative I could agree to modifying each pass to keep the convergence intrinsics. After all, they are important, but the widening the 'hadSideEffect' meaning could be discussed.
I however would be against the 3rd solution: SPIR-V benefits greatly from the convergence intrinsics presence to correctly structurize loops.
>From b2dbe55df7cb7e9958f7e836c35136751736650a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= <brioche at google.com>
Date: Mon, 7 Apr 2025 17:39:10 +0200
Subject: [PATCH] [IR] Mark convergence intrins as has-side-effect
When a callee is marked as `convergent`, some targets like HLSL/SPIR-V
add a convergent token to the call.
This is valid if both functions are marked as `convergent`.
ADCE/BDCE and other DCE passes were allowed to remove convergence
intrinsics when their token were unused.
This meant a leaf function could lose all its convergence intrinsics.
This would allow further optimization to remove the `convergent`
attribute from the callee.
Issue was the caller was not updated, and we now had a convergence token
attached to a call function calling a non-convergent function.
This can be solved in different ways:
- modify DCE passes to keep calls marked as convergent.
- add a 'hasSideEffect' to the intrinsics definition, preventing DCE to
remove the intrinsic.
- fix optimization passed removing the attribute by also removing the
tokens from the call.
I picked the second option: mark those as `hasSideEffects`, because
convergence intrinsics presence impact the divergence/reconvergence
location of the IR, hence their simple presence has an implicit meaning.
This is particularly important for SPIR-V as the control flow shape will
depend on the presence of those intrinsics.
An alternative I could agree to modifying each pass to keep the
convergence intrinsics. After all, they are important, but the widening
the 'hadSideEffect' meaning could be discussed.
I however would be against the 3rd solution: SPIR-V benefits greatly
from the convergence intrinsics presence to correctly structurize loops.
---
.../builtins/RWBuffer-constructor-opt.hlsl | 3 +-
clang/test/CodeGenHLSL/builtins/distance.hlsl | 8 ++++
clang/test/CodeGenHLSL/builtins/length.hlsl | 8 ++++
clang/test/CodeGenHLSL/builtins/reflect.hlsl | 8 ++++
.../test/CodeGenHLSL/builtins/smoothstep.hlsl | 8 ++++
clang/test/CodeGenSPIRV/Builtins/distance.c | 3 ++
clang/test/CodeGenSPIRV/Builtins/length.c | 3 ++
clang/test/CodeGenSPIRV/Builtins/reflect.c | 3 ++
clang/test/CodeGenSPIRV/Builtins/smoothstep.c | 4 ++
llvm/include/llvm/IR/Intrinsics.td | 9 ++--
llvm/test/Transforms/ADCE/convergence.ll | 46 ++++++++++++++++++
llvm/test/Transforms/BDCE/convergence.ll | 47 +++++++++++++++++++
llvm/test/Transforms/DCE/op_bundles.ll | 1 +
.../Transforms/FunctionAttrs/convergent.ll | 16 ++++++-
.../regression-convergence-tokens.ll | 8 ++--
.../LoopUnroll/convergent.controlled.ll | 8 ++++
16 files changed, 174 insertions(+), 9 deletions(-)
create mode 100644 llvm/test/Transforms/ADCE/convergence.ll
create mode 100644 llvm/test/Transforms/BDCE/convergence.ll
diff --git a/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor-opt.hlsl b/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor-opt.hlsl
index 56c523f6bc8cf..25062b8537aca 100644
--- a/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor-opt.hlsl
+++ b/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor-opt.hlsl
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -O3 -o - %s | FileCheck %s
-// RUN: %clang_cc1 -triple spirv-vulkan-compute -x hlsl -emit-llvm -O3 -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple spirv-vulkan-compute -x hlsl -emit-llvm -O3 -o - %s | FileCheck %s --check-prefixes=CHECK,SPIRV
// All referenced to an unused resource should be removed by optimizations.
RWBuffer<float> Buf : register(u5, space3);
@@ -10,6 +10,7 @@ void main() {
// CHECK-NOT: resource.handlefrombinding
// CHECK: define void @main()
// CHECK-NEXT: entry:
+// SPIRV-NEXT: %0 = tail call token @llvm.experimental.convergence.entry()
// CHECK-NEXT: ret void
// CHECK-NOT: resource.handlefrombinding
}
diff --git a/clang/test/CodeGenHLSL/builtins/distance.hlsl b/clang/test/CodeGenHLSL/builtins/distance.hlsl
index e830903261c8c..1d8f986bd12eb 100644
--- a/clang/test/CodeGenHLSL/builtins/distance.hlsl
+++ b/clang/test/CodeGenHLSL/builtins/distance.hlsl
@@ -16,6 +16,7 @@
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) half @_Z18test_distance_halfDhDh(
// SPVCHECK-SAME: half noundef nofpclass(nan inf) [[X:%.*]], half noundef nofpclass(nan inf) [[Y:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: {{.*}} = tail call token @llvm.experimental.convergence.entry()
// SPVCHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn half [[X]], [[Y]]
// SPVCHECK-NEXT: [[ELT_ABS_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef half @llvm.fabs.f16(half [[SUB_I]])
// SPVCHECK-NEXT: ret half [[ELT_ABS_I]]
@@ -33,6 +34,7 @@ half test_distance_half(half X, half Y) { return distance(X, Y); }
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) half @_Z19test_distance_half2Dv2_DhS_(
// SPVCHECK-SAME: <2 x half> noundef nofpclass(nan inf) [[X:%.*]], <2 x half> noundef nofpclass(nan inf) [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: {{.*}} = tail call token @llvm.experimental.convergence.entry()
// SPVCHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <2 x half> [[X]], [[Y]]
// SPVCHECK-NEXT: [[SPV_LENGTH_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef half @llvm.spv.length.v2f16(<2 x half> [[SUB_I]])
// SPVCHECK-NEXT: ret half [[SPV_LENGTH_I]]
@@ -50,6 +52,7 @@ half test_distance_half2(half2 X, half2 Y) { return distance(X, Y); }
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) half @_Z19test_distance_half3Dv3_DhS_(
// SPVCHECK-SAME: <3 x half> noundef nofpclass(nan inf) [[X:%.*]], <3 x half> noundef nofpclass(nan inf) [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: {{.*}} = tail call token @llvm.experimental.convergence.entry()
// SPVCHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <3 x half> [[X]], [[Y]]
// SPVCHECK-NEXT: [[SPV_LENGTH_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef half @llvm.spv.length.v3f16(<3 x half> [[SUB_I]])
// SPVCHECK-NEXT: ret half [[SPV_LENGTH_I]]
@@ -67,6 +70,7 @@ half test_distance_half3(half3 X, half3 Y) { return distance(X, Y); }
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) half @_Z19test_distance_half4Dv4_DhS_(
// SPVCHECK-SAME: <4 x half> noundef nofpclass(nan inf) [[X:%.*]], <4 x half> noundef nofpclass(nan inf) [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: {{.*}} = tail call token @llvm.experimental.convergence.entry()
// SPVCHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <4 x half> [[X]], [[Y]]
// SPVCHECK-NEXT: [[SPV_LENGTH_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef half @llvm.spv.length.v4f16(<4 x half> [[SUB_I]])
// SPVCHECK-NEXT: ret half [[SPV_LENGTH_I]]
@@ -83,6 +87,7 @@ half test_distance_half4(half4 X, half4 Y) { return distance(X, Y); }
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) float @_Z19test_distance_floatff(
// SPVCHECK-SAME: float noundef nofpclass(nan inf) [[X:%.*]], float noundef nofpclass(nan inf) [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: {{.*}} = tail call token @llvm.experimental.convergence.entry()
// SPVCHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn float [[X]], [[Y]]
// SPVCHECK-NEXT: [[ELT_ABS_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef float @llvm.fabs.f32(float [[SUB_I]])
// SPVCHECK-NEXT: ret float [[ELT_ABS_I]]
@@ -100,6 +105,7 @@ float test_distance_float(float X, float Y) { return distance(X, Y); }
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) float @_Z20test_distance_float2Dv2_fS_(
// SPVCHECK-SAME: <2 x float> noundef nofpclass(nan inf) [[X:%.*]], <2 x float> noundef nofpclass(nan inf) [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: {{.*}} = tail call token @llvm.experimental.convergence.entry()
// SPVCHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <2 x float> [[X]], [[Y]]
// SPVCHECK-NEXT: [[SPV_LENGTH_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef float @llvm.spv.length.v2f32(<2 x float> [[SUB_I]])
// SPVCHECK-NEXT: ret float [[SPV_LENGTH_I]]
@@ -117,6 +123,7 @@ float test_distance_float2(float2 X, float2 Y) { return distance(X, Y); }
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) float @_Z20test_distance_float3Dv3_fS_(
// SPVCHECK-SAME: <3 x float> noundef nofpclass(nan inf) [[X:%.*]], <3 x float> noundef nofpclass(nan inf) [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: {{.*}} = tail call token @llvm.experimental.convergence.entry()
// SPVCHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <3 x float> [[X]], [[Y]]
// SPVCHECK-NEXT: [[SPV_LENGTH_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef float @llvm.spv.length.v3f32(<3 x float> [[SUB_I]])
// SPVCHECK-NEXT: ret float [[SPV_LENGTH_I]]
@@ -134,6 +141,7 @@ float test_distance_float3(float3 X, float3 Y) { return distance(X, Y); }
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) float @_Z20test_distance_float4Dv4_fS_(
// SPVCHECK-SAME: <4 x float> noundef nofpclass(nan inf) [[X:%.*]], <4 x float> noundef nofpclass(nan inf) [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: {{.*}} = tail call token @llvm.experimental.convergence.entry()
// SPVCHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <4 x float> [[X]], [[Y]]
// SPVCHECK-NEXT: [[SPV_LENGTH_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef float @llvm.spv.length.v4f32(<4 x float> [[SUB_I]])
// SPVCHECK-NEXT: ret float [[SPV_LENGTH_I]]
diff --git a/clang/test/CodeGenHLSL/builtins/length.hlsl b/clang/test/CodeGenHLSL/builtins/length.hlsl
index 2d4bbd995298f..9597d33f70d62 100644
--- a/clang/test/CodeGenHLSL/builtins/length.hlsl
+++ b/clang/test/CodeGenHLSL/builtins/length.hlsl
@@ -20,6 +20,7 @@
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) half @_Z16test_length_halfDh(
// SPVCHECK-SAME: half noundef nofpclass(nan inf) [[P0:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: {{.*}} = tail call token @llvm.experimental.convergence.entry()
// SPVCHECK-NEXT: [[ELT_ABS_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef half @llvm.fabs.f16(half [[P0]])
// SPVCHECK-NEXT: ret half [[ELT_ABS_I]]
//
@@ -42,6 +43,7 @@ half test_length_half(half p0)
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) half @_Z17test_length_half2Dv2_Dh(
// SPVCHECK-SAME: <2 x half> noundef nofpclass(nan inf) [[P0:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: {{.*}} = tail call token @llvm.experimental.convergence.entry()
// SPVCHECK-NEXT: [[SPV_LENGTH_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef half @llvm.spv.length.v2f16(<2 x half> [[P0]])
// SPVCHECK-NEXT: ret half [[SPV_LENGTH_I]]
//
@@ -61,6 +63,7 @@ half test_length_half2(half2 p0)
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) half @_Z17test_length_half3Dv3_Dh(
// SPVCHECK-SAME: <3 x half> noundef nofpclass(nan inf) [[P0:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: {{.*}} = tail call token @llvm.experimental.convergence.entry()
// SPVCHECK-NEXT: [[SPV_LENGTH_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef half @llvm.spv.length.v3f16(<3 x half> [[P0]])
// SPVCHECK-NEXT: ret half [[SPV_LENGTH_I]]
//
@@ -80,6 +83,7 @@ half test_length_half3(half3 p0)
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) half @_Z17test_length_half4Dv4_Dh(
// SPVCHECK-SAME: <4 x half> noundef nofpclass(nan inf) [[P0:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: {{.*}} = tail call token @llvm.experimental.convergence.entry()
// SPVCHECK-NEXT: [[SPV_LENGTH_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef half @llvm.spv.length.v4f16(<4 x half> [[P0]])
// SPVCHECK-NEXT: ret half [[SPV_LENGTH_I]]
//
@@ -98,6 +102,7 @@ half test_length_half4(half4 p0)
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) float @_Z17test_length_floatf(
// SPVCHECK-SAME: float noundef nofpclass(nan inf) [[P0:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: {{.*}} = tail call token @llvm.experimental.convergence.entry()
// SPVCHECK-NEXT: [[ELT_ABS_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef float @llvm.fabs.f32(float [[P0]])
// SPVCHECK-NEXT: ret float [[ELT_ABS_I]]
//
@@ -117,6 +122,7 @@ float test_length_float(float p0)
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) float @_Z18test_length_float2Dv2_f(
// SPVCHECK-SAME: <2 x float> noundef nofpclass(nan inf) [[P0:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: {{.*}} = tail call token @llvm.experimental.convergence.entry()
// SPVCHECK-NEXT: [[SPV_LENGTH_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef float @llvm.spv.length.v2f32(<2 x float> [[P0]])
// SPVCHECK-NEXT: ret float [[SPV_LENGTH_I]]
//
@@ -136,6 +142,7 @@ float test_length_float2(float2 p0)
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) float @_Z18test_length_float3Dv3_f(
// SPVCHECK-SAME: <3 x float> noundef nofpclass(nan inf) [[P0:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: {{.*}} = tail call token @llvm.experimental.convergence.entry()
// SPVCHECK-NEXT: [[SPV_LENGTH_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef float @llvm.spv.length.v3f32(<3 x float> [[P0]])
// SPVCHECK-NEXT: ret float [[SPV_LENGTH_I]]
//
@@ -155,6 +162,7 @@ float test_length_float3(float3 p0)
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) float @_Z18test_length_float4Dv4_f(
// SPVCHECK-SAME: <4 x float> noundef nofpclass(nan inf) [[P0:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: {{.*}} = tail call token @llvm.experimental.convergence.entry()
// SPVCHECK-NEXT: [[SPV_LENGTH_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef float @llvm.spv.length.v4f32(<4 x float> [[P0]])
// SPVCHECK-NEXT: ret float [[SPV_LENGTH_I]]
//
diff --git a/clang/test/CodeGenHLSL/builtins/reflect.hlsl b/clang/test/CodeGenHLSL/builtins/reflect.hlsl
index 35ee059697c4b..3f1f653e0f0f9 100644
--- a/clang/test/CodeGenHLSL/builtins/reflect.hlsl
+++ b/clang/test/CodeGenHLSL/builtins/reflect.hlsl
@@ -18,6 +18,7 @@
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) half @_Z17test_reflect_halfDhDh(
// SPVCHECK-SAME: half noundef nofpclass(nan inf) [[I:%.*]], half noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: {{.*}} = tail call token @llvm.experimental.convergence.entry()
// SPVCHECK-NEXT: [[MUL_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[I]], 0xH4000
// SPVCHECK-NEXT: [[TMP0:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[N]], [[N]]
// SPVCHECK-NEXT: [[MUL2_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[TMP0]], [[MUL_I]]
@@ -42,6 +43,7 @@ half test_reflect_half(half I, half N) {
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <2 x half> @_Z18test_reflect_half2Dv2_DhS_(
// SPVCHECK-SAME: <2 x half> noundef nofpclass(nan inf) [[I:%.*]], <2 x half> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: {{.*}} = tail call token @llvm.experimental.convergence.entry()
// SPVCHECK-NEXT: [[SPV_REFLECT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef <2 x half> @llvm.spv.reflect.v2f16(<2 x half> [[I]], <2 x half> [[N]])
// SPVCHECK-NEXT: ret <2 x half> [[SPV_REFLECT_I]]
//
@@ -63,6 +65,7 @@ half2 test_reflect_half2(half2 I, half2 N) {
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <3 x half> @_Z18test_reflect_half3Dv3_DhS_(
// SPVCHECK-SAME: <3 x half> noundef nofpclass(nan inf) [[I:%.*]], <3 x half> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: {{.*}} = tail call token @llvm.experimental.convergence.entry()
// SPVCHECK-NEXT: [[SPV_REFLECT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef <3 x half> @llvm.spv.reflect.v3f16(<3 x half> [[I]], <3 x half> [[N]])
// SPVCHECK-NEXT: ret <3 x half> [[SPV_REFLECT_I]]
//
@@ -84,6 +87,7 @@ half3 test_reflect_half3(half3 I, half3 N) {
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <4 x half> @_Z18test_reflect_half4Dv4_DhS_(
// SPVCHECK-SAME: <4 x half> noundef nofpclass(nan inf) [[I:%.*]], <4 x half> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: {{.*}} = tail call token @llvm.experimental.convergence.entry()
// SPVCHECK-NEXT: [[SPV_REFLECT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef <4 x half> @llvm.spv.reflect.v4f16(<4 x half> [[I]], <4 x half> [[N]])
// SPVCHECK-NEXT: ret <4 x half> [[SPV_REFLECT_I]]
//
@@ -103,6 +107,7 @@ half4 test_reflect_half4(half4 I, half4 N) {
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) float @_Z18test_reflect_floatff(
// SPVCHECK-SAME: float noundef nofpclass(nan inf) [[I:%.*]], float noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: {{.*}} = tail call token @llvm.experimental.convergence.entry()
// SPVCHECK-NEXT: [[MUL_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[I]], 2.000000e+00
// SPVCHECK-NEXT: [[TMP0:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[N]], [[N]]
// SPVCHECK-NEXT: [[MUL2_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[TMP0]], [[MUL_I]]
@@ -127,6 +132,7 @@ float test_reflect_float(float I, float N) {
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <2 x float> @_Z19test_reflect_float2Dv2_fS_(
// SPVCHECK-SAME: <2 x float> noundef nofpclass(nan inf) [[I:%.*]], <2 x float> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: {{.*}} = tail call token @llvm.experimental.convergence.entry()
// SPVCHECK-NEXT: [[SPV_REFLECT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef <2 x float> @llvm.spv.reflect.v2f32(<2 x float> [[I]], <2 x float> [[N]])
// SPVCHECK-NEXT: ret <2 x float> [[SPV_REFLECT_I]]
//
@@ -148,6 +154,7 @@ float2 test_reflect_float2(float2 I, float2 N) {
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <3 x float> @_Z19test_reflect_float3Dv3_fS_(
// SPVCHECK-SAME: <3 x float> noundef nofpclass(nan inf) [[I:%.*]], <3 x float> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: {{.*}} = tail call token @llvm.experimental.convergence.entry()
// SPVCHECK-NEXT: [[SPV_REFLECT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef <3 x float> @llvm.spv.reflect.v3f32(<3 x float> [[I]], <3 x float> [[N]])
// SPVCHECK-NEXT: ret <3 x float> [[SPV_REFLECT_I]]
//
@@ -169,6 +176,7 @@ float3 test_reflect_float3(float3 I, float3 N) {
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <4 x float> @_Z19test_reflect_float4Dv4_fS_(
// SPVCHECK-SAME: <4 x float> noundef nofpclass(nan inf) [[I:%.*]], <4 x float> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: {{.*}} = tail call token @llvm.experimental.convergence.entry()
// SPVCHECK-NEXT: [[SPV_REFLECT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef <4 x float> @llvm.spv.reflect.v4f32(<4 x float> [[I]], <4 x float> [[N]])
// SPVCHECK-NEXT: ret <4 x float> [[SPV_REFLECT_I]]
//
diff --git a/clang/test/CodeGenHLSL/builtins/smoothstep.hlsl b/clang/test/CodeGenHLSL/builtins/smoothstep.hlsl
index f2328c7330e6c..de95c11a138e7 100644
--- a/clang/test/CodeGenHLSL/builtins/smoothstep.hlsl
+++ b/clang/test/CodeGenHLSL/builtins/smoothstep.hlsl
@@ -22,6 +22,7 @@
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) half @_Z20test_smoothstep_halfDhDhDh(
// SPVCHECK-SAME: half noundef nofpclass(nan inf) [[MIN:%.*]], half noundef nofpclass(nan inf) [[MAX:%.*]], half noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: {{.*}} = tail call token @llvm.experimental.convergence.entry()
// SPVCHECK-NEXT: [[SPV_SMOOTHSTEP_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef half @llvm.spv.smoothstep.f16(half [[MIN]], half [[MAX]], half [[X]])
// SPVCHECK-NEXT: ret half [[SPV_SMOOTHSTEP_I]]
//
@@ -43,6 +44,7 @@ half test_smoothstep_half(half Min, half Max, half X) { return smoothstep(Min, M
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <2 x half> @_Z21test_smoothstep_half2Dv2_DhS_S_(
// SPVCHECK-SAME: <2 x half> noundef nofpclass(nan inf) [[MIN:%.*]], <2 x half> noundef nofpclass(nan inf) [[MAX:%.*]], <2 x half> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: {{.*}} = tail call token @llvm.experimental.convergence.entry()
// SPVCHECK-NEXT: [[SPV_SMOOTHSTEP_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef <2 x half> @llvm.spv.smoothstep.v2f16(<2 x half> [[MIN]], <2 x half> [[MAX]], <2 x half> [[X]])
// SPVCHECK-NEXT: ret <2 x half> [[SPV_SMOOTHSTEP_I]]
//
@@ -64,6 +66,7 @@ half2 test_smoothstep_half2(half2 Min, half2 Max, half2 X) { return smoothstep(M
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <3 x half> @_Z21test_smoothstep_half3Dv3_DhS_S_(
// SPVCHECK-SAME: <3 x half> noundef nofpclass(nan inf) [[MIN:%.*]], <3 x half> noundef nofpclass(nan inf) [[MAX:%.*]], <3 x half> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: {{.*}} = tail call token @llvm.experimental.convergence.entry()
// SPVCHECK-NEXT: [[SPV_SMOOTHSTEP_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef <3 x half> @llvm.spv.smoothstep.v3f16(<3 x half> [[MIN]], <3 x half> [[MAX]], <3 x half> [[X]])
// SPVCHECK-NEXT: ret <3 x half> [[SPV_SMOOTHSTEP_I]]
//
@@ -85,6 +88,7 @@ half3 test_smoothstep_half3(half3 Min, half3 Max, half3 X) { return smoothstep(M
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <4 x half> @_Z21test_smoothstep_half4Dv4_DhS_S_(
// SPVCHECK-SAME: <4 x half> noundef nofpclass(nan inf) [[MIN:%.*]], <4 x half> noundef nofpclass(nan inf) [[MAX:%.*]], <4 x half> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: {{.*}} = tail call token @llvm.experimental.convergence.entry()
// SPVCHECK-NEXT: [[SPV_SMOOTHSTEP_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef <4 x half> @llvm.spv.smoothstep.v4f16(<4 x half> [[MIN]], <4 x half> [[MAX]], <4 x half> [[X]])
// SPVCHECK-NEXT: ret <4 x half> [[SPV_SMOOTHSTEP_I]]
//
@@ -106,6 +110,7 @@ half4 test_smoothstep_half4(half4 Min, half4 Max, half4 X) { return smoothstep(M
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) float @_Z21test_smoothstep_floatfff(
// SPVCHECK-SAME: float noundef nofpclass(nan inf) [[MIN:%.*]], float noundef nofpclass(nan inf) [[MAX:%.*]], float noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: {{.*}} = tail call token @llvm.experimental.convergence.entry()
// SPVCHECK-NEXT: [[SPV_SMOOTHSTEP_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef float @llvm.spv.smoothstep.f32(float [[MIN]], float [[MAX]], float [[X]])
// SPVCHECK-NEXT: ret float [[SPV_SMOOTHSTEP_I]]
//
@@ -127,6 +132,7 @@ float test_smoothstep_float(float Min, float Max, float X) { return smoothstep(M
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <2 x float> @_Z22test_smoothstep_float2Dv2_fS_S_(
// SPVCHECK-SAME: <2 x float> noundef nofpclass(nan inf) [[MIN:%.*]], <2 x float> noundef nofpclass(nan inf) [[MAX:%.*]], <2 x float> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: {{.*}} = tail call token @llvm.experimental.convergence.entry()
// SPVCHECK-NEXT: [[SPV_SMOOTHSTEP_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef <2 x float> @llvm.spv.smoothstep.v2f32(<2 x float> [[MIN]], <2 x float> [[MAX]], <2 x float> [[X]])
// SPVCHECK-NEXT: ret <2 x float> [[SPV_SMOOTHSTEP_I]]
//
@@ -148,6 +154,7 @@ float2 test_smoothstep_float2(float2 Min, float2 Max, float2 X) { return smooths
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <3 x float> @_Z22test_smoothstep_float3Dv3_fS_S_(
// SPVCHECK-SAME: <3 x float> noundef nofpclass(nan inf) [[MIN:%.*]], <3 x float> noundef nofpclass(nan inf) [[MAX:%.*]], <3 x float> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: {{.*}} = tail call token @llvm.experimental.convergence.entry()
// SPVCHECK-NEXT: [[SPV_SMOOTHSTEP_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef <3 x float> @llvm.spv.smoothstep.v3f32(<3 x float> [[MIN]], <3 x float> [[MAX]], <3 x float> [[X]])
// SPVCHECK-NEXT: ret <3 x float> [[SPV_SMOOTHSTEP_I]]
//
@@ -169,6 +176,7 @@ float3 test_smoothstep_float3(float3 Min, float3 Max, float3 X) { return smooths
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <4 x float> @_Z22test_smoothstep_float4Dv4_fS_S_(
// SPVCHECK-SAME: <4 x float> noundef nofpclass(nan inf) [[MIN:%.*]], <4 x float> noundef nofpclass(nan inf) [[MAX:%.*]], <4 x float> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: {{.*}} = tail call token @llvm.experimental.convergence.entry()
// SPVCHECK-NEXT: [[SPV_SMOOTHSTEP_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef <4 x float> @llvm.spv.smoothstep.v4f32(<4 x float> [[MIN]], <4 x float> [[MAX]], <4 x float> [[X]])
// SPVCHECK-NEXT: ret <4 x float> [[SPV_SMOOTHSTEP_I]]
//
diff --git a/clang/test/CodeGenSPIRV/Builtins/distance.c b/clang/test/CodeGenSPIRV/Builtins/distance.c
index 76c684b932c1d..13dfade1a189a 100644
--- a/clang/test/CodeGenSPIRV/Builtins/distance.c
+++ b/clang/test/CodeGenSPIRV/Builtins/distance.c
@@ -9,6 +9,7 @@ typedef float float4 __attribute__((ext_vector_type(4)));
// CHECK-LABEL: define spir_func float @test_distance_float2(
// CHECK-SAME: <2 x float> noundef [[X:%.*]], <2 x float> noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[TMP0:%.*]] = tail call token @llvm.experimental.convergence.entry()
// CHECK-NEXT: [[SPV_DISTANCE:%.*]] = tail call float @llvm.spv.distance.v2f32(<2 x float> [[X]], <2 x float> [[Y]])
// CHECK-NEXT: ret float [[SPV_DISTANCE]]
//
@@ -17,6 +18,7 @@ float test_distance_float2(float2 X, float2 Y) { return __builtin_spirv_distance
// CHECK-LABEL: define spir_func float @test_distance_float3(
// CHECK-SAME: <3 x float> noundef [[X:%.*]], <3 x float> noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[TMP0:%.*]] = tail call token @llvm.experimental.convergence.entry()
// CHECK-NEXT: [[SPV_DISTANCE:%.*]] = tail call float @llvm.spv.distance.v3f32(<3 x float> [[X]], <3 x float> [[Y]])
// CHECK-NEXT: ret float [[SPV_DISTANCE]]
//
@@ -25,6 +27,7 @@ float test_distance_float3(float3 X, float3 Y) { return __builtin_spirv_distance
// CHECK-LABEL: define spir_func float @test_distance_float4(
// CHECK-SAME: <4 x float> noundef [[X:%.*]], <4 x float> noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[TMP0:%.*]] = tail call token @llvm.experimental.convergence.entry()
// CHECK-NEXT: [[SPV_DISTANCE:%.*]] = tail call float @llvm.spv.distance.v4f32(<4 x float> [[X]], <4 x float> [[Y]])
// CHECK-NEXT: ret float [[SPV_DISTANCE]]
//
diff --git a/clang/test/CodeGenSPIRV/Builtins/length.c b/clang/test/CodeGenSPIRV/Builtins/length.c
index 59e7c298dd816..3c6e4592e02f8 100644
--- a/clang/test/CodeGenSPIRV/Builtins/length.c
+++ b/clang/test/CodeGenSPIRV/Builtins/length.c
@@ -9,6 +9,7 @@ typedef float float4 __attribute__((ext_vector_type(4)));
// CHECK-LABEL: define spir_func float @test_length_float2(
// CHECK-SAME: <2 x float> noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[TMP0:%.*]] = tail call token @llvm.experimental.convergence.entry()
// CHECK-NEXT: [[SPV_LENGTH:%.*]] = tail call float @llvm.spv.length.v2f32(<2 x float> [[X]])
// CHECK-NEXT: ret float [[SPV_LENGTH]]
//
@@ -17,6 +18,7 @@ float test_length_float2(float2 X) { return __builtin_spirv_length(X); }
// CHECK-LABEL: define spir_func float @test_length_float3(
// CHECK-SAME: <3 x float> noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[TMP0:%.*]] = tail call token @llvm.experimental.convergence.entry()
// CHECK-NEXT: [[SPV_LENGTH:%.*]] = tail call float @llvm.spv.length.v3f32(<3 x float> [[X]])
// CHECK-NEXT: ret float [[SPV_LENGTH]]
//
@@ -25,6 +27,7 @@ float test_length_float3(float3 X) { return __builtin_spirv_length(X); }
// CHECK-LABEL: define spir_func float @test_length_float4(
// CHECK-SAME: <4 x float> noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[TMP0:%.*]] = tail call token @llvm.experimental.convergence.entry()
// CHECK-NEXT: [[SPV_LENGTH:%.*]] = tail call float @llvm.spv.length.v4f32(<4 x float> [[X]])
// CHECK-NEXT: ret float [[SPV_LENGTH]]
//
diff --git a/clang/test/CodeGenSPIRV/Builtins/reflect.c b/clang/test/CodeGenSPIRV/Builtins/reflect.c
index f51ac27a07457..e1e784fb8b961 100644
--- a/clang/test/CodeGenSPIRV/Builtins/reflect.c
+++ b/clang/test/CodeGenSPIRV/Builtins/reflect.c
@@ -9,6 +9,7 @@ typedef float float4 __attribute__((ext_vector_type(4)));
// CHECK-LABEL: define spir_func <2 x float> @test_reflect_float2(
// CHECK-SAME: <2 x float> noundef [[X:%.*]], <2 x float> noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[TMP0:%.*]] = tail call token @llvm.experimental.convergence.entry()
// CHECK-NEXT: [[SPV_REFLECT:%.*]] = tail call <2 x float> @llvm.spv.reflect.v2f32(<2 x float> [[X]], <2 x float> [[Y]])
// CHECK-NEXT: ret <2 x float> [[SPV_REFLECT]]
//
@@ -17,6 +18,7 @@ float2 test_reflect_float2(float2 X, float2 Y) { return __builtin_spirv_reflect(
// CHECK-LABEL: define spir_func <3 x float> @test_reflect_float3(
// CHECK-SAME: <3 x float> noundef [[X:%.*]], <3 x float> noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[TMP0:%.*]] = tail call token @llvm.experimental.convergence.entry()
// CHECK-NEXT: [[SPV_REFLECT:%.*]] = tail call <3 x float> @llvm.spv.reflect.v3f32(<3 x float> [[X]], <3 x float> [[Y]])
// CHECK-NEXT: ret <3 x float> [[SPV_REFLECT]]
//
@@ -25,6 +27,7 @@ float3 test_reflect_float3(float3 X, float3 Y) { return __builtin_spirv_reflect(
// CHECK-LABEL: define spir_func <4 x float> @test_reflect_float4(
// CHECK-SAME: <4 x float> noundef [[X:%.*]], <4 x float> noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[TMP0:%.*]] = tail call token @llvm.experimental.convergence.entry()
// CHECK-NEXT: [[SPV_REFLECT:%.*]] = tail call <4 x float> @llvm.spv.reflect.v4f32(<4 x float> [[X]], <4 x float> [[Y]])
// CHECK-NEXT: ret <4 x float> [[SPV_REFLECT]]
//
diff --git a/clang/test/CodeGenSPIRV/Builtins/smoothstep.c b/clang/test/CodeGenSPIRV/Builtins/smoothstep.c
index 714db4d9f728c..1c7a37a89d059 100644
--- a/clang/test/CodeGenSPIRV/Builtins/smoothstep.c
+++ b/clang/test/CodeGenSPIRV/Builtins/smoothstep.c
@@ -9,6 +9,7 @@ typedef float float4 __attribute__((ext_vector_type(4)));
// CHECK-LABEL: define spir_func float @test_smoothstep_float(
// CHECK-SAME: float noundef [[MIN:%.*]], float noundef [[MAX:%.*]], float noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[TMP0:%.*]] = tail call token @llvm.experimental.convergence.entry()
// CHECK-NEXT: [[SPV_SMOOTHSTEP:%.*]] = tail call float @llvm.spv.smoothstep.f32(float [[MIN]], float [[MAX]], float [[X]])
// CHECK-NEXT: ret float [[SPV_SMOOTHSTEP]]
//
@@ -17,6 +18,7 @@ float test_smoothstep_float(float Min, float Max, float X) { return __builtin_sp
// CHECK-LABEL: define spir_func <2 x float> @test_smoothstep_float2(
// CHECK-SAME: <2 x float> noundef [[MIN:%.*]], <2 x float> noundef [[MAX:%.*]], <2 x float> noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[TMP0:%.*]] = tail call token @llvm.experimental.convergence.entry()
// CHECK-NEXT: [[SPV_SMOOTHSTEP:%.*]] = tail call <2 x float> @llvm.spv.smoothstep.v2f32(<2 x float> [[MIN]], <2 x float> [[MAX]], <2 x float> [[X]])
// CHECK-NEXT: ret <2 x float> [[SPV_SMOOTHSTEP]]
//
@@ -25,6 +27,7 @@ float2 test_smoothstep_float2(float2 Min, float2 Max, float2 X) { return __built
// CHECK-LABEL: define spir_func <3 x float> @test_smoothstep_float3(
// CHECK-SAME: <3 x float> noundef [[MIN:%.*]], <3 x float> noundef [[MAX:%.*]], <3 x float> noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[TMP0:%.*]] = tail call token @llvm.experimental.convergence.entry()
// CHECK-NEXT: [[SPV_SMOOTHSTEP:%.*]] = tail call <3 x float> @llvm.spv.smoothstep.v3f32(<3 x float> [[MIN]], <3 x float> [[MAX]], <3 x float> [[X]])
// CHECK-NEXT: ret <3 x float> [[SPV_SMOOTHSTEP]]
//
@@ -33,6 +36,7 @@ float3 test_smoothstep_float3(float3 Min, float3 Max, float3 X) { return __built
// CHECK-LABEL: define spir_func <4 x float> @test_smoothstep_float4(
// CHECK-SAME: <4 x float> noundef [[MIN:%.*]], <4 x float> noundef [[MAX:%.*]], <4 x float> noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[TMP0:%.*]] = tail call token @llvm.experimental.convergence.entry()
// CHECK-NEXT: [[SPV_SMOOTHSTEP:%.*]] = tail call <4 x float> @llvm.spv.smoothstep.v4f32(<4 x float> [[MIN]], <4 x float> [[MAX]], <4 x float> [[X]])
// CHECK-NEXT: ret <4 x float> [[SPV_SMOOTHSTEP]]
//
diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td
index d10b07ccd91c2..ea08877466f73 100644
--- a/llvm/include/llvm/IR/Intrinsics.td
+++ b/llvm/include/llvm/IR/Intrinsics.td
@@ -2858,11 +2858,14 @@ def int_ptrauth_sign_generic :
//===------- Convergence Intrinsics ---------------------------------------===//
def int_experimental_convergence_entry
- : DefaultAttrsIntrinsic<[llvm_token_ty], [], [IntrNoMem, IntrConvergent]>;
+ : DefaultAttrsIntrinsic<[llvm_token_ty], [],
+ [IntrNoMem, IntrConvergent, IntrHasSideEffects]>;
def int_experimental_convergence_anchor
- : DefaultAttrsIntrinsic<[llvm_token_ty], [], [IntrNoMem, IntrConvergent]>;
+ : DefaultAttrsIntrinsic<[llvm_token_ty], [],
+ [IntrNoMem, IntrConvergent, IntrHasSideEffects]>;
def int_experimental_convergence_loop
- : DefaultAttrsIntrinsic<[llvm_token_ty], [], [IntrNoMem, IntrConvergent]>;
+ : DefaultAttrsIntrinsic<[llvm_token_ty], [],
+ [IntrNoMem, IntrConvergent, IntrHasSideEffects]>;
//===----------------------------------------------------------------------===//
// Target-specific intrinsics
diff --git a/llvm/test/Transforms/ADCE/convergence.ll b/llvm/test/Transforms/ADCE/convergence.ll
new file mode 100644
index 0000000000000..b1d3922b2237a
--- /dev/null
+++ b/llvm/test/Transforms/ADCE/convergence.ll
@@ -0,0 +1,46 @@
+; RUN: opt %s -passes=adce -S | FileCheck %s
+
+; CHECK: Function Attrs: convergent
+; CHECK-NEXT: define i32 @foo(i32 %a) #0 {
+define i32 @foo(i32 %a) #0 {
+entry:
+; CHECK: %0 = call token @llvm.experimental.convergence.entry()
+ %0 = call token @llvm.experimental.convergence.entry()
+ ret i32 %a
+}
+
+; CHECK: Function Attrs: convergent
+; CHECK-NEXT: define void @bar() #0 {
+define void @bar() #0 {
+entry:
+; CHECK: %0 = call token @llvm.experimental.convergence.anchor()
+ %0 = call token @llvm.experimental.convergence.anchor()
+ ret void
+}
+
+; CHECK: Function Attrs: convergent
+; CHECK-NEXT: define void @baz() #0 {
+define void @baz() #0 {
+entry:
+; CHECK: %0 = call token @llvm.experimental.convergence.entry()
+ %0 = call token @llvm.experimental.convergence.entry()
+ br label %header
+
+header:
+; CHECK: %1 = call token @llvm.experimental.convergence.loop() [ "convergencectrl"(token %0) ]
+ %1 = call token @llvm.experimental.convergence.loop() [ "convergencectrl"(token %0) ]
+ br i1 true, label %body, label %exit
+
+body:
+ br label %header
+
+exit:
+ ret void
+}
+
+declare token @llvm.experimental.convergence.entry() #1
+declare token @llvm.experimental.convergence.anchor() #1
+declare token @llvm.experimental.convergence.loop() #1
+
+attributes #0 = { convergent }
+attributes #1 = { convergent nocallback nofree nosync nounwind willreturn memory(none) }
diff --git a/llvm/test/Transforms/BDCE/convergence.ll b/llvm/test/Transforms/BDCE/convergence.ll
new file mode 100644
index 0000000000000..c5a84a30980e7
--- /dev/null
+++ b/llvm/test/Transforms/BDCE/convergence.ll
@@ -0,0 +1,47 @@
+; RUN: opt %s -passes=bdce -S | FileCheck %s
+
+; CHECK: Function Attrs: convergent
+; CHECK-NEXT: define i32 @foo(i32 %a) #0 {
+define i32 @foo(i32 %a) #0 {
+entry:
+; CHECK: %0 = call token @llvm.experimental.convergence.entry()
+ %0 = call token @llvm.experimental.convergence.entry()
+ ret i32 %a
+}
+
+; CHECK: Function Attrs: convergent
+; CHECK-NEXT: define void @bar() #0 {
+define void @bar() #0 {
+entry:
+; CHECK: %0 = call token @llvm.experimental.convergence.anchor()
+ %0 = call token @llvm.experimental.convergence.anchor()
+ ret void
+}
+
+; CHECK: Function Attrs: convergent
+; CHECK-NEXT: define void @baz() #0 {
+define void @baz() #0 {
+entry:
+; CHECK: %0 = call token @llvm.experimental.convergence.entry()
+ %0 = call token @llvm.experimental.convergence.entry()
+ br label %header
+
+header:
+; CHECK: %1 = call token @llvm.experimental.convergence.loop() [ "convergencectrl"(token %0) ]
+ %1 = call token @llvm.experimental.convergence.loop() [ "convergencectrl"(token %0) ]
+ br i1 true, label %body, label %exit
+
+body:
+ br label %header
+
+exit:
+ ret void
+}
+
+declare token @llvm.experimental.convergence.entry() #1
+declare token @llvm.experimental.convergence.anchor() #1
+declare token @llvm.experimental.convergence.loop() #1
+
+attributes #0 = { convergent }
+attributes #1 = { convergent nocallback nofree nosync nounwind willreturn memory(none) }
+
diff --git a/llvm/test/Transforms/DCE/op_bundles.ll b/llvm/test/Transforms/DCE/op_bundles.ll
index 0d3b4db8265e8..6726e1f1a0f9d 100644
--- a/llvm/test/Transforms/DCE/op_bundles.ll
+++ b/llvm/test/Transforms/DCE/op_bundles.ll
@@ -4,6 +4,7 @@
define void @dead_readfirstlane_convergencetoken(<2 x i32> %src) convergent {
; CHECK-LABEL: define void @dead_readfirstlane_convergencetoken(
; CHECK-SAME: <2 x i32> [[SRC:%.*]]) #[[ATTR0:[0-9]+]] {
+; CHECK-NEXT: [[T:%.*]] = tail call token @llvm.experimental.convergence.entry()
; CHECK-NEXT: ret void
;
%t = tail call token @llvm.experimental.convergence.entry()
diff --git a/llvm/test/Transforms/FunctionAttrs/convergent.ll b/llvm/test/Transforms/FunctionAttrs/convergent.ll
index fe8029d39d924..e46981c06affe 100644
--- a/llvm/test/Transforms/FunctionAttrs/convergent.ll
+++ b/llvm/test/Transforms/FunctionAttrs/convergent.ll
@@ -1,5 +1,5 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes
-; RUN: opt -passes=function-attrs -S < %s | FileCheck %s
+; RUN: opt -passes=function-attrs -S %s | FileCheck %s
define i32 @nonleaf() convergent {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
@@ -129,3 +129,17 @@ define i32 @noopt_friend() convergent {
%a = call i32 @noopt()
ret i32 0
}
+
+define i32 @leaf_convergent() convergent {
+; CHECK: Function Attrs: convergent mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CHECK-LABEL: define {{[^@]+}}@leaf_convergent
+; CHECK-SAME: () #[[ATTR7:[0-9]+]] {
+; CHECK-NEXT: %1 = call token @llvm.experimental.convergence.entry()
+; CHECK-NEXT: ret i32 0
+ %1 = call token @llvm.experimental.convergence.entry()
+ ret i32 0
+}
+
+declare token @llvm.experimental.convergence.entry() #1
+
+attributes #1 = { convergent nocallback nofree nosync nounwind willreturn memory(none) }
diff --git a/llvm/test/Transforms/IRNormalizer/regression-convergence-tokens.ll b/llvm/test/Transforms/IRNormalizer/regression-convergence-tokens.ll
index 88eff971b9576..559dca38cbb0f 100644
--- a/llvm/test/Transforms/IRNormalizer/regression-convergence-tokens.ll
+++ b/llvm/test/Transforms/IRNormalizer/regression-convergence-tokens.ll
@@ -6,10 +6,10 @@ define i32 @nested(i32 %src) #0 {
; CHECK-LABEL: define i32 @nested(
; CHECK-SAME: i32 [[A0:%.*]]) #[[ATTR0:[0-9]+]] {
; CHECK-NEXT: [[BB15160:.*:]]
-; CHECK-NEXT: [[T1:%.*]] = call token @llvm.experimental.convergence.entry()
-; CHECK-NEXT: %"vl77672llvm.experimental.convergence.anchor()" = call token @llvm.experimental.convergence.anchor()
-; CHECK-NEXT: %"op68297(vl77672)" = call i32 @llvm.amdgcn.readfirstlane.i32(i32 [[A0]]) [ "convergencectrl"(token %"vl77672llvm.experimental.convergence.anchor()") ]
-; CHECK-NEXT: ret i32 %"op68297(vl77672)"
+; CHECK-NEXT: %"op91455llvm.experimental.convergence.entry()" = call token @llvm.experimental.convergence.entry()
+; CHECK-NEXT: %"vl15160llvm.experimental.convergence.anchor()" = call token @llvm.experimental.convergence.anchor()
+; CHECK-NEXT: %"op68297(vl15160)" = call i32 @llvm.amdgcn.readfirstlane.i32(i32 [[A0]]) [ "convergencectrl"(token %"vl15160llvm.experimental.convergence.anchor()") ]
+; CHECK-NEXT: ret i32 %"op68297(vl15160)"
;
%t1 = call token @llvm.experimental.convergence.entry()
%t2 = call token @llvm.experimental.convergence.anchor()
diff --git a/llvm/test/Transforms/LoopUnroll/convergent.controlled.ll b/llvm/test/Transforms/LoopUnroll/convergent.controlled.ll
index 7fd4eb18f16eb..89a0867c92a53 100644
--- a/llvm/test/Transforms/LoopUnroll/convergent.controlled.ll
+++ b/llvm/test/Transforms/LoopUnroll/convergent.controlled.ll
@@ -431,6 +431,7 @@ define i32 @extended_inner_loop_2(i32 %n, i1 %cond) {
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[L3:%.*]]
; CHECK: l3:
+; CHECK-NEXT: [[TOK_LOOP:%.*]] = call token @llvm.experimental.convergence.anchor()
; CHECK-NEXT: br label [[L2:%.*]], !llvm.loop [[LOOP4]]
; CHECK: l2:
; CHECK-NEXT: [[TOK_L2:%.*]] = call token @llvm.experimental.convergence.anchor()
@@ -438,6 +439,7 @@ define i32 @extended_inner_loop_2(i32 %n, i1 %cond) {
; CHECK-NEXT: br i1 [[COND:%.*]], label [[L2]], label [[LATCH:%.*]], !llvm.loop [[LOOP4]]
; CHECK: latch:
; CHECK-NEXT: call void @f() [ "convergencectrl"(token [[TOK_L2]]) ]
+; CHECK-NEXT: [[TOK_LOOP_1:%.*]] = call token @llvm.experimental.convergence.anchor()
; CHECK-NEXT: br label [[L2_1:%.*]], !llvm.loop [[LOOP4]]
; CHECK: l2.1:
; CHECK-NEXT: [[TOK_L2_1:%.*]] = call token @llvm.experimental.convergence.anchor()
@@ -445,6 +447,7 @@ define i32 @extended_inner_loop_2(i32 %n, i1 %cond) {
; CHECK-NEXT: br i1 [[COND]], label [[L2_1]], label [[LATCH_1:%.*]], !llvm.loop [[LOOP4]]
; CHECK: latch.1:
; CHECK-NEXT: call void @f() [ "convergencectrl"(token [[TOK_L2_1]]) ]
+; CHECK-NEXT: [[TOK_LOOP_2:%.*]] = call token @llvm.experimental.convergence.anchor()
; CHECK-NEXT: br label [[L2_2:%.*]], !llvm.loop [[LOOP4]]
; CHECK: l2.2:
; CHECK-NEXT: [[TOK_L2_2:%.*]] = call token @llvm.experimental.convergence.anchor()
@@ -452,6 +455,7 @@ define i32 @extended_inner_loop_2(i32 %n, i1 %cond) {
; CHECK-NEXT: br i1 [[COND]], label [[L2_2]], label [[LATCH_2:%.*]], !llvm.loop [[LOOP4]]
; CHECK: latch.2:
; CHECK-NEXT: call void @f() [ "convergencectrl"(token [[TOK_L2_2]]) ]
+; CHECK-NEXT: [[TOK_LOOP_3:%.*]] = call token @llvm.experimental.convergence.anchor()
; CHECK-NEXT: br label [[L2_3:%.*]], !llvm.loop [[LOOP4]]
; CHECK: l2.3:
; CHECK-NEXT: [[TOK_L2_3:%.*]] = call token @llvm.experimental.convergence.anchor()
@@ -491,6 +495,7 @@ define i32 @unroll_nest(i32 %n, i1 %cond) {
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[L3:%.*]]
; CHECK: l3:
+; CHECK-NEXT: [[TOK_LOOP:%.*]] = call token @llvm.experimental.convergence.anchor()
; CHECK-NEXT: br label [[L2:%.*]], !llvm.loop [[LOOP4]]
; CHECK: l2:
; CHECK-NEXT: [[TOK_L2:%.*]] = call token @llvm.experimental.convergence.anchor()
@@ -501,6 +506,7 @@ define i32 @unroll_nest(i32 %n, i1 %cond) {
; CHECK-NEXT: call void @f() [ "convergencectrl"(token [[TOK_L2_1]]) ]
; CHECK-NEXT: br i1 [[COND]], label [[L2]], label [[LATCH]], !llvm.loop [[LOOP9:![0-9]+]]
; CHECK: latch:
+; CHECK-NEXT: [[TOK_LOOP_1:%.*]] = call token @llvm.experimental.convergence.anchor()
; CHECK-NEXT: br label [[L2_12:%.*]], !llvm.loop [[LOOP4]]
; CHECK: l2.12:
; CHECK-NEXT: [[TOK_L2_11:%.*]] = call token @llvm.experimental.convergence.anchor()
@@ -511,6 +517,7 @@ define i32 @unroll_nest(i32 %n, i1 %cond) {
; CHECK-NEXT: call void @f() [ "convergencectrl"(token [[TOK_L2_1_1]]) ]
; CHECK-NEXT: br i1 [[COND]], label [[L2_12]], label [[LATCH_1]], !llvm.loop [[LOOP9]]
; CHECK: latch.1:
+; CHECK-NEXT: [[TOK_LOOP_2:%.*]] = call token @llvm.experimental.convergence.anchor()
; CHECK-NEXT: br label [[L2_2:%.*]], !llvm.loop [[LOOP4]]
; CHECK: l2.2:
; CHECK-NEXT: [[TOK_L2_2:%.*]] = call token @llvm.experimental.convergence.anchor()
@@ -521,6 +528,7 @@ define i32 @unroll_nest(i32 %n, i1 %cond) {
; CHECK-NEXT: call void @f() [ "convergencectrl"(token [[TOK_L2_1_2]]) ]
; CHECK-NEXT: br i1 [[COND]], label [[L2_2]], label [[LATCH_2]], !llvm.loop [[LOOP9]]
; CHECK: latch.2:
+; CHECK-NEXT: [[TOK_LOOP_3:%.*]] = call token @llvm.experimental.convergence.anchor()
; CHECK-NEXT: br label [[L2_3:%.*]], !llvm.loop [[LOOP4]]
; CHECK: l2.3:
; CHECK-NEXT: [[TOK_L2_3:%.*]] = call token @llvm.experimental.convergence.anchor()
More information about the llvm-commits
mailing list