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 @@ -12586,6 +12586,33 @@ return DAG.getNode(ISD::CTPOP, DL, VT, NewZext); } +// If we have (zext (abs X)) where X is a type that will be promoted by type +// legalization, convert to (abs (sext X)). But don't extend past a legal type. +static SDValue widenAbs(SDNode *Extend, SelectionDAG &DAG) { + assert(Extend->getOpcode() == ISD::ZERO_EXTEND && "Expected zero extend."); + + EVT VT = Extend->getValueType(0); + if (VT.isVector()) + return SDValue(); + + SDValue Abs = Extend->getOperand(0); + if (Abs.getOpcode() != ISD::ABS || !Abs.hasOneUse()) + return SDValue(); + + EVT AbsVT = Abs.getValueType(); + const TargetLowering &TLI = DAG.getTargetLoweringInfo(); + if (TLI.getTypeAction(*DAG.getContext(), AbsVT) != + TargetLowering::TypePromoteInteger) + return SDValue(); + + EVT LegalVT = TLI.getTypeToTransformTo(*DAG.getContext(), AbsVT); + + SDValue SExt = + DAG.getNode(ISD::SIGN_EXTEND, SDLoc(Abs), LegalVT, Abs.getOperand(0)); + SDValue NewAbs = DAG.getNode(ISD::ABS, SDLoc(Abs), LegalVT, SExt); + return DAG.getZExtOrTrunc(NewAbs, SDLoc(Extend), VT); +} + SDValue DAGCombiner::visitZERO_EXTEND(SDNode *N) { SDValue N0 = N->getOperand(0); EVT VT = N->getValueType(0); @@ -12850,6 +12877,9 @@ if (SDValue NewCtPop = widenCtPop(N, DAG)) return NewCtPop; + if (SDValue V = widenAbs(N, DAG)) + return V; + if (SDValue Res = tryToFoldExtendSelectLoad(N, TLI, DAG)) return Res; diff --git a/llvm/test/CodeGen/RISCV/iabs.ll b/llvm/test/CodeGen/RISCV/iabs.ll --- a/llvm/test/CodeGen/RISCV/iabs.ll +++ b/llvm/test/CodeGen/RISCV/iabs.ll @@ -513,32 +513,28 @@ define signext i32 @zext_abs8(i8 signext %x) { ; RV32I-LABEL: zext_abs8: ; RV32I: # %bb.0: -; RV32I-NEXT: srai a1, a0, 7 +; RV32I-NEXT: srai a1, a0, 31 ; RV32I-NEXT: xor a0, a0, a1 ; RV32I-NEXT: sub a0, a0, a1 -; RV32I-NEXT: andi a0, a0, 255 ; RV32I-NEXT: ret ; ; RV32ZBB-LABEL: zext_abs8: ; RV32ZBB: # %bb.0: ; RV32ZBB-NEXT: neg a1, a0 ; RV32ZBB-NEXT: max a0, a0, a1 -; RV32ZBB-NEXT: andi a0, a0, 255 ; RV32ZBB-NEXT: ret ; ; RV64I-LABEL: zext_abs8: ; RV64I: # %bb.0: -; RV64I-NEXT: srai a1, a0, 7 +; RV64I-NEXT: srai a1, a0, 63 ; RV64I-NEXT: xor a0, a0, a1 -; RV64I-NEXT: subw a0, a0, a1 -; RV64I-NEXT: andi a0, a0, 255 +; RV64I-NEXT: sub a0, a0, a1 ; RV64I-NEXT: ret ; ; RV64ZBB-LABEL: zext_abs8: ; RV64ZBB: # %bb.0: ; RV64ZBB-NEXT: neg a1, a0 ; RV64ZBB-NEXT: max a0, a0, a1 -; RV64ZBB-NEXT: andi a0, a0, 255 ; RV64ZBB-NEXT: ret %a = call i8 @llvm.abs.i8(i8 %x, i1 false) %b = zext i8 %a to i32 @@ -548,34 +544,28 @@ define signext i32 @zext_abs16(i16 signext %x) { ; RV32I-LABEL: zext_abs16: ; RV32I: # %bb.0: -; RV32I-NEXT: srai a1, a0, 15 +; RV32I-NEXT: srai a1, a0, 31 ; RV32I-NEXT: xor a0, a0, a1 ; RV32I-NEXT: sub a0, a0, a1 -; RV32I-NEXT: slli a0, a0, 16 -; RV32I-NEXT: srli a0, a0, 16 ; RV32I-NEXT: ret ; ; RV32ZBB-LABEL: zext_abs16: ; RV32ZBB: # %bb.0: ; RV32ZBB-NEXT: neg a1, a0 ; RV32ZBB-NEXT: max a0, a0, a1 -; RV32ZBB-NEXT: zext.h a0, a0 ; RV32ZBB-NEXT: ret ; ; RV64I-LABEL: zext_abs16: ; RV64I: # %bb.0: -; RV64I-NEXT: srai a1, a0, 15 +; RV64I-NEXT: srai a1, a0, 63 ; RV64I-NEXT: xor a0, a0, a1 -; RV64I-NEXT: subw a0, a0, a1 -; RV64I-NEXT: slli a0, a0, 48 -; RV64I-NEXT: srli a0, a0, 48 +; RV64I-NEXT: sub a0, a0, a1 ; RV64I-NEXT: ret ; ; RV64ZBB-LABEL: zext_abs16: ; RV64ZBB: # %bb.0: ; RV64ZBB-NEXT: neg a1, a0 ; RV64ZBB-NEXT: max a0, a0, a1 -; RV64ZBB-NEXT: zext.h a0, a0 ; RV64ZBB-NEXT: ret %a = call i16 @llvm.abs.i16(i16 %x, i1 false) %b = zext i16 %a to i32 @@ -585,10 +575,9 @@ define i64 @zext64_abs8(i8 signext %x) { ; RV32I-LABEL: zext64_abs8: ; RV32I: # %bb.0: -; RV32I-NEXT: srai a1, a0, 7 +; RV32I-NEXT: srai a1, a0, 31 ; RV32I-NEXT: xor a0, a0, a1 ; RV32I-NEXT: sub a0, a0, a1 -; RV32I-NEXT: andi a0, a0, 255 ; RV32I-NEXT: li a1, 0 ; RV32I-NEXT: ret ; @@ -596,23 +585,20 @@ ; RV32ZBB: # %bb.0: ; RV32ZBB-NEXT: neg a1, a0 ; RV32ZBB-NEXT: max a0, a0, a1 -; RV32ZBB-NEXT: andi a0, a0, 255 ; RV32ZBB-NEXT: li a1, 0 ; RV32ZBB-NEXT: ret ; ; RV64I-LABEL: zext64_abs8: ; RV64I: # %bb.0: -; RV64I-NEXT: srai a1, a0, 7 +; RV64I-NEXT: srai a1, a0, 63 ; RV64I-NEXT: xor a0, a0, a1 -; RV64I-NEXT: subw a0, a0, a1 -; RV64I-NEXT: andi a0, a0, 255 +; RV64I-NEXT: sub a0, a0, a1 ; RV64I-NEXT: ret ; ; RV64ZBB-LABEL: zext64_abs8: ; RV64ZBB: # %bb.0: ; RV64ZBB-NEXT: neg a1, a0 ; RV64ZBB-NEXT: max a0, a0, a1 -; RV64ZBB-NEXT: andi a0, a0, 255 ; RV64ZBB-NEXT: ret %a = call i8 @llvm.abs.i8(i8 %x, i1 false) %b = zext i8 %a to i64 @@ -622,11 +608,9 @@ define i64 @zext64_abs16(i16 signext %x) { ; RV32I-LABEL: zext64_abs16: ; RV32I: # %bb.0: -; RV32I-NEXT: srai a1, a0, 15 +; RV32I-NEXT: srai a1, a0, 31 ; RV32I-NEXT: xor a0, a0, a1 ; RV32I-NEXT: sub a0, a0, a1 -; RV32I-NEXT: slli a0, a0, 16 -; RV32I-NEXT: srli a0, a0, 16 ; RV32I-NEXT: li a1, 0 ; RV32I-NEXT: ret ; @@ -634,24 +618,20 @@ ; RV32ZBB: # %bb.0: ; RV32ZBB-NEXT: neg a1, a0 ; RV32ZBB-NEXT: max a0, a0, a1 -; RV32ZBB-NEXT: zext.h a0, a0 ; RV32ZBB-NEXT: li a1, 0 ; RV32ZBB-NEXT: ret ; ; RV64I-LABEL: zext64_abs16: ; RV64I: # %bb.0: -; RV64I-NEXT: srai a1, a0, 15 +; RV64I-NEXT: srai a1, a0, 63 ; RV64I-NEXT: xor a0, a0, a1 -; RV64I-NEXT: subw a0, a0, a1 -; RV64I-NEXT: slli a0, a0, 48 -; RV64I-NEXT: srli a0, a0, 48 +; RV64I-NEXT: sub a0, a0, a1 ; RV64I-NEXT: ret ; ; RV64ZBB-LABEL: zext64_abs16: ; RV64ZBB: # %bb.0: ; RV64ZBB-NEXT: neg a1, a0 ; RV64ZBB-NEXT: max a0, a0, a1 -; RV64ZBB-NEXT: zext.h a0, a0 ; RV64ZBB-NEXT: ret %a = call i16 @llvm.abs.i16(i16 %x, i1 false) %b = zext i16 %a to i64 @@ -661,11 +641,11 @@ define void @zext16_abs8(i8 %x, ptr %p) { ; RV32I-LABEL: zext16_abs8: ; RV32I: # %bb.0: -; RV32I-NEXT: slli a2, a0, 24 -; RV32I-NEXT: srai a2, a2, 31 +; RV32I-NEXT: slli a0, a0, 24 +; RV32I-NEXT: srai a0, a0, 24 +; RV32I-NEXT: srai a2, a0, 31 ; RV32I-NEXT: xor a0, a0, a2 ; RV32I-NEXT: sub a0, a0, a2 -; RV32I-NEXT: andi a0, a0, 255 ; RV32I-NEXT: sh a0, 0(a1) ; RV32I-NEXT: ret ; @@ -674,17 +654,16 @@ ; RV32ZBB-NEXT: sext.b a0, a0 ; RV32ZBB-NEXT: neg a2, a0 ; RV32ZBB-NEXT: max a0, a0, a2 -; RV32ZBB-NEXT: andi a0, a0, 255 ; RV32ZBB-NEXT: sh a0, 0(a1) ; RV32ZBB-NEXT: ret ; ; RV64I-LABEL: zext16_abs8: ; RV64I: # %bb.0: -; RV64I-NEXT: slli a2, a0, 56 -; RV64I-NEXT: srai a2, a2, 63 +; RV64I-NEXT: slli a0, a0, 56 +; RV64I-NEXT: srai a0, a0, 56 +; RV64I-NEXT: srai a2, a0, 63 ; RV64I-NEXT: xor a0, a0, a2 ; RV64I-NEXT: subw a0, a0, a2 -; RV64I-NEXT: andi a0, a0, 255 ; RV64I-NEXT: sh a0, 0(a1) ; RV64I-NEXT: ret ; @@ -693,7 +672,6 @@ ; RV64ZBB-NEXT: sext.b a0, a0 ; RV64ZBB-NEXT: neg a2, a0 ; RV64ZBB-NEXT: max a0, a0, a2 -; RV64ZBB-NEXT: andi a0, a0, 255 ; RV64ZBB-NEXT: sh a0, 0(a1) ; RV64ZBB-NEXT: ret %a = call i8 @llvm.abs.i8(i8 %x, i1 false)