Index: lib/Transforms/InstCombine/InstCombineAndOrXor.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -2226,6 +2226,92 @@ } } + // ((V< ((V&C5)<>C3 == C2>>C4, for both logical shifts + // + // These patterns will also be transformed: + // ((V&C5)< ((V&C5)< ((V&C5)< bool { + BinaryOperator *Sh; + if (!match(V, m_BinOp(Sh)) || + !match(Sh, m_LogicalShift(m_BinOp(IntermediateInstr), + m_ConstantInt(ShiftBy))) || + !match(IntermediateInstr, + m_And(m_Value(Source), m_ConstantInt(PreShiftMask)))) + return false; + ShiftOpcode = Sh->getOpcode(); + PostShiftMask = cast( + ConstantExpr::get(Sh->getOpcode(), PreShiftMask, ShiftBy)); + return true; + }; + // match (V< 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 ((MatchShiftOfAnd(Op0, Source0, ShiftOpcode0, ShiftBy0, PreShiftMask0, + PostShiftMask0, IntermediateInstr0) || + MatchAndOfShift(Op0, Source0, ShiftOpcode0, ShiftBy0, PreShiftMask0, + PostShiftMask0, IntermediateInstr0)) && + (MatchShiftOfAnd(Op1, Source1, ShiftOpcode1, ShiftBy1, PreShiftMask1, + PostShiftMask1, IntermediateInstr1) || + 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,115 @@ +; 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 +} + +define i32 @multiuse1(i32 %x) local_unnamed_addr { +; CHECK-LABEL: @multiuse1( +; CHECK-NEXT: [[AND:%.*]] = and i32 %x, 6 +; CHECK-NEXT: [[SHR:%.*]] = lshr exact i32 [[AND]], 1 +; CHECK-NEXT: [[SHL:%.*]] = shl nuw nsw i32 [[AND]], 6 +; CHECK-NEXT: [[OR:%.*]] = or i32 [[SHR]], [[SHL]] +; CHECK-NEXT: ret i32 [[OR]] +; + %1 = and i32 %x, 2 + %2 = and i32 %x, 4 + %3 = shl nuw nsw i32 %1, 6 + %4 = lshr exact i32 %1, 1 + %5 = shl nuw nsw i32 %2, 6 + %6 = lshr exact i32 %2, 1 + %7 = or i32 %3, %5 + %8 = or i32 %4, %6 + %9 = or i32 %8, %7 + ret i32 %9 +} + +define i32 @multiuse2(i32 %x) local_unnamed_addr { +; CHECK-LABEL: @multiuse2( +; CHECK-NEXT: [[AND:%.*]] = and i32 %x, 126 +; CHECK-NEXT: [[SHL1:%.*]] = shl nuw nsw i32 [[AND]], 8 +; CHECK-NEXT: [[SHL2:%.*]] = shl nuw nsw i32 [[AND]], 1 +; CHECK-NEXT: [[OR:%.*]] = or i32 [[SHL1]], [[SHL2]] +; CHECK-NEXT: ret i32 [[OR]] +; + %1 = and i32 %x, 6 + %2 = shl nuw nsw i32 %1, 8 + %3 = shl nuw nsw i32 %1, 1 + %4 = and i32 %x, 24 + %5 = shl nuw nsw i32 %4, 8 + %6 = shl nuw nsw i32 %4, 1 + %7 = and i32 %x, 96 + %8 = shl nuw nsw i32 %7, 8 + %9 = shl nuw nsw i32 %7, 1 + %10 = or i32 %2, %5 + %11 = or i32 %8, %10 + %12 = or i32 %9, %6 + %13 = or i32 %3, %12 + %14 = or i32 %11, %13 + ret i32 %14 +} + +define i32 @multiuse3(i32 %x) local_unnamed_addr { +; CHECK-LABEL: @multiuse3( +; CHECK-NEXT: [[AND:%.*]] = and i32 %x, 126 +; CHECK-NEXT: [[SHR:%.*]] = lshr exact i32 [[AND]], 1 +; CHECK-NEXT: [[SHL:%.*]] = shl nuw nsw i32 [[AND]], 6 +; CHECK-NEXT: [[OR:%.*]] = or i32 [[SHR]], [[SHL]] +; CHECK-NEXT: ret i32 [[OR]] +; + %1 = and i32 %x, 96 + %2 = shl nuw nsw i32 %1, 6 + %3 = lshr exact i32 %1, 1 + %4 = shl i32 %x, 6 + %5 = and i32 %4, 1920 + %6 = or i32 %2, %5 + %7 = lshr i32 %x, 1 + %8 = and i32 %7, 15 + %9 = or i32 %3, %8 + %10 = or i32 %9, %6 + ret i32 %10 +}