diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp index d5826b46d738e..5d00919dfa783 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(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(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(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(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(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 ef46204c00ac2..89500747992f9 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 7d5dbe22dfd09..bd99b1c44a57e 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