Index: lib/Transforms/InstCombine/InstCombineAndOrXor.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -2226,6 +2226,65 @@ } } + // ((V< ((V&C5)<>C3 == C2>>C4, for both logical shifts + { + auto MatchAndOfShift = [](Value *V, Value *&Source, + Instruction::BinaryOps &ShiftOpcode, + ConstantInt *&ShiftBy, ConstantInt *&PreShiftMask, + ConstantInt *&PostShiftMask, + BinaryOperator *&IntermediateInstr) -> bool { + if (!match(V, m_And(m_BinOp(IntermediateInstr), + m_ConstantInt(PostShiftMask))) || + !match(IntermediateInstr, + m_LogicalShift(m_Value(Source), m_ConstantInt(ShiftBy)))) + return false; + ShiftOpcode = IntermediateInstr->getOpcode(); + Instruction::BinaryOps InverseOpcode = + IntermediateInstr->getOpcode() == Instruction::Shl ? Instruction::LShr + : Instruction::Shl; + PreShiftMask = cast( + ConstantExpr::get(InverseOpcode, PostShiftMask, ShiftBy)); + return true; + }; + Value *Source0, *Source1; + Instruction::BinaryOps ShiftOpcode0, ShiftOpcode1; + ConstantInt *ShiftBy0, *ShiftBy1, *PreShiftMask0, *PreShiftMask1, + *PostShiftMask0, *PostShiftMask1; + BinaryOperator *IntermediateInstr0, *IntermediateInstr1; + if (MatchAndOfShift(Op0, Source0, ShiftOpcode0, ShiftBy0, PreShiftMask0, + PostShiftMask0, IntermediateInstr0) && + MatchAndOfShift(Op1, Source1, ShiftOpcode1, ShiftBy1, PreShiftMask1, + PostShiftMask1, IntermediateInstr1) && + Source0 == Source1) { + if (ShiftBy0 == ShiftBy1 && ShiftOpcode0 == ShiftOpcode1) { + // ((V< (V<hasOneUse() + Op1->hasOneUse() + + IntermediateInstr0->hasOneUse() + + IntermediateInstr1->hasOneUse(); + if (SavedInstructions >= 2) { + Value *Sh = Builder.CreateBinOp(ShiftOpcode0, Source0, ShiftBy0); + Constant *Mask = ConstantExpr::get(Instruction::Or, PostShiftMask0, + PostShiftMask1); + return BinaryOperator::CreateAnd(Sh, Mask); + } + } + Value *CommonOperand; + if (PreShiftMask0 == PreShiftMask1 && + match(Op0, m_BinOp(m_Value(CommonOperand), m_Value())) && + !match(Op1, m_BinOp(m_Specific(CommonOperand), m_Value())) && + (IntermediateInstr0->hasOneUse() || + IntermediateInstr1->hasOneUse())) { + Value *MaskedSource = Builder.CreateAnd(Source0, PreShiftMask0); + Value *NewOp0 = + Builder.CreateBinOp(ShiftOpcode0, MaskedSource, ShiftBy0); + Value *NewOp1 = + Builder.CreateBinOp(ShiftOpcode1, MaskedSource, ShiftBy1); + return BinaryOperator::CreateOr(NewOp0, NewOp1); + } + } + } + return Changed ? &I : nullptr; } Index: test/Transforms/InstCombine/or-or-shift.ll =================================================================== --- test/Transforms/InstCombine/or-or-shift.ll +++ test/Transforms/InstCombine/or-or-shift.ll @@ -0,0 +1,50 @@ +; RUN: opt -S -instcombine < %s | FileCheck %s + +define i32 @or_and_shifts1(i32 %x) local_unnamed_addr #0 { +; CHECK-LABEL: @or_and_shifts1( +; CHECK-NEXT: [[AND:%.*]] = and i32 %x, 1 +; CHECK-NEXT: [[SHL1:%.*]] = shl nuw nsw i32 [[AND]], 3 +; CHECK-NEXT: [[SHL2:%.*]] = shl nuw nsw i32 [[AND]], 5 +; CHECK-NEXT: [[OR:%.*]] = or i32 [[SHL1]], [[SHL2]] +; CHECK-NEXT: ret i32 [[OR]] +; + %1 = shl i32 %x, 3 + %2 = and i32 %1, 15 + %3 = shl i32 %x, 5 + %4 = and i32 %3, 60 + %5 = or i32 %2, %4 + ret i32 %5 +} + +define i32 @or_and_shifts2(i32 %x) local_unnamed_addr #0 { +; CHECK-LABEL: @or_and_shifts2( +; CHECK-NEXT: [[AND:%.*]] = and i32 %x, 112 +; CHECK-NEXT: [[SHL:%.*]] = shl nuw nsw i32 [[AND]], 3 +; CHECK-NEXT: [[SHR:%.*]] = lshr exact i32 [[AND]], 4 +; CHECK-NEXT: [[OR:%.*]] = or i32 [[SHL]], [[SHR]] +; CHECK-NEXT: ret i32 [[OR]] +; + %1 = shl i32 %x, 3 + %2 = and i32 %1, 896 + %3 = lshr i32 %x, 4 + %4 = and i32 %3, 7 + %5 = or i32 %2, %4 + ret i32 %5 +} + +define i32 @or_and_shift_shift_and(i32 %x) local_unnamed_addr #0 { +; CHECK-LABEL: @or_and_shift_shift_and( +; CHECK-NEXT: [[AND:%.*]] = and i32 %x, 7 +; CHECK-NEXT: [[SHL1:%.*]] = shl nuw nsw i32 [[AND]], 3 +; CHECK-NEXT: [[SHL2:%.*]] = shl nuw nsw i32 [[AND]], 2 +; CHECK-NEXT: [[OR:%.*]] = or i32 [[SHL1]], [[SHL2]] +; CHECK-NEXT: ret i32 [[OR]] +; + %1 = and i32 %x, 7 + %2 = shl i32 %1, 3 + %3 = shl i32 %x, 2 + %4 = and i32 %3, 28 + %5 = or i32 %2, %4 + ret i32 %5 +} +