-
Notifications
You must be signed in to change notification settings - Fork 15.4k
[GlobalOpt] Add range metadata to loads from constant global variables #127695
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
base: main
Are you sure you want to change the base?
Conversation
|
@llvm/pr-subscribers-llvm-transforms Author: None (Ralender) ChangesThis Change fixes #125003 I put the process of extracting range metadata from global in GlobalOpt because it is thematically linked and GlobalOpt is only 2 times in the standard O3 pipeline. Full diff: https://github.com/llvm/llvm-project/pull/127695.diff 2 Files Affected:
|
nikic
left a comment
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.
Looks like a reasonable idea.
|
See also the fold at llvm-project/llvm/lib/Transforms/AggressiveInstCombine/AggressiveInstCombine.cpp Lines 829 to 916 in db5bc8e
|
The only thing I dont understand Why it does llvm-project/llvm/lib/Transforms/AggressiveInstCombine/AggressiveInstCombine.cpp Lines 844 to 846 in db5bc8e
|
c2123a2 to
ad4e92e
Compare
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
ad4e92e to
6ffd9ae
Compare
|
I added the logic similar to the after having wrote the code, maybe the process to find closed-forms of the Stride and Offset with alignment are too complicated and error prone. but this should be able to handle a wide variety of GEPs. |
|
ping |
|
@nikic ping |
6ffd9ae to
eccfa9f
Compare
|
rebased |
dtcxzyw
left a comment
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 you rebase the branch again? Then I can run some external tests for this patch.
| if (!isa_and_nonnull<ConstantInt>(Cst)) | ||
| // Lambda captures of a struct binding is only available starting | ||
| // in C++20, so we skip to the next element with goto | ||
| goto NextGroup; | ||
|
|
||
| // MD_range is order agnostics | ||
| SMin = APIntOps::smin(SMin, Cst->getUniqueInteger()); | ||
| SMax = APIntOps::smax(SMax, Cst->getUniqueInteger()); |
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.
| if (!isa_and_nonnull<ConstantInt>(Cst)) | |
| // Lambda captures of a struct binding is only available starting | |
| // in C++20, so we skip to the next element with goto | |
| goto NextGroup; | |
| // MD_range is order agnostics | |
| SMin = APIntOps::smin(SMin, Cst->getUniqueInteger()); | |
| SMax = APIntOps::smax(SMax, Cst->getUniqueInteger()); | |
| if (auto *CI = dyn_cast<ConstantInt>(Cst)) { | |
| // MD_range is order agnostics | |
| SMin = APIntOps::smin(SMin, CI->getValue()); | |
| SMax = APIntOps::smax(SMax, CI->getValue()); | |
| } | |
| else { | |
| // Lambda captures of a struct binding is only available starting | |
| // in C++20, so we skip to the next element with goto | |
| goto NextGroup; | |
| } |
| ret i32 %0 | ||
| } | ||
|
|
||
| ; This could be supported also be supported, but for now it not. |
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.
| ; This could be supported also be supported, but for now it not. | |
| ; This could also be supported, but for now it is not. |
| } | ||
|
|
||
| ; This could be supported also be supported, but for now it not. | ||
| define dso_local signext i8 @multi_dimentional0(i8 zeroext %0, i8 zeroext %1) local_unnamed_addr #0 { |
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.
| define dso_local signext i8 @multi_dimentional0(i8 zeroext %0, i8 zeroext %1) local_unnamed_addr #0 { | |
| define i8 @multi_dimentional0(i8 zeroext %0, i8 zeroext %1) { |
| Changed = true; | ||
| if (SMin == SMax) { | ||
| for (LoadInst *LI : Loads) | ||
| LI->replaceAllUsesWith(ConstantInt::get(AP.Ty, SMin)); |
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.
Missing tests for this case.
| LI->replaceAllUsesWith(ConstantInt::get(AP.Ty, SMin)); | ||
| } else { | ||
| // The Range is allowed to wrap | ||
| MDNode *RNode = MDHelper.createRange(SMin, SMax + 1); |
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.
We should not add the range metadata for [INT_MIN, INT_MAX]. It will assert since we don't know if it represents a full range or an empty range.
llvm-project/llvm/lib/IR/ConstantRange.cpp
Lines 2268 to 2288 in 2ba5e0a
| ConstantRange llvm::getConstantRangeFromMetadata(const MDNode &Ranges) { | |
| const unsigned NumRanges = Ranges.getNumOperands() / 2; | |
| assert(NumRanges >= 1 && "Must have at least one range!"); | |
| assert(Ranges.getNumOperands() % 2 == 0 && "Must be a sequence of pairs"); | |
| auto *FirstLow = mdconst::extract<ConstantInt>(Ranges.getOperand(0)); | |
| auto *FirstHigh = mdconst::extract<ConstantInt>(Ranges.getOperand(1)); | |
| ConstantRange CR(FirstLow->getValue(), FirstHigh->getValue()); | |
| for (unsigned i = 1; i < NumRanges; ++i) { | |
| auto *Low = mdconst::extract<ConstantInt>(Ranges.getOperand(2 * i + 0)); | |
| auto *High = mdconst::extract<ConstantInt>(Ranges.getOperand(2 * i + 1)); | |
| // Note: unionWith will potentially create a range that contains values not | |
| // contained in any of the original N ranges. | |
| CR = CR.unionWith(ConstantRange(Low->getValue(), High->getValue())); | |
| } | |
| return CR; | |
| } |
llvm-project/llvm/lib/IR/ConstantRange.cpp
Lines 56 to 57 in 2ba5e0a
| assert((Lower != Upper || (Lower.isMaxValue() || Lower.isMinValue())) && | |
| "Lower == Upper, but they aren't min or max value!"); |
|
|
||
| // Commented out because I dont understand why we would need this | ||
| // But it was part of getStrideAndModOffsetOfGEP | ||
| // // Only keep a power of two factor for non-inbounds |
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.
Related patch: https://reviews.llvm.org/D146622
cc @khei4 @nikic
| } | ||
| } | ||
|
|
||
| for (auto [AP, Loads] : LoadsByAccess) { |
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.
| for (auto [AP, Loads] : LoadsByAccess) { | |
| for (auto &[AP, Loads] : LoadsByAccess) { |
| if (!GEP->collectOffset(DL, IndexBW, VarOffsets, Curr.Offset)) | ||
| continue; | ||
|
|
||
| for (auto [V, Scale] : VarOffsets) { |
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.
| for (auto [V, Scale] : VarOffsets) { | |
| for (auto &[V, Scale] : VarOffsets) { |
This Change fixes #125003
I put the process of extracting range metadata from global in GlobalOpt because it is thematically linked and GlobalOpt is only 2 times in the standard O3 pipeline.
Also the logic only act on linear 1D arrays when all access to one global use the same type. but these resitriction could be lifted if there is interest.