#include "llvm/ADT/SmallVector.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/MemoryBuiltins.h"
-#include "llvm/Analysis/ScalarEvolution.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/Analysis/ValueTracking.h"
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.addRequired<DominatorTreeWrapperPass>();
- AU.addRequired<ScalarEvolutionWrapperPass>();
AU.addRequired<TargetTransformInfoWrapperPass>();
AU.addRequired<LoopInfoWrapperPass>();
AU.setPreservesCFG();
class SeparateConstOffsetFromGEP {
public:
SeparateConstOffsetFromGEP(
- DominatorTree *DT, ScalarEvolution *SE, LoopInfo *LI,
- TargetLibraryInfo *TLI,
+ DominatorTree *DT, LoopInfo *LI, TargetLibraryInfo *TLI,
function_ref<TargetTransformInfo &(Function &)> GetTTI, bool LowerGEP)
- : DT(DT), SE(SE), LI(LI), TLI(TLI), GetTTI(GetTTI), LowerGEP(LowerGEP) {}
+ : DT(DT), LI(LI), TLI(TLI), GetTTI(GetTTI), LowerGEP(LowerGEP) {}
bool run(Function &F);
private:
+ /// Track the operands of an add or sub.
+ using ExprKey = std::pair<Value *, Value *>;
+
+ /// Create a pair for use as a map key for a commutable operation.
+ static ExprKey createNormalizedCommutablePair(Value *A, Value *B) {
+ if (A < B)
+ return {A, B};
+ return {B, A};
+ }
+
/// Tries to split the given GEP into a variadic base and a constant offset,
/// and returns true if the splitting succeeds.
bool splitGEP(GetElementPtrInst *GEP);
/// Find the closest dominator of <Dominatee> that is equivalent to <Key>.
Instruction *findClosestMatchingDominator(
- const SCEV *Key, Instruction *Dominatee,
- DenseMap<const SCEV *, SmallVector<Instruction *, 2>> &DominatingExprs);
+ ExprKey Key, Instruction *Dominatee,
+ DenseMap<ExprKey, SmallVector<Instruction *, 2>> &DominatingExprs);
/// Verify F is free of dead code.
void verifyNoDeadCode(Function &F);
const DataLayout *DL = nullptr;
DominatorTree *DT = nullptr;
- ScalarEvolution *SE;
LoopInfo *LI;
TargetLibraryInfo *TLI;
// Retrieved lazily since not always used.
/// multiple GEPs with a single index.
bool LowerGEP;
- DenseMap<const SCEV *, SmallVector<Instruction *, 2>> DominatingAdds;
- DenseMap<const SCEV *, SmallVector<Instruction *, 2>> DominatingSubs;
+ DenseMap<ExprKey, SmallVector<Instruction *, 2>> DominatingAdds;
+ DenseMap<ExprKey, SmallVector<Instruction *, 2>> DominatingSubs;
};
} // end anonymous namespace
if (skipFunction(F))
return false;
auto *DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
- auto *SE = &getAnalysis<ScalarEvolutionWrapperPass>().getSE();
auto *LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
auto *TLI = &getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(F);
auto GetTTI = [this](Function &F) -> TargetTransformInfo & {
return this->getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);
};
- SeparateConstOffsetFromGEP Impl(DT, SE, LI, TLI, GetTTI, LowerGEP);
+ SeparateConstOffsetFromGEP Impl(DT, LI, TLI, GetTTI, LowerGEP);
return Impl.run(F);
}
}
Instruction *SeparateConstOffsetFromGEP::findClosestMatchingDominator(
- const SCEV *Key, Instruction *Dominatee,
- DenseMap<const SCEV *, SmallVector<Instruction *, 2>> &DominatingExprs) {
+ ExprKey Key, Instruction *Dominatee,
+ DenseMap<ExprKey, SmallVector<Instruction *, 2>> &DominatingExprs) {
auto Pos = DominatingExprs.find(Key);
if (Pos == DominatingExprs.end())
return nullptr;
}
bool SeparateConstOffsetFromGEP::reuniteExts(Instruction *I) {
- if (!SE->isSCEVable(I->getType()))
+ if (!I->getType()->isIntOrIntVectorTy())
return false;
// Dom: LHS+RHS
Value *LHS = nullptr, *RHS = nullptr;
if (match(I, m_Add(m_SExt(m_Value(LHS)), m_SExt(m_Value(RHS))))) {
if (LHS->getType() == RHS->getType()) {
- const SCEV *Key =
- SE->getAddExpr(SE->getUnknown(LHS), SE->getUnknown(RHS));
+ ExprKey Key = createNormalizedCommutablePair(LHS, RHS);
if (auto *Dom = findClosestMatchingDominator(Key, I, DominatingAdds)) {
Instruction *NewSExt = new SExtInst(Dom, I->getType(), "", I);
NewSExt->takeName(I);
}
} else if (match(I, m_Sub(m_SExt(m_Value(LHS)), m_SExt(m_Value(RHS))))) {
if (LHS->getType() == RHS->getType()) {
- const SCEV *Key = SE->getAddExpr(
- SE->getUnknown(LHS), SE->getNegativeSCEV(SE->getUnknown(RHS)));
- if (auto *Dom = findClosestMatchingDominator(Key, I, DominatingSubs)) {
+ if (auto *Dom =
+ findClosestMatchingDominator({LHS, RHS}, I, DominatingSubs)) {
Instruction *NewSExt = new SExtInst(Dom, I->getType(), "", I);
NewSExt->takeName(I);
I->replaceAllUsesWith(NewSExt);
// Add I to DominatingExprs if it's an add/sub that can't sign overflow.
if (match(I, m_NSWAdd(m_Value(LHS), m_Value(RHS)))) {
if (programUndefinedIfPoison(I)) {
- const SCEV *Key =
- SE->getAddExpr(SE->getUnknown(LHS), SE->getUnknown(RHS));
+ ExprKey Key = createNormalizedCommutablePair(LHS, RHS);
DominatingAdds[Key].push_back(I);
}
} else if (match(I, m_NSWSub(m_Value(LHS), m_Value(RHS)))) {
- if (programUndefinedIfPoison(I)) {
- const SCEV *Key = SE->getAddExpr(
- SE->getUnknown(LHS), SE->getNegativeSCEV(SE->getUnknown(RHS)));
- DominatingSubs[Key].push_back(I);
- }
+ if (programUndefinedIfPoison(I))
+ DominatingSubs[{LHS, RHS}].push_back(I);
}
return false;
}
PreservedAnalyses
SeparateConstOffsetFromGEPPass::run(Function &F, FunctionAnalysisManager &AM) {
auto *DT = &AM.getResult<DominatorTreeAnalysis>(F);
- auto *SE = &AM.getResult<ScalarEvolutionAnalysis>(F);
auto *LI = &AM.getResult<LoopAnalysis>(F);
auto *TLI = &AM.getResult<TargetLibraryAnalysis>(F);
auto GetTTI = [&AM](Function &F) -> TargetTransformInfo & {
return AM.getResult<TargetIRAnalysis>(F);
};
- SeparateConstOffsetFromGEP Impl(DT, SE, LI, TLI, GetTTI, LowerGEP);
+ SeparateConstOffsetFromGEP Impl(DT, LI, TLI, GetTTI, LowerGEP);
if (!Impl.run(F))
return PreservedAnalyses::all();
PreservedAnalyses PA;
; CHECK-SAME: (<2 x i32> [[ARG0:%.*]], <2 x i32> [[ARG1:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[ADD_NSW:%.*]] = add nsw <2 x i32> [[ARG0]], [[ARG1]]
-; CHECK-NEXT: [[ARG0_SEXT:%.*]] = sext <2 x i32> [[ARG0]] to <2 x i64>
-; CHECK-NEXT: [[ARG1_SEXT:%.*]] = sext <2 x i32> [[ARG1]] to <2 x i64>
-; CHECK-NEXT: [[ADD_SEXT:%.*]] = add <2 x i64> [[ARG0_SEXT]], [[ARG1_SEXT]]
+; CHECK-NEXT: [[ADD_SEXT:%.*]] = sext <2 x i32> [[ADD_NSW]] to <2 x i64>
; CHECK-NEXT: call void @use.v2i32(<2 x i32> [[ADD_NSW]])
; CHECK-NEXT: ret <2 x i64> [[ADD_SEXT]]
;
; CHECK-SAME: (<2 x i32> [[ARG0:%.*]], <2 x i32> [[ARG1:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[SUB_NSW:%.*]] = sub nsw <2 x i32> [[ARG0]], [[ARG1]]
-; CHECK-NEXT: [[ARG0_SEXT:%.*]] = sext <2 x i32> [[ARG0]] to <2 x i64>
-; CHECK-NEXT: [[ARG1_SEXT:%.*]] = sext <2 x i32> [[ARG1]] to <2 x i64>
-; CHECK-NEXT: [[SUB_SEXT:%.*]] = sub <2 x i64> [[ARG0_SEXT]], [[ARG1_SEXT]]
+; CHECK-NEXT: [[SUB_SEXT:%.*]] = sext <2 x i32> [[SUB_NSW]] to <2 x i64>
; CHECK-NEXT: call void @use.v2i32(<2 x i32> [[SUB_NSW]])
; CHECK-NEXT: ret <2 x i64> [[SUB_SEXT]]
;
; CHECK-SAME: (<2 x i32> [[ARG0:%.*]], <2 x i32> [[ARG1:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[ADD_NSW:%.*]] = add nsw <2 x i32> [[ARG0]], [[ARG1]]
-; CHECK-NEXT: [[ARG0_SEXT:%.*]] = sext <2 x i32> [[ARG0]] to <2 x i64>
-; CHECK-NEXT: [[ARG1_SEXT:%.*]] = sext <2 x i32> [[ARG1]] to <2 x i64>
-; CHECK-NEXT: [[ADD_SEXT:%.*]] = add <2 x i64> [[ARG1_SEXT]], [[ARG0_SEXT]]
+; CHECK-NEXT: [[ADD_SEXT:%.*]] = sext <2 x i32> [[ADD_NSW]] to <2 x i64>
; CHECK-NEXT: call void @use.v2i32(<2 x i32> [[ADD_NSW]])
; CHECK-NEXT: ret <2 x i64> [[ADD_SEXT]]
;