[llvm] [AMDGPU] Improve amdgcn_kill verification (PR #208220)

Robert Imschweiler via llvm-commits llvm-commits at lists.llvm.org
Wed Jul 8 09:20:07 PDT 2026


https://github.com/ro-i updated https://github.com/llvm/llvm-project/pull/208220

>From 1d9708a43f1ab3fbe0df197170097e4ae189cb8c Mon Sep 17 00:00:00 2001
From: Robert Imschweiler <robert.imschweiler at amd.com>
Date: Wed, 8 Jul 2026 07:55:45 -0500
Subject: [PATCH 1/3] [AMDGPU] Improve amdgcn_kill verification

---
 llvm/lib/IR/VerifierAMDGPU.cpp | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/IR/VerifierAMDGPU.cpp b/llvm/lib/IR/VerifierAMDGPU.cpp
index 04cb214ef2520..ab63307570b28 100644
--- a/llvm/lib/IR/VerifierAMDGPU.cpp
+++ b/llvm/lib/IR/VerifierAMDGPU.cpp
@@ -145,7 +145,12 @@ void llvm::verifyAMDGPUIntrinsicCall(VerifierSupport &VS, Intrinsic::ID ID,
       Check(CBI->getNumIndirectDests() == 1,
             "callbr amdgcn_kill only supports one indirect dest");
       bool Unreachable = isa<UnreachableInst>(CBI->getIndirectDest(0)->begin());
-      CallInst *CI = dyn_cast<CallInst>(CBI->getIndirectDest(0)->begin());
+      // We assume that amdgcn_unreachable is only introduced by
+      // AMDGPUUnifyDivergentExitNodes, which replaces the block's original
+      // unreachable terminator by a call to amdgcn_unreachable + a return.
+      const Instruction *Term = CBI->getIndirectDest(0)->getTerminator();
+      const CallInst *CI =
+          Term ? dyn_cast_if_present<CallInst>(Term->getPrevNode()) : nullptr;
       Check(Unreachable ||
                 (CI && CI->getIntrinsicID() == Intrinsic::amdgcn_unreachable),
             "callbr amdgcn_kill indirect dest needs to be unreachable");

>From 553ef7e5e5f318b82a777456117b57c64a64941b Mon Sep 17 00:00:00 2001
From: Robert Imschweiler <robert.imschweiler at amd.com>
Date: Wed, 8 Jul 2026 09:07:20 -0500
Subject: [PATCH 2/3] add test and also improve unreachable detection

---
 llvm/lib/IR/VerifierAMDGPU.cpp                |  3 +-
 llvm/test/CodeGen/AMDGPU/callbr-intrinsics.ll | 60 +++++++++++++++++++
 2 files changed, 61 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/IR/VerifierAMDGPU.cpp b/llvm/lib/IR/VerifierAMDGPU.cpp
index ab63307570b28..a668d3135644e 100644
--- a/llvm/lib/IR/VerifierAMDGPU.cpp
+++ b/llvm/lib/IR/VerifierAMDGPU.cpp
@@ -144,14 +144,13 @@ void llvm::verifyAMDGPUIntrinsicCall(VerifierSupport &VS, Intrinsic::ID ID,
     if (auto *CBI = dyn_cast<CallBrInst>(&Call)) {
       Check(CBI->getNumIndirectDests() == 1,
             "callbr amdgcn_kill only supports one indirect dest");
-      bool Unreachable = isa<UnreachableInst>(CBI->getIndirectDest(0)->begin());
       // We assume that amdgcn_unreachable is only introduced by
       // AMDGPUUnifyDivergentExitNodes, which replaces the block's original
       // unreachable terminator by a call to amdgcn_unreachable + a return.
       const Instruction *Term = CBI->getIndirectDest(0)->getTerminator();
       const CallInst *CI =
           Term ? dyn_cast_if_present<CallInst>(Term->getPrevNode()) : nullptr;
-      Check(Unreachable ||
+      Check(isa_and_nonnull<UnreachableInst>(Term) ||
                 (CI && CI->getIntrinsicID() == Intrinsic::amdgcn_unreachable),
             "callbr amdgcn_kill indirect dest needs to be unreachable");
     }
diff --git a/llvm/test/CodeGen/AMDGPU/callbr-intrinsics.ll b/llvm/test/CodeGen/AMDGPU/callbr-intrinsics.ll
index 8ac31b3c70ed7..123c817202723 100644
--- a/llvm/test/CodeGen/AMDGPU/callbr-intrinsics.ll
+++ b/llvm/test/CodeGen/AMDGPU/callbr-intrinsics.ll
@@ -113,3 +113,63 @@ cont:
 kill:
   unreachable
 }
+
+define void @test_kill_unreachable_not_first(ptr %src, ptr %dst, i1 %c) {
+; CHECK-LABEL: test_kill_unreachable_not_first:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; CHECK-NEXT:    flat_load_dword v0, v[0:1]
+; CHECK-NEXT:    v_and_b32_e32 v1, 1, v4
+; CHECK-NEXT:    v_cmp_eq_u32_e32 vcc, 1, v1
+; CHECK-NEXT:    s_mov_b64 s[4:5], exec
+; CHECK-NEXT:    s_andn2_b64 s[6:7], exec, vcc
+; CHECK-NEXT:    s_andn2_b64 s[4:5], s[4:5], s[6:7]
+; CHECK-NEXT:    s_cbranch_scc0 .LBB2_2
+; CHECK-NEXT:  ; %bb.1:
+; CHECK-NEXT:    s_and_b64 exec, exec, s[4:5]
+; CHECK-NEXT:    s_waitcnt vmcnt(0) lgkmcnt(0)
+; CHECK-NEXT:    flat_store_dword v[2:3], v0
+; CHECK-NEXT:    s_waitcnt vmcnt(0) lgkmcnt(0)
+; CHECK-NEXT:    s_setpc_b64 s[30:31]
+; CHECK-NEXT:  .LBB2_2:
+; CHECK-NEXT:    s_mov_b64 exec, 0
+; CHECK-NEXT:    s_endpgm
+;
+; GISEL-LABEL: test_kill_unreachable_not_first:
+; GISEL:       ; %bb.0:
+; GISEL-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GISEL-NEXT:    flat_load_dword v0, v[0:1]
+; GISEL-NEXT:    v_and_b32_e32 v1, 1, v4
+; GISEL-NEXT:    v_cmp_ne_u32_e32 vcc, 0, v1
+; GISEL-NEXT:    s_mov_b64 s[4:5], exec
+; GISEL-NEXT:    s_andn2_b64 s[6:7], exec, vcc
+; GISEL-NEXT:    s_andn2_b64 s[4:5], s[4:5], s[6:7]
+; GISEL-NEXT:    s_cbranch_scc0 .LBB2_4
+; GISEL-NEXT:  ; %bb.1:
+; GISEL-NEXT:    s_and_b64 exec, exec, s[4:5]
+; GISEL-NEXT:  ; %bb.2: ; %cont
+; GISEL-NEXT:    s_waitcnt vmcnt(0) lgkmcnt(0)
+; GISEL-NEXT:    flat_store_dword v[2:3], v0
+; GISEL-NEXT:    s_waitcnt vmcnt(0) lgkmcnt(0)
+; GISEL-NEXT:    s_setpc_b64 s[30:31]
+; GISEL-NEXT:  .LBB2_3: ; Inline asm indirect target
+; GISEL-NEXT:    ; %kill
+; GISEL-NEXT:    ; Label of block must be emitted
+; GISEL-NEXT:    s_waitcnt vmcnt(0) lgkmcnt(0)
+; GISEL-NEXT:    v_mov_b32_e32 v0, 0
+; GISEL-NEXT:    flat_store_dword v[2:3], v0
+; GISEL-NEXT:    ; divergent unreachable
+; GISEL-NEXT:    s_waitcnt vmcnt(0) lgkmcnt(0)
+; GISEL-NEXT:    s_setpc_b64 s[30:31]
+; GISEL-NEXT:  .LBB2_4:
+; GISEL-NEXT:    s_mov_b64 exec, 0
+; GISEL-NEXT:    s_endpgm
+  %a = load i32, ptr %src, align 4
+  callbr void @llvm.amdgcn.kill(i1 %c) to label %cont [label %kill]
+kill:
+  store i32 0, ptr %dst, align 4
+  unreachable
+cont:
+  store i32 %a, ptr %dst, align 4
+  ret void
+}

>From 940824d4d5775ac557a8ac6e36ec5f7c616d3924 Mon Sep 17 00:00:00 2001
From: Robert Imschweiler <robert.imschweiler at amd.com>
Date: Wed, 8 Jul 2026 11:19:25 -0500
Subject: [PATCH 3/3] move tests

---
 llvm/test/Assembler/callbr.ll                 | 41 +++++++++++++
 llvm/test/CodeGen/AMDGPU/callbr-intrinsics.ll | 60 -------------------
 2 files changed, 41 insertions(+), 60 deletions(-)

diff --git a/llvm/test/Assembler/callbr.ll b/llvm/test/Assembler/callbr.ll
index 37fd777e1a395..6e63bdcbfa9ca 100644
--- a/llvm/test/Assembler/callbr.ll
+++ b/llvm/test/Assembler/callbr.ll
@@ -1,6 +1,7 @@
 ; RUN: llvm-as < %s | llvm-dis | FileCheck %s
 
 declare void @llvm.amdgcn.kill(i1)
+declare void @llvm.amdgcn.unreachable()
 
 define void @test_kill(i1 %c) {
 ; CHECK-LABEL: define void @test_kill(
@@ -18,3 +19,43 @@ kill:
 cont:
   ret void
 }
+
+define void @test_kill_unreachable_not_first(i1 %c, ptr %p) {
+; CHECK-LABEL: define void @test_kill_unreachable_not_first(
+; CHECK-SAME: i1 [[C:%.*]], ptr [[P:%.*]]) {
+; CHECK-NEXT:    callbr void @llvm.amdgcn.kill(i1 [[C]])
+; CHECK-NEXT:            to label %[[CONT:.*]] [label %kill]
+; CHECK:       [[KILL:.*:]]
+; CHECK-NEXT:    store i32 0, ptr [[P]], align 4
+; CHECK-NEXT:    unreachable
+; CHECK:       [[CONT]]:
+; CHECK-NEXT:    ret void
+;
+  callbr void @llvm.amdgcn.kill(i1 %c) to label %cont [label %kill]
+kill:
+  store i32 0, ptr %p, align 4
+  unreachable
+cont:
+  ret void
+}
+
+define void @test_kill_amdgcn_unreachable_not_first(i1 %c, ptr %p) {
+; CHECK-LABEL: define void @test_kill_amdgcn_unreachable_not_first(
+; CHECK-SAME: i1 [[C:%.*]], ptr [[P:%.*]]) {
+; CHECK-NEXT:    callbr void @llvm.amdgcn.kill(i1 [[C]])
+; CHECK-NEXT:            to label %[[CONT:.*]] [label %kill]
+; CHECK:       [[KILL:.*:]]
+; CHECK-NEXT:    store i32 0, ptr [[P]], align 4
+; CHECK-NEXT:    call void @llvm.amdgcn.unreachable()
+; CHECK-NEXT:    ret void
+; CHECK:       [[CONT]]:
+; CHECK-NEXT:    ret void
+;
+  callbr void @llvm.amdgcn.kill(i1 %c) to label %cont [label %kill]
+kill:
+  store i32 0, ptr %p, align 4
+  call void @llvm.amdgcn.unreachable()
+  ret void
+cont:
+  ret void
+}
diff --git a/llvm/test/CodeGen/AMDGPU/callbr-intrinsics.ll b/llvm/test/CodeGen/AMDGPU/callbr-intrinsics.ll
index 123c817202723..8ac31b3c70ed7 100644
--- a/llvm/test/CodeGen/AMDGPU/callbr-intrinsics.ll
+++ b/llvm/test/CodeGen/AMDGPU/callbr-intrinsics.ll
@@ -113,63 +113,3 @@ cont:
 kill:
   unreachable
 }
-
-define void @test_kill_unreachable_not_first(ptr %src, ptr %dst, i1 %c) {
-; CHECK-LABEL: test_kill_unreachable_not_first:
-; CHECK:       ; %bb.0:
-; CHECK-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; CHECK-NEXT:    flat_load_dword v0, v[0:1]
-; CHECK-NEXT:    v_and_b32_e32 v1, 1, v4
-; CHECK-NEXT:    v_cmp_eq_u32_e32 vcc, 1, v1
-; CHECK-NEXT:    s_mov_b64 s[4:5], exec
-; CHECK-NEXT:    s_andn2_b64 s[6:7], exec, vcc
-; CHECK-NEXT:    s_andn2_b64 s[4:5], s[4:5], s[6:7]
-; CHECK-NEXT:    s_cbranch_scc0 .LBB2_2
-; CHECK-NEXT:  ; %bb.1:
-; CHECK-NEXT:    s_and_b64 exec, exec, s[4:5]
-; CHECK-NEXT:    s_waitcnt vmcnt(0) lgkmcnt(0)
-; CHECK-NEXT:    flat_store_dword v[2:3], v0
-; CHECK-NEXT:    s_waitcnt vmcnt(0) lgkmcnt(0)
-; CHECK-NEXT:    s_setpc_b64 s[30:31]
-; CHECK-NEXT:  .LBB2_2:
-; CHECK-NEXT:    s_mov_b64 exec, 0
-; CHECK-NEXT:    s_endpgm
-;
-; GISEL-LABEL: test_kill_unreachable_not_first:
-; GISEL:       ; %bb.0:
-; GISEL-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GISEL-NEXT:    flat_load_dword v0, v[0:1]
-; GISEL-NEXT:    v_and_b32_e32 v1, 1, v4
-; GISEL-NEXT:    v_cmp_ne_u32_e32 vcc, 0, v1
-; GISEL-NEXT:    s_mov_b64 s[4:5], exec
-; GISEL-NEXT:    s_andn2_b64 s[6:7], exec, vcc
-; GISEL-NEXT:    s_andn2_b64 s[4:5], s[4:5], s[6:7]
-; GISEL-NEXT:    s_cbranch_scc0 .LBB2_4
-; GISEL-NEXT:  ; %bb.1:
-; GISEL-NEXT:    s_and_b64 exec, exec, s[4:5]
-; GISEL-NEXT:  ; %bb.2: ; %cont
-; GISEL-NEXT:    s_waitcnt vmcnt(0) lgkmcnt(0)
-; GISEL-NEXT:    flat_store_dword v[2:3], v0
-; GISEL-NEXT:    s_waitcnt vmcnt(0) lgkmcnt(0)
-; GISEL-NEXT:    s_setpc_b64 s[30:31]
-; GISEL-NEXT:  .LBB2_3: ; Inline asm indirect target
-; GISEL-NEXT:    ; %kill
-; GISEL-NEXT:    ; Label of block must be emitted
-; GISEL-NEXT:    s_waitcnt vmcnt(0) lgkmcnt(0)
-; GISEL-NEXT:    v_mov_b32_e32 v0, 0
-; GISEL-NEXT:    flat_store_dword v[2:3], v0
-; GISEL-NEXT:    ; divergent unreachable
-; GISEL-NEXT:    s_waitcnt vmcnt(0) lgkmcnt(0)
-; GISEL-NEXT:    s_setpc_b64 s[30:31]
-; GISEL-NEXT:  .LBB2_4:
-; GISEL-NEXT:    s_mov_b64 exec, 0
-; GISEL-NEXT:    s_endpgm
-  %a = load i32, ptr %src, align 4
-  callbr void @llvm.amdgcn.kill(i1 %c) to label %cont [label %kill]
-kill:
-  store i32 0, ptr %dst, align 4
-  unreachable
-cont:
-  store i32 %a, ptr %dst, align 4
-  ret void
-}



More information about the llvm-commits mailing list