[DAGCombiner][RISCV] Pre-promote (zext (abs X)) to (abs (sext X)) when X has an illeg...
authorCraig Topper <craig.topper@sifive.com>
Fri, 13 Jan 2023 18:04:00 +0000 (10:04 -0800)
committerCraig Topper <craig.topper@sifive.com>
Fri, 13 Jan 2023 18:40:25 +0000 (10:40 -0800)
Type legalization will insert a sign extend anyway. By doing it
early we can remove the zext. ComputeNumSignBits can't spot it
after type legalization because type legalization may expand
the abs to sra+xor+sub.

If the zext result type is larger than the type to be promoted to,
we'll promote to a legal type and then zext the rest of the way.
If the legal type is larger than the destination type we can promote
and then truncate.

Reviewed By: asb

Differential Revision: https://reviews.llvm.org/D140509

llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
llvm/test/CodeGen/RISCV/iabs.ll

index 278d82c..b8eb279 100644 (file)
@@ -12602,6 +12602,33 @@ static SDValue widenCtPop(SDNode *Extend, SelectionDAG &DAG) {
   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);
@@ -12866,6 +12893,9 @@ SDValue DAGCombiner::visitZERO_EXTEND(SDNode *N) {
   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;
 
index 5c7636d..7a1d57e 100644 (file)
@@ -513,32 +513,28 @@ define i64 @zext_abs32(i32 %x) {
 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_abs8(i8 signext %x) {
 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 signext i32 @zext_abs16(i16 signext %x) {
 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 @@ define i64 @zext64_abs8(i8 signext %x) {
 ; 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_abs8(i8 signext %x) {
 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 @@ define i64 @zext64_abs16(i16 signext %x) {
 ; 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 i64 @zext64_abs16(i16 signext %x) {
 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 @@ define void @zext16_abs8(i8 %x, ptr %p) {
 ; 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 @@ define void @zext16_abs8(i8 %x, ptr %p) {
 ; 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)