-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[InstCombine] Fold (X & C1) | C2
into X & (C1 | C2)
iff (X & C2) == C2
#76470
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-llvm-transforms Author: Yingwei Zheng (dtcxzyw) ChangesAlive2: https://alive2.llvm.org/ce/z/VKJYaS Full diff: https://github.com/llvm/llvm-project/pull/76470.diff 2 Files Affected:
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index 63b1e0f64a8824..6958418ba7f3fa 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -3872,6 +3872,14 @@ Instruction *InstCombinerImpl::visitOr(BinaryOperator &I) {
}
}
+ // (X & C1) | C2 -> X & (C1 | C2) iff (X & C2) == C2
+ if (match(Op0, m_OneUse(m_And(m_Value(X), m_APInt(C1)))) &&
+ match(Op1, m_APInt(C2))) {
+ KnownBits KnownX = computeKnownBits(X, /*Depth*/ 0, &I);
+ if ((KnownX.One & *C2) == *C2)
+ return BinaryOperator::CreateAnd(X, ConstantInt::get(Ty, *C1 | *C2));
+ }
+
return nullptr;
}
diff --git a/llvm/test/Transforms/InstCombine/or.ll b/llvm/test/Transforms/InstCombine/or.ll
index 805546099398b4..010ef239744188 100644
--- a/llvm/test/Transforms/InstCombine/or.ll
+++ b/llvm/test/Transforms/InstCombine/or.ll
@@ -1636,3 +1636,98 @@ define i32 @assoc_cast_assoc_disjoint(i16 %x) {
%c = or disjoint i32 %b, 65536
ret i32 %c
}
+
+; (X & C1) | C2 -> X & (C1 | C2) iff (X & C2) == C2
+define i32 @test_or_and_disjoint(i32 %a) {
+; CHECK-LABEL: @test_or_and_disjoint(
+; CHECK-NEXT: [[A0:%.*]] = and i32 [[A:%.*]], 24
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A0]], 8
+; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+; CHECK: if.then:
+; CHECK-NEXT: [[A2:%.*]] = and i32 [[A]], 15
+; CHECK-NEXT: ret i32 [[A2]]
+; CHECK: if.else:
+; CHECK-NEXT: ret i32 0
+;
+ %a0 = and i32 %a, 24
+ %cmp = icmp eq i32 %a0, 8
+ br i1 %cmp, label %if.then, label %if.else
+if.then:
+ %a1 = and i32 %a, 7
+ %a2 = or i32 %a1, 8
+ ret i32 %a2
+if.else:
+ ret i32 0
+}
+
+define i32 @test_or_and_mixed(i32 %a) {
+; CHECK-LABEL: @test_or_and_mixed(
+; CHECK-NEXT: [[A0:%.*]] = and i32 [[A:%.*]], 27
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A0]], 11
+; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+; CHECK: if.then:
+; CHECK-NEXT: [[A2:%.*]] = and i32 [[A]], 15
+; CHECK-NEXT: ret i32 [[A2]]
+; CHECK: if.else:
+; CHECK-NEXT: ret i32 0
+;
+ %a0 = and i32 %a, 27
+ %cmp = icmp eq i32 %a0, 11
+ br i1 %cmp, label %if.then, label %if.else
+if.then:
+ %a1 = and i32 %a, 7
+ %a2 = or i32 %a1, 11
+ ret i32 %a2
+if.else:
+ ret i32 0
+}
+
+; Negative tests
+
+define i32 @test_or_and_disjoint_fail(i32 %a) {
+; CHECK-LABEL: @test_or_and_disjoint_fail(
+; CHECK-NEXT: [[A0:%.*]] = and i32 [[A:%.*]], 24
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A0]], 16
+; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+; CHECK: if.then:
+; CHECK-NEXT: [[A1:%.*]] = and i32 [[A]], 7
+; CHECK-NEXT: [[A2:%.*]] = or disjoint i32 [[A1]], 8
+; CHECK-NEXT: ret i32 [[A2]]
+; CHECK: if.else:
+; CHECK-NEXT: ret i32 0
+;
+ %a0 = and i32 %a, 24
+ %cmp = icmp eq i32 %a0, 16
+ br i1 %cmp, label %if.then, label %if.else
+if.then:
+ %a1 = and i32 %a, 7
+ %a2 = or i32 %a1, 8
+ ret i32 %a2
+if.else:
+ ret i32 0
+}
+
+define i32 @test_or_and_disjoint_multiuse(i32 %a) {
+; CHECK-LABEL: @test_or_and_disjoint_multiuse(
+; CHECK-NEXT: [[A0:%.*]] = and i32 [[A:%.*]], 24
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A0]], 8
+; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+; CHECK: if.then:
+; CHECK-NEXT: [[A1:%.*]] = and i32 [[A]], 7
+; CHECK-NEXT: call void @use(i32 [[A1]])
+; CHECK-NEXT: [[A2:%.*]] = or disjoint i32 [[A1]], 8
+; CHECK-NEXT: ret i32 [[A2]]
+; CHECK: if.else:
+; CHECK-NEXT: ret i32 0
+;
+ %a0 = and i32 %a, 24
+ %cmp = icmp eq i32 %a0, 8
+ br i1 %cmp, label %if.then, label %if.else
+if.then:
+ %a1 = and i32 %a, 7
+ call void @use(i32 %a1)
+ %a2 = or i32 %a1, 8
+ ret i32 %a2
+if.else:
+ ret i32 0
+}
|
Does this have compile-time impact? |
Compile-time impact: http://llvm-compile-time-tracker.com/compare.php?from=38c9390b59c4d2b9181614d6a909887497d3692f&to=b96af27a97818b41a127113f4d4313aa704b2469&stat=instructions:u
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Alive2: https://alive2.llvm.org/ce/z/VKJYaS