diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp @@ -1383,6 +1383,9 @@ if (Instruction *X = foldNoWrapAdd(I, Builder)) return X; + if (Instruction *R = foldBinOpShiftWithShift(I)) + return R; + Value *LHS = I.getOperand(0), *RHS = I.getOperand(1); Type *Ty = I.getType(); if (Ty->isIntOrIntVectorTy(1)) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -2053,6 +2053,9 @@ if (Value *V = SimplifyBSwap(I, Builder)) return replaceInstUsesWith(I, V); + if (Instruction *R = foldBinOpShiftWithShift(I)) + return R; + Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1); Value *X, *Y; @@ -3097,6 +3100,9 @@ if (Instruction *Concat = matchOrConcat(I, Builder)) return replaceInstUsesWith(I, Concat); + if (Instruction *R = foldBinOpShiftWithShift(I)) + return R; + Value *X, *Y; const APInt *CV; if (match(&I, m_c_Or(m_OneUse(m_Xor(m_Value(X), m_APInt(CV))), m_Value(Y))) && @@ -4170,6 +4176,9 @@ if (Instruction *R = foldNot(I)) return R; + if (Instruction *R = foldBinOpShiftWithShift(I)) + return R; + // Fold (X & M) ^ (Y & ~M) -> (X & M) | (Y & ~M) // This it a special case in haveNoCommonBitsSet, but the computeKnownBits // calls in there are unnecessary as SimplifyDemandedInstructionBits should diff --git a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h --- a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h +++ b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h @@ -450,6 +450,23 @@ Value *SimplifySelectsFeedingBinaryOp(BinaryOperator &I, Value *LHS, Value *RHS); + // (Binop1 (Binop2 (logic_shift X, C), C1), (logic_shift Y, C)) + // IFF + // 1) the logic_shifts match + // 2) either both binops are binops and one is `and` or + // BinOp1 is `and` + // (logic_shift (inv_logic_shift C1, C), C) == C1 or + // + // -> (logic_shift (Binop1 (Binop2 X, inv_logic_shift(C1, C)), Y), C) + // + // (Binop1 (Binop2 (logic_shift X, Amt), Mask), (logic_shift Y, Amt)) + // IFF + // 1) the logic_shifts match + // 2) BinOp1 == BinOp2 (if BinOp == `add`, then also requires `shl`). + // + // -> (BinOp (logic_shift (BinOp X, Y)), Mask) + Instruction *foldBinOpShiftWithShift(BinaryOperator &I); + /// This tries to simplify binary operations by factorizing out common terms /// (e. g. "(A*B)+(A*C)" -> "A*(B+C)"). Value *tryFactorizationFolds(BinaryOperator &I); diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp --- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -730,6 +730,112 @@ return RetVal; } +Instruction *InstCombinerImpl::foldBinOpShiftWithShift(BinaryOperator &I) { + Constant *CMask, *CShift; + Value *X, *Y, *ShiftedX, *Mask, *Shift; + unsigned ShOpc, BinOpc; + + auto IsValidBinOpc = [](unsigned Opc) { + switch (Opc) { + default: + return false; + case Instruction::And: + case Instruction::Or: + case Instruction::Xor: + case Instruction::Add: + // Skip Sub as we only match constant masks which will canonicalize to use + // add. + return true; + } + }; + + auto MatchBinOp = [&](unsigned ShOpnum) -> Instruction * { + if (!match(I.getOperand(ShOpnum), + m_OneUse(m_LogicalShift(m_Value(Y), m_Value(Shift))))) + return nullptr; + if (!match(I.getOperand(1 - ShOpnum), + m_BinOp(m_Value(ShiftedX), m_Value(Mask)))) + return nullptr; + + if (!match(ShiftedX, + m_OneUse(m_LogicalShift(m_Value(X), m_Specific(Shift))))) + return nullptr; + + // Make sure we are matching instruction shifts and not ConstantExpr + auto *IY = dyn_cast(I.getOperand(ShOpnum)); + auto *IX = dyn_cast(ShiftedX); + if (!IY || !IX) + return nullptr; + + // LHS and RHS need same shift opcode + ShOpc = IY->getOpcode(); + if (ShOpc != IX->getOpcode()) + return nullptr; + + // Make sure binop is real instruction and not ContstantExpr + auto *BO2 = dyn_cast(I.getOperand(1 - ShOpnum)); + if (!BO2) + return nullptr; + + BinOpc = BO2->getOpcode(); + // Make sure we have valid binops. + if (!IsValidBinOpc(I.getOpcode()) || !IsValidBinOpc(BinOpc)) + return nullptr; + + // If BinOp1 == BinOp2 and its bitwise or shl with add, then just + // reassosiate to drop the shift irrelivant of constants. + if (BinOpc == I.getOpcode() && + (Instruction::isBitwiseLogicOp(BinOpc) || ShOpc == Instruction::Shl)) { + Value *NewBinOp2 = Builder.CreateBinOp(I.getOpcode(), X, Y); + Value *NewBinOp1 = Builder.CreateBinOp( + static_cast(ShOpc), NewBinOp2, Shift); + return BinaryOperator::Create(I.getOpcode(), NewBinOp1, Mask); + } + + // Otherwise we can only reassosiate by constant shifting the mask, so + // ensure we have constants. + if (!match(Shift, m_ImmConstant(CShift))) + return nullptr; + if (!match(Mask, m_ImmConstant(CMask))) + return nullptr; + + // If the BinOp1 is `and` we don't need to check the mask. + unsigned InvShOpc = + ShOpc == Instruction::LShr ? Instruction::Shl : Instruction::LShr; + if (I.getOpcode() == Instruction::And) { + // Pass + } + // If BinOp2 is `and` and BinOp1 is a bitwise op, any mask works. + else if (Instruction::isBitwiseLogicOp(I.getOpcode()) && + BinOpc == Instruction::And) { + // Pass + } + // If both BinOp1 and BinOp2 are bitwise ops and: + // (logic_shift (inv_logic_shift Mask, ShAmt), ShAmt) == Mask + // Then we are good. + else if (Instruction::isBitwiseLogicOp(I.getOpcode()) && + Instruction::isBitwiseLogicOp(BinOpc) && + ConstantExpr::get(ShOpc, + ConstantExpr::get(InvShOpc, CMask, CShift), + CShift) == CMask) { + // Pass + } else { + return nullptr; + } + + Constant *NewCMask = ConstantExpr::get(InvShOpc, CMask, CShift); + Value *NewBinOp2 = Builder.CreateBinOp( + static_cast(BinOpc), X, NewCMask); + Value *NewBinOp1 = Builder.CreateBinOp(I.getOpcode(), Y, NewBinOp2); + return BinaryOperator::Create(static_cast(ShOpc), + NewBinOp1, CShift); + }; + + if (Instruction *R = MatchBinOp(0)) + return R; + return MatchBinOp(1); +} + Value *InstCombinerImpl::tryFactorizationFolds(BinaryOperator &I) { Value *LHS = I.getOperand(0), *RHS = I.getOperand(1); BinaryOperator *Op0 = dyn_cast(LHS); diff --git a/llvm/test/Transforms/InstCombine/binop-and-shifts.ll b/llvm/test/Transforms/InstCombine/binop-and-shifts.ll --- a/llvm/test/Transforms/InstCombine/binop-and-shifts.ll +++ b/llvm/test/Transforms/InstCombine/binop-and-shifts.ll @@ -3,10 +3,9 @@ define i8 @shl_and_and(i8 %x, i8 %y) { ; CHECK-LABEL: @shl_and_and( -; CHECK-NEXT: [[SHIFT1:%.*]] = shl i8 [[X:%.*]], 4 -; CHECK-NEXT: [[SHIFT2:%.*]] = shl i8 [[Y:%.*]], 4 -; CHECK-NEXT: [[BW2:%.*]] = and i8 [[SHIFT2]], 80 -; CHECK-NEXT: [[BW1:%.*]] = and i8 [[SHIFT1]], [[BW2]] +; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[Y:%.*]], [[X:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = shl i8 [[TMP1]], 4 +; CHECK-NEXT: [[BW1:%.*]] = and i8 [[TMP2]], 80 ; CHECK-NEXT: ret i8 [[BW1]] ; %shift1 = shl i8 %x, 4 @@ -48,10 +47,9 @@ define <2 x i8> @lshr_and_or(<2 x i8> %x, <2 x i8> %y) { ; CHECK-LABEL: @lshr_and_or( -; CHECK-NEXT: [[SHIFT1:%.*]] = lshr <2 x i8> [[X:%.*]], -; CHECK-NEXT: [[SHIFT2:%.*]] = lshr <2 x i8> [[Y:%.*]], -; CHECK-NEXT: [[BW2:%.*]] = and <2 x i8> [[SHIFT1]], -; CHECK-NEXT: [[BW1:%.*]] = or <2 x i8> [[SHIFT2]], [[BW2]] +; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i8> [[X:%.*]], +; CHECK-NEXT: [[TMP2:%.*]] = or <2 x i8> [[TMP1]], [[Y:%.*]] +; CHECK-NEXT: [[BW1:%.*]] = lshr <2 x i8> [[TMP2]], ; CHECK-NEXT: ret <2 x i8> [[BW1]] ; %shift1 = lshr <2 x i8> %x, @@ -78,10 +76,9 @@ define i8 @shl_and_xor(i8 %x, i8 %y) { ; CHECK-LABEL: @shl_and_xor( -; CHECK-NEXT: [[SHIFT1:%.*]] = shl i8 [[X:%.*]], 1 -; CHECK-NEXT: [[SHIFT2:%.*]] = shl i8 [[Y:%.*]], 1 -; CHECK-NEXT: [[BW2:%.*]] = and i8 [[SHIFT1]], 20 -; CHECK-NEXT: [[BW1:%.*]] = xor i8 [[SHIFT2]], [[BW2]] +; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[X:%.*]], 10 +; CHECK-NEXT: [[TMP2:%.*]] = xor i8 [[TMP1]], [[Y:%.*]] +; CHECK-NEXT: [[BW1:%.*]] = shl i8 [[TMP2]], 1 ; CHECK-NEXT: ret i8 [[BW1]] ; %shift1 = shl i8 %x, 1 @@ -108,10 +105,9 @@ define i8 @lshr_or_and(i8 %x, i8 %y) { ; CHECK-LABEL: @lshr_or_and( -; CHECK-NEXT: [[SHIFT1:%.*]] = lshr i8 [[X:%.*]], 5 -; CHECK-NEXT: [[SHIFT2:%.*]] = lshr i8 [[Y:%.*]], 5 -; CHECK-NEXT: [[BW2:%.*]] = or i8 [[SHIFT1]], 6 -; CHECK-NEXT: [[BW1:%.*]] = and i8 [[BW2]], [[SHIFT2]] +; CHECK-NEXT: [[TMP1:%.*]] = or i8 [[X:%.*]], -64 +; CHECK-NEXT: [[TMP2:%.*]] = and i8 [[TMP1]], [[Y:%.*]] +; CHECK-NEXT: [[BW1:%.*]] = lshr i8 [[TMP2]], 5 ; CHECK-NEXT: ret i8 [[BW1]] ; %shift1 = lshr i8 %x, 5 @@ -123,10 +119,9 @@ define i8 @lshr_or_or_fail(i8 %x, i8 %y) { ; CHECK-LABEL: @lshr_or_or_fail( -; CHECK-NEXT: [[SHIFT1:%.*]] = lshr i8 [[X:%.*]], 5 -; CHECK-NEXT: [[SHIFT2:%.*]] = lshr i8 [[Y:%.*]], 5 -; CHECK-NEXT: [[BW2:%.*]] = or i8 [[SHIFT2]], -58 -; CHECK-NEXT: [[BW1:%.*]] = or i8 [[SHIFT1]], [[BW2]] +; CHECK-NEXT: [[TMP1:%.*]] = or i8 [[Y:%.*]], [[X:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = lshr i8 [[TMP1]], 5 +; CHECK-NEXT: [[BW1:%.*]] = or i8 [[TMP2]], -58 ; CHECK-NEXT: ret i8 [[BW1]] ; %shift1 = lshr i8 %x, 5 @@ -138,10 +133,9 @@ define <2 x i8> @shl_xor_and(<2 x i8> %x, <2 x i8> %y) { ; CHECK-LABEL: @shl_xor_and( -; CHECK-NEXT: [[SHIFT1:%.*]] = shl <2 x i8> [[X:%.*]], -; CHECK-NEXT: [[SHIFT2:%.*]] = shl <2 x i8> [[Y:%.*]], -; CHECK-NEXT: [[BW2:%.*]] = xor <2 x i8> [[SHIFT2]], -; CHECK-NEXT: [[BW1:%.*]] = and <2 x i8> [[BW2]], [[SHIFT1]] +; CHECK-NEXT: [[TMP1:%.*]] = xor <2 x i8> [[Y:%.*]], +; CHECK-NEXT: [[TMP2:%.*]] = and <2 x i8> [[TMP1]], [[X:%.*]] +; CHECK-NEXT: [[BW1:%.*]] = shl <2 x i8> [[TMP2]], ; CHECK-NEXT: ret <2 x i8> [[BW1]] ; %shift1 = shl <2 x i8> %x, @@ -169,10 +163,9 @@ declare void @llvm.assume(i1) define i8 @lshr_or_or_no_const(i8 %x, i8 %y, i8 %sh, i8 %mask) { ; CHECK-LABEL: @lshr_or_or_no_const( -; CHECK-NEXT: [[SHIFT1:%.*]] = lshr i8 [[X:%.*]], [[SH:%.*]] -; CHECK-NEXT: [[SHIFT2:%.*]] = lshr i8 [[Y:%.*]], [[SH]] -; CHECK-NEXT: [[BW2:%.*]] = or i8 [[SHIFT2]], [[MASK:%.*]] -; CHECK-NEXT: [[BW1:%.*]] = or i8 [[SHIFT1]], [[BW2]] +; CHECK-NEXT: [[TMP1:%.*]] = or i8 [[Y:%.*]], [[X:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = lshr i8 [[TMP1]], [[SH:%.*]] +; CHECK-NEXT: [[BW1:%.*]] = or i8 [[TMP2]], [[MASK:%.*]] ; CHECK-NEXT: ret i8 [[BW1]] ; %shift1 = lshr i8 %x, %sh @@ -199,10 +192,9 @@ define i8 @shl_xor_xor_no_const(i8 %x, i8 %y, i8 %sh, i8 %mask) { ; CHECK-LABEL: @shl_xor_xor_no_const( -; CHECK-NEXT: [[SHIFT1:%.*]] = shl i8 [[X:%.*]], [[SH:%.*]] -; CHECK-NEXT: [[SHIFT2:%.*]] = shl i8 [[Y:%.*]], [[SH]] -; CHECK-NEXT: [[BW2:%.*]] = xor i8 [[SHIFT2]], [[MASK:%.*]] -; CHECK-NEXT: [[BW1:%.*]] = xor i8 [[SHIFT1]], [[BW2]] +; CHECK-NEXT: [[TMP1:%.*]] = xor i8 [[Y:%.*]], [[X:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = shl i8 [[TMP1]], [[SH:%.*]] +; CHECK-NEXT: [[BW1:%.*]] = xor i8 [[TMP2]], [[MASK:%.*]] ; CHECK-NEXT: ret i8 [[BW1]] ; %shift1 = shl i8 %x, %sh @@ -214,10 +206,9 @@ define <2 x i8> @shl_and_and_no_const(<2 x i8> %x, <2 x i8> %y, <2 x i8> %sh, <2 x i8> %mask) { ; CHECK-LABEL: @shl_and_and_no_const( -; CHECK-NEXT: [[SHIFT1:%.*]] = shl <2 x i8> [[X:%.*]], [[SH:%.*]] -; CHECK-NEXT: [[SHIFT2:%.*]] = shl <2 x i8> [[Y:%.*]], [[SH]] -; CHECK-NEXT: [[BW2:%.*]] = and <2 x i8> [[SHIFT2]], [[MASK:%.*]] -; CHECK-NEXT: [[BW1:%.*]] = and <2 x i8> [[SHIFT1]], [[BW2]] +; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i8> [[Y:%.*]], [[X:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = shl <2 x i8> [[TMP1]], [[SH:%.*]] +; CHECK-NEXT: [[BW1:%.*]] = and <2 x i8> [[TMP2]], [[MASK:%.*]] ; CHECK-NEXT: ret <2 x i8> [[BW1]] ; %shift1 = shl <2 x i8> %x, %sh @@ -229,10 +220,9 @@ define i8 @shl_add_add_no_const(i8 %x, i8 %y, i8 %sh, i8 %mask) { ; CHECK-LABEL: @shl_add_add_no_const( -; CHECK-NEXT: [[SHIFT1:%.*]] = shl i8 [[X:%.*]], [[SH:%.*]] -; CHECK-NEXT: [[SHIFT2:%.*]] = shl i8 [[Y:%.*]], [[SH]] -; CHECK-NEXT: [[BW2:%.*]] = add i8 [[SHIFT2]], [[MASK:%.*]] -; CHECK-NEXT: [[BW1:%.*]] = add i8 [[SHIFT1]], [[BW2]] +; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[Y:%.*]], [[X:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = shl i8 [[TMP1]], [[SH:%.*]] +; CHECK-NEXT: [[BW1:%.*]] = add i8 [[TMP2]], [[MASK:%.*]] ; CHECK-NEXT: ret i8 [[BW1]] ; %shift1 = shl i8 %x, %sh @@ -259,10 +249,9 @@ define <2 x i8> @lshr_add_and(<2 x i8> %x, <2 x i8> %y) { ; CHECK-LABEL: @lshr_add_and( -; CHECK-NEXT: [[SHIFT1:%.*]] = lshr <2 x i8> [[X:%.*]], -; CHECK-NEXT: [[SHIFT2:%.*]] = lshr <2 x i8> [[Y:%.*]], -; CHECK-NEXT: [[BW2:%.*]] = add <2 x i8> [[SHIFT2]], -; CHECK-NEXT: [[BW1:%.*]] = and <2 x i8> [[SHIFT1]], [[BW2]] +; CHECK-NEXT: [[TMP1:%.*]] = add <2 x i8> [[Y:%.*]], +; CHECK-NEXT: [[TMP2:%.*]] = and <2 x i8> [[TMP1]], [[X:%.*]] +; CHECK-NEXT: [[BW1:%.*]] = lshr <2 x i8> [[TMP2]], ; CHECK-NEXT: ret <2 x i8> [[BW1]] ; %shift1 = lshr <2 x i8> %x, @@ -289,10 +278,9 @@ define <2 x i8> @shl_or_or_good_mask(<2 x i8> %x, <2 x i8> %y) { ; CHECK-LABEL: @shl_or_or_good_mask( -; CHECK-NEXT: [[SHIFT1:%.*]] = shl <2 x i8> [[X:%.*]], -; CHECK-NEXT: [[SHIFT2:%.*]] = shl <2 x i8> [[Y:%.*]], -; CHECK-NEXT: [[BW2:%.*]] = or <2 x i8> [[SHIFT2]], -; CHECK-NEXT: [[BW1:%.*]] = or <2 x i8> [[SHIFT1]], [[BW2]] +; CHECK-NEXT: [[TMP1:%.*]] = or <2 x i8> [[Y:%.*]], [[X:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = shl <2 x i8> [[TMP1]], +; CHECK-NEXT: [[BW1:%.*]] = or <2 x i8> [[TMP2]], ; CHECK-NEXT: ret <2 x i8> [[BW1]] ; %shift1 = shl <2 x i8> %x, @@ -304,10 +292,9 @@ define <2 x i8> @shl_or_or_fail_bad_mask(<2 x i8> %x, <2 x i8> %y) { ; CHECK-LABEL: @shl_or_or_fail_bad_mask( -; CHECK-NEXT: [[SHIFT1:%.*]] = shl <2 x i8> [[X:%.*]], -; CHECK-NEXT: [[SHIFT2:%.*]] = shl <2 x i8> [[Y:%.*]], -; CHECK-NEXT: [[BW2:%.*]] = or <2 x i8> [[SHIFT2]], -; CHECK-NEXT: [[BW1:%.*]] = or <2 x i8> [[SHIFT1]], [[BW2]] +; CHECK-NEXT: [[TMP1:%.*]] = or <2 x i8> [[Y:%.*]], [[X:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = shl <2 x i8> [[TMP1]], +; CHECK-NEXT: [[BW1:%.*]] = or <2 x i8> [[TMP2]], ; CHECK-NEXT: ret <2 x i8> [[BW1]] ; %shift1 = shl <2 x i8> %x, @@ -319,10 +306,9 @@ define i8 @lshr_xor_or_good_mask(i8 %x, i8 %y) { ; CHECK-LABEL: @lshr_xor_or_good_mask( -; CHECK-NEXT: [[SHIFT1:%.*]] = lshr i8 [[X:%.*]], 4 -; CHECK-NEXT: [[SHIFT2:%.*]] = lshr i8 [[Y:%.*]], 4 -; CHECK-NEXT: [[BW21:%.*]] = or i8 [[SHIFT2]], 48 -; CHECK-NEXT: [[BW1:%.*]] = or i8 [[SHIFT1]], [[BW21]] +; CHECK-NEXT: [[TMP1:%.*]] = or i8 [[Y:%.*]], [[X:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = lshr i8 [[TMP1]], 4 +; CHECK-NEXT: [[BW1:%.*]] = or i8 [[TMP2]], 48 ; CHECK-NEXT: ret i8 [[BW1]] ; %shift1 = lshr i8 %x, 4 @@ -349,10 +335,9 @@ define <2 x i8> @lshr_or_xor_good_mask(<2 x i8> %x, <2 x i8> %y) { ; CHECK-LABEL: @lshr_or_xor_good_mask( -; CHECK-NEXT: [[SHIFT1:%.*]] = lshr <2 x i8> [[X:%.*]], -; CHECK-NEXT: [[SHIFT2:%.*]] = lshr <2 x i8> [[Y:%.*]], -; CHECK-NEXT: [[BW2:%.*]] = or <2 x i8> [[SHIFT2]], -; CHECK-NEXT: [[BW1:%.*]] = xor <2 x i8> [[SHIFT1]], [[BW2]] +; CHECK-NEXT: [[TMP1:%.*]] = or <2 x i8> [[Y:%.*]], +; CHECK-NEXT: [[TMP2:%.*]] = xor <2 x i8> [[TMP1]], [[X:%.*]] +; CHECK-NEXT: [[BW1:%.*]] = lshr <2 x i8> [[TMP2]], ; CHECK-NEXT: ret <2 x i8> [[BW1]] ; %shift1 = lshr <2 x i8> %x, @@ -379,9 +364,9 @@ define i8 @shl_xor_xor_good_mask(i8 %x, i8 %y) { ; CHECK-LABEL: @shl_xor_xor_good_mask( -; CHECK-NEXT: [[SHIFT21:%.*]] = xor i8 [[Y:%.*]], [[X:%.*]] -; CHECK-NEXT: [[TMP1:%.*]] = shl i8 [[SHIFT21]], 1 -; CHECK-NEXT: [[BW1:%.*]] = xor i8 [[TMP1]], 88 +; CHECK-NEXT: [[TMP1:%.*]] = xor i8 [[Y:%.*]], [[X:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = shl i8 [[TMP1]], 1 +; CHECK-NEXT: [[BW1:%.*]] = xor i8 [[TMP2]], 88 ; CHECK-NEXT: ret i8 [[BW1]] ; %shift1 = shl i8 %x, 1 @@ -408,10 +393,9 @@ define i8 @shl_add_and(i8 %x, i8 %y) { ; CHECK-LABEL: @shl_add_and( -; CHECK-NEXT: [[SHIFT1:%.*]] = shl i8 [[X:%.*]], 1 -; CHECK-NEXT: [[SHIFT2:%.*]] = shl i8 [[Y:%.*]], 1 -; CHECK-NEXT: [[BW2:%.*]] = add i8 [[SHIFT2]], -64 -; CHECK-NEXT: [[BW1:%.*]] = and i8 [[SHIFT1]], [[BW2]] +; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[Y:%.*]], 96 +; CHECK-NEXT: [[TMP2:%.*]] = and i8 [[TMP1]], [[X:%.*]] +; CHECK-NEXT: [[BW1:%.*]] = shl i8 [[TMP2]], 1 ; CHECK-NEXT: ret i8 [[BW1]] ; %shift1 = shl i8 %x, 1 diff --git a/llvm/test/Transforms/InstCombine/or-shifted-masks.ll b/llvm/test/Transforms/InstCombine/or-shifted-masks.ll --- a/llvm/test/Transforms/InstCombine/or-shifted-masks.ll +++ b/llvm/test/Transforms/InstCombine/or-shifted-masks.ll @@ -75,16 +75,10 @@ define i32 @multiuse2(i32 %x) { ; CHECK-LABEL: @multiuse2( -; CHECK-NEXT: [[I:%.*]] = shl i32 [[X:%.*]], 1 -; CHECK-NEXT: [[I2:%.*]] = and i32 [[I]], 12 -; CHECK-NEXT: [[I6:%.*]] = shl i32 [[X]], 8 -; CHECK-NEXT: [[I7:%.*]] = and i32 [[I6]], 24576 -; CHECK-NEXT: [[I14:%.*]] = shl i32 [[X]], 8 -; CHECK-NEXT: [[I9:%.*]] = and i32 [[I14]], 7680 -; CHECK-NEXT: [[I10:%.*]] = or i32 [[I7]], [[I9]] -; CHECK-NEXT: [[I85:%.*]] = shl i32 [[X]], 1 -; CHECK-NEXT: [[I11:%.*]] = and i32 [[I85]], 240 -; CHECK-NEXT: [[I12:%.*]] = or i32 [[I2]], [[I11]] +; CHECK-NEXT: [[TMP1:%.*]] = shl i32 [[X:%.*]], 8 +; CHECK-NEXT: [[I10:%.*]] = and i32 [[TMP1]], 32256 +; CHECK-NEXT: [[TMP2:%.*]] = shl i32 [[X]], 1 +; CHECK-NEXT: [[I12:%.*]] = and i32 [[TMP2]], 252 ; CHECK-NEXT: [[I13:%.*]] = or i32 [[I10]], [[I12]] ; CHECK-NEXT: ret i32 [[I13]] ; @@ -107,15 +101,10 @@ define i32 @multiuse3(i32 %x) { ; CHECK-LABEL: @multiuse3( -; CHECK-NEXT: [[I:%.*]] = and i32 [[X:%.*]], 96 -; CHECK-NEXT: [[I1:%.*]] = shl nuw nsw i32 [[I]], 6 -; CHECK-NEXT: [[I2:%.*]] = lshr exact i32 [[I]], 1 -; CHECK-NEXT: [[I3:%.*]] = shl i32 [[X]], 6 -; CHECK-NEXT: [[I4:%.*]] = and i32 [[I3]], 1920 -; CHECK-NEXT: [[I5:%.*]] = or i32 [[I1]], [[I4]] -; CHECK-NEXT: [[I6:%.*]] = lshr i32 [[X]], 1 -; CHECK-NEXT: [[I7:%.*]] = and i32 [[I6]], 15 -; CHECK-NEXT: [[I8:%.*]] = or i32 [[I2]], [[I7]] +; CHECK-NEXT: [[TMP1:%.*]] = shl i32 [[X:%.*]], 6 +; CHECK-NEXT: [[I5:%.*]] = and i32 [[TMP1]], 8064 +; CHECK-NEXT: [[TMP2:%.*]] = lshr i32 [[X]], 1 +; CHECK-NEXT: [[I8:%.*]] = and i32 [[TMP2]], 63 ; CHECK-NEXT: [[I9:%.*]] = or i32 [[I8]], [[I5]] ; CHECK-NEXT: ret i32 [[I9]] ; @@ -134,20 +123,18 @@ define i32 @multiuse4(i32 %x) local_unnamed_addr { ; CHECK-LABEL: @multiuse4( -; CHECK-NEXT: [[I:%.*]] = and i32 [[X:%.*]], 100663296 -; CHECK-NEXT: [[I1:%.*]] = icmp sgt i32 [[X]], -1 +; CHECK-NEXT: [[I1:%.*]] = icmp sgt i32 [[X:%.*]], -1 ; CHECK-NEXT: br i1 [[I1]], label [[IF:%.*]], label [[ELSE:%.*]] ; CHECK: if: -; CHECK-NEXT: [[I2:%.*]] = lshr exact i32 [[I]], 22 +; CHECK-NEXT: [[I:%.*]] = lshr i32 [[X]], 22 +; CHECK-NEXT: [[I2:%.*]] = and i32 [[I]], 24 ; CHECK-NEXT: [[I3:%.*]] = lshr i32 [[X]], 22 ; CHECK-NEXT: [[I4:%.*]] = and i32 [[I3]], 480 ; CHECK-NEXT: [[I5:%.*]] = or i32 [[I4]], [[I2]] ; CHECK-NEXT: br label [[END:%.*]] ; CHECK: else: -; CHECK-NEXT: [[I6:%.*]] = lshr exact i32 [[I]], 17 -; CHECK-NEXT: [[I7:%.*]] = lshr i32 [[X]], 17 -; CHECK-NEXT: [[I8:%.*]] = and i32 [[I7]], 15360 -; CHECK-NEXT: [[I9:%.*]] = or i32 [[I8]], [[I6]] +; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[X]], 17 +; CHECK-NEXT: [[I9:%.*]] = and i32 [[TMP1]], 16128 ; CHECK-NEXT: br label [[END]] ; CHECK: end: ; CHECK-NEXT: [[I10:%.*]] = phi i32 [ [[I5]], [[IF]] ], [ [[I9]], [[ELSE]] ]