#include "llvm/Transforms/Utils/ScalarEvolutionExpander.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/Analysis/InstructionSimplify.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/PatternMatch.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Utils/LoopUtils.h"
#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
#define SCEV_DEBUG_WITH_TYPE(TYPE, X) DEBUG_WITH_TYPE(TYPE, X)
#else
#define SCEV_DEBUG_WITH_TYPE(TYPE, X)
#endif
using namespace llvm;
cl::opt<unsigned> llvm::SCEVCheapExpansionBudget(
"scev-cheap-expansion-budget", cl::Hidden, cl::init(4),
cl::desc("When performing SCEV expansion only if it is cheap to do, this "
"controls the budget that is considered cheap (default = 4)"));
using namespace PatternMatch;
Value *SCEVExpander::ReuseOrCreateCast(Value *V, Type *Ty,
Instruction::CastOps Op,
BasicBlock::iterator IP) {
BasicBlock::iterator BIP = Builder.GetInsertPoint();
Value *Ret = nullptr;
for (User *U : V->users()) {
if (U->getType() != Ty)
continue;
CastInst *CI = dyn_cast<CastInst>(U);
if (!CI || CI->getOpcode() != Op)
continue;
if (IP->getParent() == CI->getParent() && &*BIP != CI &&
(&*IP == CI || CI->comesBefore(&*IP))) {
Ret = CI;
break;
}
}
if (!Ret) {
SCEVInsertPointGuard Guard(Builder, this);
Builder.SetInsertPoint(&*IP);
Ret = Builder.CreateCast(Op, V, Ty, V->getName());
}
assert(!isa<Instruction>(Ret) ||
SE.DT.dominates(cast<Instruction>(Ret), &*BIP));
return Ret;
}
BasicBlock::iterator
SCEVExpander::findInsertPointAfter(Instruction *I,
Instruction *MustDominate) const {
BasicBlock::iterator IP = ++I->getIterator();
if (auto *II = dyn_cast<InvokeInst>(I))
IP = II->getNormalDest()->begin();
while (isa<PHINode>(IP))
++IP;
if (isa<FuncletPadInst>(IP) || isa<LandingPadInst>(IP)) {
++IP;
} else if (isa<CatchSwitchInst>(IP)) {
IP = MustDominate->getParent()->getFirstInsertionPt();
} else {
assert(!IP->isEHPad() && "unexpected eh pad!");
}
while (isInsertedInstruction(&*IP) && &*IP != MustDominate)
++IP;
return IP;
}
BasicBlock::iterator
SCEVExpander::GetOptimalInsertionPointForCastOf(Value *V) const {
if (Argument *A = dyn_cast<Argument>(V)) {
BasicBlock::iterator IP = A->getParent()->getEntryBlock().begin();
while ((isa<BitCastInst>(IP) &&
isa<Argument>(cast<BitCastInst>(IP)->getOperand(0)) &&
cast<BitCastInst>(IP)->getOperand(0) != A) ||
isa<DbgInfoIntrinsic>(IP))
++IP;
return IP;
}
if (Instruction *I = dyn_cast<Instruction>(V))
return findInsertPointAfter(I, &*Builder.GetInsertPoint());
assert(isa<Constant>(V) &&
"Expected the cast argument to be a global/constant");
return Builder.GetInsertBlock()
->getParent()
->getEntryBlock()
.getFirstInsertionPt();
}
Value *SCEVExpander::InsertNoopCastOfTo(Value *V, Type *Ty) {
Instruction::CastOps Op = CastInst::getCastOpcode(V, false, Ty, false);
assert((Op == Instruction::BitCast ||
Op == Instruction::PtrToInt ||
Op == Instruction::IntToPtr) &&
"InsertNoopCastOfTo cannot perform non-noop casts!");
assert(SE.getTypeSizeInBits(V->getType()) == SE.getTypeSizeInBits(Ty) &&
"InsertNoopCastOfTo cannot change sizes!");
if (Op == Instruction::IntToPtr) {
auto *PtrTy = cast<PointerType>(Ty);
if (DL.isNonIntegralPointerType(PtrTy)) {
auto *Int8PtrTy = Builder.getInt8PtrTy(PtrTy->getAddressSpace());
assert(DL.getTypeAllocSize(Builder.getInt8Ty()) == 1 &&
"alloc size of i8 must by 1 byte for the GEP to be correct");
auto *GEP = Builder.CreateGEP(
Builder.getInt8Ty(), Constant::getNullValue(Int8PtrTy), V, "uglygep");
return Builder.CreateBitCast(GEP, Ty);
}
}
if (Op == Instruction::BitCast) {
if (V->getType() == Ty)
return V;
if (CastInst *CI = dyn_cast<CastInst>(V)) {
if (CI->getOperand(0)->getType() == Ty)
return CI->getOperand(0);
}
}
if ((Op == Instruction::PtrToInt || Op == Instruction::IntToPtr) &&
SE.getTypeSizeInBits(Ty) == SE.getTypeSizeInBits(V->getType())) {
if (CastInst *CI = dyn_cast<CastInst>(V))
if ((CI->getOpcode() == Instruction::PtrToInt ||
CI->getOpcode() == Instruction::IntToPtr) &&
SE.getTypeSizeInBits(CI->getType()) ==
SE.getTypeSizeInBits(CI->getOperand(0)->getType()))
return CI->getOperand(0);
if (ConstantExpr *CE = dyn_cast<ConstantExpr>(V))
if ((CE->getOpcode() == Instruction::PtrToInt ||
CE->getOpcode() == Instruction::IntToPtr) &&
SE.getTypeSizeInBits(CE->getType()) ==
SE.getTypeSizeInBits(CE->getOperand(0)->getType()))
return CE->getOperand(0);
}
if (Constant *C = dyn_cast<Constant>(V))
return ConstantExpr::getCast(Op, C, Ty);
return ReuseOrCreateCast(V, Ty, Op, GetOptimalInsertionPointForCastOf(V));
}
Value *SCEVExpander::InsertBinop(Instruction::BinaryOps Opcode,
Value *LHS, Value *RHS,
SCEV::NoWrapFlags Flags, bool IsSafeToHoist) {
if (Constant *CLHS = dyn_cast<Constant>(LHS))
if (Constant *CRHS = dyn_cast<Constant>(RHS))
if (Constant *Res = ConstantFoldBinaryOpOperands(Opcode, CLHS, CRHS, DL))
return Res;
unsigned ScanLimit = 6;
BasicBlock::iterator BlockBegin = Builder.GetInsertBlock()->begin();
BasicBlock::iterator IP = Builder.GetInsertPoint();
if (IP != BlockBegin) {
--IP;
for (; ScanLimit; --IP, --ScanLimit) {
if (isa<DbgInfoIntrinsic>(IP))
ScanLimit++;
auto canGenerateIncompatiblePoison = [&Flags](Instruction *I) {
if (isa<OverflowingBinaryOperator>(I)) {
if (I->hasNoSignedWrap() != (Flags & SCEV::FlagNSW))
return true;
if (I->hasNoUnsignedWrap() != (Flags & SCEV::FlagNUW))
return true;
}
if (isa<PossiblyExactOperator>(I) && I->isExact())
return true;
return false;
};
if (IP->getOpcode() == (unsigned)Opcode && IP->getOperand(0) == LHS &&
IP->getOperand(1) == RHS && !canGenerateIncompatiblePoison(&*IP))
return &*IP;
if (IP == BlockBegin) break;
}
}
DebugLoc Loc = Builder.GetInsertPoint()->getDebugLoc();
SCEVInsertPointGuard Guard(Builder, this);
if (IsSafeToHoist) {
while (const Loop *L = SE.LI.getLoopFor(Builder.GetInsertBlock())) {
if (!L->isLoopInvariant(LHS) || !L->isLoopInvariant(RHS)) break;
BasicBlock *Preheader = L->getLoopPreheader();
if (!Preheader) break;
Builder.SetInsertPoint(Preheader->getTerminator());
}
}
Instruction *BO = Builder.Insert(BinaryOperator::Create(Opcode, LHS, RHS));
BO->setDebugLoc(Loc);
if (Flags & SCEV::FlagNUW)
BO->setHasNoUnsignedWrap();
if (Flags & SCEV::FlagNSW)
BO->setHasNoSignedWrap();
return BO;
}
static bool FactorOutConstant(const SCEV *&S, const SCEV *&Remainder,
const SCEV *Factor, ScalarEvolution &SE,
const DataLayout &DL) {
if (Factor->isOne())
return true;
if (S == Factor) {
S = SE.getConstant(S->getType(), 1);
return true;
}
if (const SCEVConstant *C = dyn_cast<SCEVConstant>(S)) {
if (C->isZero())
return true;
if (const SCEVConstant *FC = dyn_cast<SCEVConstant>(Factor)) {
ConstantInt *CI =
ConstantInt::get(SE.getContext(), C->getAPInt().sdiv(FC->getAPInt()));
if (!CI->isZero()) {
const SCEV *Div = SE.getConstant(CI);
S = Div;
Remainder = SE.getAddExpr(
Remainder, SE.getConstant(C->getAPInt().srem(FC->getAPInt())));
return true;
}
}
}
if (const SCEVMulExpr *M = dyn_cast<SCEVMulExpr>(S)) {
if (const SCEVConstant *FC = dyn_cast<SCEVConstant>(Factor))
if (const SCEVConstant *C = dyn_cast<SCEVConstant>(M->getOperand(0)))
if (!C->getAPInt().srem(FC->getAPInt())) {
SmallVector<const SCEV *, 4> NewMulOps(M->operands());
NewMulOps[0] = SE.getConstant(C->getAPInt().sdiv(FC->getAPInt()));
S = SE.getMulExpr(NewMulOps);
return true;
}
}
if (const SCEVAddRecExpr *A = dyn_cast<SCEVAddRecExpr>(S)) {
const SCEV *Step = A->getStepRecurrence(SE);
const SCEV *StepRem = SE.getConstant(Step->getType(), 0);
if (!FactorOutConstant(Step, StepRem, Factor, SE, DL))
return false;
if (!StepRem->isZero())
return false;
const SCEV *Start = A->getStart();
if (!FactorOutConstant(Start, Remainder, Factor, SE, DL))
return false;
S = SE.getAddRecExpr(Start, Step, A->getLoop(),
A->getNoWrapFlags(SCEV::FlagNW));
return true;
}
return false;
}
static void SimplifyAddOperands(SmallVectorImpl<const SCEV *> &Ops,
Type *Ty,
ScalarEvolution &SE) {
unsigned NumAddRecs = 0;
for (unsigned i = Ops.size(); i > 0 && isa<SCEVAddRecExpr>(Ops[i-1]); --i)
++NumAddRecs;
SmallVector<const SCEV *, 8> NoAddRecs(Ops.begin(), Ops.end() - NumAddRecs);
SmallVector<const SCEV *, 8> AddRecs(Ops.end() - NumAddRecs, Ops.end());
const SCEV *Sum = NoAddRecs.empty() ?
SE.getConstant(Ty, 0) :
SE.getAddExpr(NoAddRecs);
Ops.clear();
if (const SCEVAddExpr *Add = dyn_cast<SCEVAddExpr>(Sum))
Ops.append(Add->op_begin(), Add->op_end());
else if (!Sum->isZero())
Ops.push_back(Sum);
Ops.append(AddRecs.begin(), AddRecs.end());
}
static void SplitAddRecs(SmallVectorImpl<const SCEV *> &Ops,
Type *Ty,
ScalarEvolution &SE) {
SmallVector<const SCEV *, 8> AddRecs;
for (unsigned i = 0, e = Ops.size(); i != e; ++i)
while (const SCEVAddRecExpr *A = dyn_cast<SCEVAddRecExpr>(Ops[i])) {
const SCEV *Start = A->getStart();
if (Start->isZero()) break;
const SCEV *Zero = SE.getConstant(Ty, 0);
AddRecs.push_back(SE.getAddRecExpr(Zero,
A->getStepRecurrence(SE),
A->getLoop(),
A->getNoWrapFlags(SCEV::FlagNW)));
if (const SCEVAddExpr *Add = dyn_cast<SCEVAddExpr>(Start)) {
Ops[i] = Zero;
Ops.append(Add->op_begin(), Add->op_end());
e += Add->getNumOperands();
} else {
Ops[i] = Start;
}
}
if (!AddRecs.empty()) {
Ops.append(AddRecs.begin(), AddRecs.end());
SimplifyAddOperands(Ops, Ty, SE);
}
}
Value *SCEVExpander::expandAddToGEP(const SCEV *const *op_begin,
const SCEV *const *op_end,
PointerType *PTy,
Type *Ty,
Value *V) {
SmallVector<Value *, 4> GepIndices;
SmallVector<const SCEV *, 8> Ops(op_begin, op_end);
bool AnyNonZeroIndices = false;
SplitAddRecs(Ops, Ty, SE);
Type *IntIdxTy = DL.getIndexType(PTy);
if (!PTy->isOpaque()) {
Type *ElTy = PTy->getNonOpaquePointerElementType();
for (;;) {
SmallVector<const SCEV *, 8> ScaledOps;
if (ElTy->isSized()) {
const SCEV *ElSize = SE.getSizeOfExpr(IntIdxTy, ElTy);
if (!ElSize->isZero()) {
SmallVector<const SCEV *, 8> NewOps;
for (const SCEV *Op : Ops) {
const SCEV *Remainder = SE.getConstant(Ty, 0);
if (FactorOutConstant(Op, Remainder, ElSize, SE, DL)) {
ScaledOps.push_back(Op);
if (!Remainder->isZero())
NewOps.push_back(Remainder);
AnyNonZeroIndices = true;
} else {
NewOps.push_back(Op);
}
}
if (!ScaledOps.empty()) {
Ops = NewOps;
SimplifyAddOperands(Ops, Ty, SE);
}
}
}
Value *Scaled =
ScaledOps.empty()
? Constant::getNullValue(Ty)
: expandCodeForImpl(SE.getAddExpr(ScaledOps), Ty, false);
GepIndices.push_back(Scaled);
while (StructType *STy = dyn_cast<StructType>(ElTy)) {
bool FoundFieldNo = false;
if (STy->getNumElements() == 0) break;
if (Ops.empty())
break;
if (const SCEVConstant *C = dyn_cast<SCEVConstant>(Ops[0]))
if (SE.getTypeSizeInBits(C->getType()) <= 64) {
const StructLayout &SL = *DL.getStructLayout(STy);
uint64_t FullOffset = C->getValue()->getZExtValue();
if (FullOffset < SL.getSizeInBytes()) {
unsigned ElIdx = SL.getElementContainingOffset(FullOffset);
GepIndices.push_back(
ConstantInt::get(Type::getInt32Ty(Ty->getContext()), ElIdx));
ElTy = STy->getTypeAtIndex(ElIdx);
Ops[0] =
SE.getConstant(Ty, FullOffset - SL.getElementOffset(ElIdx));
AnyNonZeroIndices = true;
FoundFieldNo = true;
}
}
if (!FoundFieldNo) {
ElTy = STy->getTypeAtIndex(0u);
GepIndices.push_back(
Constant::getNullValue(Type::getInt32Ty(Ty->getContext())));
}
}
if (ArrayType *ATy = dyn_cast<ArrayType>(ElTy))
ElTy = ATy->getElementType();
else
break;
}
}
if (!AnyNonZeroIndices) {
if (!PTy->isOpaque())
V = InsertNoopCastOfTo(V,
Type::getInt8PtrTy(Ty->getContext(), PTy->getAddressSpace()));
assert(!isa<Instruction>(V) ||
SE.DT.dominates(cast<Instruction>(V), &*Builder.GetInsertPoint()));
Value *Idx = expandCodeForImpl(SE.getAddExpr(Ops), Ty, false);
if (Constant *CLHS = dyn_cast<Constant>(V))
if (Constant *CRHS = dyn_cast<Constant>(Idx))
return ConstantExpr::getGetElementPtr(Type::getInt8Ty(Ty->getContext()),
CLHS, CRHS);
unsigned ScanLimit = 6;
BasicBlock::iterator BlockBegin = Builder.GetInsertBlock()->begin();
BasicBlock::iterator IP = Builder.GetInsertPoint();
if (IP != BlockBegin) {
--IP;
for (; ScanLimit; --IP, --ScanLimit) {
if (isa<DbgInfoIntrinsic>(IP))
ScanLimit++;
if (IP->getOpcode() == Instruction::GetElementPtr &&
IP->getOperand(0) == V && IP->getOperand(1) == Idx &&
cast<GEPOperator>(&*IP)->getSourceElementType() ==
Type::getInt8Ty(Ty->getContext()))
return &*IP;
if (IP == BlockBegin) break;
}
}
SCEVInsertPointGuard Guard(Builder, this);
while (const Loop *L = SE.LI.getLoopFor(Builder.GetInsertBlock())) {
if (!L->isLoopInvariant(V) || !L->isLoopInvariant(Idx)) break;
BasicBlock *Preheader = L->getLoopPreheader();
if (!Preheader) break;
Builder.SetInsertPoint(Preheader->getTerminator());
}
return Builder.CreateGEP(Builder.getInt8Ty(), V, Idx, "uglygep");
}
{
SCEVInsertPointGuard Guard(Builder, this);
while (const Loop *L = SE.LI.getLoopFor(Builder.GetInsertBlock())) {
if (!L->isLoopInvariant(V)) break;
bool AnyIndexNotLoopInvariant = any_of(
GepIndices, [L](Value *Op) { return !L->isLoopInvariant(Op); });
if (AnyIndexNotLoopInvariant)
break;
BasicBlock *Preheader = L->getLoopPreheader();
if (!Preheader) break;
Builder.SetInsertPoint(Preheader->getTerminator());
}
Value *Casted = V;
if (V->getType() != PTy)
Casted = InsertNoopCastOfTo(Casted, PTy);
Value *GEP = Builder.CreateGEP(PTy->getNonOpaquePointerElementType(),
Casted, GepIndices, "scevgep");
Ops.push_back(SE.getUnknown(GEP));
}
return expand(SE.getAddExpr(Ops));
}
Value *SCEVExpander::expandAddToGEP(const SCEV *Op, PointerType *PTy, Type *Ty,
Value *V) {
const SCEV *const Ops[1] = {Op};
return expandAddToGEP(Ops, Ops + 1, PTy, Ty, V);
}
static const Loop *PickMostRelevantLoop(const Loop *A, const Loop *B,
DominatorTree &DT) {
if (!A) return B;
if (!B) return A;
if (A->contains(B)) return B;
if (B->contains(A)) return A;
if (DT.dominates(A->getHeader(), B->getHeader())) return B;
if (DT.dominates(B->getHeader(), A->getHeader())) return A;
return A; }
const Loop *SCEVExpander::getRelevantLoop(const SCEV *S) {
auto Pair = RelevantLoops.insert(std::make_pair(S, nullptr));
if (!Pair.second)
return Pair.first->second;
if (isa<SCEVConstant>(S))
return nullptr;
if (const SCEVUnknown *U = dyn_cast<SCEVUnknown>(S)) {
if (const Instruction *I = dyn_cast<Instruction>(U->getValue()))
return Pair.first->second = SE.LI.getLoopFor(I->getParent());
return nullptr;
}
if (const SCEVNAryExpr *N = dyn_cast<SCEVNAryExpr>(S)) {
const Loop *L = nullptr;
if (const SCEVAddRecExpr *AR = dyn_cast<SCEVAddRecExpr>(S))
L = AR->getLoop();
for (const SCEV *Op : N->operands())
L = PickMostRelevantLoop(L, getRelevantLoop(Op), SE.DT);
return RelevantLoops[N] = L;
}
if (const SCEVCastExpr *C = dyn_cast<SCEVCastExpr>(S)) {
const Loop *Result = getRelevantLoop(C->getOperand());
return RelevantLoops[C] = Result;
}
if (const SCEVUDivExpr *D = dyn_cast<SCEVUDivExpr>(S)) {
const Loop *Result = PickMostRelevantLoop(
getRelevantLoop(D->getLHS()), getRelevantLoop(D->getRHS()), SE.DT);
return RelevantLoops[D] = Result;
}
llvm_unreachable("Unexpected SCEV type!");
}
namespace {
class LoopCompare {
DominatorTree &DT;
public:
explicit LoopCompare(DominatorTree &dt) : DT(dt) {}
bool operator()(std::pair<const Loop *, const SCEV *> LHS,
std::pair<const Loop *, const SCEV *> RHS) const {
if (LHS.second->getType()->isPointerTy() !=
RHS.second->getType()->isPointerTy())
return LHS.second->getType()->isPointerTy();
if (LHS.first != RHS.first)
return PickMostRelevantLoop(LHS.first, RHS.first, DT) != LHS.first;
if (LHS.second->isNonConstantNegative()) {
if (!RHS.second->isNonConstantNegative())
return false;
} else if (RHS.second->isNonConstantNegative())
return true;
return false;
}
};
}
Value *SCEVExpander::visitAddExpr(const SCEVAddExpr *S) {
Type *Ty = SE.getEffectiveSCEVType(S->getType());
SmallVector<std::pair<const Loop *, const SCEV *>, 8> OpsAndLoops;
for (const SCEV *Op : reverse(S->operands()))
OpsAndLoops.push_back(std::make_pair(getRelevantLoop(Op), Op));
llvm::stable_sort(OpsAndLoops, LoopCompare(SE.DT));
Value *Sum = nullptr;
for (auto I = OpsAndLoops.begin(), E = OpsAndLoops.end(); I != E;) {
const Loop *CurLoop = I->first;
const SCEV *Op = I->second;
if (!Sum) {
Sum = expand(Op);
++I;
continue;
}
assert(!Op->getType()->isPointerTy() && "Only first op can be pointer");
if (PointerType *PTy = dyn_cast<PointerType>(Sum->getType())) {
SmallVector<const SCEV *, 4> NewOps;
for (; I != E && I->first == CurLoop; ++I) {
const SCEV *X = I->second;
if (const SCEVUnknown *U = dyn_cast<SCEVUnknown>(X))
if (!isa<Instruction>(U->getValue()))
X = SE.getSCEV(U->getValue());
NewOps.push_back(X);
}
Sum = expandAddToGEP(NewOps.begin(), NewOps.end(), PTy, Ty, Sum);
} else if (Op->isNonConstantNegative()) {
Value *W = expandCodeForImpl(SE.getNegativeSCEV(Op), Ty, false);
Sum = InsertNoopCastOfTo(Sum, Ty);
Sum = InsertBinop(Instruction::Sub, Sum, W, SCEV::FlagAnyWrap,
true);
++I;
} else {
Value *W = expandCodeForImpl(Op, Ty, false);
Sum = InsertNoopCastOfTo(Sum, Ty);
if (isa<Constant>(Sum)) std::swap(Sum, W);
Sum = InsertBinop(Instruction::Add, Sum, W, S->getNoWrapFlags(),
true);
++I;
}
}
return Sum;
}
Value *SCEVExpander::visitMulExpr(const SCEVMulExpr *S) {
Type *Ty = SE.getEffectiveSCEVType(S->getType());
SmallVector<std::pair<const Loop *, const SCEV *>, 8> OpsAndLoops;
for (const SCEV *Op : reverse(S->operands()))
OpsAndLoops.push_back(std::make_pair(getRelevantLoop(Op), Op));
llvm::stable_sort(OpsAndLoops, LoopCompare(SE.DT));
Value *Prod = nullptr;
auto I = OpsAndLoops.begin();
const auto ExpandOpBinPowN = [this, &I, &OpsAndLoops, &Ty]() {
auto E = I;
uint64_t Exponent = 0;
const uint64_t MaxExponent = UINT64_MAX >> 1;
while (E != OpsAndLoops.end() && *I == *E && Exponent != MaxExponent) {
++Exponent;
++E;
}
assert(Exponent > 0 && "Trying to calculate a zeroth exponent of operand?");
Value *P = expandCodeForImpl(I->second, Ty, false);
Value *Result = nullptr;
if (Exponent & 1)
Result = P;
for (uint64_t BinExp = 2; BinExp <= Exponent; BinExp <<= 1) {
P = InsertBinop(Instruction::Mul, P, P, SCEV::FlagAnyWrap,
true);
if (Exponent & BinExp)
Result = Result ? InsertBinop(Instruction::Mul, Result, P,
SCEV::FlagAnyWrap,
true)
: P;
}
I = E;
assert(Result && "Nothing was expanded?");
return Result;
};
while (I != OpsAndLoops.end()) {
if (!Prod) {
Prod = ExpandOpBinPowN();
} else if (I->second->isAllOnesValue()) {
Prod = InsertNoopCastOfTo(Prod, Ty);
Prod = InsertBinop(Instruction::Sub, Constant::getNullValue(Ty), Prod,
SCEV::FlagAnyWrap, true);
++I;
} else {
Value *W = ExpandOpBinPowN();
Prod = InsertNoopCastOfTo(Prod, Ty);
if (isa<Constant>(Prod)) std::swap(Prod, W);
const APInt *RHS;
if (match(W, m_Power2(RHS))) {
assert(!Ty->isVectorTy() && "vector types are not SCEVable");
auto NWFlags = S->getNoWrapFlags();
if (RHS->logBase2() == RHS->getBitWidth() - 1)
NWFlags = ScalarEvolution::clearFlags(NWFlags, SCEV::FlagNSW);
Prod = InsertBinop(Instruction::Shl, Prod,
ConstantInt::get(Ty, RHS->logBase2()), NWFlags,
true);
} else {
Prod = InsertBinop(Instruction::Mul, Prod, W, S->getNoWrapFlags(),
true);
}
}
}
return Prod;
}
Value *SCEVExpander::visitUDivExpr(const SCEVUDivExpr *S) {
Type *Ty = SE.getEffectiveSCEVType(S->getType());
Value *LHS = expandCodeForImpl(S->getLHS(), Ty, false);
if (const SCEVConstant *SC = dyn_cast<SCEVConstant>(S->getRHS())) {
const APInt &RHS = SC->getAPInt();
if (RHS.isPowerOf2())
return InsertBinop(Instruction::LShr, LHS,
ConstantInt::get(Ty, RHS.logBase2()),
SCEV::FlagAnyWrap, true);
}
Value *RHS = expandCodeForImpl(S->getRHS(), Ty, false);
return InsertBinop(Instruction::UDiv, LHS, RHS, SCEV::FlagAnyWrap,
SE.isKnownNonZero(S->getRHS()));
}
bool SCEVExpander::isNormalAddRecExprPHI(PHINode *PN, Instruction *IncV,
const Loop *L) {
if (IncV->getNumOperands() == 0 || isa<PHINode>(IncV) ||
(isa<CastInst>(IncV) && !isa<BitCastInst>(IncV)))
return false;
if (L == IVIncInsertLoop) {
for (Use &Op : llvm::drop_begin(IncV->operands()))
if (Instruction *OInst = dyn_cast<Instruction>(Op))
if (!SE.DT.dominates(OInst, IVIncInsertPos))
return false;
}
IncV = dyn_cast<Instruction>(IncV->getOperand(0));
if (!IncV)
return false;
if (IncV->mayHaveSideEffects())
return false;
if (IncV == PN)
return true;
return isNormalAddRecExprPHI(PN, IncV, L);
}
Instruction *SCEVExpander::getIVIncOperand(Instruction *IncV,
Instruction *InsertPos,
bool allowScale) {
if (IncV == InsertPos)
return nullptr;
switch (IncV->getOpcode()) {
default:
return nullptr;
case Instruction::Add:
case Instruction::Sub: {
Instruction *OInst = dyn_cast<Instruction>(IncV->getOperand(1));
if (!OInst || SE.DT.dominates(OInst, InsertPos))
return dyn_cast<Instruction>(IncV->getOperand(0));
return nullptr;
}
case Instruction::BitCast:
return dyn_cast<Instruction>(IncV->getOperand(0));
case Instruction::GetElementPtr:
for (Use &U : llvm::drop_begin(IncV->operands())) {
if (isa<Constant>(U))
continue;
if (Instruction *OInst = dyn_cast<Instruction>(U)) {
if (!SE.DT.dominates(OInst, InsertPos))
return nullptr;
}
if (allowScale) {
continue;
}
if (IncV->getNumOperands() != 2)
return nullptr;
unsigned AS = cast<PointerType>(IncV->getType())->getAddressSpace();
if (IncV->getType() != Type::getInt1PtrTy(SE.getContext(), AS)
&& IncV->getType() != Type::getInt8PtrTy(SE.getContext(), AS))
return nullptr;
break;
}
return dyn_cast<Instruction>(IncV->getOperand(0));
}
}
void SCEVExpander::fixupInsertPoints(Instruction *I) {
BasicBlock::iterator It(*I);
BasicBlock::iterator NewInsertPt = std::next(It);
if (Builder.GetInsertPoint() == It)
Builder.SetInsertPoint(&*NewInsertPt);
for (auto *InsertPtGuard : InsertPointGuards)
if (InsertPtGuard->GetInsertPoint() == It)
InsertPtGuard->SetInsertPoint(NewInsertPt);
}
bool SCEVExpander::hoistIVInc(Instruction *IncV, Instruction *InsertPos) {
if (SE.DT.dominates(IncV, InsertPos))
return true;
if (isa<PHINode>(InsertPos) ||
!SE.DT.dominates(InsertPos->getParent(), IncV->getParent()))
return false;
if (!SE.LI.movementPreservesLCSSAForm(IncV, InsertPos))
return false;
SmallVector<Instruction*, 4> IVIncs;
for(;;) {
Instruction *Oper = getIVIncOperand(IncV, InsertPos, true);
if (!Oper)
return false;
IVIncs.push_back(IncV);
IncV = Oper;
if (SE.DT.dominates(IncV, InsertPos))
break;
}
for (Instruction *I : llvm::reverse(IVIncs)) {
fixupInsertPoints(I);
I->moveBefore(InsertPos);
}
return true;
}
bool SCEVExpander::isExpandedAddRecExprPHI(PHINode *PN, Instruction *IncV,
const Loop *L) {
for(Instruction *IVOper = IncV;
(IVOper = getIVIncOperand(IVOper, L->getLoopPreheader()->getTerminator(),
false));) {
if (IVOper == PN)
return true;
}
return false;
}
Value *SCEVExpander::expandIVInc(PHINode *PN, Value *StepV, const Loop *L,
Type *ExpandTy, Type *IntTy,
bool useSubtract) {
Value *IncV;
if (ExpandTy->isPointerTy()) {
PointerType *GEPPtrTy = cast<PointerType>(ExpandTy);
if (!isa<ConstantInt>(StepV))
GEPPtrTy = PointerType::get(Type::getInt1Ty(SE.getContext()),
GEPPtrTy->getAddressSpace());
IncV = expandAddToGEP(SE.getSCEV(StepV), GEPPtrTy, IntTy, PN);
if (IncV->getType() != PN->getType())
IncV = Builder.CreateBitCast(IncV, PN->getType());
} else {
IncV = useSubtract ?
Builder.CreateSub(PN, StepV, Twine(IVName) + ".iv.next") :
Builder.CreateAdd(PN, StepV, Twine(IVName) + ".iv.next");
}
return IncV;
}
static bool canBeCheaplyTransformed(ScalarEvolution &SE,
const SCEVAddRecExpr *Phi,
const SCEVAddRecExpr *Requested,
bool &InvertStep) {
if (Phi->getType()->isPointerTy())
return false;
Type *PhiTy = SE.getEffectiveSCEVType(Phi->getType());
Type *RequestedTy = SE.getEffectiveSCEVType(Requested->getType());
if (RequestedTy->getIntegerBitWidth() > PhiTy->getIntegerBitWidth())
return false;
Phi = dyn_cast<SCEVAddRecExpr>(SE.getTruncateOrNoop(Phi, RequestedTy));
if (!Phi)
return false;
if (Phi == Requested) {
InvertStep = false;
return true;
}
if (SE.getMinusSCEV(Requested->getStart(), Requested) == Phi) {
InvertStep = true;
return true;
}
return false;
}
static bool IsIncrementNSW(ScalarEvolution &SE, const SCEVAddRecExpr *AR) {
if (!isa<IntegerType>(AR->getType()))
return false;
unsigned BitWidth = cast<IntegerType>(AR->getType())->getBitWidth();
Type *WideTy = IntegerType::get(AR->getType()->getContext(), BitWidth * 2);
const SCEV *Step = AR->getStepRecurrence(SE);
const SCEV *OpAfterExtend = SE.getAddExpr(SE.getSignExtendExpr(Step, WideTy),
SE.getSignExtendExpr(AR, WideTy));
const SCEV *ExtendAfterOp =
SE.getSignExtendExpr(SE.getAddExpr(AR, Step), WideTy);
return ExtendAfterOp == OpAfterExtend;
}
static bool IsIncrementNUW(ScalarEvolution &SE, const SCEVAddRecExpr *AR) {
if (!isa<IntegerType>(AR->getType()))
return false;
unsigned BitWidth = cast<IntegerType>(AR->getType())->getBitWidth();
Type *WideTy = IntegerType::get(AR->getType()->getContext(), BitWidth * 2);
const SCEV *Step = AR->getStepRecurrence(SE);
const SCEV *OpAfterExtend = SE.getAddExpr(SE.getZeroExtendExpr(Step, WideTy),
SE.getZeroExtendExpr(AR, WideTy));
const SCEV *ExtendAfterOp =
SE.getZeroExtendExpr(SE.getAddExpr(AR, Step), WideTy);
return ExtendAfterOp == OpAfterExtend;
}
PHINode *
SCEVExpander::getAddRecExprPHILiterally(const SCEVAddRecExpr *Normalized,
const Loop *L,
Type *ExpandTy,
Type *IntTy,
Type *&TruncTy,
bool &InvertStep) {
assert((!IVIncInsertLoop||IVIncInsertPos) && "Uninitialized insert position");
BasicBlock *LatchBlock = L->getLoopLatch();
if (LatchBlock) {
PHINode *AddRecPhiMatch = nullptr;
Instruction *IncV = nullptr;
TruncTy = nullptr;
InvertStep = false;
bool TryNonMatchingSCEV =
IVIncInsertLoop &&
SE.DT.properlyDominates(LatchBlock, IVIncInsertLoop->getHeader());
for (PHINode &PN : L->getHeader()->phis()) {
if (!SE.isSCEVable(PN.getType()))
continue;
if (!PN.isComplete()) {
SCEV_DEBUG_WITH_TYPE(
DebugType, dbgs() << "One incomplete PHI is found: " << PN << "\n");
continue;
}
const SCEVAddRecExpr *PhiSCEV = dyn_cast<SCEVAddRecExpr>(SE.getSCEV(&PN));
if (!PhiSCEV)
continue;
bool IsMatchingSCEV = PhiSCEV == Normalized;
if (!IsMatchingSCEV && !TryNonMatchingSCEV)
continue;
Instruction *TempIncV =
dyn_cast<Instruction>(PN.getIncomingValueForBlock(LatchBlock));
if (!TempIncV)
continue;
if (LSRMode) {
if (!isExpandedAddRecExprPHI(&PN, TempIncV, L))
continue;
} else {
if (!isNormalAddRecExprPHI(&PN, TempIncV, L))
continue;
}
if (IsMatchingSCEV) {
IncV = TempIncV;
TruncTy = nullptr;
InvertStep = false;
AddRecPhiMatch = &PN;
break;
}
if ((!TruncTy || InvertStep) &&
canBeCheaplyTransformed(SE, PhiSCEV, Normalized, InvertStep)) {
AddRecPhiMatch = &PN;
IncV = TempIncV;
TruncTy = SE.getEffectiveSCEVType(Normalized->getType());
}
}
if (AddRecPhiMatch) {
InsertedValues.insert(AddRecPhiMatch);
rememberInstruction(IncV);
ReusedValues.insert(AddRecPhiMatch);
ReusedValues.insert(IncV);
return AddRecPhiMatch;
}
}
SCEVInsertPointGuard Guard(Builder, this);
PostIncLoopSet SavedPostIncLoops = PostIncLoops;
PostIncLoops.clear();
assert(L->getLoopPreheader() &&
"Can't expand add recurrences without a loop preheader!");
Value *StartV =
expandCodeForImpl(Normalized->getStart(), ExpandTy,
L->getLoopPreheader()->getTerminator(), false);
assert(!isa<Instruction>(StartV) ||
SE.DT.properlyDominates(cast<Instruction>(StartV)->getParent(),
L->getHeader()));
const SCEV *Step = Normalized->getStepRecurrence(SE);
bool useSubtract = !ExpandTy->isPointerTy() && Step->isNonConstantNegative();
if (useSubtract)
Step = SE.getNegativeSCEV(Step);
Value *StepV = expandCodeForImpl(
Step, IntTy, &*L->getHeader()->getFirstInsertionPt(), false);
bool IncrementIsNUW = !useSubtract && IsIncrementNUW(SE, Normalized);
bool IncrementIsNSW = !useSubtract && IsIncrementNSW(SE, Normalized);
BasicBlock *Header = L->getHeader();
Builder.SetInsertPoint(Header, Header->begin());
pred_iterator HPB = pred_begin(Header), HPE = pred_end(Header);
PHINode *PN = Builder.CreatePHI(ExpandTy, std::distance(HPB, HPE),
Twine(IVName) + ".iv");
for (pred_iterator HPI = HPB; HPI != HPE; ++HPI) {
BasicBlock *Pred = *HPI;
if (!L->contains(Pred)) {
PN->addIncoming(StartV, Pred);
continue;
}
Instruction *InsertPos = L == IVIncInsertLoop ?
IVIncInsertPos : Pred->getTerminator();
Builder.SetInsertPoint(InsertPos);
Value *IncV = expandIVInc(PN, StepV, L, ExpandTy, IntTy, useSubtract);
if (isa<OverflowingBinaryOperator>(IncV)) {
if (IncrementIsNUW)
cast<BinaryOperator>(IncV)->setHasNoUnsignedWrap();
if (IncrementIsNSW)
cast<BinaryOperator>(IncV)->setHasNoSignedWrap();
}
PN->addIncoming(IncV, Pred);
}
PostIncLoops = SavedPostIncLoops;
InsertedValues.insert(PN);
InsertedIVs.push_back(PN);
return PN;
}
Value *SCEVExpander::expandAddRecExprLiterally(const SCEVAddRecExpr *S) {
Type *STy = S->getType();
Type *IntTy = SE.getEffectiveSCEVType(STy);
const Loop *L = S->getLoop();
const SCEVAddRecExpr *Normalized = S;
if (PostIncLoops.count(L)) {
PostIncLoopSet Loops;
Loops.insert(L);
Normalized = cast<SCEVAddRecExpr>(normalizeForPostIncUse(S, Loops, SE));
}
const SCEV *Start = Normalized->getStart();
const SCEV *PostLoopOffset = nullptr;
if (!SE.properlyDominates(Start, L->getHeader())) {
PostLoopOffset = Start;
Start = SE.getConstant(Normalized->getType(), 0);
Normalized = cast<SCEVAddRecExpr>(
SE.getAddRecExpr(Start, Normalized->getStepRecurrence(SE),
Normalized->getLoop(),
Normalized->getNoWrapFlags(SCEV::FlagNW)));
}
const SCEV *Step = Normalized->getStepRecurrence(SE);
const SCEV *PostLoopScale = nullptr;
if (!SE.dominates(Step, L->getHeader())) {
PostLoopScale = Step;
Step = SE.getConstant(Normalized->getType(), 1);
if (!Start->isZero()) {
assert(!PostLoopOffset && "Start not-null but PostLoopOffset set?");
PostLoopOffset = Start;
Start = SE.getConstant(Normalized->getType(), 0);
}
Normalized =
cast<SCEVAddRecExpr>(SE.getAddRecExpr(
Start, Step, Normalized->getLoop(),
Normalized->getNoWrapFlags(SCEV::FlagNW)));
}
Type *ExpandTy = PostLoopScale ? IntTy : STy;
Type *AddRecPHIExpandTy =
DL.isNonIntegralPointerType(STy) ? Normalized->getType() : ExpandTy;
Type *TruncTy = nullptr;
bool InvertStep = false;
PHINode *PN = getAddRecExprPHILiterally(Normalized, L, AddRecPHIExpandTy,
IntTy, TruncTy, InvertStep);
Value *Result;
if (!PostIncLoops.count(L))
Result = PN;
else {
BasicBlock *LatchBlock = L->getLoopLatch();
assert(LatchBlock && "PostInc mode requires a unique loop latch!");
Result = PN->getIncomingValueForBlock(LatchBlock);
if (isa<OverflowingBinaryOperator>(Result)) {
auto *I = cast<Instruction>(Result);
if (!S->hasNoUnsignedWrap())
I->setHasNoUnsignedWrap(false);
if (!S->hasNoSignedWrap())
I->setHasNoSignedWrap(false);
}
if (isa<Instruction>(Result) &&
!SE.DT.dominates(cast<Instruction>(Result),
&*Builder.GetInsertPoint())) {
bool useSubtract =
!ExpandTy->isPointerTy() && Step->isNonConstantNegative();
if (useSubtract)
Step = SE.getNegativeSCEV(Step);
Value *StepV;
{
SCEVInsertPointGuard Guard(Builder, this);
StepV = expandCodeForImpl(
Step, IntTy, &*L->getHeader()->getFirstInsertionPt(), false);
}
Result = expandIVInc(PN, StepV, L, ExpandTy, IntTy, useSubtract);
}
}
if (TruncTy) {
Type *ResTy = Result->getType();
if (ResTy != SE.getEffectiveSCEVType(ResTy))
Result = InsertNoopCastOfTo(Result, SE.getEffectiveSCEVType(ResTy));
if (TruncTy != Result->getType())
Result = Builder.CreateTrunc(Result, TruncTy);
if (InvertStep)
Result = Builder.CreateSub(
expandCodeForImpl(Normalized->getStart(), TruncTy, false), Result);
}
if (PostLoopScale) {
assert(S->isAffine() && "Can't linearly scale non-affine recurrences.");
Result = InsertNoopCastOfTo(Result, IntTy);
Result = Builder.CreateMul(Result,
expandCodeForImpl(PostLoopScale, IntTy, false));
}
if (PostLoopOffset) {
if (PointerType *PTy = dyn_cast<PointerType>(ExpandTy)) {
if (Result->getType()->isIntegerTy()) {
Value *Base = expandCodeForImpl(PostLoopOffset, ExpandTy, false);
Result = expandAddToGEP(SE.getUnknown(Result), PTy, IntTy, Base);
} else {
Result = expandAddToGEP(PostLoopOffset, PTy, IntTy, Result);
}
} else {
Result = InsertNoopCastOfTo(Result, IntTy);
Result = Builder.CreateAdd(
Result, expandCodeForImpl(PostLoopOffset, IntTy, false));
}
}
return Result;
}
Value *SCEVExpander::visitAddRecExpr(const SCEVAddRecExpr *S) {
if (!CanonicalMode || (S->getNumOperands() > 2))
return expandAddRecExprLiterally(S);
Type *Ty = SE.getEffectiveSCEVType(S->getType());
const Loop *L = S->getLoop();
PHINode *CanonicalIV = nullptr;
if (PHINode *PN = L->getCanonicalInductionVariable())
if (SE.getTypeSizeInBits(PN->getType()) >= SE.getTypeSizeInBits(Ty))
CanonicalIV = PN;
if (CanonicalIV &&
SE.getTypeSizeInBits(CanonicalIV->getType()) > SE.getTypeSizeInBits(Ty) &&
!S->getType()->isPointerTy()) {
SmallVector<const SCEV *, 4> NewOps(S->getNumOperands());
for (unsigned i = 0, e = S->getNumOperands(); i != e; ++i)
NewOps[i] = SE.getAnyExtendExpr(S->op_begin()[i], CanonicalIV->getType());
Value *V = expand(SE.getAddRecExpr(NewOps, S->getLoop(),
S->getNoWrapFlags(SCEV::FlagNW)));
BasicBlock::iterator NewInsertPt =
findInsertPointAfter(cast<Instruction>(V), &*Builder.GetInsertPoint());
V = expandCodeForImpl(SE.getTruncateExpr(SE.getUnknown(V), Ty), nullptr,
&*NewInsertPt, false);
return V;
}
if (!S->getStart()->isZero()) {
if (PointerType *PTy = dyn_cast<PointerType>(S->getType())) {
Value *StartV = expand(SE.getPointerBase(S));
assert(StartV->getType() == PTy && "Pointer type mismatch for GEP!");
return expandAddToGEP(SE.removePointerBase(S), PTy, Ty, StartV);
}
SmallVector<const SCEV *, 4> NewOps(S->operands());
NewOps[0] = SE.getConstant(Ty, 0);
const SCEV *Rest = SE.getAddRecExpr(NewOps, L,
S->getNoWrapFlags(SCEV::FlagNW));
const SCEV *AddExprLHS = SE.getUnknown(expand(S->getStart()));
const SCEV *AddExprRHS = SE.getUnknown(expand(Rest));
return expand(SE.getAddExpr(AddExprLHS, AddExprRHS));
}
if (!CanonicalIV) {
BasicBlock *Header = L->getHeader();
pred_iterator HPB = pred_begin(Header), HPE = pred_end(Header);
CanonicalIV = PHINode::Create(Ty, std::distance(HPB, HPE), "indvar",
&Header->front());
rememberInstruction(CanonicalIV);
SmallSet<BasicBlock *, 4> PredSeen;
Constant *One = ConstantInt::get(Ty, 1);
for (pred_iterator HPI = HPB; HPI != HPE; ++HPI) {
BasicBlock *HP = *HPI;
if (!PredSeen.insert(HP).second) {
CanonicalIV->addIncoming(CanonicalIV->getIncomingValueForBlock(HP), HP);
continue;
}
if (L->contains(HP)) {
Instruction *Add = BinaryOperator::CreateAdd(CanonicalIV, One,
"indvar.next",
HP->getTerminator());
Add->setDebugLoc(HP->getTerminator()->getDebugLoc());
rememberInstruction(Add);
CanonicalIV->addIncoming(Add, HP);
} else {
CanonicalIV->addIncoming(Constant::getNullValue(Ty), HP);
}
}
}
if (S->isAffine() && S->getOperand(1)->isOne()) {
assert(Ty == SE.getEffectiveSCEVType(CanonicalIV->getType()) &&
"IVs with types different from the canonical IV should "
"already have been handled!");
return CanonicalIV;
}
if (S->isAffine()) return
expand(SE.getTruncateOrNoop(
SE.getMulExpr(SE.getUnknown(CanonicalIV),
SE.getNoopOrAnyExtend(S->getOperand(1),
CanonicalIV->getType())),
Ty));
const SCEV *IH = SE.getUnknown(CanonicalIV);
const SCEV *NewS = S;
const SCEV *Ext = SE.getNoopOrAnyExtend(S, CanonicalIV->getType());
if (isa<SCEVAddRecExpr>(Ext))
NewS = Ext;
const SCEV *V = cast<SCEVAddRecExpr>(NewS)->evaluateAtIteration(IH, SE);
const SCEV *T = SE.getTruncateOrNoop(V, Ty);
return expand(T);
}
Value *SCEVExpander::visitPtrToIntExpr(const SCEVPtrToIntExpr *S) {
Value *V =
expandCodeForImpl(S->getOperand(), S->getOperand()->getType(), false);
return ReuseOrCreateCast(V, S->getType(), CastInst::PtrToInt,
GetOptimalInsertionPointForCastOf(V));
}
Value *SCEVExpander::visitTruncateExpr(const SCEVTruncateExpr *S) {
Type *Ty = SE.getEffectiveSCEVType(S->getType());
Value *V = expandCodeForImpl(
S->getOperand(), SE.getEffectiveSCEVType(S->getOperand()->getType()),
false);
return Builder.CreateTrunc(V, Ty);
}
Value *SCEVExpander::visitZeroExtendExpr(const SCEVZeroExtendExpr *S) {
Type *Ty = SE.getEffectiveSCEVType(S->getType());
Value *V = expandCodeForImpl(
S->getOperand(), SE.getEffectiveSCEVType(S->getOperand()->getType()),
false);
return Builder.CreateZExt(V, Ty);
}
Value *SCEVExpander::visitSignExtendExpr(const SCEVSignExtendExpr *S) {
Type *Ty = SE.getEffectiveSCEVType(S->getType());
Value *V = expandCodeForImpl(
S->getOperand(), SE.getEffectiveSCEVType(S->getOperand()->getType()),
false);
return Builder.CreateSExt(V, Ty);
}
Value *SCEVExpander::expandMinMaxExpr(const SCEVNAryExpr *S,
Intrinsic::ID IntrinID, Twine Name,
bool IsSequential) {
Value *LHS = expand(S->getOperand(S->getNumOperands() - 1));
Type *Ty = LHS->getType();
if (IsSequential)
LHS = Builder.CreateFreeze(LHS);
for (int i = S->getNumOperands() - 2; i >= 0; --i) {
Value *RHS = expandCodeForImpl(S->getOperand(i), Ty, false);
if (IsSequential && i != 0)
RHS = Builder.CreateFreeze(RHS);
Value *Sel;
if (Ty->isIntegerTy())
Sel = Builder.CreateIntrinsic(IntrinID, {Ty}, {LHS, RHS},
nullptr, Name);
else {
Value *ICmp =
Builder.CreateICmp(MinMaxIntrinsic::getPredicate(IntrinID), LHS, RHS);
Sel = Builder.CreateSelect(ICmp, LHS, RHS, Name);
}
LHS = Sel;
}
return LHS;
}
Value *SCEVExpander::visitSMaxExpr(const SCEVSMaxExpr *S) {
return expandMinMaxExpr(S, Intrinsic::smax, "smax");
}
Value *SCEVExpander::visitUMaxExpr(const SCEVUMaxExpr *S) {
return expandMinMaxExpr(S, Intrinsic::umax, "umax");
}
Value *SCEVExpander::visitSMinExpr(const SCEVSMinExpr *S) {
return expandMinMaxExpr(S, Intrinsic::smin, "smin");
}
Value *SCEVExpander::visitUMinExpr(const SCEVUMinExpr *S) {
return expandMinMaxExpr(S, Intrinsic::umin, "umin");
}
Value *SCEVExpander::visitSequentialUMinExpr(const SCEVSequentialUMinExpr *S) {
return expandMinMaxExpr(S, Intrinsic::umin, "umin", true);
}
Value *SCEVExpander::expandCodeForImpl(const SCEV *SH, Type *Ty,
Instruction *IP, bool Root) {
setInsertPoint(IP);
Value *V = expandCodeForImpl(SH, Ty, Root);
return V;
}
Value *SCEVExpander::expandCodeForImpl(const SCEV *SH, Type *Ty, bool Root) {
Value *V = expand(SH);
if (PreserveLCSSA) {
if (auto *Inst = dyn_cast<Instruction>(V)) {
Instruction *Tmp;
if (Inst->getType()->isIntegerTy())
Tmp = cast<Instruction>(Builder.CreateIntToPtr(
Inst, Inst->getType()->getPointerTo(), "tmp.lcssa.user"));
else {
assert(Inst->getType()->isPointerTy());
Tmp = cast<Instruction>(Builder.CreatePtrToInt(
Inst, Type::getInt32Ty(Inst->getContext()), "tmp.lcssa.user"));
}
V = fixupLCSSAFormFor(Tmp, 0);
InsertedValues.erase(Tmp);
InsertedPostIncValues.erase(Tmp);
Tmp->eraseFromParent();
}
}
InsertedExpressions[std::make_pair(SH, &*Builder.GetInsertPoint())] = V;
if (Ty) {
assert(SE.getTypeSizeInBits(Ty) == SE.getTypeSizeInBits(SH->getType()) &&
"non-trivial casts should be done with the SCEVs directly!");
V = InsertNoopCastOfTo(V, Ty);
}
return V;
}
Value *SCEVExpander::FindValueInExprValueMap(const SCEV *S,
const Instruction *InsertPt) {
if (!CanonicalMode && SE.containsAddRecurrence(S))
return nullptr;
if (isa<SCEVConstant>(S))
return nullptr;
for (Value *V : SE.getSCEVValues(S)) {
Instruction *EntInst = dyn_cast<Instruction>(V);
if (!EntInst)
continue;
assert(EntInst->getFunction() == InsertPt->getFunction());
if (S->getType() == V->getType() &&
SE.DT.dominates(EntInst, InsertPt) &&
(SE.LI.getLoopFor(EntInst->getParent()) == nullptr ||
SE.LI.getLoopFor(EntInst->getParent())->contains(InsertPt)))
return V;
}
return nullptr;
}
Value *SCEVExpander::expand(const SCEV *S) {
Instruction *InsertPt = &*Builder.GetInsertPoint();
auto SafeToHoist = [](const SCEV *S) {
return !SCEVExprContains(S, [](const SCEV *S) {
if (const auto *D = dyn_cast<SCEVUDivExpr>(S)) {
if (const auto *SC = dyn_cast<SCEVConstant>(D->getRHS()))
return SC->getValue()->isZero();
return true;
}
return false;
});
};
if (SafeToHoist(S)) {
for (Loop *L = SE.LI.getLoopFor(Builder.GetInsertBlock());;
L = L->getParentLoop()) {
if (SE.isLoopInvariant(S, L)) {
if (!L) break;
if (BasicBlock *Preheader = L->getLoopPreheader())
InsertPt = Preheader->getTerminator();
else
InsertPt = &*L->getHeader()->getFirstInsertionPt();
} else {
if (L && SE.hasComputableLoopEvolution(S, L) && !PostIncLoops.count(L))
InsertPt = &*L->getHeader()->getFirstInsertionPt();
while (InsertPt->getIterator() != Builder.GetInsertPoint() &&
(isInsertedInstruction(InsertPt) ||
isa<DbgInfoIntrinsic>(InsertPt))) {
InsertPt = &*std::next(InsertPt->getIterator());
}
break;
}
}
}
auto I = InsertedExpressions.find(std::make_pair(S, InsertPt));
if (I != InsertedExpressions.end())
return I->second;
SCEVInsertPointGuard Guard(Builder, this);
Builder.SetInsertPoint(InsertPt);
Value *V = FindValueInExprValueMap(S, InsertPt);
if (!V)
V = visit(S);
else {
if (auto *I = dyn_cast<Instruction>(V))
if (I->hasPoisonGeneratingFlags() && !programUndefinedIfPoison(I))
I->dropPoisonGeneratingFlags();
}
InsertedExpressions[std::make_pair(S, InsertPt)] = V;
return V;
}
void SCEVExpander::rememberInstruction(Value *I) {
auto DoInsert = [this](Value *V) {
if (!PostIncLoops.empty())
InsertedPostIncValues.insert(V);
else
InsertedValues.insert(V);
};
DoInsert(I);
if (!PreserveLCSSA)
return;
if (auto *Inst = dyn_cast<Instruction>(I)) {
for (unsigned OpIdx = 0, OpEnd = Inst->getNumOperands(); OpIdx != OpEnd;
OpIdx++)
fixupLCSSAFormFor(Inst, OpIdx);
}
}
unsigned
SCEVExpander::replaceCongruentIVs(Loop *L, const DominatorTree *DT,
SmallVectorImpl<WeakTrackingVH> &DeadInsts,
const TargetTransformInfo *TTI) {
SmallVector<PHINode*, 8> Phis;
for (PHINode &PN : L->getHeader()->phis())
Phis.push_back(&PN);
if (TTI)
llvm::stable_sort(Phis, [](Value *LHS, Value *RHS) {
if (!LHS->getType()->isIntegerTy() || !RHS->getType()->isIntegerTy())
return RHS->getType()->isIntegerTy() && !LHS->getType()->isIntegerTy();
return RHS->getType()->getPrimitiveSizeInBits().getFixedSize() <
LHS->getType()->getPrimitiveSizeInBits().getFixedSize();
});
unsigned NumElim = 0;
DenseMap<const SCEV *, PHINode *> ExprToIVMap;
for (PHINode *Phi : Phis) {
auto SimplifyPHINode = [&](PHINode *PN) -> Value * {
if (Value *V = simplifyInstruction(PN, {DL, &SE.TLI, &SE.DT, &SE.AC}))
return V;
if (!SE.isSCEVable(PN->getType()))
return nullptr;
auto *Const = dyn_cast<SCEVConstant>(SE.getSCEV(PN));
if (!Const)
return nullptr;
return Const->getValue();
};
if (Value *V = SimplifyPHINode(Phi)) {
if (V->getType() != Phi->getType())
continue;
Phi->replaceAllUsesWith(V);
DeadInsts.emplace_back(Phi);
++NumElim;
SCEV_DEBUG_WITH_TYPE(DebugType,
dbgs() << "INDVARS: Eliminated constant iv: " << *Phi
<< '\n');
continue;
}
if (!SE.isSCEVable(Phi->getType()))
continue;
PHINode *&OrigPhiRef = ExprToIVMap[SE.getSCEV(Phi)];
if (!OrigPhiRef) {
OrigPhiRef = Phi;
if (Phi->getType()->isIntegerTy() && TTI &&
TTI->isTruncateFree(Phi->getType(), Phis.back()->getType())) {
const SCEV *TruncExpr =
SE.getTruncateExpr(SE.getSCEV(Phi), Phis.back()->getType());
ExprToIVMap[TruncExpr] = Phi;
}
continue;
}
if (OrigPhiRef->getType()->isPointerTy() != Phi->getType()->isPointerTy())
continue;
if (BasicBlock *LatchBlock = L->getLoopLatch()) {
Instruction *OrigInc = dyn_cast<Instruction>(
OrigPhiRef->getIncomingValueForBlock(LatchBlock));
Instruction *IsomorphicInc =
dyn_cast<Instruction>(Phi->getIncomingValueForBlock(LatchBlock));
if (OrigInc && IsomorphicInc) {
if (OrigPhiRef->getType() == Phi->getType() &&
!(ChainedPhis.count(Phi) ||
isExpandedAddRecExprPHI(OrigPhiRef, OrigInc, L)) &&
(ChainedPhis.count(Phi) ||
isExpandedAddRecExprPHI(Phi, IsomorphicInc, L))) {
std::swap(OrigPhiRef, Phi);
std::swap(OrigInc, IsomorphicInc);
}
const SCEV *TruncExpr =
SE.getTruncateOrNoop(SE.getSCEV(OrigInc), IsomorphicInc->getType());
if (OrigInc != IsomorphicInc &&
TruncExpr == SE.getSCEV(IsomorphicInc) &&
SE.LI.replacementPreservesLCSSAForm(IsomorphicInc, OrigInc) &&
hoistIVInc(OrigInc, IsomorphicInc)) {
SCEV_DEBUG_WITH_TYPE(
DebugType, dbgs() << "INDVARS: Eliminated congruent iv.inc: "
<< *IsomorphicInc << '\n');
Value *NewInc = OrigInc;
if (OrigInc->getType() != IsomorphicInc->getType()) {
Instruction *IP = nullptr;
if (PHINode *PN = dyn_cast<PHINode>(OrigInc))
IP = &*PN->getParent()->getFirstInsertionPt();
else
IP = OrigInc->getNextNode();
IRBuilder<> Builder(IP);
Builder.SetCurrentDebugLocation(IsomorphicInc->getDebugLoc());
NewInc = Builder.CreateTruncOrBitCast(
OrigInc, IsomorphicInc->getType(), IVName);
}
IsomorphicInc->replaceAllUsesWith(NewInc);
DeadInsts.emplace_back(IsomorphicInc);
}
}
}
SCEV_DEBUG_WITH_TYPE(DebugType,
dbgs() << "INDVARS: Eliminated congruent iv: " << *Phi
<< '\n');
SCEV_DEBUG_WITH_TYPE(
DebugType, dbgs() << "INDVARS: Original iv: " << *OrigPhiRef << '\n');
++NumElim;
Value *NewIV = OrigPhiRef;
if (OrigPhiRef->getType() != Phi->getType()) {
IRBuilder<> Builder(&*L->getHeader()->getFirstInsertionPt());
Builder.SetCurrentDebugLocation(Phi->getDebugLoc());
NewIV = Builder.CreateTruncOrBitCast(OrigPhiRef, Phi->getType(), IVName);
}
Phi->replaceAllUsesWith(NewIV);
DeadInsts.emplace_back(Phi);
}
return NumElim;
}
Value *SCEVExpander::getRelatedExistingExpansion(const SCEV *S,
const Instruction *At,
Loop *L) {
using namespace llvm::PatternMatch;
SmallVector<BasicBlock *, 4> ExitingBlocks;
L->getExitingBlocks(ExitingBlocks);
for (BasicBlock *BB : ExitingBlocks) {
ICmpInst::Predicate Pred;
Instruction *LHS, *RHS;
if (!match(BB->getTerminator(),
m_Br(m_ICmp(Pred, m_Instruction(LHS), m_Instruction(RHS)),
m_BasicBlock(), m_BasicBlock())))
continue;
if (SE.getSCEV(LHS) == S && SE.DT.dominates(LHS, At))
return LHS;
if (SE.getSCEV(RHS) == S && SE.DT.dominates(RHS, At))
return RHS;
}
return FindValueInExprValueMap(S, At);
}
template<typename T> static InstructionCost costAndCollectOperands(
const SCEVOperand &WorkItem, const TargetTransformInfo &TTI,
TargetTransformInfo::TargetCostKind CostKind,
SmallVectorImpl<SCEVOperand> &Worklist) {
const T *S = cast<T>(WorkItem.S);
InstructionCost Cost = 0;
struct OperationIndices {
OperationIndices(unsigned Opc, size_t min, size_t max) :
Opcode(Opc), MinIdx(min), MaxIdx(max) { }
unsigned Opcode;
size_t MinIdx;
size_t MaxIdx;
};
SmallVector<OperationIndices, 2> Operations;
auto CastCost = [&](unsigned Opcode) -> InstructionCost {
Operations.emplace_back(Opcode, 0, 0);
return TTI.getCastInstrCost(Opcode, S->getType(),
S->getOperand(0)->getType(),
TTI::CastContextHint::None, CostKind);
};
auto ArithCost = [&](unsigned Opcode, unsigned NumRequired,
unsigned MinIdx = 0,
unsigned MaxIdx = 1) -> InstructionCost {
Operations.emplace_back(Opcode, MinIdx, MaxIdx);
return NumRequired *
TTI.getArithmeticInstrCost(Opcode, S->getType(), CostKind);
};
auto CmpSelCost = [&](unsigned Opcode, unsigned NumRequired, unsigned MinIdx,
unsigned MaxIdx) -> InstructionCost {
Operations.emplace_back(Opcode, MinIdx, MaxIdx);
Type *OpType = S->getOperand(0)->getType();
return NumRequired * TTI.getCmpSelInstrCost(
Opcode, OpType, CmpInst::makeCmpResultType(OpType),
CmpInst::BAD_ICMP_PREDICATE, CostKind);
};
switch (S->getSCEVType()) {
case scCouldNotCompute:
llvm_unreachable("Attempt to use a SCEVCouldNotCompute object!");
case scUnknown:
case scConstant:
return 0;
case scPtrToInt:
Cost = CastCost(Instruction::PtrToInt);
break;
case scTruncate:
Cost = CastCost(Instruction::Trunc);
break;
case scZeroExtend:
Cost = CastCost(Instruction::ZExt);
break;
case scSignExtend:
Cost = CastCost(Instruction::SExt);
break;
case scUDivExpr: {
unsigned Opcode = Instruction::UDiv;
if (auto *SC = dyn_cast<SCEVConstant>(S->getOperand(1)))
if (SC->getAPInt().isPowerOf2())
Opcode = Instruction::LShr;
Cost = ArithCost(Opcode, 1);
break;
}
case scAddExpr:
Cost = ArithCost(Instruction::Add, S->getNumOperands() - 1);
break;
case scMulExpr:
Cost = ArithCost(Instruction::Mul, S->getNumOperands() - 1);
break;
case scSMaxExpr:
case scUMaxExpr:
case scSMinExpr:
case scUMinExpr:
case scSequentialUMinExpr: {
Cost += CmpSelCost(Instruction::ICmp, S->getNumOperands() - 1, 0, 1);
Cost += CmpSelCost(Instruction::Select, S->getNumOperands() - 1, 0, 2);
switch (S->getSCEVType()) {
case scSequentialUMinExpr: {
Cost += CmpSelCost(Instruction::ICmp, S->getNumOperands() - 1, 0, 0);
Cost += ArithCost(Instruction::Or,
S->getNumOperands() > 2 ? S->getNumOperands() - 2 : 0);
Cost += CmpSelCost(Instruction::Select, 1, 0, 1);
break;
}
default:
assert(!isa<SCEVSequentialMinMaxExpr>(S) &&
"Unhandled SCEV expression type?");
break;
}
break;
}
case scAddRecExpr: {
int NumTerms = llvm::count_if(S->operands(), [](const SCEV *Op) {
return !Op->isZero();
});
assert(NumTerms >= 1 && "Polynominal should have at least one term.");
assert(!(*std::prev(S->operands().end()))->isZero() &&
"Last operand should not be zero");
int NumNonZeroDegreeNonOneTerms =
llvm::count_if(S->operands(), [](const SCEV *Op) {
auto *SConst = dyn_cast<SCEVConstant>(Op);
return !SConst || SConst->getAPInt().ugt(1);
});
InstructionCost AddCost = ArithCost(Instruction::Add, NumTerms - 1,
1, 1);
InstructionCost MulCost =
ArithCost(Instruction::Mul, NumNonZeroDegreeNonOneTerms);
Cost = AddCost + MulCost;
int PolyDegree = S->getNumOperands() - 1;
assert(PolyDegree >= 1 && "Should be at least affine.");
Cost += MulCost * (PolyDegree - 1);
break;
}
}
for (auto &CostOp : Operations) {
for (auto SCEVOp : enumerate(S->operands())) {
size_t MinIdx = std::max(SCEVOp.index(), CostOp.MinIdx);
size_t OpIdx = std::min(MinIdx, CostOp.MaxIdx);
Worklist.emplace_back(CostOp.Opcode, OpIdx, SCEVOp.value());
}
}
return Cost;
}
bool SCEVExpander::isHighCostExpansionHelper(
const SCEVOperand &WorkItem, Loop *L, const Instruction &At,
InstructionCost &Cost, unsigned Budget, const TargetTransformInfo &TTI,
SmallPtrSetImpl<const SCEV *> &Processed,
SmallVectorImpl<SCEVOperand> &Worklist) {
if (Cost > Budget)
return true;
const SCEV *S = WorkItem.S;
if (!isa<SCEVConstant>(S) && !Processed.insert(S).second)
return false;
if (getRelatedExistingExpansion(S, &At, L))
return false;
TargetTransformInfo::TargetCostKind CostKind =
L->getHeader()->getParent()->hasMinSize()
? TargetTransformInfo::TCK_CodeSize
: TargetTransformInfo::TCK_RecipThroughput;
switch (S->getSCEVType()) {
case scCouldNotCompute:
llvm_unreachable("Attempt to use a SCEVCouldNotCompute object!");
case scUnknown:
return false;
case scConstant: {
if (CostKind != TargetTransformInfo::TCK_CodeSize)
return false;
const APInt &Imm = cast<SCEVConstant>(S)->getAPInt();
Type *Ty = S->getType();
Cost += TTI.getIntImmCostInst(
WorkItem.ParentOpcode, WorkItem.OperandIdx, Imm, Ty, CostKind);
return Cost > Budget;
}
case scTruncate:
case scPtrToInt:
case scZeroExtend:
case scSignExtend: {
Cost +=
costAndCollectOperands<SCEVCastExpr>(WorkItem, TTI, CostKind, Worklist);
return false; }
case scUDivExpr: {
if (getRelatedExistingExpansion(
SE.getAddExpr(S, SE.getConstant(S->getType(), 1)), &At, L))
return false;
Cost +=
costAndCollectOperands<SCEVUDivExpr>(WorkItem, TTI, CostKind, Worklist);
return false; }
case scAddExpr:
case scMulExpr:
case scUMaxExpr:
case scSMaxExpr:
case scUMinExpr:
case scSMinExpr:
case scSequentialUMinExpr: {
assert(cast<SCEVNAryExpr>(S)->getNumOperands() > 1 &&
"Nary expr should have more than 1 operand.");
Cost +=
costAndCollectOperands<SCEVNAryExpr>(WorkItem, TTI, CostKind, Worklist);
return Cost > Budget;
}
case scAddRecExpr: {
assert(cast<SCEVAddRecExpr>(S)->getNumOperands() >= 2 &&
"Polynomial should be at least linear");
Cost += costAndCollectOperands<SCEVAddRecExpr>(
WorkItem, TTI, CostKind, Worklist);
return Cost > Budget;
}
}
llvm_unreachable("Unknown SCEV kind!");
}
Value *SCEVExpander::expandCodeForPredicate(const SCEVPredicate *Pred,
Instruction *IP) {
assert(IP);
switch (Pred->getKind()) {
case SCEVPredicate::P_Union:
return expandUnionPredicate(cast<SCEVUnionPredicate>(Pred), IP);
case SCEVPredicate::P_Compare:
return expandComparePredicate(cast<SCEVComparePredicate>(Pred), IP);
case SCEVPredicate::P_Wrap: {
auto *AddRecPred = cast<SCEVWrapPredicate>(Pred);
return expandWrapPredicate(AddRecPred, IP);
}
}
llvm_unreachable("Unknown SCEV predicate type");
}
Value *SCEVExpander::expandComparePredicate(const SCEVComparePredicate *Pred,
Instruction *IP) {
Value *Expr0 =
expandCodeForImpl(Pred->getLHS(), Pred->getLHS()->getType(), IP, false);
Value *Expr1 =
expandCodeForImpl(Pred->getRHS(), Pred->getRHS()->getType(), IP, false);
Builder.SetInsertPoint(IP);
auto InvPred = ICmpInst::getInversePredicate(Pred->getPredicate());
auto *I = Builder.CreateICmp(InvPred, Expr0, Expr1, "ident.check");
return I;
}
Value *SCEVExpander::generateOverflowCheck(const SCEVAddRecExpr *AR,
Instruction *Loc, bool Signed) {
assert(AR->isAffine() && "Cannot generate RT check for "
"non-affine expression");
SmallVector<const SCEVPredicate *, 4> Pred;
const SCEV *ExitCount =
SE.getPredicatedBackedgeTakenCount(AR->getLoop(), Pred);
assert(!isa<SCEVCouldNotCompute>(ExitCount) && "Invalid loop count");
const SCEV *Step = AR->getStepRecurrence(SE);
const SCEV *Start = AR->getStart();
Type *ARTy = AR->getType();
unsigned SrcBits = SE.getTypeSizeInBits(ExitCount->getType());
unsigned DstBits = SE.getTypeSizeInBits(ARTy);
IntegerType *CountTy = IntegerType::get(Loc->getContext(), SrcBits);
Builder.SetInsertPoint(Loc);
Value *TripCountVal = expandCodeForImpl(ExitCount, CountTy, Loc, false);
IntegerType *Ty =
IntegerType::get(Loc->getContext(), SE.getTypeSizeInBits(ARTy));
Value *StepValue = expandCodeForImpl(Step, Ty, Loc, false);
Value *NegStepValue =
expandCodeForImpl(SE.getNegativeSCEV(Step), Ty, Loc, false);
Value *StartValue = expandCodeForImpl(Start, ARTy, Loc, false);
ConstantInt *Zero =
ConstantInt::get(Loc->getContext(), APInt::getZero(DstBits));
Builder.SetInsertPoint(Loc);
Value *StepCompare = Builder.CreateICmp(ICmpInst::ICMP_SLT, StepValue, Zero);
Value *AbsStep = Builder.CreateSelect(StepCompare, NegStepValue, StepValue);
auto ComputeEndCheck = [&]() -> Value * {
if (!Signed && Start->isZero() && SE.isKnownPositive(Step))
return ConstantInt::getFalse(Loc->getContext());
Value *TruncTripCount = Builder.CreateZExtOrTrunc(TripCountVal, Ty);
Value *MulV, *OfMul;
if (Step->isOne()) {
MulV = TruncTripCount;
OfMul = ConstantInt::getFalse(MulV->getContext());
} else {
auto *MulF = Intrinsic::getDeclaration(Loc->getModule(),
Intrinsic::umul_with_overflow, Ty);
CallInst *Mul =
Builder.CreateCall(MulF, {AbsStep, TruncTripCount}, "mul");
MulV = Builder.CreateExtractValue(Mul, 0, "mul.result");
OfMul = Builder.CreateExtractValue(Mul, 1, "mul.overflow");
}
Value *Add = nullptr, *Sub = nullptr;
bool NeedPosCheck = !SE.isKnownNegative(Step);
bool NeedNegCheck = !SE.isKnownPositive(Step);
if (PointerType *ARPtrTy = dyn_cast<PointerType>(ARTy)) {
StartValue = InsertNoopCastOfTo(
StartValue, Builder.getInt8PtrTy(ARPtrTy->getAddressSpace()));
Value *NegMulV = Builder.CreateNeg(MulV);
if (NeedPosCheck)
Add = Builder.CreateGEP(Builder.getInt8Ty(), StartValue, MulV);
if (NeedNegCheck)
Sub = Builder.CreateGEP(Builder.getInt8Ty(), StartValue, NegMulV);
} else {
if (NeedPosCheck)
Add = Builder.CreateAdd(StartValue, MulV);
if (NeedNegCheck)
Sub = Builder.CreateSub(StartValue, MulV);
}
Value *EndCompareLT = nullptr;
Value *EndCompareGT = nullptr;
Value *EndCheck = nullptr;
if (NeedPosCheck)
EndCheck = EndCompareLT = Builder.CreateICmp(
Signed ? ICmpInst::ICMP_SLT : ICmpInst::ICMP_ULT, Add, StartValue);
if (NeedNegCheck)
EndCheck = EndCompareGT = Builder.CreateICmp(
Signed ? ICmpInst::ICMP_SGT : ICmpInst::ICMP_UGT, Sub, StartValue);
if (NeedPosCheck && NeedNegCheck) {
EndCheck = Builder.CreateSelect(StepCompare, EndCompareGT, EndCompareLT);
}
return Builder.CreateOr(EndCheck, OfMul);
};
Value *EndCheck = ComputeEndCheck();
if (SE.getTypeSizeInBits(CountTy) > SE.getTypeSizeInBits(Ty)) {
auto MaxVal = APInt::getMaxValue(DstBits).zext(SrcBits);
auto *BackedgeCheck =
Builder.CreateICmp(ICmpInst::ICMP_UGT, TripCountVal,
ConstantInt::get(Loc->getContext(), MaxVal));
BackedgeCheck = Builder.CreateAnd(
BackedgeCheck, Builder.CreateICmp(ICmpInst::ICMP_NE, StepValue, Zero));
EndCheck = Builder.CreateOr(EndCheck, BackedgeCheck);
}
return EndCheck;
}
Value *SCEVExpander::expandWrapPredicate(const SCEVWrapPredicate *Pred,
Instruction *IP) {
const auto *A = cast<SCEVAddRecExpr>(Pred->getExpr());
Value *NSSWCheck = nullptr, *NUSWCheck = nullptr;
if (Pred->getFlags() & SCEVWrapPredicate::IncrementNUSW)
NUSWCheck = generateOverflowCheck(A, IP, false);
if (Pred->getFlags() & SCEVWrapPredicate::IncrementNSSW)
NSSWCheck = generateOverflowCheck(A, IP, true);
if (NUSWCheck && NSSWCheck)
return Builder.CreateOr(NUSWCheck, NSSWCheck);
if (NUSWCheck)
return NUSWCheck;
if (NSSWCheck)
return NSSWCheck;
return ConstantInt::getFalse(IP->getContext());
}
Value *SCEVExpander::expandUnionPredicate(const SCEVUnionPredicate *Union,
Instruction *IP) {
SmallVector<Value *> Checks;
for (auto Pred : Union->getPredicates()) {
Checks.push_back(expandCodeForPredicate(Pred, IP));
Builder.SetInsertPoint(IP);
}
if (Checks.empty())
return ConstantInt::getFalse(IP->getContext());
return Builder.CreateOr(Checks);
}
Value *SCEVExpander::fixupLCSSAFormFor(Instruction *User, unsigned OpIdx) {
assert(PreserveLCSSA);
SmallVector<Instruction *, 1> ToUpdate;
auto *OpV = User->getOperand(OpIdx);
auto *OpI = dyn_cast<Instruction>(OpV);
if (!OpI)
return OpV;
Loop *DefLoop = SE.LI.getLoopFor(OpI->getParent());
Loop *UseLoop = SE.LI.getLoopFor(User->getParent());
if (!DefLoop || UseLoop == DefLoop || DefLoop->contains(UseLoop))
return OpV;
ToUpdate.push_back(OpI);
SmallVector<PHINode *, 16> PHIsToRemove;
formLCSSAForInstructions(ToUpdate, SE.DT, SE.LI, &SE, Builder, &PHIsToRemove);
for (PHINode *PN : PHIsToRemove) {
if (!PN->use_empty())
continue;
InsertedValues.erase(PN);
InsertedPostIncValues.erase(PN);
PN->eraseFromParent();
}
return User->getOperand(OpIdx);
}
namespace {
struct SCEVFindUnsafe {
ScalarEvolution &SE;
bool CanonicalMode;
bool IsUnsafe = false;
SCEVFindUnsafe(ScalarEvolution &SE, bool CanonicalMode)
: SE(SE), CanonicalMode(CanonicalMode) {}
bool follow(const SCEV *S) {
if (const SCEVUDivExpr *D = dyn_cast<SCEVUDivExpr>(S)) {
if (!SE.isKnownNonZero(D->getRHS())) {
IsUnsafe = true;
return false;
}
}
if (const SCEVAddRecExpr *AR = dyn_cast<SCEVAddRecExpr>(S)) {
const SCEV *Step = AR->getStepRecurrence(SE);
if (!AR->isAffine() && !SE.dominates(Step, AR->getLoop()->getHeader())) {
IsUnsafe = true;
return false;
}
if (!AR->getLoop()->getLoopPreheader() &&
(!CanonicalMode || !AR->isAffine())) {
IsUnsafe = true;
return false;
}
}
return true;
}
bool isDone() const { return IsUnsafe; }
};
}
bool SCEVExpander::isSafeToExpand(const SCEV *S) const {
SCEVFindUnsafe Search(SE, CanonicalMode);
visitAll(S, Search);
return !Search.IsUnsafe;
}
bool SCEVExpander::isSafeToExpandAt(const SCEV *S,
const Instruction *InsertionPoint) const {
if (!isSafeToExpand(S))
return false;
if (SE.properlyDominates(S, InsertionPoint->getParent()))
return true;
if (SE.dominates(S, InsertionPoint->getParent())) {
if (InsertionPoint->getParent()->getTerminator() == InsertionPoint)
return true;
if (const SCEVUnknown *U = dyn_cast<SCEVUnknown>(S))
if (llvm::is_contained(InsertionPoint->operand_values(), U->getValue()))
return true;
}
return false;
}
void SCEVExpanderCleaner::cleanup() {
if (ResultUsed)
return;
auto InsertedInstructions = Expander.getAllInsertedInstructions();
#ifndef NDEBUG
SmallPtrSet<Instruction *, 8> InsertedSet(InsertedInstructions.begin(),
InsertedInstructions.end());
(void)InsertedSet;
#endif
Expander.clear();
for (Instruction *I : reverse(InsertedInstructions)) {
#ifndef NDEBUG
assert(all_of(I->users(),
[&InsertedSet](Value *U) {
return InsertedSet.contains(cast<Instruction>(U));
}) &&
"removed instruction should only be used by instructions inserted "
"during expansion");
#endif
assert(!I->getType()->isVoidTy() &&
"inserted instruction should have non-void types");
I->replaceAllUsesWith(UndefValue::get(I->getType()));
I->eraseFromParent();
}
}