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 @@ -7480,6 +7480,29 @@ return (LHS->getAPIntValue() + RHS->getAPIntValue()) == EltSizeInBits; }; + auto ApplyMasks = [&](SDValue Res) { + // If there is an AND of either shifted operand, apply it to the result. + if (LHSMask.getNode() || RHSMask.getNode()) { + SDValue AllOnes = DAG.getAllOnesConstant(DL, VT); + SDValue Mask = AllOnes; + + if (LHSMask.getNode()) { + SDValue RHSBits = DAG.getNode(ISD::SRL, DL, VT, AllOnes, RHSShiftAmt); + Mask = DAG.getNode(ISD::AND, DL, VT, Mask, + DAG.getNode(ISD::OR, DL, VT, LHSMask, RHSBits)); + } + if (RHSMask.getNode()) { + SDValue LHSBits = DAG.getNode(ISD::SHL, DL, VT, AllOnes, LHSShiftAmt); + Mask = DAG.getNode(ISD::AND, DL, VT, Mask, + DAG.getNode(ISD::OR, DL, VT, RHSMask, LHSBits)); + } + + Res = DAG.getNode(ISD::AND, DL, VT, Res, Mask); + } + + return Res; + }; + // TODO: Support pre-legalization funnel-shift by constant. bool IsRotate = LHSShift.getOperand(0) == RHSShift.getOperand(0); if (!IsRotate && !(HasFSHL || HasFSHR)) { @@ -7504,18 +7527,21 @@ return false; }; - // (shl (X | Y), C1) | (srl X, C2) --> (rotl X, C1) | (shl Y, C1) + SDValue Res; if (matchOr(LHSShiftArg, RHSShiftArg)) { + // (shl (X | Y), C1) | (srl X, C2) --> (rotl X, C1) | (shl Y, C1) SDValue RotX = DAG.getNode(ISD::ROTL, DL, VT, X, LHSShiftAmt); SDValue ShlY = DAG.getNode(ISD::SHL, DL, VT, Y, LHSShiftAmt); - return DAG.getNode(ISD::OR, DL, VT, RotX, ShlY); - } - // (shl X, C1) | (srl (X | Y), C2) --> (rotl X, C1) | (srl Y, C2) - if (matchOr(RHSShiftArg, LHSShiftArg)) { + Res = DAG.getNode(ISD::OR, DL, VT, RotX, ShlY); + } else if (matchOr(RHSShiftArg, LHSShiftArg)) { + // (shl X, C1) | (srl (X | Y), C2) --> (rotl X, C1) | (srl Y, C2) SDValue RotX = DAG.getNode(ISD::ROTL, DL, VT, X, LHSShiftAmt); SDValue SrlY = DAG.getNode(ISD::SRL, DL, VT, Y, RHSShiftAmt); - return DAG.getNode(ISD::OR, DL, VT, RotX, SrlY); - } + Res = DAG.getNode(ISD::OR, DL, VT, RotX, SrlY); + } else + return SDValue(); + + return ApplyMasks(Res); } return SDValue(); // Requires funnel shift support. @@ -7538,26 +7564,7 @@ RHSShiftArg, UseFSHL ? LHSShiftAmt : RHSShiftAmt); } - // If there is an AND of either shifted operand, apply it to the result. - if (LHSMask.getNode() || RHSMask.getNode()) { - SDValue AllOnes = DAG.getAllOnesConstant(DL, VT); - SDValue Mask = AllOnes; - - if (LHSMask.getNode()) { - SDValue RHSBits = DAG.getNode(ISD::SRL, DL, VT, AllOnes, RHSShiftAmt); - Mask = DAG.getNode(ISD::AND, DL, VT, Mask, - DAG.getNode(ISD::OR, DL, VT, LHSMask, RHSBits)); - } - if (RHSMask.getNode()) { - SDValue LHSBits = DAG.getNode(ISD::SHL, DL, VT, AllOnes, LHSShiftAmt); - Mask = DAG.getNode(ISD::AND, DL, VT, Mask, - DAG.getNode(ISD::OR, DL, VT, RHSMask, LHSBits)); - } - - Res = DAG.getNode(ISD::AND, DL, VT, Res, Mask); - } - - return Res; + return ApplyMasks(Res); } // Even pre-legalization, we can't easily rotate/funnel-shift by a variable diff --git a/llvm/test/CodeGen/AArch64/pr55201.ll b/llvm/test/CodeGen/AArch64/pr55201.ll --- a/llvm/test/CodeGen/AArch64/pr55201.ll +++ b/llvm/test/CodeGen/AArch64/pr55201.ll @@ -5,7 +5,8 @@ ; CHECK-LABEL: f: ; CHECK: // %bb.0: ; CHECK-NEXT: ror w8, w0, #27 -; CHECK-NEXT: orr w0, w8, #0x20 +; CHECK-NEXT: orr w8, w8, #0x20 +; CHECK-NEXT: and w0, w8, #0xffffffe1 ; CHECK-NEXT: ret %or1 = or i32 %x, 1 %sh1 = shl i32 %or1, 5 diff --git a/llvm/test/CodeGen/RISCV/pr55201.ll b/llvm/test/CodeGen/RISCV/pr55201.ll --- a/llvm/test/CodeGen/RISCV/pr55201.ll +++ b/llvm/test/CodeGen/RISCV/pr55201.ll @@ -6,6 +6,7 @@ ; CHECK: # %bb.0: ; CHECK-NEXT: rori a0, a0, 27 ; CHECK-NEXT: ori a0, a0, 32 +; CHECK-NEXT: andi a0, a0, -31 ; CHECK-NEXT: ret %or1 = or i32 %x, 1 %sh1 = shl i32 %or1, 5