-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
[InstCombine] Remove redundant alignment assumptions. #123348
base: main
Are you sure you want to change the base?
Conversation
@llvm/pr-subscribers-llvm-transforms Author: Florian Hahn (fhahn) ChangesUse known bits to remove redundant alignment assumptions. Libc++ now adds alignment assumptions for std::vector::begin() and std::vector::end(), so I expect we will see quite a bit more assumptions in C++ [1]. Try to clean up some redundant ones to start with. [1] #108961 Full diff: https://github.com/llvm/llvm-project/pull/123348.diff 2 Files Affected:
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index 842881156dc67f..ab628e94235913 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -3199,12 +3199,13 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
// TODO: apply range metadata for range check patterns?
}
- // Separate storage assumptions apply to the underlying allocations, not any
- // particular pointer within them. When evaluating the hints for AA purposes
- // we getUnderlyingObject them; by precomputing the answers here we can
- // avoid having to do so repeatedly there.
for (unsigned Idx = 0; Idx < II->getNumOperandBundles(); Idx++) {
OperandBundleUse OBU = II->getOperandBundleAt(Idx);
+
+ // Separate storage assumptions apply to the underlying allocations, not
+ // any particular pointer within them. When evaluating the hints for AA
+ // purposes we getUnderlyingObject them; by precomputing the answers here
+ // we can avoid having to do so repeatedly there.
if (OBU.getTagName() == "separate_storage") {
assert(OBU.Inputs.size() == 2);
auto MaybeSimplifyHint = [&](const Use &U) {
@@ -3218,6 +3219,28 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
MaybeSimplifyHint(OBU.Inputs[0]);
MaybeSimplifyHint(OBU.Inputs[1]);
}
+
+ // Try to remove redundant alignment assumptions.
+ if (OBU.getTagName() == "align" && OBU.Inputs.size() == 2) {
+ RetainedKnowledge RK = getKnowledgeFromBundle(
+ *cast<AssumeInst>(II), II->bundle_op_info_begin()[Idx]);
+ if (!RK || RK.AttrKind != Attribute::Alignment ||
+ !isPowerOf2_64(RK.ArgValue))
+ continue;
+
+ // Try to get the instruction before the assumption to use as context.
+ Instruction *CtxI = nullptr;
+ if (CtxI && II->getParent()->begin() != II->getIterator())
+ CtxI = II->getPrevNode();
+
+ auto Known = computeKnownBits(RK.WasOn, 1, CtxI);
+ unsigned KnownAlign = 1 << Known.countMinTrailingZeros();
+ if (KnownAlign < RK.ArgValue)
+ continue;
+
+ auto *New = CallBase::removeOperandBundle(II, OBU.getTagID());
+ return New;
+ }
}
// Convert nonnull assume like:
diff --git a/llvm/test/Transforms/InstCombine/assume-align.ll b/llvm/test/Transforms/InstCombine/assume-align.ll
index f0e02574330861..962ad4f792a0d1 100644
--- a/llvm/test/Transforms/InstCombine/assume-align.ll
+++ b/llvm/test/Transforms/InstCombine/assume-align.ll
@@ -175,7 +175,6 @@ define ptr @dont_fold_assume_align_zero_of_loaded_pointer_into_align_metadata(pt
define ptr @redundant_assume_align_1(ptr %p) {
; CHECK-LABEL: @redundant_assume_align_1(
; CHECK-NEXT: [[P2:%.*]] = load ptr, ptr [[P:%.*]], align 8
-; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[P2]], i32 1) ]
; CHECK-NEXT: call void @foo(ptr [[P2]])
; CHECK-NEXT: ret ptr [[P2]]
;
@@ -189,7 +188,6 @@ define ptr @redundant_assume_align_1(ptr %p) {
define ptr @redundant_assume_align_8_via_align_metadata(ptr %p) {
; CHECK-LABEL: @redundant_assume_align_8_via_align_metadata(
; CHECK-NEXT: [[P2:%.*]] = load ptr, ptr [[P:%.*]], align 8, !align [[META0:![0-9]+]]
-; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[P2]], i32 8) ]
; CHECK-NEXT: call void @foo(ptr [[P2]])
; CHECK-NEXT: ret ptr [[P2]]
;
@@ -214,8 +212,7 @@ define ptr @assume_align_16_via_align_metadata(ptr %p) {
define ptr @redundant_assume_align_8_via_align_attribute(ptr align 8 %p) {
; CHECK-LABEL: @redundant_assume_align_8_via_align_attribute(
-; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[P:%.*]], i32 8) ]
-; CHECK-NEXT: call void @foo(ptr [[P]])
+; CHECK-NEXT: call void @foo(ptr [[P:%.*]])
; CHECK-NEXT: ret ptr [[P]]
;
call void @llvm.assume(i1 true) [ "align"(ptr %p, i32 8) ]
|
Can this ever delete unrecoverable information? |
// Try to get the instruction before the assumption to use as context. | ||
Instruction *CtxI = nullptr; | ||
if (CtxI && II->getParent()->begin() != II->getIterator()) | ||
CtxI = II->getPrevNode(); |
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.
Hm, I don't get how this works. Don't we scan forward across guaranteed-to-transfer instructions and should find the assume that way? Esp. as we disable the ephemeral value handling for these assumptions.
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.
At the moment, assumes aren't used by IC's computeKnownBits in general because it doesn't pass through AssumptionCache (probably good to improve separately), so this here was intended to just help with using other context-sensitive info.
I've removed it for now.
CtxI = II->getPrevNode(); | ||
|
||
auto Known = computeKnownBits(RK.WasOn, 1, CtxI); | ||
unsigned KnownAlign = 1 << Known.countMinTrailingZeros(); |
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.
Can overflow?
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.
Yep, should be fixed in the latest version, although I am not sure how to create a test case where it would actually overflow
18fce21
to
be0e9ee
Compare
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.
Can this ever delete unrecoverable information?
The main case where we can lose info is if we derive the alignment from an argument and later inline the function; then the align arg attribute will be gone. Updated to only do this for pointers not derived from an argument.
Without support for GEP recurrences, we would also lose information in some cases when using the alignment of a call result, but that should be fixed with #123518
https://github.com/dtcxzyw/llvm-opt-benchmark/pull/1984/files shows the impact with with both #123518 and this PR
CtxI = II->getPrevNode(); | ||
|
||
auto Known = computeKnownBits(RK.WasOn, 1, CtxI); | ||
unsigned KnownAlign = 1 << Known.countMinTrailingZeros(); |
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.
Yep, should be fixed in the latest version, although I am not sure how to create a test case where it would actually overflow
Hmm, maybe we should re-emit alignment assumptions during inlining? |
Eventually yes/maybe. The problem is that adding assumptions at the moment can lead to worse results, so before emitting more assumptions I think we should make sure we can clean up ones that don't add any value. This patch is a small step towards getting better at cleaning things up. @dtcxzyw's https://github.com/dtcxzyw/llvm-opt-benchmark/ is super helpful at surfacing cases where assumptions (or dropping them) causes issues. The current patch together with #123518 is a first step that shouldn't cause any regressions. |
2100fea
to
36756d6
Compare
Use known bits to remove redundant alignment assumptions.
Libc++ now adds alignment assumptions for std::vector::begin() and std::vector::end(), so I expect we will see quite a bit more assumptions in C++ [1]. Try to clean up some redundant ones to start with.
[1] #108961