[llvm] 0da9aac - [InstCombine] Extend bitmask mul combine to handle independent operands (#142503)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Jul 7 13:50:45 PDT 2025
Author: Jeffrey Byrnes
Date: 2025-07-07T13:50:42-07:00
New Revision: 0da9aacf4898fc9debfd930ab3dfbac7084c5e2a
URL: https://github.com/llvm/llvm-project/commit/0da9aacf4898fc9debfd930ab3dfbac7084c5e2a
DIFF: https://github.com/llvm/llvm-project/commit/0da9aacf4898fc9debfd930ab3dfbac7084c5e2a.diff
LOG: [InstCombine] Extend bitmask mul combine to handle independent operands (#142503)
This extends https://github.com/llvm/llvm-project/pull/136013 to capture
cases where the combineable bitmask muls are nested under multiple
or-disjoints.
This PR is meant for commits starting at
8c403c912046505ffc10378560c2fc48f214af6a
op1 = or-disjoint mul(and (X, C1), D) , reg1
op2 = or-disjoint mul(and (X, C2), D) , reg2
out = or-disjoint op1, op2
->
temp1 = or-disjoint reg1, reg2
out = or-disjoint mul(and (X, (C1 + C2)), D), temp1
Case1: https://alive2.llvm.org/ce/z/dHApyV
Case2: https://alive2.llvm.org/ce/z/Jz-Nag
Case3: https://alive2.llvm.org/ce/z/3xBnEV
Added:
Modified:
llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
llvm/lib/Transforms/InstCombine/InstCombineInternal.h
llvm/test/Transforms/InstCombine/or-bitmask.ll
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index dd16cfaeecd45..706cb828acc63 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -3602,6 +3602,11 @@ struct DecomposedBitMaskMul {
APInt Mask;
bool NUW;
bool NSW;
+
+ bool isCombineableWith(const DecomposedBitMaskMul Other) {
+ return X == Other.X && !Mask.intersects(Other.Mask) &&
+ Factor == Other.Factor;
+ }
};
static std::optional<DecomposedBitMaskMul> matchBitmaskMul(Value *V) {
@@ -3659,6 +3664,59 @@ static std::optional<DecomposedBitMaskMul> matchBitmaskMul(Value *V) {
return std::nullopt;
}
+/// (A & N) * C + (A & M) * C -> (A & (N + M)) & C
+/// This also accepts the equivalent select form of (A & N) * C
+/// expressions i.e. !(A & N) ? 0 : N * C)
+static Value *foldBitmaskMul(Value *Op0, Value *Op1,
+ InstCombiner::BuilderTy &Builder) {
+ auto Decomp1 = matchBitmaskMul(Op1);
+ if (!Decomp1)
+ return nullptr;
+
+ auto Decomp0 = matchBitmaskMul(Op0);
+ if (!Decomp0)
+ return nullptr;
+
+ if (Decomp0->isCombineableWith(*Decomp1)) {
+ Value *NewAnd = Builder.CreateAnd(
+ Decomp0->X,
+ ConstantInt::get(Decomp0->X->getType(), Decomp0->Mask + Decomp1->Mask));
+
+ return Builder.CreateMul(
+ NewAnd, ConstantInt::get(NewAnd->getType(), Decomp1->Factor), "",
+ Decomp0->NUW && Decomp1->NUW, Decomp0->NSW && Decomp1->NSW);
+ }
+
+ return nullptr;
+}
+
+Value *InstCombinerImpl::foldDisjointOr(Value *LHS, Value *RHS) {
+ if (Value *Res = foldBitmaskMul(LHS, RHS, Builder))
+ return Res;
+
+ return nullptr;
+}
+
+Value *InstCombinerImpl::reassociateDisjointOr(Value *LHS, Value *RHS) {
+
+ Value *X, *Y;
+ if (match(RHS, m_OneUse(m_DisjointOr(m_Value(X), m_Value(Y))))) {
+ if (Value *Res = foldDisjointOr(LHS, X))
+ return Builder.CreateOr(Res, Y, "", /*IsDisjoint=*/true);
+ if (Value *Res = foldDisjointOr(LHS, Y))
+ return Builder.CreateOr(Res, X, "", /*IsDisjoint=*/true);
+ }
+
+ if (match(LHS, m_OneUse(m_DisjointOr(m_Value(X), m_Value(Y))))) {
+ if (Value *Res = foldDisjointOr(X, RHS))
+ return Builder.CreateOr(Res, Y, "", /*IsDisjoint=*/true);
+ if (Value *Res = foldDisjointOr(Y, RHS))
+ return Builder.CreateOr(Res, X, "", /*IsDisjoint=*/true);
+ }
+
+ return nullptr;
+}
+
// FIXME: We use commutative matchers (m_c_*) for some, but not all, matches
// here. We should standardize that construct where it is needed or choose some
// other way to ensure that commutated variants of patterns are not missed.
@@ -3741,28 +3799,11 @@ Instruction *InstCombinerImpl::visitOr(BinaryOperator &I) {
/*NSW=*/true, /*NUW=*/true))
return R;
- // (A & N) * C + (A & M) * C -> (A & (N + M)) & C
- // This also accepts the equivalent select form of (A & N) * C
- // expressions i.e. !(A & N) ? 0 : N * C)
- auto Decomp1 = matchBitmaskMul(I.getOperand(1));
- if (Decomp1) {
- auto Decomp0 = matchBitmaskMul(I.getOperand(0));
- if (Decomp0 && Decomp0->X == Decomp1->X &&
- (Decomp0->Mask & Decomp1->Mask).isZero() &&
- Decomp0->Factor == Decomp1->Factor) {
-
- Value *NewAnd = Builder.CreateAnd(
- Decomp0->X, ConstantInt::get(Decomp0->X->getType(),
- (Decomp0->Mask + Decomp1->Mask)));
-
- auto *Combined = BinaryOperator::CreateMul(
- NewAnd, ConstantInt::get(NewAnd->getType(), Decomp1->Factor));
-
- Combined->setHasNoUnsignedWrap(Decomp0->NUW && Decomp1->NUW);
- Combined->setHasNoSignedWrap(Decomp0->NSW && Decomp1->NSW);
- return Combined;
- }
- }
+ if (Value *Res = foldBitmaskMul(I.getOperand(0), I.getOperand(1), Builder))
+ return replaceInstUsesWith(I, Res);
+
+ if (Value *Res = reassociateDisjointOr(I.getOperand(0), I.getOperand(1)))
+ return replaceInstUsesWith(I, Res);
}
Value *X, *Y;
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
index 9adde8094d44d..1b963952f1d61 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
+++ b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
@@ -439,6 +439,10 @@ class LLVM_LIBRARY_VISIBILITY InstCombinerImpl final
Value *reassociateBooleanAndOr(Value *LHS, Value *X, Value *Y, Instruction &I,
bool IsAnd, bool RHSIsLogical);
+ Value *foldDisjointOr(Value *LHS, Value *RHS);
+
+ Value *reassociateDisjointOr(Value *LHS, Value *RHS);
+
Instruction *
canonicalizeConditionalNegationViaMathToSelect(BinaryOperator &i);
diff --git a/llvm/test/Transforms/InstCombine/or-bitmask.ll b/llvm/test/Transforms/InstCombine/or-bitmask.ll
index 3c992dfea569a..2ee34cdc034ad 100644
--- a/llvm/test/Transforms/InstCombine/or-bitmask.ll
+++ b/llvm/test/Transforms/InstCombine/or-bitmask.ll
@@ -451,6 +451,448 @@ define i32 @and_mul_non_disjoint(i32 %in) {
ret i32 %out
}
+define i32 @unrelated_ops(i32 %in, i32 %in2) {
+; CHECK-LABEL: @unrelated_ops(
+; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[IN:%.*]], 15
+; CHECK-NEXT: [[TMP2:%.*]] = mul nuw nsw i32 [[TMP1]], 72
+; CHECK-NEXT: [[OUT:%.*]] = or disjoint i32 [[TMP2]], [[IN2:%.*]]
+; CHECK-NEXT: ret i32 [[OUT]]
+;
+ %and0 = and i32 %in, 3
+ %temp = mul nuw nsw i32 %and0, 72
+ %and1 = and i32 %in, 12
+ %temp2 = mul nuw nsw i32 %and1, 72
+ %temp3 = or disjoint i32 %in2, %temp2
+ %out = or disjoint i32 %temp, %temp3
+ ret i32 %out
+}
+
+define i32 @unrelated_ops1(i32 %in, i32 %in2) {
+; CHECK-LABEL: @unrelated_ops1(
+; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[IN:%.*]], 15
+; CHECK-NEXT: [[TMP2:%.*]] = mul nuw nsw i32 [[TMP1]], 72
+; CHECK-NEXT: [[OUT:%.*]] = or disjoint i32 [[TMP2]], [[IN2:%.*]]
+; CHECK-NEXT: ret i32 [[OUT]]
+;
+ %and0 = and i32 %in, 3
+ %temp = mul nuw nsw i32 %and0, 72
+ %and1 = and i32 %in, 12
+ %temp2 = mul nuw nsw i32 %and1, 72
+ %temp3 = or disjoint i32 %in2, %temp
+ %out = or disjoint i32 %temp3, %temp2
+ ret i32 %out
+}
+
+define i32 @unrelated_ops2(i32 %in, i32 %in2, i32 %in3) {
+; CHECK-LABEL: @unrelated_ops2(
+; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[IN:%.*]], 3
+; CHECK-NEXT: [[TMP2:%.*]] = mul nuw nsw i32 [[TMP1]], 72
+; CHECK-NEXT: [[TEMP3:%.*]] = or disjoint i32 [[TMP2]], [[IN4:%.*]]
+; CHECK-NEXT: [[AND1:%.*]] = and i32 [[IN]], 12
+; CHECK-NEXT: [[IN2:%.*]] = mul nuw nsw i32 [[AND1]], 72
+; CHECK-NEXT: [[TMP3:%.*]] = or disjoint i32 [[IN3:%.*]], [[IN2]]
+; CHECK-NEXT: [[OUT:%.*]] = or disjoint i32 [[TEMP3]], [[TMP3]]
+; CHECK-NEXT: ret i32 [[OUT]]
+;
+ %and0 = and i32 %in, 3
+ %temp = mul nuw nsw i32 %and0, 72
+ %temp3 = or disjoint i32 %temp, %in3
+ %and1 = and i32 %in, 12
+ %temp2 = mul nuw nsw i32 %and1, 72
+ %temp4 = or disjoint i32 %in2, %temp2
+ %out = or disjoint i32 %temp3, %temp4
+ ret i32 %out
+}
+
+define i32 @unrelated_ops3(i32 %in, i32 %in2, i32 %in3) {
+; CHECK-LABEL: @unrelated_ops3(
+; CHECK-NEXT: [[AND0:%.*]] = and i32 [[IN:%.*]], 2
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND0]], 0
+; CHECK-NEXT: [[TEMP:%.*]] = select i1 [[CMP]], i32 0, i32 144
+; CHECK-NEXT: [[TEMP3:%.*]] = or disjoint i32 [[TEMP]], [[IN3:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[IN]], 12
+; CHECK-NEXT: [[TEMP2:%.*]] = mul nuw nsw i32 [[TMP2]], 72
+; CHECK-NEXT: [[TEMP4:%.*]] = or disjoint i32 [[IN2:%.*]], [[TEMP2]]
+; CHECK-NEXT: [[OUT:%.*]] = or disjoint i32 [[TEMP3]], [[TEMP4]]
+; CHECK-NEXT: ret i32 [[OUT]]
+;
+ %and0 = and i32 %in, 2
+ %cmp = icmp eq i32 %and0, 0
+ %temp = select i1 %cmp, i32 0, i32 144
+ %temp3 = or disjoint i32 %temp, %in3
+ %and1 = and i32 %in, 12
+ %temp2 = mul nuw nsw i32 %and1, 72
+ %temp4 = or disjoint i32 %in2, %temp2
+ %out = or disjoint i32 %temp3, %temp4
+ ret i32 %out
+}
+
+define i32 @unrelated_ops4(i32 %in, i32 %in2, i32 %in3) {
+; CHECK-LABEL: @unrelated_ops4(
+; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[IN:%.*]], 12
+; CHECK-NEXT: [[TMP3:%.*]] = mul nuw nsw i32 [[TMP2]], 72
+; CHECK-NEXT: [[TEMP3:%.*]] = or disjoint i32 [[IN4:%.*]], [[TMP3]]
+; CHECK-NEXT: [[AND1:%.*]] = and i32 [[IN]], 2
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND1]], 0
+; CHECK-NEXT: [[IN3:%.*]] = select i1 [[CMP]], i32 0, i32 144
+; CHECK-NEXT: [[TMP4:%.*]] = or disjoint i32 [[IN3]], [[IN2:%.*]]
+; CHECK-NEXT: [[OUT:%.*]] = or disjoint i32 [[TEMP3]], [[TMP4]]
+; CHECK-NEXT: ret i32 [[OUT]]
+;
+ %and0 = and i32 %in, 12
+ %temp = mul nuw nsw i32 %and0, 72
+ %temp3 = or disjoint i32 %in2, %temp
+ %and1 = and i32 %in, 2
+ %cmp = icmp eq i32 %and1, 0
+ %temp2 = select i1 %cmp, i32 0, i32 144
+ %temp4 = or disjoint i32 %temp2, %in3
+ %out = or disjoint i32 %temp3, %temp4
+ ret i32 %out
+}
+
+define i32 @unrelated_ops5(i32 %in, i32 %in2, i32 %in3) {
+; CHECK-LABEL: @unrelated_ops5(
+; CHECK-NEXT: [[AND0:%.*]] = and i32 [[IN:%.*]], 2
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND0]], 0
+; CHECK-NEXT: [[IN3:%.*]] = select i1 [[CMP]], i32 0, i32 144
+; CHECK-NEXT: [[TMP4:%.*]] = or disjoint i32 [[IN3]], [[IN2:%.*]]
+; CHECK-NEXT: [[AND1:%.*]] = and i32 [[IN]], 4
+; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i32 [[AND1]], 0
+; CHECK-NEXT: [[TEMP2:%.*]] = select i1 [[CMP2]], i32 0, i32 288
+; CHECK-NEXT: [[TMP3:%.*]] = or disjoint i32 [[IN4:%.*]], [[TEMP2]]
+; CHECK-NEXT: [[OUT:%.*]] = or disjoint i32 [[TMP4]], [[TMP3]]
+; CHECK-NEXT: ret i32 [[OUT]]
+;
+ %and0 = and i32 %in, 2
+ %cmp = icmp eq i32 %and0, 0
+ %temp = select i1 %cmp, i32 0, i32 144
+ %temp3 = or disjoint i32 %temp, %in3
+ %and1 = and i32 %in, 4
+ %cmp2 = icmp eq i32 %and1, 0
+ %temp2 = select i1 %cmp2, i32 0, i32 288
+ %temp4 = or disjoint i32 %in2, %temp2
+ %out = or disjoint i32 %temp3, %temp4
+ ret i32 %out
+}
+
+define i32 @unrelated_ops6(i32 %in, i32 %in2, i32 %in3) {
+; CHECK-LABEL: @unrelated_ops6(
+; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[IN:%.*]], 3
+; CHECK-NEXT: [[TMP2:%.*]] = mul nuw nsw i32 [[TMP1]], 72
+; CHECK-NEXT: [[TEMP3:%.*]] = or disjoint i32 [[IN4:%.*]], [[TMP2]]
+; CHECK-NEXT: [[AND1:%.*]] = and i32 [[IN]], 12
+; CHECK-NEXT: [[IN2:%.*]] = mul nuw nsw i32 [[AND1]], 72
+; CHECK-NEXT: [[TMP3:%.*]] = or disjoint i32 [[IN3:%.*]], [[IN2]]
+; CHECK-NEXT: [[OUT:%.*]] = or disjoint i32 [[TEMP3]], [[TMP3]]
+; CHECK-NEXT: ret i32 [[OUT]]
+;
+ %and0 = and i32 %in, 3
+ %temp = mul nuw nsw i32 %and0, 72
+ %temp3 = or disjoint i32 %in3, %temp
+ %and1 = and i32 %in, 12
+ %temp2 = mul nuw nsw i32 %and1, 72
+ %temp4 = or disjoint i32 %in2, %temp2
+ %out = or disjoint i32 %temp3, %temp4
+ ret i32 %out
+}
+
+define i32 @unrelated_ops7(i32 %in, i32 %in2, i32 %in3) {
+; CHECK-LABEL: @unrelated_ops7(
+; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[IN:%.*]], 3
+; CHECK-NEXT: [[TMP2:%.*]] = mul nuw nsw i32 [[TMP1]], 72
+; CHECK-NEXT: [[TEMP3:%.*]] = or disjoint i32 [[IN4:%.*]], [[TMP2]]
+; CHECK-NEXT: [[AND1:%.*]] = and i32 [[IN]], 12
+; CHECK-NEXT: [[IN3:%.*]] = mul nuw nsw i32 [[AND1]], 72
+; CHECK-NEXT: [[TMP3:%.*]] = or disjoint i32 [[IN3]], [[IN2:%.*]]
+; CHECK-NEXT: [[OUT:%.*]] = or disjoint i32 [[TEMP3]], [[TMP3]]
+; CHECK-NEXT: ret i32 [[OUT]]
+;
+ %and0 = and i32 %in, 3
+ %temp = mul nuw nsw i32 %and0, 72
+ %temp3 = or disjoint i32 %in3, %temp
+ %and1 = and i32 %in, 12
+ %temp2 = mul nuw nsw i32 %and1, 72
+ %temp4 = or disjoint i32 %temp2, %in2
+ %out = or disjoint i32 %temp3, %temp4
+ ret i32 %out
+}
+
+define i32 @unrelated_ops8(i32 %in, i32 %in2, i32 %in3) {
+; CHECK-LABEL: @unrelated_ops8(
+; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[IN:%.*]], 3
+; CHECK-NEXT: [[TMP2:%.*]] = mul nuw nsw i32 [[TMP1]], 72
+; CHECK-NEXT: [[TEMP3:%.*]] = or disjoint i32 [[TMP2]], [[IN4:%.*]]
+; CHECK-NEXT: [[AND1:%.*]] = and i32 [[IN]], 12
+; CHECK-NEXT: [[IN3:%.*]] = mul nuw nsw i32 [[AND1]], 72
+; CHECK-NEXT: [[TMP3:%.*]] = or disjoint i32 [[IN3]], [[IN2:%.*]]
+; CHECK-NEXT: [[OUT:%.*]] = or disjoint i32 [[TEMP3]], [[TMP3]]
+; CHECK-NEXT: ret i32 [[OUT]]
+;
+ %and0 = and i32 %in, 3
+ %temp = mul nuw nsw i32 %and0, 72
+ %temp3 = or disjoint i32 %temp, %in3
+ %and1 = and i32 %in, 12
+ %temp2 = mul nuw nsw i32 %and1, 72
+ %temp4 = or disjoint i32 %temp2, %in2
+ %out = or disjoint i32 %temp3, %temp4
+ ret i32 %out
+}
+
+define i32 @unrelated_ops_nocombine(i32 %in, i32 %in2, i32 %in3) {
+; CHECK-LABEL: @unrelated_ops_nocombine(
+; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[IN:%.*]], 3
+; CHECK-NEXT: [[TEMP:%.*]] = mul nuw nsw i32 [[TMP1]], 72
+; CHECK-NEXT: [[TMP4:%.*]] = or disjoint i32 [[TEMP]], [[IN3:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[IN]], 7
+; CHECK-NEXT: [[TEMP2:%.*]] = mul nuw nsw i32 [[TMP2]], 72
+; CHECK-NEXT: [[TMP3:%.*]] = or disjoint i32 [[IN2:%.*]], [[TEMP2]]
+; CHECK-NEXT: [[OUT:%.*]] = or disjoint i32 [[TMP4]], [[TMP3]]
+; CHECK-NEXT: ret i32 [[OUT]]
+;
+ %and0 = and i32 %in, 3
+ %temp = mul nuw nsw i32 %and0, 72
+ %temp3 = or disjoint i32 %temp, %in3
+ %and1 = and i32 %in, 7
+ %temp2 = mul nuw nsw i32 %and1, 72
+ %temp4 = or disjoint i32 %in2, %temp2
+ %out = or disjoint i32 %temp3, %temp4
+ ret i32 %out
+}
+
+define i32 @unrelated_ops_nocombine1(i32 %in, i32 %in2, i32 %in3) {
+; CHECK-LABEL: @unrelated_ops_nocombine1(
+; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[IN:%.*]], 3
+; CHECK-NEXT: [[TEMP:%.*]] = mul nuw nsw i32 [[TMP1]], 72
+; CHECK-NEXT: [[TMP4:%.*]] = or disjoint i32 [[TEMP]], [[IN3:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[IN]], 12
+; CHECK-NEXT: [[TEMP2:%.*]] = mul nuw nsw i32 [[TMP2]], 36
+; CHECK-NEXT: [[TMP3:%.*]] = or disjoint i32 [[IN2:%.*]], [[TEMP2]]
+; CHECK-NEXT: [[OUT:%.*]] = or disjoint i32 [[TMP4]], [[TMP3]]
+; CHECK-NEXT: ret i32 [[OUT]]
+;
+ %and0 = and i32 %in, 3
+ %temp = mul nuw nsw i32 %and0, 72
+ %temp3 = or disjoint i32 %temp, %in3
+ %and1 = and i32 %in, 12
+ %temp2 = mul nuw nsw i32 %and1, 36
+ %temp4 = or disjoint i32 %in2, %temp2
+ %out = or disjoint i32 %temp3, %temp4
+ ret i32 %out
+}
+
+define i32 @unrelated_nondisjoint(i32 %in, i32 %in2) {
+; CHECK-LABEL: @unrelated_nondisjoint(
+; CHECK-NEXT: [[AND0:%.*]] = and i32 [[IN:%.*]], 3
+; CHECK-NEXT: [[TEMP:%.*]] = mul nuw nsw i32 [[AND0]], 72
+; CHECK-NEXT: [[AND1:%.*]] = and i32 [[IN]], 12
+; CHECK-NEXT: [[TEMP2:%.*]] = mul nuw nsw i32 [[AND1]], 72
+; CHECK-NEXT: [[TEMP3:%.*]] = or disjoint i32 [[IN2:%.*]], [[TEMP]]
+; CHECK-NEXT: [[OUT:%.*]] = or i32 [[TEMP3]], [[TEMP2]]
+; CHECK-NEXT: ret i32 [[OUT]]
+;
+ %and0 = and i32 %in, 3
+ %temp = mul nuw nsw i32 %and0, 72
+ %and1 = and i32 %in, 12
+ %temp2 = mul nuw nsw i32 %and1, 72
+ %temp3 = or disjoint i32 %in2, %temp
+ %out = or i32 %temp3, %temp2
+ ret i32 %out
+}
+
+define i32 @unrelated_nondisjoint1(i32 %in, i32 %in2) {
+; CHECK-LABEL: @unrelated_nondisjoint1(
+; CHECK-NEXT: [[AND0:%.*]] = and i32 [[IN:%.*]], 3
+; CHECK-NEXT: [[TEMP:%.*]] = mul nuw nsw i32 [[AND0]], 72
+; CHECK-NEXT: [[AND1:%.*]] = and i32 [[IN]], 12
+; CHECK-NEXT: [[TEMP2:%.*]] = mul nuw nsw i32 [[AND1]], 72
+; CHECK-NEXT: [[TEMP3:%.*]] = or i32 [[IN2:%.*]], [[TEMP]]
+; CHECK-NEXT: [[OUT:%.*]] = or disjoint i32 [[TEMP3]], [[TEMP2]]
+; CHECK-NEXT: ret i32 [[OUT]]
+;
+ %and0 = and i32 %in, 3
+ %temp = mul nuw nsw i32 %and0, 72
+ %and1 = and i32 %in, 12
+ %temp2 = mul nuw nsw i32 %and1, 72
+ %temp3 = or i32 %in2, %temp
+ %out = or disjoint i32 %temp3, %temp2
+ ret i32 %out
+}
+
+declare void @use(i32)
+
+define i32 @multi_use(i32 %in, i32 %in2) {
+; CHECK-LABEL: @multi_use(
+; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[IN:%.*]], 15
+; CHECK-NEXT: [[TMP2:%.*]] = mul nuw nsw i32 [[TMP1]], 72
+; CHECK-NEXT: [[OUT:%.*]] = or disjoint i32 [[TMP2]], [[IN2:%.*]]
+; CHECK-NEXT: call void @use(i32 [[OUT]])
+; CHECK-NEXT: ret i32 [[OUT]]
+;
+ %and0 = and i32 %in, 3
+ %temp = mul nuw nsw i32 %and0, 72
+ %and1 = and i32 %in, 12
+ %temp2 = mul nuw nsw i32 %and1, 72
+ %temp3 = or disjoint i32 %in2, %temp
+ %out = or disjoint i32 %temp3, %temp2
+ call void @use(i32 %out)
+ ret i32 %out
+}
+
+define i32 @multi_use1(i32 %in, i32 %in2) {
+; CHECK-LABEL: @multi_use1(
+; CHECK-NEXT: [[AND0:%.*]] = and i32 [[IN:%.*]], 3
+; CHECK-NEXT: [[TEMP:%.*]] = mul nuw nsw i32 [[AND0]], 72
+; CHECK-NEXT: [[AND1:%.*]] = and i32 [[IN]], 12
+; CHECK-NEXT: [[TEMP2:%.*]] = mul nuw nsw i32 [[AND1]], 72
+; CHECK-NEXT: [[TEMP3:%.*]] = or disjoint i32 [[IN2:%.*]], [[TEMP]]
+; CHECK-NEXT: [[OUT:%.*]] = or disjoint i32 [[TEMP3]], [[TEMP2]]
+; CHECK-NEXT: call void @use(i32 [[TEMP3]])
+; CHECK-NEXT: ret i32 [[OUT]]
+;
+ %and0 = and i32 %in, 3
+ %temp = mul nuw nsw i32 %and0, 72
+ %and1 = and i32 %in, 12
+ %temp2 = mul nuw nsw i32 %and1, 72
+ %temp3 = or disjoint i32 %in2, %temp
+ %out = or disjoint i32 %temp3, %temp2
+ call void @use(i32 %temp3)
+ ret i32 %out
+}
+
+define i32 @multi_use2(i32 %in, i32 %in2) {
+; CHECK-LABEL: @multi_use2(
+; CHECK-NEXT: [[AND0:%.*]] = and i32 [[IN:%.*]], 3
+; CHECK-NEXT: [[TEMP:%.*]] = mul nuw nsw i32 [[AND0]], 72
+; CHECK-NEXT: [[AND1:%.*]] = and i32 [[IN]], 12
+; CHECK-NEXT: [[TEMP2:%.*]] = mul nuw nsw i32 [[AND1]], 72
+; CHECK-NEXT: [[TEMP3:%.*]] = or disjoint i32 [[IN2:%.*]], [[TEMP]]
+; CHECK-NEXT: [[OUT:%.*]] = or disjoint i32 [[TEMP3]], [[TEMP2]]
+; CHECK-NEXT: call void @use(i32 [[TEMP3]])
+; CHECK-NEXT: ret i32 [[OUT]]
+;
+ %and0 = and i32 %in, 3
+ %temp = mul nuw nsw i32 %and0, 72
+ %and1 = and i32 %in, 12
+ %temp2 = mul nuw nsw i32 %and1, 72
+ %temp3 = or disjoint i32 %in2, %temp
+ %out = or disjoint i32 %temp3, %temp2
+ call void @use(i32 %temp3)
+ ret i32 %out
+}
+
+define i32 @multi_use3(i32 %in, i32 %in2) {
+; CHECK-LABEL: @multi_use3(
+; CHECK-NEXT: [[AND1:%.*]] = and i32 [[IN:%.*]], 12
+; CHECK-NEXT: [[TEMP2:%.*]] = mul nuw nsw i32 [[AND1]], 72
+; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[IN]], 15
+; CHECK-NEXT: [[TMP2:%.*]] = mul nuw nsw i32 [[TMP1]], 72
+; CHECK-NEXT: [[OUT:%.*]] = or disjoint i32 [[TMP2]], [[IN2:%.*]]
+; CHECK-NEXT: call void @use(i32 [[TEMP2]])
+; CHECK-NEXT: ret i32 [[OUT]]
+;
+ %and0 = and i32 %in, 3
+ %temp = mul nuw nsw i32 %and0, 72
+ %and1 = and i32 %in, 12
+ %temp2 = mul nuw nsw i32 %and1, 72
+ %temp3 = or disjoint i32 %in2, %temp
+ %out = or disjoint i32 %temp3, %temp2
+ call void @use(i32 %temp2)
+ ret i32 %out
+}
+
+define i32 @multi_use4(i32 %in, i32 %in2) {
+; CHECK-LABEL: @multi_use4(
+; CHECK-NEXT: [[AND0:%.*]] = and i32 [[IN:%.*]], 3
+; CHECK-NEXT: [[TEMP:%.*]] = mul nuw nsw i32 [[AND0]], 72
+; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[IN]], 15
+; CHECK-NEXT: [[TMP2:%.*]] = mul nuw nsw i32 [[TMP1]], 72
+; CHECK-NEXT: [[OUT:%.*]] = or disjoint i32 [[TMP2]], [[IN2:%.*]]
+; CHECK-NEXT: call void @use(i32 [[TEMP]])
+; CHECK-NEXT: ret i32 [[OUT]]
+;
+ %and0 = and i32 %in, 3
+ %temp = mul nuw nsw i32 %and0, 72
+ %and1 = and i32 %in, 12
+ %temp2 = mul nuw nsw i32 %and1, 72
+ %temp3 = or disjoint i32 %in2, %temp
+ %out = or disjoint i32 %temp3, %temp2
+ call void @use(i32 %temp)
+ ret i32 %out
+}
+
+define i32 @multi_use5(i32 %in, i32 %in2) {
+; CHECK-LABEL: @multi_use5(
+; CHECK-NEXT: [[AND1:%.*]] = and i32 [[IN:%.*]], 12
+; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[IN]], 15
+; CHECK-NEXT: [[TMP2:%.*]] = mul nuw nsw i32 [[TMP1]], 72
+; CHECK-NEXT: [[OUT:%.*]] = or disjoint i32 [[TMP2]], [[IN2:%.*]]
+; CHECK-NEXT: call void @use(i32 [[AND1]])
+; CHECK-NEXT: ret i32 [[OUT]]
+;
+ %and0 = and i32 %in, 3
+ %temp = mul nuw nsw i32 %and0, 72
+ %and1 = and i32 %in, 12
+ %temp2 = mul nuw nsw i32 %and1, 72
+ %temp3 = or disjoint i32 %in2, %temp
+ %out = or disjoint i32 %temp3, %temp2
+ call void @use(i32 %and1)
+ ret i32 %out
+}
+
+define i32 @multi_use6(i32 %in, i32 %in2) {
+; CHECK-LABEL: @multi_use6(
+; CHECK-NEXT: [[AND0:%.*]] = and i32 [[IN:%.*]], 3
+; CHECK-NEXT: [[TEMP:%.*]] = mul nuw nsw i32 [[AND0]], 72
+; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[IN]], 15
+; CHECK-NEXT: [[TMP2:%.*]] = mul nuw nsw i32 [[TMP1]], 72
+; CHECK-NEXT: [[OUT:%.*]] = or disjoint i32 [[TMP2]], [[IN2:%.*]]
+; CHECK-NEXT: call void @use(i32 [[TEMP]])
+; CHECK-NEXT: ret i32 [[OUT]]
+;
+ %and0 = and i32 %in, 3
+ %temp = mul nuw nsw i32 %and0, 72
+ %and1 = and i32 %in, 12
+ %temp2 = mul nuw nsw i32 %and1, 72
+ %temp3 = or disjoint i32 %in2, %temp
+ %out = or disjoint i32 %temp3, %temp2
+ call void @use(i32 %temp)
+ ret i32 %out
+}
+
+define i32 @multi_use7(i32 %in, i32 %in2) {
+; CHECK-LABEL: @multi_use7(
+; CHECK-NEXT: [[AND0:%.*]] = and i32 [[IN:%.*]], 3
+; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[IN]], 15
+; CHECK-NEXT: [[TMP2:%.*]] = mul nuw nsw i32 [[TMP1]], 72
+; CHECK-NEXT: [[OUT:%.*]] = or disjoint i32 [[TMP2]], [[IN2:%.*]]
+; CHECK-NEXT: call void @use(i32 [[AND0]])
+; CHECK-NEXT: ret i32 [[OUT]]
+;
+ %and0 = and i32 %in, 3
+ %temp = mul nuw nsw i32 %and0, 72
+ %and1 = and i32 %in, 12
+ %temp2 = mul nuw nsw i32 %and1, 72
+ %temp3 = or disjoint i32 %in2, %temp
+ %out = or disjoint i32 %temp3, %temp2
+ call void @use(i32 %and0)
+ ret i32 %out
+}
+
+define i32 @no_chain(i32 %in, i32 %in2, i32 %in3) {
+; CHECK-LABEL: @no_chain(
+; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[IN:%.*]], 3
+; CHECK-NEXT: [[TEMP:%.*]] = mul nuw nsw i32 [[TMP1]], 72
+; CHECK-NEXT: [[TEMP3:%.*]] = or disjoint i32 [[TEMP]], [[IN3:%.*]]
+; CHECK-NEXT: [[OUT:%.*]] = or disjoint i32 [[TEMP3]], [[IN2:%.*]]
+; CHECK-NEXT: ret i32 [[OUT]]
+;
+ %and0 = and i32 %in, 3
+ %temp = mul nuw nsw i32 %and0, 72
+ %temp3 = or disjoint i32 %temp, %in3
+ %out = or disjoint i32 %temp3, %in2
+ ret i32 %out
+}
+
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
; CONSTSPLAT: {{.*}}
; CONSTVEC: {{.*}}
More information about the llvm-commits
mailing list