[llvm] a304d70 - [RISCV] Reorder (and/or/xor (shl X, C1), C2) if we can form ANDI/ORI/XORI.

Craig Topper via llvm-commits llvm-commits at lists.llvm.org
Wed Jul 27 17:41:10 PDT 2022


Author: Craig Topper
Date: 2022-07-27T17:35:26-07:00
New Revision: a304d70ee9b8611b60eb1951cbf62cd447520a36

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

LOG: [RISCV] Reorder (and/or/xor (shl X, C1), C2) if we can form ANDI/ORI/XORI.

InstCombine and DAGCombine prefer to keep shl before binops.

This patch teaches isel to convert to (shl (and/or/xor X, C1 >> C2), C2)
if (C1 >> C2) is a simm12. The idea was taken from X86's isel code.

There's a special case implemented for a sext_inreg between the
shift and the binop.

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

Added: 
    

Modified: 
    llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
    llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h
    llvm/test/CodeGen/RISCV/narrow-shl-cst.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
index d5826b46d738..5d00919dfa78 100644
--- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
@@ -579,6 +579,84 @@ void RISCVDAGToDAGISel::selectVSETVLI(SDNode *Node) {
   ReplaceNode(Node, CurDAG->getMachineNode(Opcode, DL, VTs, Ops));
 }
 
+bool RISCVDAGToDAGISel::tryShrinkShlLogicImm(SDNode *Node) {
+  MVT VT = Node->getSimpleValueType(0);
+  unsigned Opcode = Node->getOpcode();
+  assert((Opcode == ISD::AND || Opcode == ISD::OR || Opcode == ISD::XOR) &&
+         "Unexpected opcode");
+  SDLoc DL(Node);
+
+  // For operations of the form (x << C1) op C2, check if we can use
+  // ANDI/ORI/XORI by transforming it into (x op (C2>>C1)) << C1.
+  SDValue N0 = Node->getOperand(0);
+  SDValue N1 = Node->getOperand(1);
+
+  ConstantSDNode *Cst = dyn_cast<ConstantSDNode>(N1);
+  if (!Cst)
+    return false;
+
+  int64_t Val = Cst->getSExtValue();
+
+  // Check if immediate can already use ANDI/ORI/XORI.
+  if (isInt<12>(Val))
+    return false;
+
+  SDValue Shift = N0;
+
+  // If Val is simm32 and we have a sext_inreg from i32, then the binop
+  // produces at least 33 sign bits. We can peek through the sext_inreg and use
+  // a SLLIW at the end.
+  bool SignExt = false;
+  if (isInt<32>(Val) && N0.getOpcode() == ISD::SIGN_EXTEND_INREG &&
+      N0.hasOneUse() && cast<VTSDNode>(N0.getOperand(1))->getVT() == MVT::i32) {
+    SignExt = true;
+    Shift = N0.getOperand(0);
+  }
+
+  if (Shift.getOpcode() != ISD::SHL || !Shift.hasOneUse())
+    return false;
+
+  ConstantSDNode *ShlCst = dyn_cast<ConstantSDNode>(Shift.getOperand(1));
+  if (!ShlCst)
+    return false;
+
+  uint64_t ShAmt = ShlCst->getZExtValue();
+
+  // Make sure that we don't change the operation by removing bits.
+  // This only matters for OR and XOR, AND is unaffected.
+  uint64_t RemovedBitsMask = maskTrailingOnes<uint64_t>(ShAmt);
+  if (Opcode != ISD::AND && (Val & RemovedBitsMask) != 0)
+    return false;
+
+  int64_t ShiftedVal = Val >> ShAmt;
+  if (!isInt<12>(ShiftedVal))
+    return false;
+
+  // If we peeked through a sext_inreg, make sure the shift is valid for SLLIW.
+  if (SignExt && ShAmt >= 32)
+    return false;
+
+  // Ok, we can reorder to get a smaller immediate.
+  unsigned BinOpc;
+  switch (Opcode) {
+  default: llvm_unreachable("Unexpected opcode");
+  case ISD::AND: BinOpc = RISCV::ANDI; break;
+  case ISD::OR:  BinOpc = RISCV::ORI;  break;
+  case ISD::XOR: BinOpc = RISCV::XORI; break;
+  }
+
+  unsigned ShOpc = SignExt ? RISCV::SLLIW : RISCV::SLLI;
+
+  SDNode *BinOp =
+      CurDAG->getMachineNode(BinOpc, DL, VT, Shift.getOperand(0),
+                             CurDAG->getTargetConstant(ShiftedVal, DL, VT));
+  SDNode *SLLI =
+      CurDAG->getMachineNode(ShOpc, DL, VT, SDValue(BinOp, 0),
+                             CurDAG->getTargetConstant(ShAmt, DL, VT));
+  ReplaceNode(Node, SLLI);
+  return true;
+}
+
 void RISCVDAGToDAGISel::Select(SDNode *Node) {
   // If we have a custom node, we have already selected.
   if (Node->isMachineOpcode()) {
@@ -739,6 +817,12 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) {
     ReplaceNode(Node, SRAI);
     return;
   }
+  case ISD::OR:
+  case ISD::XOR:
+    if (tryShrinkShlLogicImm(Node))
+      return;
+
+    break;
   case ISD::AND: {
     auto *N1C = dyn_cast<ConstantSDNode>(Node->getOperand(1));
     if (!N1C)
@@ -922,6 +1006,9 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) {
       }
     }
 
+    if (tryShrinkShlLogicImm(Node))
+      return;
+
     break;
   }
   case ISD::MUL: {

diff  --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h
index ef46204c00ac..89500747992f 100644
--- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h
+++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h
@@ -49,6 +49,8 @@ class RISCVDAGToDAGISel : public SelectionDAGISel {
   bool SelectFrameAddrRegImm(SDValue Addr, SDValue &Base, SDValue &Offset);
   bool SelectAddrRegImm(SDValue Addr, SDValue &Base, SDValue &Offset);
 
+  bool tryShrinkShlLogicImm(SDNode *Node);
+
   bool selectShiftMask(SDValue N, unsigned ShiftWidth, SDValue &ShAmt);
   bool selectShiftMaskXLen(SDValue N, SDValue &ShAmt) {
     return selectShiftMask(N, Subtarget->getXLen(), ShAmt);

diff  --git a/llvm/test/CodeGen/RISCV/narrow-shl-cst.ll b/llvm/test/CodeGen/RISCV/narrow-shl-cst.ll
index 7d5dbe22dfd0..bd99b1c44a57 100644
--- a/llvm/test/CodeGen/RISCV/narrow-shl-cst.ll
+++ b/llvm/test/CodeGen/RISCV/narrow-shl-cst.ll
@@ -5,18 +5,14 @@
 define signext i32 @test1(i32 signext %x) nounwind {
 ; RV32-LABEL: test1:
 ; RV32:       # %bb.0:
+; RV32-NEXT:    ori a0, a0, 31
 ; RV32-NEXT:    slli a0, a0, 10
-; RV32-NEXT:    lui a1, 8
-; RV32-NEXT:    addi a1, a1, -1024
-; RV32-NEXT:    or a0, a0, a1
 ; RV32-NEXT:    ret
 ;
 ; RV64-LABEL: test1:
 ; RV64:       # %bb.0:
+; RV64-NEXT:    ori a0, a0, 31
 ; RV64-NEXT:    slliw a0, a0, 10
-; RV64-NEXT:    lui a1, 8
-; RV64-NEXT:    addiw a1, a1, -1024
-; RV64-NEXT:    or a0, a0, a1
 ; RV64-NEXT:    ret
   %or = shl i32 %x, 10
   %shl = or i32 %or, 31744
@@ -26,18 +22,14 @@ define signext i32 @test1(i32 signext %x) nounwind {
 define signext i32 @test2(i32 signext %x) nounwind {
 ; RV32-LABEL: test2:
 ; RV32:       # %bb.0:
+; RV32-NEXT:    xori a0, a0, 31
 ; RV32-NEXT:    slli a0, a0, 10
-; RV32-NEXT:    lui a1, 8
-; RV32-NEXT:    addi a1, a1, -1024
-; RV32-NEXT:    xor a0, a0, a1
 ; RV32-NEXT:    ret
 ;
 ; RV64-LABEL: test2:
 ; RV64:       # %bb.0:
+; RV64-NEXT:    xori a0, a0, 31
 ; RV64-NEXT:    slliw a0, a0, 10
-; RV64-NEXT:    lui a1, 8
-; RV64-NEXT:    addiw a1, a1, -1024
-; RV64-NEXT:    xor a0, a0, a1
 ; RV64-NEXT:    ret
   %xor = shl i32 %x, 10
   %shl = xor i32 %xor, 31744
@@ -47,19 +39,15 @@ define signext i32 @test2(i32 signext %x) nounwind {
 define i64 @test3(i64 %x) nounwind {
 ; RV32-LABEL: test3:
 ; RV32:       # %bb.0:
-; RV32-NEXT:    slli a0, a0, 8
-; RV32-NEXT:    lui a1, 15
-; RV32-NEXT:    addi a1, a1, 256
-; RV32-NEXT:    and a1, a0, a1
+; RV32-NEXT:    andi a0, a0, 241
+; RV32-NEXT:    slli a1, a0, 8
 ; RV32-NEXT:    li a0, 0
 ; RV32-NEXT:    ret
 ;
 ; RV64-LABEL: test3:
 ; RV64:       # %bb.0:
+; RV64-NEXT:    andi a0, a0, 241
 ; RV64-NEXT:    slli a0, a0, 40
-; RV64-NEXT:    li a1, 241
-; RV64-NEXT:    slli a1, a1, 40
-; RV64-NEXT:    and a0, a0, a1
 ; RV64-NEXT:    ret
   %and = shl i64 %x, 40
   %shl = and i64 %and, 264982302294016
@@ -69,19 +57,15 @@ define i64 @test3(i64 %x) nounwind {
 define i64 @test4(i64 %x) nounwind {
 ; RV32-LABEL: test4:
 ; RV32:       # %bb.0:
-; RV32-NEXT:    slli a0, a0, 8
-; RV32-NEXT:    lui a1, 15
-; RV32-NEXT:    addi a1, a1, 256
-; RV32-NEXT:    or a1, a0, a1
+; RV32-NEXT:    ori a0, a0, 241
+; RV32-NEXT:    slli a1, a0, 8
 ; RV32-NEXT:    li a0, 0
 ; RV32-NEXT:    ret
 ;
 ; RV64-LABEL: test4:
 ; RV64:       # %bb.0:
+; RV64-NEXT:    ori a0, a0, 241
 ; RV64-NEXT:    slli a0, a0, 40
-; RV64-NEXT:    li a1, 241
-; RV64-NEXT:    slli a1, a1, 40
-; RV64-NEXT:    or a0, a0, a1
 ; RV64-NEXT:    ret
   %or = shl i64 %x, 40
   %shl = or i64 %or, 264982302294016
@@ -91,19 +75,15 @@ define i64 @test4(i64 %x) nounwind {
 define i64 @test5(i64 %x) nounwind {
 ; RV32-LABEL: test5:
 ; RV32:       # %bb.0:
-; RV32-NEXT:    slli a0, a0, 8
-; RV32-NEXT:    lui a1, 2
-; RV32-NEXT:    addi a1, a1, -256
-; RV32-NEXT:    or a1, a0, a1
+; RV32-NEXT:    ori a0, a0, 31
+; RV32-NEXT:    slli a1, a0, 8
 ; RV32-NEXT:    li a0, 0
 ; RV32-NEXT:    ret
 ;
 ; RV64-LABEL: test5:
 ; RV64:       # %bb.0:
+; RV64-NEXT:    ori a0, a0, 31
 ; RV64-NEXT:    slli a0, a0, 40
-; RV64-NEXT:    li a1, 31
-; RV64-NEXT:    slli a1, a1, 40
-; RV64-NEXT:    or a0, a0, a1
 ; RV64-NEXT:    ret
   %or = shl i64 %x, 40
   %shl = or i64 %or, 34084860461056
@@ -113,19 +93,15 @@ define i64 @test5(i64 %x) nounwind {
 define i64 @test6(i64 %x) nounwind {
 ; RV32-LABEL: test6:
 ; RV32:       # %bb.0:
-; RV32-NEXT:    slli a0, a0, 8
-; RV32-NEXT:    lui a1, 15
-; RV32-NEXT:    addi a1, a1, 256
-; RV32-NEXT:    xor a1, a0, a1
+; RV32-NEXT:    xori a0, a0, 241
+; RV32-NEXT:    slli a1, a0, 8
 ; RV32-NEXT:    li a0, 0
 ; RV32-NEXT:    ret
 ;
 ; RV64-LABEL: test6:
 ; RV64:       # %bb.0:
+; RV64-NEXT:    xori a0, a0, 241
 ; RV64-NEXT:    slli a0, a0, 40
-; RV64-NEXT:    li a1, 241
-; RV64-NEXT:    slli a1, a1, 40
-; RV64-NEXT:    xor a0, a0, a1
 ; RV64-NEXT:    ret
   %xor = shl i64 %x, 40
   %shl = xor i64 %xor, 264982302294016
@@ -135,19 +111,15 @@ define i64 @test6(i64 %x) nounwind {
 define i64 @test7(i64 %x) nounwind {
 ; RV32-LABEL: test7:
 ; RV32:       # %bb.0:
-; RV32-NEXT:    slli a0, a0, 8
-; RV32-NEXT:    lui a1, 2
-; RV32-NEXT:    addi a1, a1, -256
-; RV32-NEXT:    xor a1, a0, a1
+; RV32-NEXT:    xori a0, a0, 31
+; RV32-NEXT:    slli a1, a0, 8
 ; RV32-NEXT:    li a0, 0
 ; RV32-NEXT:    ret
 ;
 ; RV64-LABEL: test7:
 ; RV64:       # %bb.0:
+; RV64-NEXT:    xori a0, a0, 31
 ; RV64-NEXT:    slli a0, a0, 40
-; RV64-NEXT:    li a1, 31
-; RV64-NEXT:    slli a1, a1, 40
-; RV64-NEXT:    xor a0, a0, a1
 ; RV64-NEXT:    ret
   %xor = shl i64 %x, 40
   %shl = xor i64 %xor, 34084860461056
@@ -164,10 +136,8 @@ define i64 @test8(i64 %x) nounwind {
 ;
 ; RV64-LABEL: test8:
 ; RV64:       # %bb.0:
+; RV64-NEXT:    andi a0, a0, -241
 ; RV64-NEXT:    slli a0, a0, 33
-; RV64-NEXT:    li a1, -241
-; RV64-NEXT:    slli a1, a1, 33
-; RV64-NEXT:    and a0, a0, a1
 ; RV64-NEXT:    ret
   %xor = shl i64 %x, 33
   %shl = and i64 %xor, -2070174236672
@@ -184,10 +154,8 @@ define i64 @test9(i64 %x) nounwind {
 ;
 ; RV64-LABEL: test9:
 ; RV64:       # %bb.0:
+; RV64-NEXT:    ori a0, a0, -241
 ; RV64-NEXT:    slli a0, a0, 33
-; RV64-NEXT:    li a1, -241
-; RV64-NEXT:    slli a1, a1, 33
-; RV64-NEXT:    or a0, a0, a1
 ; RV64-NEXT:    ret
   %xor = shl i64 %x, 33
   %shl = or i64 %xor, -2070174236672
@@ -204,10 +172,8 @@ define i64 @test10(i64 %x) nounwind {
 ;
 ; RV64-LABEL: test10:
 ; RV64:       # %bb.0:
+; RV64-NEXT:    xori a0, a0, -241
 ; RV64-NEXT:    slli a0, a0, 33
-; RV64-NEXT:    li a1, -241
-; RV64-NEXT:    slli a1, a1, 33
-; RV64-NEXT:    xor a0, a0, a1
 ; RV64-NEXT:    ret
   %xor = shl i64 %x, 33
   %shl = xor i64 %xor, -2070174236672
@@ -217,9 +183,8 @@ define i64 @test10(i64 %x) nounwind {
 define signext i32 @test11(i32 signext %x) nounwind {
 ; RV32-LABEL: test11:
 ; RV32:       # %bb.0:
+; RV32-NEXT:    andi a0, a0, -241
 ; RV32-NEXT:    slli a0, a0, 17
-; RV32-NEXT:    lui a1, 1040864
-; RV32-NEXT:    and a0, a0, a1
 ; RV32-NEXT:    ret
 ;
 ; RV64-LABEL: test11:
@@ -236,16 +201,14 @@ define signext i32 @test11(i32 signext %x) nounwind {
 define signext i32 @test12(i32 signext %x) nounwind {
 ; RV32-LABEL: test12:
 ; RV32:       # %bb.0:
+; RV32-NEXT:    ori a0, a0, -241
 ; RV32-NEXT:    slli a0, a0, 17
-; RV32-NEXT:    lui a1, 1040864
-; RV32-NEXT:    or a0, a0, a1
 ; RV32-NEXT:    ret
 ;
 ; RV64-LABEL: test12:
 ; RV64:       # %bb.0:
+; RV64-NEXT:    ori a0, a0, -241
 ; RV64-NEXT:    slli a0, a0, 17
-; RV64-NEXT:    lui a1, 1040864
-; RV64-NEXT:    or a0, a0, a1
 ; RV64-NEXT:    ret
   %or = shl i32 %x, 17
   %shl = or i32 %or, -31588352
@@ -255,16 +218,14 @@ define signext i32 @test12(i32 signext %x) nounwind {
 define signext i32 @test13(i32 signext %x) nounwind {
 ; RV32-LABEL: test13:
 ; RV32:       # %bb.0:
+; RV32-NEXT:    xori a0, a0, -241
 ; RV32-NEXT:    slli a0, a0, 17
-; RV32-NEXT:    lui a1, 1040864
-; RV32-NEXT:    xor a0, a0, a1
 ; RV32-NEXT:    ret
 ;
 ; RV64-LABEL: test13:
 ; RV64:       # %bb.0:
+; RV64-NEXT:    xori a0, a0, -241
 ; RV64-NEXT:    slliw a0, a0, 17
-; RV64-NEXT:    lui a1, 1040864
-; RV64-NEXT:    xor a0, a0, a1
 ; RV64-NEXT:    ret
   %or = shl i32 %x, 17
   %shl = xor i32 %or, -31588352


        


More information about the llvm-commits mailing list