19
19
#include " llvm/Analysis/ConstraintSystem.h"
20
20
#include " llvm/Analysis/GlobalsModRef.h"
21
21
#include " llvm/Analysis/LoopInfo.h"
22
+ #include " llvm/Analysis/MemoryBuiltins.h"
22
23
#include " llvm/Analysis/OptimizationRemarkEmitter.h"
23
24
#include " llvm/Analysis/ScalarEvolution.h"
24
25
#include " llvm/Analysis/ScalarEvolutionExpressions.h"
26
+ #include " llvm/Analysis/TargetLibraryInfo.h"
25
27
#include " llvm/Analysis/ValueTracking.h"
26
28
#include " llvm/IR/DataLayout.h"
27
29
#include " llvm/IR/DebugInfo.h"
@@ -170,10 +172,12 @@ struct State {
170
172
DominatorTree &DT;
171
173
LoopInfo &LI;
172
174
ScalarEvolution &SE;
175
+ TargetLibraryInfo &TLI;
173
176
SmallVector<FactOrCheck, 64 > WorkList;
174
177
175
- State (DominatorTree &DT, LoopInfo &LI, ScalarEvolution &SE)
176
- : DT(DT), LI(LI), SE(SE) {}
178
+ State (DominatorTree &DT, LoopInfo &LI, ScalarEvolution &SE,
179
+ TargetLibraryInfo &TLI)
180
+ : DT(DT), LI(LI), SE(SE), TLI(TLI) {}
177
181
178
182
// / Process block \p BB and add known facts to work-list.
179
183
void addInfoFor (BasicBlock &BB);
@@ -1109,10 +1113,50 @@ void State::addInfoForInductions(BasicBlock &BB) {
1109
1113
}
1110
1114
}
1111
1115
1116
+ static bool getConstraintFromMemoryAccess (GetElementPtrInst &GEP,
1117
+ uint64_t AccessSize,
1118
+ CmpPredicate &Pred, Value *&A,
1119
+ Value *&B, const DataLayout &DL,
1120
+ const TargetLibraryInfo &TLI) {
1121
+ auto Offset = collectOffsets (cast<GEPOperator>(GEP), DL);
1122
+ if (!Offset.NW .hasNoUnsignedWrap ())
1123
+ return false ;
1124
+
1125
+ if (Offset.VariableOffsets .size () != 1 )
1126
+ return false ;
1127
+
1128
+ ObjectSizeOpts Opts;
1129
+ // Workaround for gep inbounds, ptr null, idx.
1130
+ Opts.NullIsUnknownSize = true ;
1131
+ // Be conservative since we are not clear on whether an out of bounds access
1132
+ // to the padding is UB or not.
1133
+ Opts.RoundToAlign = true ;
1134
+ std::optional<TypeSize> Size =
1135
+ getBaseObjectSize (Offset.BasePtr , DL, &TLI, Opts);
1136
+ if (!Size || Size->isScalable ())
1137
+ return false ;
1138
+
1139
+ // Index * Scale + ConstOffset + AccessSize <= AllocSize
1140
+ // With nuw flag, we know that the index addition doesn't have unsigned wrap.
1141
+ // If (AllocSize - (ConstOffset + AccessSize)) wraps around, there is no valid
1142
+ // value for Index.
1143
+ uint64_t BitWidth = Offset.ConstantOffset .getBitWidth ();
1144
+ auto &[Index, Scale] = Offset.VariableOffsets .front ();
1145
+ APInt MaxIndex = (APInt (BitWidth, Size->getFixedValue () - AccessSize,
1146
+ /* isSigned=*/ false , /* implicitTrunc=*/ true ) -
1147
+ Offset.ConstantOffset )
1148
+ .udiv (Scale);
1149
+ Pred = ICmpInst::ICMP_ULE;
1150
+ A = Index;
1151
+ B = ConstantInt::get (Index->getType (), MaxIndex);
1152
+ return true ;
1153
+ }
1154
+
1112
1155
void State::addInfoFor (BasicBlock &BB) {
1113
1156
addInfoForInductions (BB);
1157
+ auto &DL = BB.getDataLayout ();
1114
1158
1115
- // True as long as long as the current instruction is guaranteed to execute.
1159
+ // True as long as the current instruction is guaranteed to execute.
1116
1160
bool GuaranteedToExecute = true ;
1117
1161
// Queue conditions and assumes.
1118
1162
for (Instruction &I : BB) {
@@ -1127,6 +1171,38 @@ void State::addInfoFor(BasicBlock &BB) {
1127
1171
continue ;
1128
1172
}
1129
1173
1174
+ auto AddFactFromMemoryAccess = [&](Value *Ptr, Type *AccessType) {
1175
+ auto *GEP = dyn_cast<GetElementPtrInst>(Ptr);
1176
+ if (!GEP)
1177
+ return ;
1178
+ TypeSize AccessSize = DL.getTypeStoreSize (AccessType);
1179
+ if (!AccessSize.isFixed ())
1180
+ return ;
1181
+ if (GuaranteedToExecute) {
1182
+ CmpPredicate Pred;
1183
+ Value *A, *B;
1184
+ if (getConstraintFromMemoryAccess (*GEP, AccessSize.getFixedValue (),
1185
+ Pred, A, B, DL, TLI)) {
1186
+ // The memory access is guaranteed to execute when BB is entered,
1187
+ // hence the constraint holds on entry to BB.
1188
+ WorkList.emplace_back (FactOrCheck::getConditionFact (
1189
+ DT.getNode (I.getParent ()), Pred, A, B));
1190
+ }
1191
+ } else {
1192
+ WorkList.emplace_back (
1193
+ FactOrCheck::getInstFact (DT.getNode (I.getParent ()), &I));
1194
+ }
1195
+ };
1196
+
1197
+ if (auto *LI = dyn_cast<LoadInst>(&I)) {
1198
+ if (!LI->isVolatile ())
1199
+ AddFactFromMemoryAccess (LI->getPointerOperand (), LI->getAccessType ());
1200
+ }
1201
+ if (auto *SI = dyn_cast<StoreInst>(&I)) {
1202
+ if (!SI->isVolatile ())
1203
+ AddFactFromMemoryAccess (SI->getPointerOperand (), SI->getAccessType ());
1204
+ }
1205
+
1130
1206
auto *II = dyn_cast<IntrinsicInst>(&I);
1131
1207
Intrinsic::ID ID = II ? II->getIntrinsicID () : Intrinsic::not_intrinsic;
1132
1208
switch (ID) {
@@ -1420,7 +1496,7 @@ static std::optional<bool> checkCondition(CmpInst::Predicate Pred, Value *A,
1420
1496
LLVM_DEBUG (dbgs () << " Checking " << *CheckInst << " \n " );
1421
1497
1422
1498
auto R = Info.getConstraintForSolving (Pred, A, B);
1423
- if (R.empty () || !R.isValid (Info)){
1499
+ if (R.empty () || !R.isValid (Info)) {
1424
1500
LLVM_DEBUG (dbgs () << " failed to decompose condition\n " );
1425
1501
return std::nullopt;
1426
1502
}
@@ -1785,12 +1861,13 @@ tryToSimplifyOverflowMath(IntrinsicInst *II, ConstraintInfo &Info,
1785
1861
1786
1862
static bool eliminateConstraints (Function &F, DominatorTree &DT, LoopInfo &LI,
1787
1863
ScalarEvolution &SE,
1788
- OptimizationRemarkEmitter &ORE) {
1864
+ OptimizationRemarkEmitter &ORE,
1865
+ TargetLibraryInfo &TLI) {
1789
1866
bool Changed = false ;
1790
1867
DT.updateDFSNumbers ();
1791
1868
SmallVector<Value *> FunctionArgs (llvm::make_pointer_range (F.args ()));
1792
1869
ConstraintInfo Info (F.getDataLayout (), FunctionArgs);
1793
- State S (DT, LI, SE);
1870
+ State S (DT, LI, SE, TLI );
1794
1871
std::unique_ptr<Module> ReproducerModule (
1795
1872
DumpReproducers ? new Module (F.getName (), F.getContext ()) : nullptr );
1796
1873
@@ -1960,6 +2037,26 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT, LoopInfo &LI,
1960
2037
}
1961
2038
continue ;
1962
2039
}
2040
+
2041
+ auto &DL = F.getDataLayout ();
2042
+ auto AddFactsAboutIndices = [&](Value *Ptr, Type *AccessType) {
2043
+ CmpPredicate Pred;
2044
+ Value *A, *B;
2045
+ if (getConstraintFromMemoryAccess (
2046
+ *cast<GetElementPtrInst>(Ptr),
2047
+ DL.getTypeStoreSize (AccessType).getFixedValue (), Pred, A, B, DL,
2048
+ TLI))
2049
+ AddFact (Pred, A, B);
2050
+ };
2051
+
2052
+ if (auto *LI = dyn_cast<LoadInst>(CB.Inst )) {
2053
+ AddFactsAboutIndices (LI->getPointerOperand (), LI->getAccessType ());
2054
+ continue ;
2055
+ }
2056
+ if (auto *SI = dyn_cast<StoreInst>(CB.Inst )) {
2057
+ AddFactsAboutIndices (SI->getPointerOperand (), SI->getAccessType ());
2058
+ continue ;
2059
+ }
1963
2060
}
1964
2061
1965
2062
Value *A = nullptr , *B = nullptr ;
@@ -2018,7 +2115,8 @@ PreservedAnalyses ConstraintEliminationPass::run(Function &F,
2018
2115
auto &LI = AM.getResult <LoopAnalysis>(F);
2019
2116
auto &SE = AM.getResult <ScalarEvolutionAnalysis>(F);
2020
2117
auto &ORE = AM.getResult <OptimizationRemarkEmitterAnalysis>(F);
2021
- if (!eliminateConstraints (F, DT, LI, SE, ORE))
2118
+ auto &TLI = AM.getResult <TargetLibraryAnalysis>(F);
2119
+ if (!eliminateConstraints (F, DT, LI, SE, ORE, TLI))
2022
2120
return PreservedAnalyses::all ();
2023
2121
2024
2122
PreservedAnalyses PA;
0 commit comments