Skip to content

Commit d2bd642

Browse files
committed
Introduce reassociateDisjointOr
Change-Id: I172be21fe78361f4520a893d6c97c422accbf13f
1 parent ba68836 commit d2bd642

File tree

3 files changed

+165
-99
lines changed

3 files changed

+165
-99
lines changed

llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp

Lines changed: 107 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -2365,8 +2365,7 @@ static Value *simplifyAndOrWithOpReplaced(Value *V, Value *Op, Value *RepOp,
23652365
/// number of and/or instructions might have to be created.
23662366
Value *InstCombinerImpl::reassociateBooleanAndOr(Value *LHS, Value *X, Value *Y,
23672367
Instruction &I, bool IsAnd,
2368-
bool RHSIsLogical,
2369-
bool RHSIsDisjoint) {
2368+
bool RHSIsLogical) {
23702369
Instruction::BinaryOps Opcode = IsAnd ? Instruction::And : Instruction::Or;
23712370

23722371
// LHS bop (X lop Y) --> (LHS bop X) lop Y
@@ -2380,39 +2379,6 @@ Value *InstCombinerImpl::reassociateBooleanAndOr(Value *LHS, Value *X, Value *Y,
23802379
return RHSIsLogical ? Builder.CreateLogicalOp(Opcode, X, Res)
23812380
: Builder.CreateBinOp(Opcode, X, Res);
23822381

2383-
if (RHSIsDisjoint && !IsAnd && cast<PossiblyDisjointInst>(&I)->isDisjoint()) {
2384-
if (Value *Res = foldDisjointOr(LHS, X, I)) {
2385-
auto Disjoint = cast<PossiblyDisjointInst>(Builder.CreateOr(Res, Y));
2386-
Disjoint->setIsDisjoint(true);
2387-
return cast<Value>(Disjoint);
2388-
}
2389-
if (Value *Res = foldDisjointOr(LHS, Y, I)) {
2390-
auto Disjoint = cast<PossiblyDisjointInst>(Builder.CreateOr(Res, X));
2391-
Disjoint->setIsDisjoint(true);
2392-
return cast<Value>(Disjoint);
2393-
}
2394-
Value *X1, *Y1;
2395-
if (match(LHS, m_OneUse(m_DisjointOr(m_Value(X1), m_Value(Y1))))) {
2396-
auto TryFold = [this, &I](Value *Op0, Value *Op1, Value *Rem0,
2397-
Value *Rem1) -> Value * {
2398-
if (Value *Res = foldDisjointOr(Op0, Op1, I)) {
2399-
auto Disjoint =
2400-
cast<PossiblyDisjointInst>(Builder.CreateOr(Rem0, Rem1));
2401-
Disjoint->setIsDisjoint(true);
2402-
auto Disjoint2 =
2403-
cast<PossiblyDisjointInst>(Builder.CreateOr(Disjoint, Res));
2404-
return cast<Value>(Disjoint2);
2405-
}
2406-
return nullptr;
2407-
};
2408-
2409-
if (Value *Res = TryFold(X, X1, Y, Y1))
2410-
return Res;
2411-
2412-
if (Value *Res = TryFold(X, Y1, Y, X1))
2413-
return Res;
2414-
}
2415-
}
24162382
return nullptr;
24172383
}
24182384

@@ -3578,6 +3544,56 @@ Value *InstCombinerImpl::foldAndOrOfICmps(ICmpInst *LHS, ICmpInst *RHS,
35783544
return foldAndOrOfICmpsUsingRanges(LHS, RHS, IsAnd);
35793545
}
35803546

3547+
/// If IsLogical is true, then the and/or is in select form and the transform
3548+
/// must be poison-safe.
3549+
Value *InstCombinerImpl::foldBooleanAndOr(Value *LHS, Value *RHS,
3550+
Instruction &I, bool IsAnd,
3551+
bool IsLogical) {
3552+
if (!LHS->getType()->isIntOrIntVectorTy(1))
3553+
return nullptr;
3554+
3555+
// handle (roughly):
3556+
// (icmp ne (A & B), C) | (icmp ne (A & D), E)
3557+
// (icmp eq (A & B), C) & (icmp eq (A & D), E)
3558+
if (Value *V = foldLogOpOfMaskedICmps(LHS, RHS, IsAnd, IsLogical, Builder,
3559+
SQ.getWithInstruction(&I)))
3560+
return V;
3561+
3562+
if (auto *LHSCmp = dyn_cast<ICmpInst>(LHS))
3563+
if (auto *RHSCmp = dyn_cast<ICmpInst>(RHS))
3564+
if (Value *Res = foldAndOrOfICmps(LHSCmp, RHSCmp, I, IsAnd, IsLogical))
3565+
return Res;
3566+
3567+
if (auto *LHSCmp = dyn_cast<FCmpInst>(LHS))
3568+
if (auto *RHSCmp = dyn_cast<FCmpInst>(RHS))
3569+
if (Value *Res = foldLogicOfFCmps(LHSCmp, RHSCmp, IsAnd, IsLogical))
3570+
return Res;
3571+
3572+
if (Value *Res = foldEqOfParts(LHS, RHS, IsAnd))
3573+
return Res;
3574+
3575+
return nullptr;
3576+
}
3577+
3578+
static Value *foldOrOfInversions(BinaryOperator &I,
3579+
InstCombiner::BuilderTy &Builder) {
3580+
assert(I.getOpcode() == Instruction::Or &&
3581+
"Simplification only supports or at the moment.");
3582+
3583+
Value *Cmp1, *Cmp2, *Cmp3, *Cmp4;
3584+
if (!match(I.getOperand(0), m_And(m_Value(Cmp1), m_Value(Cmp2))) ||
3585+
!match(I.getOperand(1), m_And(m_Value(Cmp3), m_Value(Cmp4))))
3586+
return nullptr;
3587+
3588+
// Check if any two pairs of the and operations are inversions of each other.
3589+
if (isKnownInversion(Cmp1, Cmp3) && isKnownInversion(Cmp2, Cmp4))
3590+
return Builder.CreateXor(Cmp1, Cmp4);
3591+
if (isKnownInversion(Cmp1, Cmp4) && isKnownInversion(Cmp2, Cmp3))
3592+
return Builder.CreateXor(Cmp1, Cmp3);
3593+
3594+
return nullptr;
3595+
}
3596+
35813597
// A decomposition of ((X & Mask) * Factor). The NUW / NSW bools
35823598
// track these properities for preservation. Note that we can decompose
35833599
// equivalent select form of this expression (e.g. (!(X & Mask) ? 0 : Mask *
@@ -3680,63 +3696,73 @@ static Value *foldBitmaskMul(Value *Op0, Value *Op1,
36803696
return nullptr;
36813697
}
36823698

3683-
/// If IsLogical is true, then the and/or is in select form and the transform
3684-
/// must be poison-safe.
36853699
Value *InstCombinerImpl::foldDisjointOr(Value *LHS, Value *RHS,
36863700
Instruction &I) {
3687-
if (Value *V = foldBitmaskMul(LHS, RHS, Builder))
3688-
return V;
3701+
if (Value *Res = foldBitmaskMul(LHS, RHS, Builder)) {
3702+
return Res;
3703+
}
36893704

36903705
return nullptr;
36913706
}
36923707

3693-
/// If IsLogical is true, then the and/or is in select form and the transform
3694-
/// must be poison-safe.
3695-
Value *InstCombinerImpl::foldBooleanAndOr(Value *LHS, Value *RHS,
3696-
Instruction &I, bool IsAnd,
3697-
bool IsLogical) {
3698-
if (!LHS->getType()->isIntOrIntVectorTy(1))
3699-
return nullptr;
3700-
3701-
// handle (roughly):
3702-
// (icmp ne (A & B), C) | (icmp ne (A & D), E)
3703-
// (icmp eq (A & B), C) & (icmp eq (A & D), E)
3704-
if (Value *V = foldLogOpOfMaskedICmps(LHS, RHS, IsAnd, IsLogical, Builder,
3705-
SQ.getWithInstruction(&I)))
3706-
return V;
3707-
3708-
if (auto *LHSCmp = dyn_cast<ICmpInst>(LHS))
3709-
if (auto *RHSCmp = dyn_cast<ICmpInst>(RHS))
3710-
if (Value *Res = foldAndOrOfICmps(LHSCmp, RHSCmp, I, IsAnd, IsLogical))
3711-
return Res;
3708+
Value *InstCombinerImpl::reassociateDisjointOr(Value *LHS, Value *RHS,
3709+
Instruction &I) {
37123710

3713-
if (auto *LHSCmp = dyn_cast<FCmpInst>(LHS))
3714-
if (auto *RHSCmp = dyn_cast<FCmpInst>(RHS))
3715-
if (Value *Res = foldLogicOfFCmps(LHSCmp, RHSCmp, IsAnd, IsLogical))
3716-
return Res;
3711+
Value *X, *Y;
3712+
if (match(RHS, m_OneUse(m_DisjointOr(m_Value(X), m_Value(Y))))) {
3713+
if (Value *Res = foldDisjointOr(LHS, X, I)) {
3714+
auto Disjoint = cast<PossiblyDisjointInst>(Builder.CreateOr(Res, Y));
3715+
Disjoint->setIsDisjoint(true);
3716+
return cast<Value>(Disjoint);
3717+
}
3718+
if (Value *Res = foldDisjointOr(LHS, Y, I)) {
3719+
auto Disjoint = cast<PossiblyDisjointInst>(Builder.CreateOr(Res, X));
3720+
Disjoint->setIsDisjoint(true);
3721+
return cast<Value>(Disjoint);
3722+
}
3723+
}
37173724

3718-
if (Value *Res = foldEqOfParts(LHS, RHS, IsAnd))
3719-
return Res;
3725+
if (match(LHS, m_OneUse(m_DisjointOr(m_Value(X), m_Value(Y))))) {
3726+
if (Value *Res = foldDisjointOr(X, RHS, I)) {
3727+
auto Disjoint = cast<PossiblyDisjointInst>(Builder.CreateOr(Res, Y));
3728+
Disjoint->setIsDisjoint(true);
3729+
return cast<Value>(Disjoint);
3730+
}
3731+
if (Value *Res = foldDisjointOr(Y, RHS, I)) {
3732+
auto Disjoint = cast<PossiblyDisjointInst>(Builder.CreateOr(Res, X));
3733+
Disjoint->setIsDisjoint(true);
3734+
return cast<Value>(Disjoint);
3735+
}
3736+
}
37203737

3721-
return nullptr;
3722-
}
3738+
Value *X1, *Y1;
3739+
if (match(LHS, m_OneUse(m_DisjointOr(m_Value(X), m_Value(Y)))) &&
3740+
(match(RHS, m_OneUse(m_DisjointOr(m_Value(X1), m_Value(Y1)))))) {
3741+
auto TryFold = [this, &I](Value *Op0, Value *Op1, Value *Rem0,
3742+
Value *Rem1) -> Value * {
3743+
if (Value *Res = foldDisjointOr(Op0, Op1, I)) {
3744+
auto Disjoint =
3745+
cast<PossiblyDisjointInst>(Builder.CreateOr(Rem0, Rem1));
3746+
Disjoint->setIsDisjoint(true);
3747+
auto Disjoint2 =
3748+
cast<PossiblyDisjointInst>(Builder.CreateOr(Disjoint, Res));
3749+
return cast<Value>(Disjoint2);
3750+
}
3751+
return nullptr;
3752+
};
37233753

3724-
static Value *foldOrOfInversions(BinaryOperator &I,
3725-
InstCombiner::BuilderTy &Builder) {
3726-
assert(I.getOpcode() == Instruction::Or &&
3727-
"Simplification only supports or at the moment.");
3754+
if (Value *Res = TryFold(X, X1, Y, Y1))
3755+
return Res;
37283756

3729-
Value *Cmp1, *Cmp2, *Cmp3, *Cmp4;
3730-
if (!match(I.getOperand(0), m_And(m_Value(Cmp1), m_Value(Cmp2))) ||
3731-
!match(I.getOperand(1), m_And(m_Value(Cmp3), m_Value(Cmp4))))
3732-
return nullptr;
3757+
if (Value *Res = TryFold(X, Y1, Y, X1))
3758+
return Res;
37333759

3734-
// Check if any two pairs of the and operations are inversions of each other.
3735-
if (isKnownInversion(Cmp1, Cmp3) && isKnownInversion(Cmp2, Cmp4))
3736-
return Builder.CreateXor(Cmp1, Cmp4);
3737-
if (isKnownInversion(Cmp1, Cmp4) && isKnownInversion(Cmp2, Cmp3))
3738-
return Builder.CreateXor(Cmp1, Cmp3);
3760+
if (Value *Res = TryFold(Y, X1, X, Y1))
3761+
return Res;
37393762

3763+
if (Value *Res = TryFold(Y, Y1, X, X1))
3764+
return Res;
3765+
}
37403766
return nullptr;
37413767
}
37423768

@@ -3825,23 +3851,8 @@ Instruction *InstCombinerImpl::visitOr(BinaryOperator &I) {
38253851
if (Value *Res = foldBitmaskMul(I.getOperand(0), I.getOperand(1), Builder))
38263852
return replaceInstUsesWith(I, Res);
38273853

3828-
Value *X, *Y;
3829-
if (match(I.getOperand(1),
3830-
m_OneUse(m_DisjointOr(m_Value(X), m_Value(Y))))) {
3831-
if (auto Res = reassociateBooleanAndOr(
3832-
I.getOperand(0), X, Y, I, /*IsAnd=*/false, /*RHSIsLogical=*/true,
3833-
/*RHSIsDisjoint*/ true)) {
3834-
return replaceInstUsesWith(I, Res);
3835-
}
3836-
}
3837-
if (match(I.getOperand(0),
3838-
m_OneUse(m_DisjointOr(m_Value(X), m_Value(Y))))) {
3839-
if (auto Res = reassociateBooleanAndOr(
3840-
I.getOperand(1), X, Y, I, /*IsAnd=*/false, /*RHSIsLogical=*/true,
3841-
/*RHSIsDisjoint*/ true)) {
3842-
return replaceInstUsesWith(I, Res);
3843-
}
3844-
}
3854+
if (Value *Res = reassociateDisjointOr(I.getOperand(0), I.getOperand(1), I))
3855+
return replaceInstUsesWith(I, Res);
38453856
}
38463857

38473858
Value *X, *Y;

llvm/lib/Transforms/InstCombine/InstCombineInternal.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -436,11 +436,12 @@ class LLVM_LIBRARY_VISIBILITY InstCombinerImpl final
436436
Value *foldBooleanAndOr(Value *LHS, Value *RHS, Instruction &I, bool IsAnd,
437437
bool IsLogical);
438438

439+
Value *reassociateBooleanAndOr(Value *LHS, Value *X, Value *Y, Instruction &I,
440+
bool IsAnd, bool RHSIsLogical);
441+
439442
Value *foldDisjointOr(Value *LHS, Value *RHS, Instruction &I);
440443

441-
Value *reassociateBooleanAndOr(Value *LHS, Value *X, Value *Y, Instruction &I,
442-
bool IsAnd, bool RHSIsLogical,
443-
bool RHSIsDisjoint = false);
444+
Value *reassociateDisjointOr(Value *LHS, Value *RHS, Instruction &I);
444445

445446
Instruction *
446447
canonicalizeConditionalNegationViaMathToSelect(BinaryOperator &i);

llvm/test/Transforms/InstCombine/or-bitmask.ll

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,60 @@ define i32 @unrelated_ops5(i32 %in, i32 %in2, i32 %in3) {
559559
ret i32 %out
560560
}
561561

562+
define i32 @unrelated_ops6(i32 %in, i32 %in2, i32 %in3) {
563+
; CHECK-LABEL: @unrelated_ops6(
564+
; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[IN:%.*]], 15
565+
; CHECK-NEXT: [[TMP2:%.*]] = mul nuw nsw i32 [[TMP1]], 72
566+
; CHECK-NEXT: [[TMP3:%.*]] = or disjoint i32 [[IN3:%.*]], [[IN2:%.*]]
567+
; CHECK-NEXT: [[OUT:%.*]] = or i32 [[TMP3]], [[TMP2]]
568+
; CHECK-NEXT: ret i32 [[OUT]]
569+
;
570+
%1 = and i32 %in, 3
571+
%temp = mul nuw nsw i32 %1, 72
572+
%temp3 = or disjoint i32 %in3, %temp
573+
%2 = and i32 %in, 12
574+
%temp2 = mul nuw nsw i32 %2, 72
575+
%temp4 = or disjoint i32 %in2, %temp2
576+
%out = or disjoint i32 %temp3, %temp4
577+
ret i32 %out
578+
}
579+
580+
define i32 @unrelated_ops7(i32 %in, i32 %in2, i32 %in3) {
581+
; CHECK-LABEL: @unrelated_ops7(
582+
; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[IN:%.*]], 15
583+
; CHECK-NEXT: [[TMP2:%.*]] = mul nuw nsw i32 [[TMP1]], 72
584+
; CHECK-NEXT: [[TMP3:%.*]] = or disjoint i32 [[IN3:%.*]], [[IN2:%.*]]
585+
; CHECK-NEXT: [[OUT:%.*]] = or i32 [[TMP3]], [[TMP2]]
586+
; CHECK-NEXT: ret i32 [[OUT]]
587+
;
588+
%1 = and i32 %in, 3
589+
%temp = mul nuw nsw i32 %1, 72
590+
%temp3 = or disjoint i32 %in3, %temp
591+
%2 = and i32 %in, 12
592+
%temp2 = mul nuw nsw i32 %2, 72
593+
%temp4 = or disjoint i32 %temp2, %in2
594+
%out = or disjoint i32 %temp3, %temp4
595+
ret i32 %out
596+
}
597+
598+
define i32 @unrelated_ops8(i32 %in, i32 %in2, i32 %in3) {
599+
; CHECK-LABEL: @unrelated_ops8(
600+
; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[IN:%.*]], 15
601+
; CHECK-NEXT: [[TMP2:%.*]] = mul nuw nsw i32 [[TMP1]], 72
602+
; CHECK-NEXT: [[TMP3:%.*]] = or disjoint i32 [[IN3:%.*]], [[IN2:%.*]]
603+
; CHECK-NEXT: [[OUT:%.*]] = or i32 [[TMP3]], [[TMP2]]
604+
; CHECK-NEXT: ret i32 [[OUT]]
605+
;
606+
%1 = and i32 %in, 3
607+
%temp = mul nuw nsw i32 %1, 72
608+
%temp3 = or disjoint i32 %temp, %in3
609+
%2 = and i32 %in, 12
610+
%temp2 = mul nuw nsw i32 %2, 72
611+
%temp4 = or disjoint i32 %temp2, %in2
612+
%out = or disjoint i32 %temp3, %temp4
613+
ret i32 %out
614+
}
615+
562616
define i32 @unrelated_ops_nocombine(i32 %in, i32 %in2, i32 %in3) {
563617
; CHECK-LABEL: @unrelated_ops_nocombine(
564618
; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[IN:%.*]], 3

0 commit comments

Comments
 (0)