[llvm] 6b25f44 - [AMDGPU] Detect trivially uniform arguments in InstCombine (#129897)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Jun 9 04:06:06 PDT 2025
Author: Jay Foad
Date: 2025-06-09T12:06:03+01:00
New Revision: 6b25f4439c2123402afbb2436745904166680dac
URL: https://github.com/llvm/llvm-project/commit/6b25f4439c2123402afbb2436745904166680dac
DIFF: https://github.com/llvm/llvm-project/commit/6b25f4439c2123402afbb2436745904166680dac.diff
LOG: [AMDGPU] Detect trivially uniform arguments in InstCombine (#129897)
Update one test to use an SGPR argument as the simplest way of getting a
uniform value.
Added:
llvm/test/Transforms/InstCombine/AMDGPU/trivially-uniform.ll
Modified:
llvm/lib/Target/AMDGPU/AMDGPUInstCombineIntrinsic.cpp
llvm/test/Transforms/InstCombine/AMDGPU/amdgcn-intrinsics.ll
Removed:
################################################################################
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUInstCombineIntrinsic.cpp b/llvm/lib/Target/AMDGPU/AMDGPUInstCombineIntrinsic.cpp
index f4f391e0a6bab..9be8821d5bf96 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUInstCombineIntrinsic.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUInstCombineIntrinsic.cpp
@@ -462,6 +462,8 @@ static bool isTriviallyUniform(const Use &U) {
Value *V = U.get();
if (isa<Constant>(V))
return true;
+ if (const auto *A = dyn_cast<Argument>(V))
+ return AMDGPU::isArgPassedInSGPR(A);
if (const auto *II = dyn_cast<IntrinsicInst>(V)) {
if (!AMDGPU::isIntrinsicAlwaysUniform(II->getIntrinsicID()))
return false;
diff --git a/llvm/test/Transforms/InstCombine/AMDGPU/amdgcn-intrinsics.ll b/llvm/test/Transforms/InstCombine/AMDGPU/amdgcn-intrinsics.ll
index 9375d56e900e0..6b5dc4b7b1276 100644
--- a/llvm/test/Transforms/InstCombine/AMDGPU/amdgcn-intrinsics.ll
+++ b/llvm/test/Transforms/InstCombine/AMDGPU/amdgcn-intrinsics.ll
@@ -2743,7 +2743,7 @@ declare i32 @llvm.amdgcn.readfirstlane(i32)
@gv = constant i32 0
-define amdgpu_kernel void @readfirstlane_constant(i32 %arg, ptr %ptr) {
+define amdgpu_cs void @readfirstlane_constant(i32 %arg, ptr %ptr) {
; CHECK-LABEL: @readfirstlane_constant(
; CHECK-NEXT: [[VAR:%.*]] = call i32 @llvm.amdgcn.readfirstlane.i32(i32 [[ARG:%.*]])
; CHECK-NEXT: store volatile i32 [[VAR]], ptr [[PTR:%.*]], align 4
@@ -2829,7 +2829,7 @@ bb1:
declare i32 @llvm.amdgcn.readlane(i32, i32)
-define amdgpu_kernel void @readlane_constant(i32 %arg, i32 %lane, ptr %ptr) {
+define amdgpu_cs void @readlane_constant(i32 %arg, i32 %lane, ptr %ptr) {
; CHECK-LABEL: @readlane_constant(
; CHECK-NEXT: [[VAR:%.*]] = call i32 @llvm.amdgcn.readlane.i32(i32 [[ARG:%.*]], i32 7)
; CHECK-NEXT: store volatile i32 [[VAR]], ptr [[PTR:%.*]], align 4
@@ -3041,14 +3041,12 @@ define amdgpu_kernel void @permlanex16_fetch_invalid_bound_ctrl(ptr addrspace(1)
; llvm.amdgcn.permlane64
; --------------------------------------------------------------------
-define amdgpu_kernel void @permlane64_uniform(ptr addrspace(1) %out, i32 %src0) {
+define amdgpu_kernel void @permlane64_uniform(ptr addrspace(1) %out, i32 %src) {
; CHECK-LABEL: @permlane64_uniform(
-; CHECK-NEXT: [[SRC1:%.*]] = call i32 @llvm.amdgcn.readfirstlane.i32(i32 [[SRC0:%.*]])
-; CHECK-NEXT: store i32 [[SRC1]], ptr addrspace(1) [[OUT:%.*]], align 4
+; CHECK-NEXT: store i32 [[SRC1:%.*]], ptr addrspace(1) [[OUT:%.*]], align 4
; CHECK-NEXT: ret void
;
- %src1 = call i32 @llvm.amdgcn.readfirstlane(i32 %src0)
- %res = call i32 @llvm.amdgcn.permlane64(i32 %src1)
+ %res = call i32 @llvm.amdgcn.permlane64(i32 %src)
store i32 %res, ptr addrspace(1) %out
ret void
}
diff --git a/llvm/test/Transforms/InstCombine/AMDGPU/trivially-uniform.ll b/llvm/test/Transforms/InstCombine/AMDGPU/trivially-uniform.ll
new file mode 100644
index 0000000000000..2a3e3929d71b2
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/AMDGPU/trivially-uniform.ll
@@ -0,0 +1,163 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt -mtriple=amdgcn -mcpu=gfx1010 -passes=instcombine -S < %s | FileCheck %s
+
+; Use readfirstlane to demonstrate when InstCombine deems an input to
+; be trivially uniform.
+
+; Constants are trivially uniform.
+define i32 @test_constant() {
+; CHECK-LABEL: define i32 @test_constant(
+; CHECK-SAME: ) #[[ATTR0:[0-9]+]] {
+; CHECK-NEXT: ret i32 7
+;
+ %r = call i32 @llvm.amdgcn.readfirstlane(i32 7)
+ ret i32 %r
+}
+
+; The result of an AlwaysUniform intrinsic is trivially uniform.
+define i32 @test_intrinsic(i32 %x) {
+; CHECK-LABEL: define i32 @test_intrinsic(
+; CHECK-SAME: i32 [[X:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[Y:%.*]] = call i32 @llvm.amdgcn.readfirstlane.i32(i32 [[X]])
+; CHECK-NEXT: ret i32 [[Y]]
+;
+ %y = call i32 @llvm.amdgcn.readfirstlane(i32 %x)
+ %r = call i32 @llvm.amdgcn.readfirstlane(i32 %y)
+ ret i32 %r
+}
+
+; In compute kernels, all arguments are trivially uniform.
+
+define amdgpu_kernel void @test_compute_i32(ptr %out, i32 %x) {
+; CHECK-LABEL: define amdgpu_kernel void @test_compute_i32(
+; CHECK-SAME: ptr [[OUT:%.*]], i32 [[X:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: store i32 [[X]], ptr [[OUT]], align 4
+; CHECK-NEXT: ret void
+;
+ %r = call i32 @llvm.amdgcn.readfirstlane(i32 %x)
+ store i32 %r, ptr %out
+ ret void
+}
+
+define amdgpu_kernel void @test_compute_i1(ptr %out, i1 %x) {
+; CHECK-LABEL: define amdgpu_kernel void @test_compute_i1(
+; CHECK-SAME: ptr [[OUT:%.*]], i1 [[X:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: store i1 [[X]], ptr [[OUT]], align 1
+; CHECK-NEXT: ret void
+;
+ %r = call i1 @llvm.amdgcn.readfirstlane(i1 %x)
+ store i1 %r, ptr %out
+ ret void
+}
+
+define amdgpu_kernel void @test_compute_v32i1(ptr %out, <32 x i1> %x) {
+; CHECK-LABEL: define amdgpu_kernel void @test_compute_v32i1(
+; CHECK-SAME: ptr [[OUT:%.*]], <32 x i1> [[X:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: store <32 x i1> [[X]], ptr [[OUT]], align 4
+; CHECK-NEXT: ret void
+;
+ %r = call <32 x i1> @llvm.amdgcn.readfirstlane(<32 x i1> %x)
+ store <32 x i1> %r, ptr %out
+ ret void
+}
+
+; In graphics shaders, inreg arguments are trivially uniform.
+
+define amdgpu_ps i32 @test_graphics_i32(i32 inreg %x) {
+; CHECK-LABEL: define amdgpu_ps i32 @test_graphics_i32(
+; CHECK-SAME: i32 inreg [[X:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: ret i32 [[X]]
+;
+ %r = call i32 @llvm.amdgcn.readfirstlane(i32 %x)
+ ret i32 %r
+}
+
+define amdgpu_ps i1 @test_graphics_i1(i1 inreg %x) {
+; CHECK-LABEL: define amdgpu_ps i1 @test_graphics_i1(
+; CHECK-SAME: i1 inreg [[X:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: ret i1 [[X]]
+;
+ %r = call i1 @llvm.amdgcn.readfirstlane(i1 %x)
+ ret i1 %r
+}
+
+define amdgpu_ps <32 x i1> @test_graphics_v32i1(<32 x i1> inreg %x) {
+; CHECK-LABEL: define amdgpu_ps <32 x i1> @test_graphics_v32i1(
+; CHECK-SAME: <32 x i1> inreg [[X:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: ret <32 x i1> [[X]]
+;
+ %r = call <32 x i1> @llvm.amdgcn.readfirstlane(<32 x i1> %x)
+ ret <32 x i1> %r
+}
+
+; In graphics shaders, non-inreg arguments are not trivially uniform.
+
+define amdgpu_ps i32 @test_graphics_i32_negative(i32 %x) {
+; CHECK-LABEL: define amdgpu_ps i32 @test_graphics_i32_negative(
+; CHECK-SAME: i32 [[X:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[R:%.*]] = call i32 @llvm.amdgcn.readfirstlane.i32(i32 [[X]])
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %r = call i32 @llvm.amdgcn.readfirstlane(i32 %x)
+ ret i32 %r
+}
+
+define amdgpu_ps i1 @test_graphics_i1_negative(i1 %x) {
+; CHECK-LABEL: define amdgpu_ps i1 @test_graphics_i1_negative(
+; CHECK-SAME: i1 [[X:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[R:%.*]] = call i1 @llvm.amdgcn.readfirstlane.i1(i1 [[X]])
+; CHECK-NEXT: ret i1 [[R]]
+;
+ %r = call i1 @llvm.amdgcn.readfirstlane(i1 %x)
+ ret i1 %r
+}
+
+define amdgpu_ps <32 x i1> @test_graphics_v32i1_negative(<32 x i1> %x) {
+; CHECK-LABEL: define amdgpu_ps <32 x i1> @test_graphics_v32i1_negative(
+; CHECK-SAME: <32 x i1> [[X:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[R:%.*]] = call <32 x i1> @llvm.amdgcn.readfirstlane.v32i1(<32 x i1> [[X]])
+; CHECK-NEXT: ret <32 x i1> [[R]]
+;
+ %r = call <32 x i1> @llvm.amdgcn.readfirstlane(<32 x i1> %x)
+ ret <32 x i1> %r
+}
+
+; Test i1 arguments in non-entry functions.
+
+define amdgpu_gfx i1 @test_callable_i1(i1 inreg %x) {
+; CHECK-LABEL: define amdgpu_gfx i1 @test_callable_i1(
+; CHECK-SAME: i1 inreg [[X:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: ret i1 [[X]]
+;
+ %r = call i1 @llvm.amdgcn.readfirstlane(i1 %x)
+ ret i1 %r
+}
+
+define amdgpu_gfx <32 x i1> @test_callable_v32i1(<32 x i1> inreg %x) {
+; CHECK-LABEL: define amdgpu_gfx <32 x i1> @test_callable_v32i1(
+; CHECK-SAME: <32 x i1> inreg [[X:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: ret <32 x i1> [[X]]
+;
+ %r = call <32 x i1> @llvm.amdgcn.readfirstlane(<32 x i1> %x)
+ ret <32 x i1> %r
+}
+
+define amdgpu_gfx i1 @test_callable_i1_negative(i1 %x) {
+; CHECK-LABEL: define amdgpu_gfx i1 @test_callable_i1_negative(
+; CHECK-SAME: i1 [[X:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[R:%.*]] = call i1 @llvm.amdgcn.readfirstlane.i1(i1 [[X]])
+; CHECK-NEXT: ret i1 [[R]]
+;
+ %r = call i1 @llvm.amdgcn.readfirstlane(i1 %x)
+ ret i1 %r
+}
+
+define amdgpu_gfx <32 x i1> @test_callable_v32i1_negative(<32 x i1> %x) {
+; CHECK-LABEL: define amdgpu_gfx <32 x i1> @test_callable_v32i1_negative(
+; CHECK-SAME: <32 x i1> [[X:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[R:%.*]] = call <32 x i1> @llvm.amdgcn.readfirstlane.v32i1(<32 x i1> [[X]])
+; CHECK-NEXT: ret <32 x i1> [[R]]
+;
+ %r = call <32 x i1> @llvm.amdgcn.readfirstlane(<32 x i1> %x)
+ ret <32 x i1> %r
+}
More information about the llvm-commits
mailing list