[llvm] [AMDGPU] Support `xor cond, -1` when lowering `BRCOND` (PR #160341)

Shilei Tian via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 23 11:48:51 PDT 2025


https://github.com/shiltian updated https://github.com/llvm/llvm-project/pull/160341

>From 2c936fd61afd04fb7ade0159f18f7ef2497eebca Mon Sep 17 00:00:00 2001
From: Shilei Tian <i at tianshilei.me>
Date: Tue, 23 Sep 2025 12:31:03 -0400
Subject: [PATCH 1/2] [AMDGPU] Support `xor cond, -1` when lowering `BRCOND`

This can happen when `xor cond, -1` is not combined.
---
 llvm/lib/Target/AMDGPU/SIISelLowering.cpp     | 23 ++++++++++++++++---
 .../CodeGen/AMDGPU/lower-brcond-with-xor.ll   | 23 +++++++++++++++++++
 2 files changed, 43 insertions(+), 3 deletions(-)
 create mode 100644 llvm/test/CodeGen/AMDGPU/lower-brcond-with-xor.ll

diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
index 0c3bfecce2d9f..01d5e013b7c11 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
@@ -7540,17 +7540,34 @@ SDValue SITargetLowering::LowerBRCOND(SDValue BRCOND, SelectionDAG &DAG) const {
   SDNode *BR = nullptr;
   SDNode *SetCC = nullptr;
 
-  if (Intr->getOpcode() == ISD::SETCC) {
+  switch (Intr->getOpcode()) {
+  case ISD::SETCC: {
     // As long as we negate the condition everything is fine
     SetCC = Intr;
     Intr = SetCC->getOperand(0).getNode();
-
-  } else {
+    break;
+  }
+  case ISD::XOR: {
+    // Similar to SETCC, if we have (xor c, -1) or (xor -1, c), we will be fine.
+    SDValue LHS = Intr->getOperand(0);
+    SDValue RHS = Intr->getOperand(1);
+    if (auto *C = dyn_cast<ConstantSDNode>(LHS); C && C->getZExtValue()) {
+      Intr = RHS.getNode();
+      break;
+    }
+    if (auto *C = dyn_cast<ConstantSDNode>(RHS); C && C->getZExtValue()) {
+      Intr = LHS.getNode();
+      break;
+    }
+    [[fallthrough]];
+  }
+  default: {
     // Get the target from BR if we don't negate the condition
     BR = findUser(BRCOND, ISD::BR);
     assert(BR && "brcond missing unconditional branch user");
     Target = BR->getOperand(1);
   }
+  }
 
   unsigned CFNode = isCFIntrinsic(Intr);
   if (CFNode == 0) {
diff --git a/llvm/test/CodeGen/AMDGPU/lower-brcond-with-xor.ll b/llvm/test/CodeGen/AMDGPU/lower-brcond-with-xor.ll
new file mode 100644
index 0000000000000..e2f8df0448f82
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/lower-brcond-with-xor.ll
@@ -0,0 +1,23 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx90a --debug-counter=dagcombine=0 -start-before=si-annotate-control-flow %s -o - | FileCheck %s
+
+define amdgpu_kernel void @test(i32 %N, ptr addrspace(1) %p) {
+; CHECK-LABEL: test:
+; CHECK:       ; %bb.0: ; %entry
+; CHECK-NEXT:    v_and_b32_e32 v0, 0x3ff, v0
+; CHECK-NEXT:    v_cmp_gt_i32_e32 vcc, 1, v0
+; CHECK-NEXT:    s_and_saveexec_b64 s[0:1], vcc
+; CHECK-NEXT:    s_endpgm
+entry:
+  %id.x = tail call i32 @llvm.amdgcn.workitem.id.x()
+  %cmp2 = icmp slt i32 %id.x, 1
+  br i1 %cmp2, label %if.then, label %exit
+
+if.then:
+  %idx.ext = zext i32 %N to i64
+  %add.ptr = getelementptr i8, ptr addrspace(1) %p, i64 %idx.ext
+  ret void
+
+exit:
+  ret void
+}

>From 8aa43956ac221f0b3ef455cedf7adf0886891ec3 Mon Sep 17 00:00:00 2001
From: Shilei Tian <i at tianshilei.me>
Date: Tue, 23 Sep 2025 14:48:13 -0400
Subject: [PATCH 2/2] assume canonical form

---
 llvm/lib/Target/AMDGPU/SIISelLowering.cpp | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
index 01d5e013b7c11..5a9036f748655 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
@@ -7548,13 +7548,9 @@ SDValue SITargetLowering::LowerBRCOND(SDValue BRCOND, SelectionDAG &DAG) const {
     break;
   }
   case ISD::XOR: {
-    // Similar to SETCC, if we have (xor c, -1) or (xor -1, c), we will be fine.
+    // Similar to SETCC, if we have (xor c, -1), we will be fine.
     SDValue LHS = Intr->getOperand(0);
     SDValue RHS = Intr->getOperand(1);
-    if (auto *C = dyn_cast<ConstantSDNode>(LHS); C && C->getZExtValue()) {
-      Intr = RHS.getNode();
-      break;
-    }
     if (auto *C = dyn_cast<ConstantSDNode>(RHS); C && C->getZExtValue()) {
       Intr = LHS.getNode();
       break;



More information about the llvm-commits mailing list