diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp --- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -9921,6 +9921,18 @@ if (SDValue NewVSel = matchVSelectOpSizesWithSetCC(N)) return NewVSel; + // If the target does not support a pop-count in the narrow source type but + // does support it in the destination type, widen the pop-count to this type: + // zext (ctpop X) --> ctpop (zext X) + // TODO: Generalize this to handle starting from anyext. + if (N0.getOpcode() == ISD::CTPOP && N0.hasOneUse() && + !TLI.isOperationLegalOrCustom(ISD::CTPOP, N0.getValueType()) && + TLI.isOperationLegalOrCustom(ISD::CTPOP, VT)) { + SDLoc DL(N); + SDValue NewZext = DAG.getZExtOrTrunc(N0.getOperand(0), DL, VT); + return DAG.getNode(ISD::CTPOP, DL, VT, NewZext); + } + return SDValue(); } diff --git a/llvm/test/CodeGen/PowerPC/popcnt-zext.ll b/llvm/test/CodeGen/PowerPC/popcnt-zext.ll --- a/llvm/test/CodeGen/PowerPC/popcnt-zext.ll +++ b/llvm/test/CodeGen/PowerPC/popcnt-zext.ll @@ -41,9 +41,8 @@ define i16 @popz_i8_i16(i8 %x) { ; FAST-LABEL: popz_i8_i16: ; FAST: # %bb.0: -; FAST-NEXT: rlwinm 3, 3, 0, 24, 31 -; FAST-NEXT: popcntw 3, 3 -; FAST-NEXT: clrldi 3, 3, 32 +; FAST-NEXT: clrldi 3, 3, 56 +; FAST-NEXT: popcntd 3, 3 ; FAST-NEXT: blr ; ; SLOW-LABEL: popz_i8_i16: @@ -114,9 +113,8 @@ define i32 @popz_i8_32(i8 %x) { ; FAST-LABEL: popz_i8_32: ; FAST: # %bb.0: -; FAST-NEXT: rlwinm 3, 3, 0, 24, 31 -; FAST-NEXT: popcntw 3, 3 -; FAST-NEXT: clrldi 3, 3, 32 +; FAST-NEXT: clrldi 3, 3, 56 +; FAST-NEXT: popcntd 3, 3 ; FAST-NEXT: blr ; ; SLOW-LABEL: popz_i8_32: @@ -187,9 +185,8 @@ define i32 @popz_i16_32(i16 %x) { ; FAST-LABEL: popz_i16_32: ; FAST: # %bb.0: -; FAST-NEXT: rlwinm 3, 3, 0, 16, 31 -; FAST-NEXT: popcntw 3, 3 -; FAST-NEXT: clrldi 3, 3, 32 +; FAST-NEXT: clrldi 3, 3, 48 +; FAST-NEXT: popcntd 3, 3 ; FAST-NEXT: blr ; ; SLOW-LABEL: popz_i16_32: