[llvm] [PowerPC] Generalize combineADDToADDZE to support i32 operands (PR #207553)

via llvm-commits llvm-commits at lists.llvm.org
Sat Jul 4 19:02:21 PDT 2026


https://github.com/AZero13 updated https://github.com/llvm/llvm-project/pull/207553

>From d8bc8d88cfad3cf29536b6774d575326d732dd40 Mon Sep 17 00:00:00 2001
From: AZero13 <gfunni234 at gmail.com>
Date: Sat, 4 Jul 2026 21:32:24 -0400
Subject: [PATCH 1/2] Precommit test (NFC)

---
 .../test/CodeGen/PowerPC/add-zext-to-addze.ll | 83 +++++++++++++++++++
 1 file changed, 83 insertions(+)
 create mode 100644 llvm/test/CodeGen/PowerPC/add-zext-to-addze.ll

diff --git a/llvm/test/CodeGen/PowerPC/add-zext-to-addze.ll b/llvm/test/CodeGen/PowerPC/add-zext-to-addze.ll
new file mode 100644
index 0000000000000..b6552b1b74e9e
--- /dev/null
+++ b/llvm/test/CodeGen/PowerPC/add-zext-to-addze.ll
@@ -0,0 +1,83 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=powerpc64le-unknown-linux-gnu -verify-machineinstrs < %s | FileCheck %s --check-prefix=PPC64
+; RUN: llc -mtriple=powerpc-unknown-linux-gnu -verify-machineinstrs < %s | FileCheck %s --check-prefix=PPC32
+
+define i64 @test_addze_64_64(i64 %x, i64 %z) {
+; PPC64-LABEL: test_addze_64_64:
+; PPC64:       # %bb.0: # %entry
+; PPC64-NEXT:    addi 4, 4, -42
+; PPC64-NEXT:    addic 4, 4, -1
+; PPC64-NEXT:    addze 3, 3
+; PPC64-NEXT:    blr
+;
+; PPC32-LABEL: test_addze_64_64:
+; PPC32:       # %bb.0: # %entry
+; PPC32-NEXT:    xori 6, 6, 42
+; PPC32-NEXT:    or 5, 6, 5
+; PPC32-NEXT:    cntlzw 5, 5
+; PPC32-NEXT:    not 5, 5
+; PPC32-NEXT:    rlwinm 5, 5, 27, 31, 31
+; PPC32-NEXT:    addc 4, 4, 5
+; PPC32-NEXT:    addze 3, 3
+; PPC32-NEXT:    blr
+entry:
+  %cmp = icmp ne i64 %z, 42
+  %ext = zext i1 %cmp to i64
+  %add = add i64 %x, %ext
+  ret i64 %add
+}
+
+define i32 @test_addze_64_32(i32 %x, i32 %z) {
+; PPC64-LABEL: test_addze_64_32:
+; PPC64:       # %bb.0: # %entry
+; PPC64-NEXT:    xori 4, 4, 42
+; PPC64-NEXT:    cntlzw 4, 4
+; PPC64-NEXT:    srwi 4, 4, 5
+; PPC64-NEXT:    xori 4, 4, 1
+; PPC64-NEXT:    add 3, 3, 4
+; PPC64-NEXT:    blr
+;
+; PPC32-LABEL: test_addze_64_32:
+; PPC32:       # %bb.0: # %entry
+; PPC32-NEXT:    mr 5, 3
+; PPC32-NEXT:    cmpwi 4, 42
+; PPC32-NEXT:    addi 3, 3, 0
+; PPC32-NEXT:    bclr 12, 2, 0
+; PPC32-NEXT:  # %bb.1: # %entry
+; PPC32-NEXT:    addi 3, 5, 1
+; PPC32-NEXT:    blr
+entry:
+  %cmp = icmp ne i32 %z, 42
+  %ext = zext i1 %cmp to i32
+  %add = add i32 %x, %ext
+  ret i32 %add
+}
+
+define i64 @test_addze_64_32_zext(i64 %x, i32 %z) {
+; PPC64-LABEL: test_addze_64_32_zext:
+; PPC64:       # %bb.0: # %entry
+; PPC64-NEXT:    xori 4, 4, 42
+; PPC64-NEXT:    cntlzw 4, 4
+; PPC64-NEXT:    srwi 4, 4, 5
+; PPC64-NEXT:    xori 4, 4, 1
+; PPC64-NEXT:    add 3, 3, 4
+; PPC64-NEXT:    blr
+;
+; PPC32-LABEL: test_addze_64_32_zext:
+; PPC32:       # %bb.0: # %entry
+; PPC32-NEXT:    cmpwi 5, 42
+; PPC32-NEXT:    li 5, 0
+; PPC32-NEXT:    bc 12, 2, .LBB2_2
+; PPC32-NEXT:  # %bb.1: # %entry
+; PPC32-NEXT:    li 5, 1
+; PPC32-NEXT:  .LBB2_2: # %entry
+; PPC32-NEXT:    addc 4, 4, 5
+; PPC32-NEXT:    addze 3, 3
+; PPC32-NEXT:    blr
+entry:
+  %cmp = icmp ne i32 %z, 42
+  %ext = zext i1 %cmp to i64
+  %add = add i64 %x, %ext
+  ret i64 %add
+}
+

>From 7646c2256724b644f224cc1a0f5cc2d71d16bf6f Mon Sep 17 00:00:00 2001
From: AZero13 <gfunni234 at gmail.com>
Date: Sat, 4 Jul 2026 21:52:07 -0400
Subject: [PATCH 2/2] [PowerPC] Generalize combineADDToADDZE to support i32
 operands

Previously, combineADDToADDZE only fired on PPC64 with i64 operands.

This patch generalizes it to handle i32 operands on both PPC64 and
PPC32:

- On PPC64 with i32 values: sign-extend to i64, perform the addic/addze
  sequence natively, then truncate the result back to i32.
- On PPC32: use the addic/addze sequence directly with i32, which is the
  native word size.

This eliminates branchy or multi-instruction boolean materialization sequences (cmpwi+bclr, xori+cntlzw+srwi+xori) in favor of the branchless addi+addic+addze idiom.
---
 llvm/lib/Target/PowerPC/PPCISelLowering.cpp   | 81 +++++++++++++------
 .../test/CodeGen/PowerPC/add-zext-to-addze.ll | 28 +++----
 2 files changed, 67 insertions(+), 42 deletions(-)

diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
index 9a4943aad6289..142fb462ace6b 100644
--- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
+++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
@@ -20014,23 +20014,31 @@ SDValue PPCTargetLowering::combineSRL(SDNode *N, DAGCombinerInfo &DCI) const {
 // Transform (add X, (zext(setne Z, C))) -> (addze X, (addic (addi Z, -C), -1))
 // Transform (add X, (zext(sete  Z, C))) -> (addze X, (subfic (addi Z, -C), 0))
 // When C is zero, the equation (addi Z, -C) can be simplified to Z
-// Requirement: -C in [-32768, 32767], X and Z are MVT::i64 types
+// Requirement: -C in [-32768, 32767]. If X or Z are i32 on PPC64,
+// they are sign-extended to i64 and the result is truncated back.
 static SDValue combineADDToADDZE(SDNode *N, SelectionDAG &DAG,
                                  const PPCSubtarget &Subtarget) {
-  if (!Subtarget.isPPC64())
-    return SDValue();
-
   SDValue LHS = N->getOperand(0);
   SDValue RHS = N->getOperand(1);
 
-  auto isZextOfCompareWithConstant = [](SDValue Op) {
-    if (Op.getOpcode() != ISD::ZERO_EXTEND || !Op.hasOneUse() ||
-        Op.getValueType() != MVT::i64)
+  EVT NativeVT = Subtarget.isPPC64() ? MVT::i64 : MVT::i32;
+  EVT VT = N->getValueType(0);
+
+  if (VT.getSizeInBits() > NativeVT.getSizeInBits())
+    return SDValue();
+
+  auto isZextOfCompareWithConstant = [VT, NativeVT](SDValue Op) {
+    if ((Op.getOpcode() != ISD::ZERO_EXTEND &&
+         Op.getOpcode() != ISD::ANY_EXTEND) ||
+        !Op.hasOneUse() || Op.getValueType() != VT)
       return false;
 
     SDValue Cmp = Op.getOperand(0);
-    if (Cmp.getOpcode() != ISD::SETCC || !Cmp.hasOneUse() ||
-        Cmp.getOperand(0).getValueType() != MVT::i64)
+    if (Cmp.getOpcode() != ISD::SETCC || !Cmp.hasOneUse())
+      return false;
+
+    EVT CmpOp0VT = Cmp.getOperand(0).getValueType();
+    if (CmpOp0VT != NativeVT && CmpOp0VT != MVT::i32)
       return false;
 
     if (auto *Constant = dyn_cast<ConstantSDNode>(Cmp.getOperand(1))) {
@@ -20054,12 +20062,21 @@ static SDValue combineADDToADDZE(SDNode *N, SelectionDAG &DAG,
 
   SDLoc DL(N);
   EVT CarryType = Subtarget.useCRBits() ? MVT::i1 : MVT::i32;
-  SDVTList VTs = DAG.getVTList(MVT::i64, CarryType);
+  SDVTList VTs = DAG.getVTList(NativeVT, CarryType);
   SDValue Cmp = RHS.getOperand(0);
   SDValue Z = Cmp.getOperand(0);
+
+  if (Z.getValueType() != NativeVT)
+    Z = DAG.getNode(ISD::SIGN_EXTEND, DL, NativeVT, Z);
+
+  SDValue ExtLHS = LHS;
+  if (ExtLHS.getValueType() != NativeVT)
+    ExtLHS = DAG.getNode(ISD::SIGN_EXTEND, DL, NativeVT, ExtLHS);
+
   auto *Constant = cast<ConstantSDNode>(Cmp.getOperand(1));
   int64_t NegConstant = 0 - Constant->getSExtValue();
 
+  SDValue Result;
   switch(cast<CondCodeSDNode>(Cmp.getOperand(2))->get()) {
   default: break;
   case ISD::SETNE: {
@@ -20069,16 +20086,19 @@ static SDValue combineADDToADDZE(SDNode *N, SelectionDAG &DAG,
     // add X, (zext(setne Z, C))--
     //                            \    when -32768 <= -C <= 32767 && C != 0
     //                             --> addze X, (addic (addi Z, -C), -1).carry
-    SDValue Add = DAG.getNode(ISD::ADD, DL, MVT::i64, Z,
-                              DAG.getConstant(NegConstant, DL, MVT::i64));
+    SDValue Add = DAG.getNode(ISD::ADD, DL, NativeVT, Z,
+                              DAG.getConstant(NativeVT == MVT::i32
+                                                  ? (uint32_t)NegConstant
+                                                  : (uint64_t)NegConstant,
+                                              DL, NativeVT));
     SDValue AddOrZ = NegConstant != 0 ? Add : Z;
-    SDValue Addc =
-        DAG.getNode(ISD::UADDO_CARRY, DL, DAG.getVTList(MVT::i64, CarryType),
-                    AddOrZ, DAG.getAllOnesConstant(DL, MVT::i64),
-                    DAG.getConstant(0, DL, CarryType));
-    return DAG.getNode(ISD::UADDO_CARRY, DL, VTs, LHS,
-                       DAG.getConstant(0, DL, MVT::i64),
-                       SDValue(Addc.getNode(), 1));
+    SDValue Addc = DAG.getNode(ISD::UADDO_CARRY, DL, VTs, AddOrZ,
+                               DAG.getAllOnesConstant(DL, NativeVT),
+                               DAG.getConstant(0, DL, CarryType));
+    Result = DAG.getNode(ISD::UADDO_CARRY, DL, VTs, ExtLHS,
+                         DAG.getConstant(0, DL, NativeVT),
+                         SDValue(Addc.getNode(), 1));
+    break;
   }
   case ISD::SETEQ: {
     //                                 when C == 0
@@ -20087,20 +20107,29 @@ static SDValue combineADDToADDZE(SDNode *N, SelectionDAG &DAG,
     // add X, (zext(sete  Z, C))--
     //                            \    when -32768 <= -C <= 32767 && C != 0
     //                             --> addze X, (subfic (addi Z, -C), 0).carry
-    SDValue Add = DAG.getNode(ISD::ADD, DL, MVT::i64, Z,
-                              DAG.getConstant(NegConstant, DL, MVT::i64));
+    SDValue Add = DAG.getNode(ISD::ADD, DL, NativeVT, Z,
+                              DAG.getConstant(NativeVT == MVT::i32
+                                                  ? (uint32_t)NegConstant
+                                                  : (uint64_t)NegConstant,
+                                              DL, NativeVT));
     SDValue AddOrZ = NegConstant != 0 ? Add : Z;
     SDValue Subc =
-        DAG.getNode(ISD::USUBO_CARRY, DL, DAG.getVTList(MVT::i64, CarryType),
-                    DAG.getConstant(0, DL, MVT::i64), AddOrZ,
-                    DAG.getConstant(0, DL, CarryType));
+        DAG.getNode(ISD::USUBO_CARRY, DL, VTs, DAG.getConstant(0, DL, NativeVT),
+                    AddOrZ, DAG.getConstant(0, DL, CarryType));
     SDValue Invert = DAG.getNode(ISD::XOR, DL, CarryType, Subc.getValue(1),
                                  DAG.getConstant(1UL, DL, CarryType));
-    return DAG.getNode(ISD::UADDO_CARRY, DL, VTs, LHS,
-                       DAG.getConstant(0, DL, MVT::i64), Invert);
+    Result = DAG.getNode(ISD::UADDO_CARRY, DL, VTs, ExtLHS,
+                         DAG.getConstant(0, DL, NativeVT), Invert);
+    break;
   }
   }
 
+  if (Result) {
+    if (Result.getValueType() != VT)
+      Result = DAG.getNode(ISD::TRUNCATE, DL, VT, Result);
+    return Result;
+  }
+
   return SDValue();
 }
 
diff --git a/llvm/test/CodeGen/PowerPC/add-zext-to-addze.ll b/llvm/test/CodeGen/PowerPC/add-zext-to-addze.ll
index b6552b1b74e9e..7bee994a958fc 100644
--- a/llvm/test/CodeGen/PowerPC/add-zext-to-addze.ll
+++ b/llvm/test/CodeGen/PowerPC/add-zext-to-addze.ll
@@ -30,21 +30,18 @@ entry:
 define i32 @test_addze_64_32(i32 %x, i32 %z) {
 ; PPC64-LABEL: test_addze_64_32:
 ; PPC64:       # %bb.0: # %entry
-; PPC64-NEXT:    xori 4, 4, 42
-; PPC64-NEXT:    cntlzw 4, 4
-; PPC64-NEXT:    srwi 4, 4, 5
-; PPC64-NEXT:    xori 4, 4, 1
-; PPC64-NEXT:    add 3, 3, 4
+; PPC64-NEXT:    extsw 4, 4
+; PPC64-NEXT:    extsw 3, 3
+; PPC64-NEXT:    addi 4, 4, -42
+; PPC64-NEXT:    addic 4, 4, -1
+; PPC64-NEXT:    addze 3, 3
 ; PPC64-NEXT:    blr
 ;
 ; PPC32-LABEL: test_addze_64_32:
 ; PPC32:       # %bb.0: # %entry
-; PPC32-NEXT:    mr 5, 3
-; PPC32-NEXT:    cmpwi 4, 42
-; PPC32-NEXT:    addi 3, 3, 0
-; PPC32-NEXT:    bclr 12, 2, 0
-; PPC32-NEXT:  # %bb.1: # %entry
-; PPC32-NEXT:    addi 3, 5, 1
+; PPC32-NEXT:    addi 4, 4, -42
+; PPC32-NEXT:    addic 4, 4, -1
+; PPC32-NEXT:    addze 3, 3
 ; PPC32-NEXT:    blr
 entry:
   %cmp = icmp ne i32 %z, 42
@@ -56,11 +53,10 @@ entry:
 define i64 @test_addze_64_32_zext(i64 %x, i32 %z) {
 ; PPC64-LABEL: test_addze_64_32_zext:
 ; PPC64:       # %bb.0: # %entry
-; PPC64-NEXT:    xori 4, 4, 42
-; PPC64-NEXT:    cntlzw 4, 4
-; PPC64-NEXT:    srwi 4, 4, 5
-; PPC64-NEXT:    xori 4, 4, 1
-; PPC64-NEXT:    add 3, 3, 4
+; PPC64-NEXT:    extsw 4, 4
+; PPC64-NEXT:    addi 4, 4, -42
+; PPC64-NEXT:    addic 4, 4, -1
+; PPC64-NEXT:    addze 3, 3
 ; PPC64-NEXT:    blr
 ;
 ; PPC32-LABEL: test_addze_64_32_zext:



More information about the llvm-commits mailing list