[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