-
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] Fold align assume into load's !align metadata if possible. #108958
base: main
Are you sure you want to change the base?
Conversation
@llvm/pr-subscribers-llvm-transforms Author: Florian Hahn (fhahn) ChangesIf an alignment assumption is valid in the context of a corresponding load of the pointer the assumption applies to, the assumption can be replaced !align metadata on the load. The benefits of folding it into !align are that existing code makes better use of !align and it allows removing the now-redundant call instructions. Full diff: https://github.com/llvm/llvm-project/pull/108958.diff 2 Files Affected:
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index 61011d55227e7b..596de10e20b6de 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -3076,12 +3076,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) {
@@ -3095,6 +3096,22 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
MaybeSimplifyHint(OBU.Inputs[0]);
MaybeSimplifyHint(OBU.Inputs[1]);
}
+
+ // Try to fold alignment assumption into a load's !align metadata, if the assumption is valid in the load's context.
+ if (OBU.getTagName() == "align" && OBU.Inputs.size() == 2) {
+ auto *LI = dyn_cast<LoadInst>(OBU.Inputs[0]);
+ if (!LI || !isValidAssumeForContext(II, LI, &DT, /*AllowEphemerals=*/true))
+ continue;
+ auto *Align = cast<ConstantInt>(OBU.Inputs[1]);
+ if (!isPowerOf2_64(Align->getZExtValue()))
+ continue;
+ LI->setMetadata(LLVMContext::MD_align,
+ MDNode::get(II->getContext(),
+ ValueAsMetadata::getConstant(
+ Align)));
+ 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 2b8ca5d25fd1a8..65256377696a59 100644
--- a/llvm/test/Transforms/InstCombine/assume-align.ll
+++ b/llvm/test/Transforms/InstCombine/assume-align.ll
@@ -123,11 +123,9 @@ define i8 @assume_align_non_pow2(ptr %p) {
ret i8 %v
}
-; TODO: Can fold alignment assumption into !align metadata on load.
define ptr @fold_assume_align_pow2_of_loaded_pointer_into_align_metadata(ptr %p) {
; CHECK-LABEL: @fold_assume_align_pow2_of_loaded_pointer_into_align_metadata(
-; CHECK-NEXT: [[P2:%.*]] = load ptr, ptr [[P:%.*]], align 8
-; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[P2]], i64 8) ]
+; CHECK-NEXT: [[P2:%.*]] = load ptr, ptr [[P:%.*]], align 8, !align [[META0:![0-9]+]]
; CHECK-NEXT: ret ptr [[P2]]
;
%p2 = load ptr, ptr %p
@@ -171,3 +169,6 @@ define ptr @dont_fold_assume_align_zero_of_loaded_pointer_into_align_metadata(pt
call void @llvm.assume(i1 true) [ "align"(ptr %p2, i64 0) ]
ret ptr %p2
}
+;.
+; CHECK: [[META0]] = !{i64 8}
+;.
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
Missing information about begin and end pointers of std::vector can lead to missed optimizations in LLVM. See llvm#101372 for a discussion of missed range check optimizations in hardened mode. Once llvm#108958 lands, the created `llvm.assume` calls for the alignment should be folded into the `load` instructions, resulting in no extra instructions after InstCombine.
auto *Align = cast<ConstantInt>(OBU.Inputs[1]); | ||
if (!isPowerOf2_64(Align->getZExtValue())) |
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.
auto *Align = cast<ConstantInt>(OBU.Inputs[1]); | |
if (!isPowerOf2_64(Align->getZExtValue())) | |
auto *Align = dyn_cast<ConstantInt>(OBU.Inputs[1]); | |
if (!Align || !isPowerOf2_64(Align->getZExtValue())) |
While attributes expect constant arguments, assume operand bundles may be provided a dynamic value, for example:
call void @llvm.assume(i1 true) ["align"(ptr %val, i32 %align)]
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 we use getKnowledgeFromBundle
here?
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.
Yes thanks! Didn't check that they also allow dynamic values.
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.
(also added a check of the type size + test)
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 we use getKnowledgeFromBundle here?
Missed this earlier, updated now, thanks!
Based on https://github.com/dtcxzyw/llvm-opt-benchmark/pull/1320/files it looks like we end up losing the alignment information in ~most cases? Presumably because SROA later comes along and removes the load. Note that for the existing non-null handling, SROA will actually rematerialize the nonnull assumption. But I'm reasonably confident that doing that for |
continue; | ||
LI->setMetadata( | ||
LLVMContext::MD_align, | ||
MDNode::get(II->getContext(), ValueAsMetadata::getConstant(Align))); |
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.
Should also add noundef to preserve the fact this is IUB.
PhaseOrdering reproducer:
Before:
After:
|
Ah that is an unfortunate! For the particular case @dtcxzyw shared, looks like the issue is Maybe for that case it would be sufficient to have early-cse re-materialize the assumption when CSE'ing an instruction with !align metadata that cannot be preserved. |
(other alternative would be to just keep the assumptions, but I was hoping this patch would help to avoid introducing too many new instructions when doing something like #108961) |
Agree. Removing assumptions reduces compilation time :)
|
2de8174
to
a7ad32d
Compare
@dtcxzyw updated this PR to include a change to |
See dtcxzyw/llvm-opt-benchmark#1312. You can request a new run yourself :) |
New results show about what I'd expect. Improvements for C++ which doesn't use |
Yep, updating the patch to avoid adding assume() if the new pointer already has !align |
If an alignment assumption is valid in the context of a corresponding load of the pointer the assumption applies to, the assumption can be replaced !align metadata on the load. The benefits of folding it into !align are that existing code makes better use of !align and it allows removing the now-redundant call instructions.
a7ad32d
to
ca75fc2
Compare
|
||
// Try to fold alignment assumption into a load's !align metadata, if the | ||
// assumption is valid in the load's context. | ||
if (OBU.getTagName() == "align" && OBU.Inputs.size() == 2) { |
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.
Is there a reason to only use the alignment assumption and not just add support for this in computeKnownBits and use that?
Missing information about begin and end pointers of std::vector can lead to missed optimizations in LLVM. See llvm#101372 for a discussion of missed range check optimizations in hardened mode. Once llvm#108958 lands, the created `llvm.assume` calls for the alignment should be folded into the `load` instructions, resulting in no extra instructions after InstCombine.
#108961) Missing information about begin and end pointers of std::vector can lead to missed optimizations in LLVM. This patch adds alignment assumptions at the point where the begin and end pointers are loaded. If the pointers would not have the same alignment, end might never get hit when incrementing begin. See #101372 for a discussion of missed range check optimizations in hardened mode. Once #108958 lands, the created `llvm.assume` calls for the alignment should be folded into the `load` instructions, resulting in no extra instructions after InstCombine. Co-authored-by: Louis Dionne <[email protected]>
…s of vector. (#108961) Missing information about begin and end pointers of std::vector can lead to missed optimizations in LLVM. This patch adds alignment assumptions at the point where the begin and end pointers are loaded. If the pointers would not have the same alignment, end might never get hit when incrementing begin. See llvm/llvm-project#101372 for a discussion of missed range check optimizations in hardened mode. Once llvm/llvm-project#108958 lands, the created `llvm.assume` calls for the alignment should be folded into the `load` instructions, resulting in no extra instructions after InstCombine. Co-authored-by: Louis Dionne <[email protected]>
llvm#108961) Missing information about begin and end pointers of std::vector can lead to missed optimizations in LLVM. This patch adds alignment assumptions at the point where the begin and end pointers are loaded. If the pointers would not have the same alignment, end might never get hit when incrementing begin. See llvm#101372 for a discussion of missed range check optimizations in hardened mode. Once llvm#108958 lands, the created `llvm.assume` calls for the alignment should be folded into the `load` instructions, resulting in no extra instructions after InstCombine. Co-authored-by: Louis Dionne <[email protected]>
If an alignment assumption is valid in the context of a corresponding load of the pointer the assumption applies to, the assumption can be replaced !align metadata on the load.
The benefits of folding it into !align are that existing code makes better use of !align and it allows removing the now-redundant call instructions.