Index: lib/Transforms/InstCombine/InstCombineAndOrXor.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -2035,6 +2035,92 @@ return SelectInst::Create(X, orTrue, orFalse); } } + + // ((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-shifted-masks.ll =================================================================== --- test/Transforms/InstCombine/or-shifted-masks.ll +++ test/Transforms/InstCombine/or-shifted-masks.ll @@ -4,10 +4,9 @@ ; CHECK-LABEL: @or_and_shifts1( ; CHECK-NEXT: [[TMP1:%.*]] = and i32 %x, 1 ; CHECK-NEXT: [[TMP2:%.*]] = shl nuw nsw i32 [[TMP1]], 3 -; CHECK-NEXT: [[TMP3:%.*]] = and i32 %x, 1 -; CHECK-NEXT: [[TMP4:%.*]] = shl nuw nsw i32 [[TMP3]], 5 -; CHECK-NEXT: [[TMP5:%.*]] = or i32 [[TMP2]], [[TMP4]] -; CHECK-NEXT: ret i32 [[TMP5]] +; CHECK-NEXT: [[TMP3:%.*]] = shl nuw nsw i32 [[TMP1]], 5 +; CHECK-NEXT: [[TMP4:%.*]] = or i32 [[TMP2]], [[TMP3]] +; CHECK-NEXT: ret i32 [[TMP4]] ; %1 = shl i32 %x, 3 %2 = and i32 %1, 15 @@ -21,10 +20,9 @@ ; CHECK-LABEL: @or_and_shifts2( ; CHECK-NEXT: [[TMP1:%.*]] = and i32 %x, 112 ; CHECK-NEXT: [[TMP2:%.*]] = shl nuw nsw i32 [[TMP1]], 3 -; CHECK-NEXT: [[TMP3:%.*]] = lshr i32 %x, 4 -; CHECK-NEXT: [[TMP4:%.*]] = and i32 [[TMP3]], 7 -; CHECK-NEXT: [[TMP5:%.*]] = or i32 [[TMP2]], [[TMP4]] -; CHECK-NEXT: ret i32 [[TMP5]] +; CHECK-NEXT: [[TMP3:%.*]] = lshr exact i32 [[TMP1]], 4 +; CHECK-NEXT: [[TMP4:%.*]] = or i32 [[TMP2]], [[TMP3]] +; CHECK-NEXT: ret i32 [[TMP4]] ; %1 = shl i32 %x, 3 %2 = and i32 %1, 896 @@ -38,10 +36,9 @@ ; CHECK-LABEL: @or_and_shift_shift_and( ; CHECK-NEXT: [[TMP1:%.*]] = and i32 %x, 7 ; CHECK-NEXT: [[TMP2:%.*]] = shl nuw nsw i32 [[TMP1]], 3 -; CHECK-NEXT: [[TMP3:%.*]] = and i32 %x, 7 -; CHECK-NEXT: [[TMP4:%.*]] = shl nuw nsw i32 [[TMP3]], 2 -; CHECK-NEXT: [[TMP5:%.*]] = or i32 [[TMP2]], [[TMP4]] -; CHECK-NEXT: ret i32 [[TMP5]] +; CHECK-NEXT: [[TMP3:%.*]] = shl nuw nsw i32 [[TMP1]], 2 +; CHECK-NEXT: [[TMP4:%.*]] = or i32 [[TMP2]], [[TMP3]] +; CHECK-NEXT: ret i32 [[TMP4]] ; %1 = and i32 %x, 7 %2 = shl i32 %1, 3 @@ -54,11 +51,10 @@ define i32 @multiuse1(i32 %x) { ; CHECK-LABEL: @multiuse1( ; CHECK-NEXT: [[TMP1:%.*]] = and i32 %x, 6 -; CHECK-NEXT: [[TMP2:%.*]] = shl nuw nsw i32 [[TMP1]], 6 -; CHECK-NEXT: [[TMP3:%.*]] = lshr i32 %x, 1 -; CHECK-NEXT: [[TMP4:%.*]] = and i32 [[TMP3]], 3 -; CHECK-NEXT: [[TMP5:%.*]] = or i32 [[TMP4]], [[TMP2]] -; CHECK-NEXT: ret i32 [[TMP5]] +; CHECK-NEXT: [[TMP2:%.*]] = lshr exact i32 [[TMP1]], 1 +; CHECK-NEXT: [[TMP3:%.*]] = shl nuw nsw i32 [[TMP1]], 6 +; CHECK-NEXT: [[TMP4:%.*]] = or i32 [[TMP2]], [[TMP3]] +; CHECK-NEXT: ret i32 [[TMP4]] ; %1 = and i32 %x, 2 %2 = and i32 %x, 4 @@ -76,10 +72,9 @@ ; CHECK-LABEL: @multiuse2( ; CHECK-NEXT: [[TMP1:%.*]] = and i32 %x, 126 ; CHECK-NEXT: [[TMP2:%.*]] = shl nuw nsw i32 [[TMP1]], 8 -; CHECK-NEXT: [[TMP3:%.*]] = and i32 %x, 126 -; CHECK-NEXT: [[TMP4:%.*]] = shl nuw nsw i32 [[TMP3]], 1 -; CHECK-NEXT: [[TMP5:%.*]] = or i32 [[TMP2]], [[TMP4]] -; CHECK-NEXT: ret i32 [[TMP5]] +; CHECK-NEXT: [[TMP3:%.*]] = shl nuw nsw i32 [[TMP1]], 1 +; CHECK-NEXT: [[TMP4:%.*]] = or i32 [[TMP2]], [[TMP3]] +; CHECK-NEXT: ret i32 [[TMP4]] ; %1 = and i32 %x, 6 %2 = shl nuw nsw i32 %1, 8 @@ -100,15 +95,11 @@ define i32 @multiuse3(i32 %x) { ; CHECK-LABEL: @multiuse3( -; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 %x, 1 -; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], 48 -; CHECK-NEXT: [[TMP3:%.*]] = and i32 %x, 126 -; CHECK-NEXT: [[TMP4:%.*]] = shl nuw nsw i32 [[TMP3]], 6 -; CHECK-NEXT: [[TMP5:%.*]] = lshr i32 %x, 1 -; CHECK-NEXT: [[TMP6:%.*]] = and i32 [[TMP5]], 15 -; CHECK-NEXT: [[TMP7:%.*]] = or i32 [[TMP2]], [[TMP6]] -; CHECK-NEXT: [[TMP8:%.*]] = or i32 [[TMP7]], [[TMP4]] -; CHECK-NEXT: ret i32 [[TMP8]] +; CHECK-NEXT: [[TMP1:%.*]] = and i32 %x, 126 +; CHECK-NEXT: [[TMP2:%.*]] = lshr exact i32 [[TMP1]], 1 +; CHECK-NEXT: [[TMP3:%.*]] = shl nuw nsw i32 [[TMP1]], 6 +; CHECK-NEXT: [[TMP4:%.*]] = or i32 [[TMP2]], [[TMP3]] +; CHECK-NEXT: ret i32 [[TMP4]] ; %1 = and i32 %x, 96 %2 = shl nuw nsw i32 %1, 6 @@ -125,24 +116,19 @@ define i32 @multiuse4(i32 %x) local_unnamed_addr #0 { ; CHECK-LABEL: @multiuse4( -; CHECK-NEXT: [[TMP1:%.*]] = and i32 %x, 100663296 -; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt i32 %x, -1 -; CHECK-NEXT: br i1 [[TMP2]], label %if, label %else +; CHECK-NEXT: [[TMP1:%.*]] = icmp sgt i32 %x, -1 +; CHECK-NEXT: br i1 [[TMP1]], label %if, label %else ; CHECK: {{.*}}if:{{.*}} -; CHECK-NEXT: [[TMP3:%.*]] = lshr exact i32 [[TMP1]], 22 -; CHECK-NEXT: [[TMP4:%.*]] = lshr i32 %x, 22 -; CHECK-NEXT: [[TMP5:%.*]] = and i32 [[TMP4]], 480 -; CHECK-NEXT: [[TMP6:%.*]] = or i32 [[TMP5]], [[TMP3]] +; CHECK-NEXT: [[TMP2:%.*]] = lshr i32 %x, 22 +; CHECK-NEXT: [[TMP3:%.*]] = and i32 [[TMP2]], 504 ; CHECK-NEXT: br label %end ; CHECK: {{.*}}else:{{.*}} -; CHECK-NEXT: [[TMP7:%.*]] = lshr exact i32 [[TMP1]], 17 -; CHECK-NEXT: [[TMP8:%.*]] = lshr i32 %x, 17 -; CHECK-NEXT: [[TMP9:%.*]] = and i32 [[TMP8]], 15360 -; CHECK-NEXT: [[TMP10:%.*]] = or i32 [[TMP9]], [[TMP7]] +; CHECK-NEXT: [[TMP4:%.*]] = lshr i32 %x, 17 +; CHECK-NEXT: [[TMP5:%.*]] = and i32 [[TMP4]], 16128 ; CHECK-NEXT: br label %end ; CHECK: {{.*}}end{{.*}} -; CHECK-NEXT: [[TMP11:%.*]] = phi i32 [ [[TMP6]], %if ], [ [[TMP10]], %else ] -; CHECK-NEXT: ret i32 [[TMP11]] +; CHECK-NEXT: [[TMP6:%.*]] = phi i32 [ [[TMP3]], %if ], [ [[TMP5]], %else ] +; CHECK-NEXT: ret i32 [[TMP6]] ; %1 = and i32 %x, 100663296 %2 = icmp sgt i32 %x, -1 @@ -169,24 +155,18 @@ define i32 @multiuse5(i32 %x) local_unnamed_addr #0 { ; CHECK-LABEL: @multiuse5( -; CHECK-NEXT: [[TMP1:%.*]] = shl i32 %x, 5 -; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt i32 %x, -1 -; CHECK-NEXT: br i1 [[TMP2]], label %if, label %else +; CHECK-NEXT: [[TMP1:%.*]] = icmp sgt i32 %x, -1 +; CHECK-NEXT: br i1 [[TMP1]], label %if, label %else ; CHECK: {{.*}}if:{{.*}} -; CHECK-NEXT: [[TMP3:%.*]] = and i32 [[TMP1]], 21760 -; CHECK-NEXT: [[TMP4:%.*]] = and i32 %x, 1360 -; CHECK-NEXT: [[TMP5:%.*]] = shl nuw nsw i32 [[TMP4]], 5 -; CHECK-NEXT: [[TMP6:%.*]] = or i32 [[TMP5]], [[TMP3]] +; CHECK-NEXT: [[TMP2:%.*]] = and i32 %x, 2040 ; CHECK-NEXT: br label %end ; CHECK: {{.*}}else:{{.*}} -; CHECK-NEXT: [[TMP7:%.*]] = and i32 [[TMP1]], 5570560 -; CHECK-NEXT: [[TMP8:%.*]] = and i32 %x, 348160 -; CHECK-NEXT: [[TMP9:%.*]] = shl nuw nsw i32 [[TMP8]], 5 -; CHECK-NEXT: [[TMP10:%.*]] = or i32 [[TMP9]], [[TMP7]] +; CHECK-NEXT: [[TMP3:%.*]] = and i32 %x, 522240 ; CHECK-NEXT: br label %end -; CHECK: {{.*}}end{{.*}} -; CHECK-NEXT: [[TMP11:%.*]] = phi i32 [ [[TMP6]], %if ], [ [[TMP10]], %else ] -; CHECK-NEXT: ret i32 [[TMP11]] +; CHECK: {{.*}}end:{{.*}} +; CHECK-NEXT: [[IN:%.*]] = phi i32 [ [[TMP2]], %if ], [ [[TMP3]], %else ] +; CHECK-NEXT: [[TMP4:%.*]] = shl nuw nsw i32 [[IN]], 5 +; CHECK-NEXT: ret i32 [[TMP4]] ; %1 = shl i32 %x, 5 %2 = icmp sgt i32 %x, -1