diff --git a/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp index 899a3c16554c9..10bf908108aef 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp @@ -512,19 +512,27 @@ Instruction *InstCombinerImpl::commonShiftTransforms(BinaryOperator &I) { if (match(Op1, m_Or(m_Value(), m_SpecificInt(BitWidth - 1)))) return replaceOperand(I, 1, ConstantInt::get(Ty, BitWidth - 1)); - Instruction *CmpIntr; - if ((I.getOpcode() == Instruction::LShr || - I.getOpcode() == Instruction::AShr) && - match(Op0, m_OneUse(m_Instruction(CmpIntr))) && - isa(CmpIntr) && - match(Op1, m_SpecificInt(Ty->getScalarSizeInBits() - 1))) { - Value *Cmp = - Builder.CreateICmp(cast(CmpIntr)->getLTPredicate(), - CmpIntr->getOperand(0), CmpIntr->getOperand(1)); - return CastInst::Create(I.getOpcode() == Instruction::LShr - ? Instruction::ZExt - : Instruction::SExt, - Cmp, Ty); + if (I.getOpcode() == Instruction::LShr || + I.getOpcode() == Instruction::AShr) { + // (l|a)shr ([x]or x, y), x --> (l|a)shr y, x + Value *X; + if (match(Op0, m_CombineOr(m_Xor(m_Value(X), m_Value(Y)), + m_Or(m_Value(X), m_Value(Y)))) && + Op1 == X) + return BinaryOperator::Create(I.getOpcode(), Y, X); + + Instruction *CmpIntr; + if (match(Op0, m_OneUse(m_Instruction(CmpIntr))) && + isa(CmpIntr) && + match(Op1, m_SpecificInt(Ty->getScalarSizeInBits() - 1))) { + Value *Cmp = + Builder.CreateICmp(cast(CmpIntr)->getLTPredicate(), + CmpIntr->getOperand(0), CmpIntr->getOperand(1)); + return CastInst::Create(I.getOpcode() == Instruction::LShr + ? Instruction::ZExt + : Instruction::SExt, + Cmp, Ty); + } } return nullptr; diff --git a/llvm/test/Transforms/InstCombine/shift-logic.ll b/llvm/test/Transforms/InstCombine/shift-logic.ll index ab8d98a9523ba..3b58af47b84ae 100644 --- a/llvm/test/Transforms/InstCombine/shift-logic.ll +++ b/llvm/test/Transforms/InstCombine/shift-logic.ll @@ -186,6 +186,7 @@ define i32 @ashr_xor(i32 %x, i32 %py) { ret i32 %sh1 } + define i32 @shr_mismatch_xor(i32 %x, i32 %y) { ; CHECK-LABEL: @shr_mismatch_xor( ; CHECK-NEXT: [[SH0:%.*]] = ashr i32 [[X:%.*]], 5 @@ -546,3 +547,100 @@ define <2 x i64> @lshr_sub_poison(<2 x i64> %x, <2 x i64> %py) { %sh1 = lshr <2 x i64> %r, ret <2 x i64> %sh1 } + +define i32 @ashr_xor_operand_match(i32 %x, i32 %y) { +; CHECK-LABEL: @ashr_xor_operand_match( +; CHECK-NEXT: [[RET:%.*]] = ashr i32 [[R:%.*]], [[X:%.*]] +; CHECK-NEXT: ret i32 [[RET]] +; + %r = xor i32 %x, %y + %ret = ashr i32 %r, %x + ret i32 %ret +} + +define i32 @ashr_xor_operand_mismtach(i32 %x, i32 %y) { +; CHECK-LABEL: @ashr_xor_operand_mismtach( +; CHECK-NEXT: [[R:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[RET:%.*]] = ashr i32 [[R]], [[Y]] +; CHECK-NEXT: ret i32 [[RET]] +; + %r = xor i32 %x, %y + %ret = ashr i32 %r, %y + ret i32 %ret +} + +define i32 @lshr_xor_operand_match(i32 %x, i32 %y) { +; CHECK-LABEL: @lshr_xor_operand_match( +; CHECK-NEXT: [[RET:%.*]] = lshr i32 [[R:%.*]], [[X:%.*]] +; CHECK-NEXT: ret i32 [[RET]] +; + %r = xor i32 %x, %y + %ret = lshr i32 %r, %x + ret i32 %ret +} + +define i32 @lshr_xor_operand_mismtach(i32 %x, i32 %y) { +; CHECK-LABEL: @lshr_xor_operand_mismtach( +; CHECK-NEXT: [[R:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[RET:%.*]] = lshr i32 [[R]], [[Y]] +; CHECK-NEXT: ret i32 [[RET]] +; + %r = xor i32 %x, %y + %ret = lshr i32 %r, %y + ret i32 %ret +} + +define i32 @ashr_or_operand_match(i32 %x, i32 %y) { +; CHECK-LABEL: @ashr_or_operand_match( +; CHECK-NEXT: [[RET:%.*]] = ashr i32 [[R:%.*]], [[X:%.*]] +; CHECK-NEXT: ret i32 [[RET]] +; + %r = or i32 %x, %y + %ret = ashr i32 %r, %x + ret i32 %ret +} + +define i32 @ashr_or_operand_mismtach(i32 %x, i32 %y) { +; CHECK-LABEL: @ashr_or_operand_mismtach( +; CHECK-NEXT: [[R:%.*]] = or i32 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[RET:%.*]] = ashr i32 [[R]], [[Y]] +; CHECK-NEXT: ret i32 [[RET]] +; + %r = or i32 %x, %y + %ret = ashr i32 %r, %y + ret i32 %ret +} + +define i32 @lshr_or_operand_match(i32 %x, i32 %y) { +; CHECK-LABEL: @lshr_or_operand_match( +; CHECK-NEXT: [[RET:%.*]] = lshr i32 [[R:%.*]], [[X:%.*]] +; CHECK-NEXT: ret i32 [[RET]] +; + %r = or i32 %x, %y + %ret = lshr i32 %r, %x + ret i32 %ret +} + +define i32 @lshr_or_operand_mismtach(i32 %x, i32 %y) { +; CHECK-LABEL: @lshr_or_operand_mismtach( +; CHECK-NEXT: [[R:%.*]] = or i32 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[RET:%.*]] = lshr i32 [[R]], [[Y]] +; CHECK-NEXT: ret i32 [[RET]] +; + %r = or i32 %x, %y + %ret = lshr i32 %r, %y + ret i32 %ret +} + +define i32 @ashr_xor_operand_match_multiuse(i32 %x, i32 %y) { +; CHECK-LABEL: @ashr_xor_operand_match_multiuse( +; CHECK-NEXT: [[Q:%.*]] = ashr i32 [[R:%.*]], [[X:%.*]] +; CHECK-NEXT: [[RET:%.*]] = xor i32 [[R]], [[Q]] +; CHECK-NEXT: [[RET1:%.*]] = xor i32 [[RET]], [[X]] +; CHECK-NEXT: ret i32 [[RET1]] +; + %r = xor i32 %x, %y + %q = ashr i32 %r, %x + %ret = xor i32 %r, %q + ret i32 %ret +}