[llvm] 5cd900c - [AArch64] Transform shift+and to shift+shift to select more shifted register

via llvm-commits llvm-commits at lists.llvm.org
Tue Dec 6 07:30:02 PST 2022


Author: chenglin.bi
Date: 2022-12-06T23:29:56+08:00
New Revision: 5cd900ce3c6edd9e0d9b163c9d6cf7f38688d2ee

URL: https://github.com/llvm/llvm-project/commit/5cd900ce3c6edd9e0d9b163c9d6cf7f38688d2ee
DIFF: https://github.com/llvm/llvm-project/commit/5cd900ce3c6edd9e0d9b163c9d6cf7f38688d2ee.diff

LOG: [AArch64] Transform shift+and to shift+shift to select more shifted register

and (shl/srl/sra, x, c), mask --> shl (srl/sra, x, c1), c2

Reviewed By: dmgreen

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

Added: 
    

Modified: 
    llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
    llvm/test/CodeGen/AArch64/shiftregister-from-and.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
index 5ed6293c4c1ab..436eff92f24ea 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
@@ -370,6 +370,7 @@ class AArch64DAGToDAGISel : public SelectionDAGISel {
 private:
   bool SelectShiftedRegister(SDValue N, bool AllowROR, SDValue &Reg,
                              SDValue &Shift);
+  bool SelectShiftedRegisterFromAnd(SDValue N, SDValue &Reg, SDValue &Shift);
   bool SelectAddrModeIndexed7S(SDValue N, unsigned Size, SDValue &Base,
                                SDValue &OffImm) {
     return SelectAddrModeIndexedBitWidth(N, true, 7, Size, Base, OffImm);
@@ -607,6 +608,84 @@ bool AArch64DAGToDAGISel::isWorthFolding(SDValue V) const {
   return false;
 }
 
+/// and (shl/srl/sra, x, c), mask --> shl (srl/sra, x, c1), c2
+/// to select more shifted register
+bool AArch64DAGToDAGISel::SelectShiftedRegisterFromAnd(SDValue N, SDValue &Reg,
+                                                       SDValue &Shift) {
+  EVT VT = N.getValueType();
+  if (VT != MVT::i32 && VT != MVT::i64)
+    return false;
+
+  if (N->getOpcode() != ISD::AND || !N->hasOneUse())
+    return false;
+  SDValue LHS = N.getOperand(0);
+  if (!LHS->hasOneUse())
+    return false;
+
+  unsigned LHSOpcode = LHS->getOpcode();
+  if (LHSOpcode != ISD::SHL && LHSOpcode != ISD::SRL && LHSOpcode != ISD::SRA)
+    return false;
+
+  ConstantSDNode *ShiftAmtNode = dyn_cast<ConstantSDNode>(LHS.getOperand(1));
+  if (!ShiftAmtNode)
+    return false;
+
+  uint64_t ShiftAmtC = ShiftAmtNode->getZExtValue();
+  ConstantSDNode *RHSC = dyn_cast<ConstantSDNode>(N.getOperand(1));
+  if (!RHSC)
+    return false;
+
+  APInt AndMask = RHSC->getAPIntValue();
+  unsigned LowZBits, MaskLen;
+  if (!AndMask.isShiftedMask(LowZBits, MaskLen))
+    return false;
+
+  unsigned BitWidth = N.getValueSizeInBits();
+  SDLoc DL(LHS);
+  uint64_t NewShiftC;
+  unsigned NewShiftOp;
+  if (LHSOpcode == ISD::SHL) {
+    // LowZBits <= ShiftAmtC will fall into isBitfieldPositioningOp
+    // BitWidth != LowZBits + MaskLen doesn't match the pattern
+    if (LowZBits <= ShiftAmtC || (BitWidth != LowZBits + MaskLen))
+      return false;
+
+    NewShiftC = LowZBits - ShiftAmtC;
+    NewShiftOp = VT == MVT::i64 ? AArch64::UBFMXri : AArch64::UBFMWri;
+  } else {
+    if (LowZBits == 0)
+      return false;
+
+    // NewShiftC >= BitWidth will fall into isBitfieldExtractOp
+    NewShiftC = LowZBits + ShiftAmtC;
+    if (NewShiftC >= BitWidth)
+      return false;
+
+    // SRA need all high bits
+    if (LHSOpcode == ISD::SRA && (BitWidth != (LowZBits + MaskLen)))
+      return false;
+
+    // SRL high bits can be 0 or 1
+    if (LHSOpcode == ISD::SRL && (BitWidth > (NewShiftC + MaskLen)))
+      return false;
+
+    if (LHSOpcode == ISD::SRL)
+      NewShiftOp = VT == MVT::i64 ? AArch64::UBFMXri : AArch64::UBFMWri;
+    else
+      NewShiftOp = VT == MVT::i64 ? AArch64::SBFMXri : AArch64::SBFMWri;
+  }
+
+  assert(NewShiftC < BitWidth && "Invalid shift amount");
+  SDValue NewShiftAmt = CurDAG->getTargetConstant(NewShiftC, DL, VT);
+  SDValue BitWidthMinus1 = CurDAG->getTargetConstant(BitWidth - 1, DL, VT);
+  Reg = SDValue(CurDAG->getMachineNode(NewShiftOp, DL, VT, LHS->getOperand(0),
+                                       NewShiftAmt, BitWidthMinus1),
+                0);
+  unsigned ShVal = AArch64_AM::getShifterImm(AArch64_AM::LSL, LowZBits);
+  Shift = CurDAG->getTargetConstant(ShVal, DL, MVT::i32);
+  return true;
+}
+
 /// SelectShiftedRegister - Select a "shifted register" operand.  If the value
 /// is not shifted, set the Shift operand to default of "LSL 0".  The logical
 /// instructions allow the shifted register to be rotated, but the arithmetic
@@ -614,6 +693,9 @@ bool AArch64DAGToDAGISel::isWorthFolding(SDValue V) const {
 /// supported.
 bool AArch64DAGToDAGISel::SelectShiftedRegister(SDValue N, bool AllowROR,
                                                 SDValue &Reg, SDValue &Shift) {
+  if (SelectShiftedRegisterFromAnd(N, Reg, Shift))
+    return true;
+
   AArch64_AM::ShiftExtendType ShType = getShiftTypeForNode(N);
   if (ShType == AArch64_AM::InvalidShiftExtend)
     return false;

diff  --git a/llvm/test/CodeGen/AArch64/shiftregister-from-and.ll b/llvm/test/CodeGen/AArch64/shiftregister-from-and.ll
index 4db550c35d829..91011ec66048f 100644
--- a/llvm/test/CodeGen/AArch64/shiftregister-from-and.ll
+++ b/llvm/test/CodeGen/AArch64/shiftregister-from-and.ll
@@ -37,9 +37,8 @@ define i64 @bic_shiftedreg_from_and(i64 %a, i64 %b) {
 define i64 @eon_shiftedreg_from_and(i64 %a, i64 %b) {
 ; CHECK-LABEL: eon_shiftedreg_from_and:
 ; CHECK:       // %bb.0:
-; CHECK-NEXT:    lsl x8, x0, #36
-; CHECK-NEXT:    and x8, x8, #0xffe0000000000000
-; CHECK-NEXT:    eon x0, x8, x1
+; CHECK-NEXT:    lsr x8, x0, #17
+; CHECK-NEXT:    eon x0, x1, x8, lsl #53
 ; CHECK-NEXT:    ret
   %shl = shl i64 %a, 36
   %and = and i64 %shl, -9007199254740992
@@ -53,9 +52,8 @@ define i64 @eon_shiftedreg_from_and(i64 %a, i64 %b) {
 define i64 @eor_shiftedreg_from_and(i64 %a, i64 %b) {
 ; CHECK-LABEL: eor_shiftedreg_from_and:
 ; CHECK:       // %bb.0:
-; CHECK-NEXT:    lsr x8, x0, #23
-; CHECK-NEXT:    and x8, x8, #0x1ffff000000
-; CHECK-NEXT:    eor x0, x8, x1
+; CHECK-NEXT:    lsr x8, x0, #47
+; CHECK-NEXT:    eor x0, x1, x8, lsl #24
 ; CHECK-NEXT:    ret
   %lshr = lshr i64 %a, 23
   %and = and i64 %lshr, 2199006478336
@@ -100,9 +98,8 @@ define i64 @orn_shiftedreg_from_and(i64 %a, i64 %b) {
 define i64 @orr_shiftedreg_from_and(i64 %a, i64 %b) {
 ; CHECK-LABEL: orr_shiftedreg_from_and:
 ; CHECK:       // %bb.0:
-; CHECK-NEXT:    lsr x8, x0, #23
-; CHECK-NEXT:    and x8, x8, #0x1ffff000000
-; CHECK-NEXT:    orr x0, x8, x1
+; CHECK-NEXT:    lsr x8, x0, #47
+; CHECK-NEXT:    orr x0, x1, x8, lsl #24
 ; CHECK-NEXT:    ret
   %lshr = lshr i64 %a, 23
   %and = and i64 %lshr, 2199006478336 ; 0x1ffff000000
@@ -116,9 +113,8 @@ define i64 @orr_shiftedreg_from_and(i64 %a, i64 %b) {
 define i64 @orr_shiftedreg_from_and_mask2(i64 %a, i64 %b) {
 ; CHECK-LABEL: orr_shiftedreg_from_and_mask2:
 ; CHECK:       // %bb.0:
-; CHECK-NEXT:    lsr x8, x0, #23
-; CHECK-NEXT:    and x8, x8, #0x1ffff000000
-; CHECK-NEXT:    orr x0, x8, x1
+; CHECK-NEXT:    lsr x8, x0, #47
+; CHECK-NEXT:    orr x0, x1, x8, lsl #24
 ; CHECK-NEXT:    ret
   %lshr = lshr i64 %a, 23
   %and = and i64 %lshr, 4398029733888 ; 0x3ffff000000
@@ -132,9 +128,8 @@ define i64 @orr_shiftedreg_from_and_mask2(i64 %a, i64 %b) {
 define i32 @add_shiftedreg_from_and(i32 %a, i32 %b) {
 ; CHECK-LABEL: add_shiftedreg_from_and:
 ; CHECK:       // %bb.0:
-; CHECK-NEXT:    asr w8, w0, #3
-; CHECK-NEXT:    and w8, w8, #0xff000000
-; CHECK-NEXT:    add w0, w8, w1
+; CHECK-NEXT:    asr w8, w0, #27
+; CHECK-NEXT:    add w0, w1, w8, lsl #24
 ; CHECK-NEXT:    ret
   %ashr = ashr i32 %a, 3
   %and = and i32 %ashr, -16777216
@@ -147,9 +142,8 @@ define i32 @add_shiftedreg_from_and(i32 %a, i32 %b) {
 define i64 @sub_shiftedreg_from_and_shl(i64 %a, i64 %b) {
 ; CHECK-LABEL: sub_shiftedreg_from_and_shl:
 ; CHECK:       // %bb.0:
-; CHECK-NEXT:    lsl x8, x0, #36
-; CHECK-NEXT:    and x8, x8, #0xffe0000000000000
-; CHECK-NEXT:    sub x0, x1, x8
+; CHECK-NEXT:    lsr x8, x0, #17
+; CHECK-NEXT:    sub x0, x1, x8, lsl #53
 ; CHECK-NEXT:    ret
   %shl = shl i64 %a, 36
   %and = and i64 %shl, -9007199254740992


        


More information about the llvm-commits mailing list