29#include "llvm/IR/PatternMatch.h"
32#include "llvm/Analysis/ScalarEvolutionExpressions.h"
41 cl::desc(
"Place 8 bools together in a single byte"));
45 cl::desc(
"Zero initialize the cache"));
49 cl::desc(
"Enable Enzyme to print performance info"));
52 "enzyme-max-cache", cl::init(
false), cl::Hidden,
54 "Avoid reallocs when possible by potentially overallocating cache"));
57 "enzyme-rewrite-accumulators", cl::init(
true), cl::Hidden,
58 cl::desc(
"Rewrite a loop-carried counter whose step is an inner loop's "
59 "trip count into a closed form of the induction variable"));
73 if (
auto AI = dyn_cast<AllocaInst>(I)) {
79 SE.eraseValueFromMap(I);
81 if (!I->use_empty()) {
83 raw_string_ostream ss(
str);
84 ss <<
"Erased value with a use:\n";
85 ss << *
newFunc->getParent() <<
"\n";
90 nullptr,
nullptr,
nullptr);
92 EmitFailure(
"GetIndexError", I->getDebugLoc(), I, ss.str());
94 I->replaceAllUsesWith(UndefValue::get(I->getType()));
96 assert(I->use_empty());
106 llvm::AllocaInst *cache = found->second.first;
108 assert(isa<Instruction>(B));
111 SmallVector<Instruction *, 3> tmpInstructions(stfound->second.begin(),
112 stfound->second.end());
114 for (
auto st : tmpInstructions)
115 cast<StoreInst>(&*st)->eraseFromParent();
116 MDNode *TBAA =
nullptr;
117 if (
auto I = dyn_cast<Instruction>(A))
118 TBAA = I->getMetadata(LLVMContext::MD_tbaa);
126 A->replaceAllUsesWith(B);
131std::pair<PHINode *, Instruction *>
136 BasicBlock *Header = L->getHeader();
138 IRBuilder<> B(Header, Header->begin());
139 PHINode *CanonicalIV = B.CreatePHI(Ty, 1, Name);
142 Instruction *Inc = cast<Instruction>(
143 B.CreateAdd(CanonicalIV, ConstantInt::get(Ty, 1), Name +
".next",
146 for (BasicBlock *Pred : predecessors(Header)) {
148 if (L->contains(Pred)) {
149 CanonicalIV->addIncoming(Inc, Pred);
151 CanonicalIV->addIncoming(ConstantInt::get(Ty, 0), Pred);
154 assert(L->getCanonicalInductionVariable() == CanonicalIV);
155 return std::pair<PHINode *, Instruction *>(CanonicalIV, Inc);
164 BasicBlock *Header = L->getHeader();
166 for (BasicBlock::iterator II = Header->begin(); isa<PHINode>(II); ++II) {
167 PHINode *PN = cast<PHINode>(II);
168 if (PN->getType() != Ty)
171 Instruction *Inc =
nullptr;
173 for (BasicBlock *Pred : predecessors(Header)) {
175 if (L->contains(Pred)) {
177 dyn_cast<BinaryOperator>(PN->getIncomingValueForBlock(Pred));
178 if (!Inc2 || Inc2->getOpcode() != Instruction::Add ||
179 Inc2->getOperand(0) != PN) {
183 auto CI = dyn_cast<ConstantInt>(Inc2->getOperand(1));
184 if (!CI || !CI->isOne()) {
196 auto CI = dyn_cast<ConstantInt>(PN->getIncomingValueForBlock(Pred));
197 if (!CI || !CI->isZero()) {
209 return std::make_pair(PN, Inc);
211 llvm::errs() << *Header <<
"\n";
212 assert(0 &&
"Could not find canonical IV");
213 return std::pair<PHINode *, Instruction *>(
nullptr,
nullptr);
237 auto AR2 = dyn_cast<SCEVAddRecExpr>(R);
239 if (!AR2 || AR2->isAffine() || AR2->getNumOperands() > 4)
241 if (!AR2->getType()->isIntegerTy())
243 PHINode *IV = AR2->getLoop()->getCanonicalInductionVariable();
254 decltype(std::declval<const SCEVAddRecExpr &>().getNoWrapFlags());
263 const SCEV *IterationNumber,
264 ScalarEvolution &SE) {
265 using namespace llvm::PatternMatch;
268 auto Ty = dyn_cast<IntegerType>(PN->getType());
269 if (!Ty || Ty->getBitWidth() < 2 || PN->getNumIncomingValues() != 2)
271 BasicBlock *Preheader = L->getLoopPreheader();
272 BasicBlock *Latch = L->getLoopLatch();
273 if (!Preheader || !Latch)
275 Value *Next = PN->getIncomingValueForBlock(Latch);
276 if (!match(Next, m_Neg(m_Specific(PN))) &&
277 !match(Next, m_Mul(m_Specific(PN), m_AllOnes())))
279 const SCEV *Init = SE.getSCEV(PN->getIncomingValueForBlock(Preheader));
280 if (!SE.isAvailableAtLoopEntry(Init, L))
282 const SCEV *I = SE.getTruncateOrZeroExtend(IterationNumber, Ty);
283 const SCEV *Two = SE.getConstant(Ty, 2);
285 SE.getMinusSCEV(I, SE.getMulExpr(Two, SE.getUDivExpr(I, Two)));
287 SE.getMinusSCEV(SE.getOne(Ty), SE.getMulExpr(Two, Parity));
288 return SE.getMulExpr(Init, Factor);
308 const SCEV *IterationNumber,
309 ScalarEvolution &SE) {
313 if (!PN->getType()->isIntegerTy() || PN->getNumIncomingValues() != 2)
315 BasicBlock *Preheader = L->getLoopPreheader();
316 BasicBlock *Latch = L->getLoopLatch();
317 if (!Preheader || !Latch)
319 Value *Init = PN->getIncomingValueForBlock(Preheader);
320 Value *Next = PN->getIncomingValueForBlock(Latch);
321 const SCEV *InitS = SE.getSCEV(Init);
322 if (!SE.isAvailableAtLoopEntry(InitS, L))
324 const SCEV *PNS = SE.getSCEV(PN);
327 SmallVector<std::pair<Value *, BasicBlock *>, 2> Arms;
329 BasicBlock *Merge = Latch;
330 if (
auto NP = dyn_cast<PHINode>(Next); NP && NP != PN &&
331 NP->getParent() != L->getHeader() &&
332 L->contains(NP->getParent())) {
333 Merge = NP->getParent();
334 for (
unsigned i = 0; i < NP->getNumIncomingValues(); i++)
335 Arms.emplace_back(NP->getIncomingValue(i), NP->getIncomingBlock(i));
337 Arms.emplace_back(Next, Latch);
343 Type *WideTy = PN->getType();
345 const SCEV *Step =
nullptr;
346 SmallVector<BasicBlock *, 2> ZeroArms;
347 for (
auto &Arm : Arms) {
348 Value *V = Arm.first;
350 ZeroArms.push_back(Arm.second);
354 if (
auto TI = dyn_cast<TruncInst>(V))
355 Wide = TI->getOperand(0);
356 Type *Ty = Wide->getType();
357 if (!Ty->isIntegerTy())
360 const SCEV *WS = SE.getSCEVAtScope(Wide, L);
361 if (WS == SE.getCouldNotCompute())
363 const SCEV *D =
nullptr;
365 for (
bool S : {
true,
false}) {
367 S ? SE.getNoopOrSignExtend(PNS, Ty) : SE.getNoopOrZeroExtend(PNS, Ty);
368 const SCEV *Cand = SE.getMinusSCEV(WS, Ext);
369 if (isa<SCEVCouldNotCompute>(Cand))
371 if (!SCEVExprContains(Cand, [&](
const SCEV *
X) {
return X == PNS; })) {
380 if (D != Step || Ty != WideTy || Sgn != Signed)
393 if (SCEVExprContains(Step, [&](
const SCEV *
X) {
394 auto AR = dyn_cast<SCEVAddRecExpr>(
X);
395 return AR && AR->getLoop() != L && !AR->getLoop()->contains(L);
398 auto Disp = SE.getLoopDisposition(Step, L);
399 if (Disp == ScalarEvolution::LoopVariant)
401 if (
auto AR = dyn_cast<SCEVAddRecExpr>(Step)) {
402 if (AR->getLoop() != L || !AR->isAffine())
404 }
else if (Disp != ScalarEvolution::LoopInvariant) {
412 if (!ZeroArms.empty()) {
413 auto AR = dyn_cast<SCEVAddRecExpr>(Step);
416 const SCEV *Zero = SE.getZero(WideTy);
421 bool NonNegative = SE.isKnownOnEveryIteration(ICmpInst::ICMP_SGE, AR, Zero);
423 auto C = dyn_cast<SCEVConstant>(AR->getStepRecurrence(SE));
426 if (C->getAPInt().isNonNegative()) {
427 NonNegative = SE.isKnownNonNegative(AR->getStart()) ||
428 SE.isLoopEntryGuardedByCond(L, ICmpInst::ICMP_SGE,
429 AR->getStart(), Zero);
431 const SCEV *BTC = SE.getBackedgeTakenCount(L);
432 if (BTC == SE.getCouldNotCompute())
434 NonNegative = SE.isKnownNonNegative(AR->evaluateAtIteration(BTC, SE));
447 for (
auto B : ZeroArms) {
448 BasicBlock *Dest = Merge;
449 Instruction *TI = B->getTerminator();
451 if (TI->getNumSuccessors() != 1)
453 BasicBlock *Pred = B->getSinglePredecessor();
457 TI = Pred->getTerminator();
461 if (TI->getSuccessor(0) == TI->getSuccessor(1) ||
462 (TI->getSuccessor(0) != Dest && TI->getSuccessor(1) != Dest))
467 ICmpInst::Predicate Q = Cmp->getPredicate();
468 if (TI->getSuccessor(1) == Dest)
469 Q = ICmpInst::getInversePredicate(Q);
470 Value *
X = Cmp->getOperand(0), *Y = Cmp->getOperand(1);
471 bool Strict =
false, Equal =
false;
473 case ICmpInst::ICMP_UGE:
474 case ICmpInst::ICMP_SGE:
476 case ICmpInst::ICMP_ULE:
477 case ICmpInst::ICMP_SLE:
480 case ICmpInst::ICMP_UGT:
481 case ICmpInst::ICMP_SGT:
484 case ICmpInst::ICMP_ULT:
485 case ICmpInst::ICMP_SLT:
489 case ICmpInst::ICMP_EQ:
495 if (!SE.isSCEVable(
X->getType()) ||
X->getType() != WideTy)
497 const SCEV *XS = SE.getSCEV(
X), *YS = SE.getSCEV(Y);
498 auto NonNeg = [&](
const SCEV *V) {
499 return SE.isKnownNonNegative(V) ||
500 SE.isLoopEntryGuardedByCond(L, ICmpInst::ICMP_SGE, V, Zero);
502 if (!Equal && !(NonNeg(XS) && NonNeg(YS)))
504 auto K = dyn_cast<SCEVConstant>(
505 SE.getMinusSCEV(Step, SE.getMinusSCEV(YS, XS)));
509 if (Equal ? !K->getAPInt().isZero() : K->getAPInt().sgt(Strict ? 1 : 0))
514 const SCEV *WideInit = Signed ? SE.getNoopOrSignExtend(InitS, WideTy)
515 : SE.getNoopOrZeroExtend(InitS, WideTy);
516 auto AR = dyn_cast<SCEVAddRecExpr>(
520 return SE.getTruncateOrNoop(
527 Loop *L, PHINode *CanonicalIV, Instruction *Increment,
529 llvm::function_ref<
void(Instruction *, Value *)> replacer,
530 llvm::function_ref<
void(Instruction *)> eraser) {
531 BasicBlock *Header = L->getHeader();
534 SmallVector<Instruction *, 8> IVsToRemove;
536 auto CanonicalSCEV = SE.getSCEV(CanonicalIV);
538 for (BasicBlock::iterator II = Header->begin(); isa<PHINode>(II);) {
539 PHINode *PN = cast<PHINode>(II);
541 if (PN == CanonicalIV)
543 if (!SE.isSCEVable(PN->getType()))
545 const SCEV *S = SE.getSCEV(PN);
546 if (SE.getCouldNotCompute() == S || isa<SCEVUnknown>(S)) {
551 const SCEV *IterationNumber = SE.getUnknown(CanonicalIV);
562 if (!SE.dominates(S, Header))
565 if (S == CanonicalSCEV) {
566 replacer(PN, CanonicalIV);
572 auto Tmp = B.CreatePHI(PN->getType(), 0);
573 for (
auto Pred : predecessors(Header))
574 Tmp->addIncoming(UndefValue::get(Tmp->getType()), Pred);
580#if LLVM_VERSION_MAJOR >= 22
581 SCEVExpander Exp(SE,
"enzyme");
583 SCEVExpander Exp(SE, Header->getParent()->getParent()->getDataLayout(),
589 Value *NewIV = Exp.expandCodeFor(S, Tmp->getType(),
getFirstNonPHI(Header));
594 if (
auto addrec = dyn_cast<SCEVAddRecExpr>(S)) {
595 if (addrec->getLoop()->getHeader() == Header) {
596 if (
auto add_or_mul = dyn_cast<BinaryOperator>(NewIV)) {
597#if LLVM_VERSION_MAJOR >= 23
598 if (any(addrec->getNoWrapFlags(llvm::SCEV::FlagNUW)))
599 add_or_mul->setHasNoUnsignedWrap(
true);
600 if (any(addrec->getNoWrapFlags(llvm::SCEV::FlagNSW)))
601 add_or_mul->setHasNoSignedWrap(
true);
603 if (addrec->getNoWrapFlags(llvm::SCEV::FlagNUW))
604 add_or_mul->setHasNoUnsignedWrap(
true);
605 if (addrec->getNoWrapFlags(llvm::SCEV::FlagNSW))
606 add_or_mul->setHasNoSignedWrap(
true);
611 replacer(Tmp, NewIV);
617 SmallVector<Instruction *, 1> toErase;
618 for (
auto use : CanonicalIV->users()) {
619 auto BO = dyn_cast<BinaryOperator>(use);
622 if (BO->getOpcode() != BinaryOperator::Add)
624 if (use == Increment)
627 Value *toadd =
nullptr;
628 if (BO->getOperand(0) == CanonicalIV) {
629 toadd = BO->getOperand(1);
631 assert(BO->getOperand(1) == CanonicalIV);
632 toadd = BO->getOperand(0);
634 if (
auto CI = dyn_cast<ConstantInt>(toadd)) {
637 BO->replaceAllUsesWith(Increment);
638 toErase.push_back(BO);
643 for (
auto BO : toErase)
648 BasicBlock *Preheader, PHINode *CanonicalIV,
650 Instruction *Increment,
651 ArrayRef<BasicBlock *> latches) {
654 for (
auto use : CanonicalIV->users()) {
655 if (
auto cmp = dyn_cast<ICmpInst>(use)) {
659 if (cmp->getOperand(0) != CanonicalIV) {
663 assert(cmp->getOperand(0) == CanonicalIV);
665 auto scv = SE.getSCEVAtScope(cmp->getOperand(1), L);
666 if (cmp->isUnsigned() ||
667 (scv != SE.getCouldNotCompute() && SE.isKnownNonNegative(scv))) {
673 if (cmp->getPredicate() == ICmpInst::ICMP_ULT ||
674 cmp->getPredicate() == ICmpInst::ICMP_SLT) {
675 cmp->setPredicate(ICmpInst::ICMP_NE);
681 if (cmp->getPredicate() == ICmpInst::ICMP_ULE ||
682 cmp->getPredicate() == ICmpInst::ICMP_SLE) {
683 IRBuilder<> builder(Preheader->getTerminator());
684 if (
auto inst = dyn_cast<Instruction>(cmp->getOperand(1))) {
685 builder.SetInsertPoint(inst->getNextNode());
689 builder.CreateNUWAdd(
691 ConstantInt::get(cmp->getOperand(1)->getType(), 1,
false)));
692 cmp->setPredicate(ICmpInst::ICMP_NE);
697 if (cmp->getPredicate() == ICmpInst::ICMP_UGE ||
698 cmp->getPredicate() == ICmpInst::ICMP_SGE) {
699 cmp->setPredicate(ICmpInst::ICMP_EQ);
705 if (cmp->getPredicate() == ICmpInst::ICMP_UGT ||
706 cmp->getPredicate() == ICmpInst::ICMP_SGT) {
707 IRBuilder<> builder(Preheader->getTerminator());
708 if (
auto inst = dyn_cast<Instruction>(cmp->getOperand(1))) {
709 builder.SetInsertPoint(inst->getNextNode());
713 builder.CreateNUWAdd(
715 ConstantInt::get(cmp->getOperand(1)->getType(), 1,
false)));
716 cmp->setPredicate(ICmpInst::ICMP_EQ);
721 if (cmp->getPredicate() == ICmpInst::ICMP_NE) {
731 for (
auto use : Increment->users()) {
732 if (
auto cmp = dyn_cast<ICmpInst>(use)) {
737 if (cmp->getOperand(0) != Increment) {
741 assert(cmp->getOperand(0) == Increment);
743 auto scv = SE.getSCEVAtScope(cmp->getOperand(1), L);
744 if (cmp->isUnsigned() ||
745 (scv != SE.getCouldNotCompute() && SE.isKnownNonNegative(scv))) {
752 if (cmp->getPredicate() == ICmpInst::ICMP_ULT ||
753 cmp->getPredicate() == ICmpInst::ICMP_SLT) {
754 cmp->setPredicate(ICmpInst::ICMP_NE);
760 if (cmp->getPredicate() == ICmpInst::ICMP_ULE ||
761 cmp->getPredicate() == ICmpInst::ICMP_SLE) {
762 cmp->setOperand(0, CanonicalIV);
763 cmp->setPredicate(ICmpInst::ICMP_NE);
769 if (cmp->getPredicate() == ICmpInst::ICMP_UGE ||
770 cmp->getPredicate() == ICmpInst::ICMP_SGE) {
771 cmp->setPredicate(ICmpInst::ICMP_EQ);
777 if (cmp->getPredicate() == ICmpInst::ICMP_UGT ||
778 cmp->getPredicate() == ICmpInst::ICMP_SGT) {
779 cmp->setOperand(0, CanonicalIV);
780 cmp->setPredicate(ICmpInst::ICMP_EQ);
794 assert(found.dynamic);
796 return cast<AllocaInst>(&*found.trueLimit);
799 ReverseLimit ? found.preheader : &
newFunc->getEntryBlock());
800 AllocaInst *LimitVar =
804 for (
auto ExitBlock : found.exitBlocks) {
805 IRBuilder<> B(ExitBlock, ExitBlock->begin());
806 auto Limit = B.CreatePHI(found.var->getType(), 1);
808 for (BasicBlock *Pred : predecessors(ExitBlock)) {
809 if (L->contains(Pred)) {
810 Limit->addIncoming(found.var, Pred);
812 Limit->addIncoming(UndefValue::get(found.var->getType()), Pred);
818 found.trueLimit = LimitVar;
826 const SCEV *MaxIterations =
nullptr;
827 const SCEV *MayExitMaxBECount =
nullptr;
829 SmallVector<BasicBlock *, 8> ExitingBlocks;
830 L->getExitingBlocks(ExitingBlocks);
834 for (
auto &ExitingBlock : ExitingBlocks) {
835 BasicBlock *Exit =
nullptr;
836 for (
auto *SBB : successors(ExitingBlock)) {
837 if (!L->contains(SBB)) {
845 ExitingBlock =
nullptr;
848 std::remove(ExitingBlocks.begin(), ExitingBlocks.end(),
nullptr),
849 ExitingBlocks.end());
853 for (BasicBlock *ExitingBlock : ExitingBlocks) {
854 assert(L->contains(ExitingBlock));
856 ScalarEvolution::ExitLimit EL =
859 bool seenHeaders =
false;
860 SmallPtrSet<BasicBlock *, 4> Seen;
861 std::deque<BasicBlock *> Todo = {ExitingBlock};
862 while (Todo.size()) {
863 auto cur = Todo.front();
867 if (!L->contains(cur))
869 if (cur == L->getHeader()) {
873 for (
auto S : successors(cur)) {
878 if (MaxIterations ==
nullptr ||
879 MaxIterations ==
SE.getCouldNotCompute()) {
880 MaxIterations = EL.ExactNotTaken;
882 if (MaxIterations !=
SE.getCouldNotCompute()) {
883 if (EL.ExactNotTaken !=
SE.getCouldNotCompute()) {
885 SE.getUMaxFromMismatchedTypes(MaxIterations, EL.ExactNotTaken);
889 if (MayExitMaxBECount ==
nullptr ||
890 EL.ExactNotTaken ==
SE.getCouldNotCompute())
891 MayExitMaxBECount = EL.ExactNotTaken;
893 if (EL.ExactNotTaken != MayExitMaxBECount) {
894 MayExitMaxBECount =
SE.getCouldNotCompute();
898 if (MayExitMaxBECount ==
nullptr) {
899 MayExitMaxBECount =
SE.getCouldNotCompute();
901 if (MaxIterations ==
nullptr) {
902 MaxIterations =
SE.getCouldNotCompute();
904 return std::make_pair(MayExitMaxBECount, MaxIterations);
909 assert(BB->getParent() ==
newFunc);
910 Loop *L =
LI.getLoopFor(BB);
918 loopContext = *found;
926 assert(
loopContexts[L].header &&
"loop must have header");
929 if (!L->getLoopPreheader()) {
930 llvm::errs() <<
"fn: " << *L->getHeader()->getParent() <<
"\n";
931 llvm::errs() <<
"L: " << *L <<
"\n";
933 assert(
loopContexts[L].preheader &&
"loop must have preheader");
940 PHINode *CanonicalIV = pair.first;
941 auto incVar = pair.second;
946 CanonicalIV,
SE, *
this, incVar,
950 .CreateAlloca(CanonicalIV->getType(),
nullptr,
951 CanonicalIV->getName() +
"'ac");
953 Align(cast<IntegerType>(CanonicalIV->getType())->getBitWidth() / 8));
955 const SCEV *Limit =
nullptr;
956 const SCEV *MaxIterations =
nullptr;
959 Value *LimitVar =
nullptr;
961 if (
SE.getCouldNotCompute() != Limit) {
963 if (CanonicalIV ==
nullptr) {
964 report_fatal_error(
"Couldn't get canonical IV.");
976 SmallVector<const SCEV *, 4> Todo = {Limit};
977 SmallPtrSet<const SCEV *, 8> Seen;
978 CallInst *ompInit =
nullptr;
979 LoadInst *boundLoad =
nullptr;
980 while (Todo.size() && !ompInit) {
981 auto S = Todo.pop_back_val();
982 if (!Seen.insert(S).second)
984 auto U = dyn_cast<SCEVUnknown>(S);
987 if (
auto N = dyn_cast<SCEVNAryExpr>(S))
988 for (
auto op : N->operands())
990 else if (
auto C = dyn_cast<SCEVCastExpr>(S))
991 Todo.push_back(C->getOperand());
992 else if (
auto D = dyn_cast<SCEVUDivExpr>(S)) {
993 Todo.push_back(D->getLHS());
994 Todo.push_back(D->getRHS());
998 auto LI = dyn_cast<LoadInst>(U->getValue());
1001 auto AI = dyn_cast<AllocaInst>(
LI->getPointerOperand());
1004 for (
auto u : AI->users()) {
1005 auto call = dyn_cast<CallInst>(u);
1008 Function *F = call->getCalledFunction();
1011 if ((F->getName() ==
"__kmpc_for_static_init_4" ||
1012 F->getName() ==
"__kmpc_for_static_init_4u" ||
1013 F->getName() ==
"__kmpc_for_static_init_8" ||
1014 F->getName() ==
"__kmpc_for_static_init_8u") &&
1015 (call->getArgOperand(4) == AI || call->getArgOperand(5) == AI)) {
1023 auto storedValue = [](Value *ptr) -> Value * {
1024 for (
auto u : ptr->users())
1025 if (
auto si = dyn_cast<StoreInst>(u))
1026 if (si->getPointerOperand() == ptr)
1027 return si->getValueOperand();
1030 Value *lb = storedValue(ompInit->getArgOperand(4));
1031 Value *ub = storedValue(ompInit->getArgOperand(5));
1035 Value *omp_lb_post =
nullptr;
1036 if (boundLoad->getPointerOperand() == ompInit->getArgOperand(4))
1037 omp_lb_post = boundLoad;
1039 for (
auto u : ompInit->getArgOperand(4)->users())
1040 if (
auto LI = dyn_cast<LoadInst>(u))
1041 if (
LI->getParent() == ompInit->getParent() &&
1042 ompInit->comesBefore(
LI)) {
1046 IRBuilder<> post(ompInit->getNextNode());
1048 post.SetInsertPoint(cast<Instruction>(omp_lb_post)->getNextNode());
1050 omp_lb_post = post.CreateLoad(
1051 lb->getType(), ompInit->getArgOperand(4),
"omp_lb_post");
1053 post.CreateSub(ub, lb), CanonicalIV->getType());
1055 post.CreateSub(omp_lb_post, lb,
"",
true,
true),
1056 CanonicalIV->getType());
1060 if (Limit->getType() != CanonicalIV->getType()) {
1061 const SCEV *Zero =
SE.getZero(Limit->getType());
1062 const Loop *outermost = L;
1063 while (outermost->getParentLoop()) {
1064 outermost = outermost->getParentLoop();
1066 BasicBlock *outermostPreheader = outermost->getLoopPreheader();
1067 Instruction *context = outermostPreheader
1068 ? outermostPreheader->getTerminator()
1070 if (
SE.isKnownPredicateAt(ICmpInst::ICMP_SGE, Limit, Zero, context)) {
1071 Limit =
SE.getZeroExtendExpr(Limit, CanonicalIV->getType());
1073 Limit =
SE.getSignExtendExpr(Limit, CanonicalIV->getType());
1077#if LLVM_VERSION_MAJOR >= 22
1078 SCEVExpander Exp(
SE,
"enzyme");
1080 SCEVExpander Exp(
SE, BB->getParent()->getParent()->getDataLayout(),
1083 LimitVar = Exp.expandCodeFor(Limit, CanonicalIV->getType(),
1090 DebugLoc loc = L->getHeader()->begin()->getDebugLoc();
1091 for (
auto &I : *L->getHeader()) {
1094 loc = I.getDebugLoc();
1097 "SE could not compute loop limit of ",
1098 L->getHeader()->getName(),
" of ",
1099 L->getHeader()->getParent()->getName(),
"lim: ", *Limit,
1100 " maxlim: ", *MaxIterations);
1113 SE.getCouldNotCompute() != MaxIterations) {
1114 if (MaxIterations->getType() != CanonicalIV->getType())
1116 SE.getZeroExtendExpr(MaxIterations, CanonicalIV->getType());
1118#if LLVM_VERSION_MAJOR >= 22
1119 SCEVExpander Exp(
SE,
"enzyme");
1121 SCEVExpander Exp(
SE, BB->getParent()->getParent()->getDataLayout(),
1126 Exp.expandCodeFor(MaxIterations, CanonicalIV->getType(),
1136 StringRef name,
bool shouldFree,
1137 bool allocateInternal,
1145 auto i64 = Type::getInt64Ty(T->getContext());
1151 SmallVector<Type *, 4> types = {T};
1152 SmallVector<PointerType *, 4> malloctypes;
1153 bool isi1 = T->isIntegerTy() && cast<IntegerType>(T)->getBitWidth() == 1;
1155 types[0] = Type::getInt8Ty(T->getContext());
1156 for (
size_t i = 0; i < sublimits.size(); ++i) {
1162 auto P = B.CreatePHI(i64, 1);
1164 CallInst *malloccall;
1170 malloctypes.push_back(cast<PointerType>(malloccall->getType()));
1171 for (
auto &I : make_early_inc_range(reverse(*BB)))
1172 I.eraseFromParent();
1174 BB->eraseFromParent();
1176 types.push_back(allocType);
1181 entryBuilder.setFastMathFlags(
getFast());
1183 entryBuilder.CreateAlloca(types.back(),
nullptr, name +
"_cache");
1185 ConstantInt *byteSizeOfType = ConstantInt::get(
1186 i64,
newFunc->getParent()->getDataLayout().getTypeAllocSizeInBits(
1191 alloc->setAlignment(Align(align));
1195 if (!isa<UndefValue>(undef_v))
1197 entryBuilder.CreateStore(undef_v, alloc));
1199 Value *storeInto = alloc;
1204 for (
int i = sublimits.size() - 1; i >= 0; i--) {
1205 const auto &containedloops = sublimits[i].second;
1207 Type *myType = types[i];
1209 ConstantInt *byteSizeOfType = ConstantInt::get(
1210 Type::getInt64Ty(T->getContext()),
1211 newFunc->getParent()->getDataLayout().getTypeAllocSizeInBits(myType) /
1214 unsigned bsize = (unsigned)byteSizeOfType->getZExtValue();
1217 CallInst *malloccall =
nullptr;
1220 if (allocateInternal) {
1222 IRBuilder<> allocationBuilder(
1223 &containedloops.back().first.preheader->back());
1225 Value *size = sublimits[i].first;
1227 size = allocationBuilder.CreateLShr(
1228 allocationBuilder.CreateAdd(
1229 size, ConstantInt::get(Type::getInt64Ty(T->getContext()), 7),
1231 ConstantInt::get(Type::getInt64Ty(T->getContext()), 3));
1233 if (extraSize && i == 0) {
1234 ValueToValueMapTy available;
1235 for (
auto &sl : sublimits) {
1236 for (
auto &cl : sl.second) {
1238 available[cl.first.var] = cl.first.var;
1241 Value *es =
unwrapM(extraSize, allocationBuilder, available,
1244 size = allocationBuilder.CreateMul(size, es,
"",
true,
1248 StoreInst *storealloc =
nullptr;
1250 if (sublimits[i].second.back().first.maxLimit) {
1251 Instruction *ZeroInst =
nullptr;
1253 allocationBuilder, myType, size, name +
"_malloccache", &malloccall,
1257 auto ident = MDNode::getDistinct(
1258 malloccall->getContext(),
1259 {ConstantAsMetadata::get(
1260 ConstantInt::getFalse(malloccall->getContext()))});
1261 malloccall->setMetadata(
1262 "enzyme_cache_alloc",
1263 MDNode::get(malloccall->getContext(), {ident}));
1267 if (firstallocation != malloccall)
1269 cast<Instruction>(firstallocation));
1271 for (
auto &actx : sublimits[i].second) {
1272 if (actx.first.offset) {
1273 malloccall->setMetadata(
"enzyme_ompfor",
1274 MDNode::get(malloccall->getContext(), {}));
1280 if (ZeroInst->getOperand(0) != malloccall) {
1282 cast<Instruction>(ZeroInst->getOperand(0)));
1286 storealloc = allocationBuilder.CreateStore(firstallocation, storeInto);
1292 if (CachePointerInvariantGroups.find(std::make_pair(
1293 (Value *)alloc, i)) == CachePointerInvariantGroups.end()) {
1294 MDNode *invgroup = MDNode::getDistinct(alloc->getContext(), {});
1295 CachePointerInvariantGroups[std::make_pair((Value *)alloc, i)] =
1298 storealloc->setMetadata(
1299 LLVMContext::MD_invariant_group,
1300 CachePointerInvariantGroups[std::make_pair((Value *)alloc, i)]);
1302 for (
auto post :
PostCacheStore(storealloc, allocationBuilder)) {
1306 llvm::PointerType *allocType = cast<PointerType>(types[i + 1]);
1307 llvm::PointerType *mallocType = malloctypes[i];
1312 auto zerostore = allocationBuilder.CreateStore(
1318 IRBuilder<> build(containedloops.back().first.incvar->getNextNode());
1319 Value *allocation = build.CreateLoad(allocType, storeInto);
1321 if (allocation->getType() != mallocType) {
1323 cast<Instruction>(build.CreateBitCast(allocation, mallocType));
1328 CallInst *realloccall =
nullptr;
1330 build, allocation, myType, containedloops.back().first.incvar, size,
1335 if (reallocation->getType() != allocType) {
1337 cast<Instruction>(build.CreateBitCast(reallocation, allocType));
1344 storealloc = build.CreateStore(reallocation, storeInto);
1356 storealloc->setAlignment(Align(alignSize));
1361 if (CachePointerInvariantGroups.find(std::make_pair((Value *)alloc, i)) ==
1362 CachePointerInvariantGroups.end()) {
1363 MDNode *invgroup = MDNode::getDistinct(alloc->getContext(), {});
1364 CachePointerInvariantGroups[std::make_pair((Value *)alloc, i)] =
1367 Type *nextType = types[i + 1];
1369 containedloops.back().first.preheader, sublimits, i, alloc, nextType,
1370 byteSizeOfType, storeInto,
1371 CachePointerInvariantGroups[std::make_pair((Value *)alloc, i)]);
1374 MDNode::getDistinct(freecall->getContext(),
1375 {ConstantAsMetadata::get(ConstantInt::getFalse(
1376 freecall->getContext()))});
1377 freecall->setMetadata(
"enzyme_cache_free",
1378 MDNode::get(freecall->getContext(), {ident}));
1380 if (freecall && malloccall) {
1382 MDNode::getDistinct(freecall->getContext(),
1383 {ConstantAsMetadata::get(ConstantInt::getTrue(
1384 freecall->getContext()))});
1385 malloccall->setMetadata(
"enzyme_cache_alloc",
1386 MDNode::get(malloccall->getContext(), {ident}));
1387 freecall->setMetadata(
"enzyme_cache_free",
1388 MDNode::get(freecall->getContext(), {ident}));
1395 IRBuilder<> v(&sublimits[i - 1].second.back().first.preheader->back());
1397 Value *idx = computeIndexOfChunk(
1398 true, v, containedloops,
1399 ValueToValueMapTy());
1401 storeInto = v.CreateLoad(types[i + 1], storeInto);
1402 cast<LoadInst>(storeInto)->setAlignment(Align(alignSize));
1403 storeInto = v.CreateGEP(types[i], storeInto, idx);
1404 cast<GetElementPtrInst>(storeInto)->setIsInBounds(
true);
1410Value *CacheUtility::computeIndexOfChunk(
1411 bool inForwardPass, IRBuilder<> &v,
1412 ArrayRef<std::pair<LoopContext, llvm::Value *>> containedloops,
1413 const ValueToValueMapTy &available) {
1415 SmallVector<Value *, 3> indices;
1418 SmallVector<Value *, 3> limits;
1421 for (
size_t i = 0; i < containedloops.size(); ++i) {
1422 const auto &pair = containedloops[i];
1424 const auto &idx = pair.first;
1425 Value *var = idx.var;
1429 if (idx.var ==
nullptr)
1430 var = ConstantInt::get(Type::getInt64Ty(
newFunc->getContext()), 0);
1431 else if (available.count(var)) {
1432 var = available.find(var)->second;
1433 }
else if (!inForwardPass) {
1434 var = v.CreateLoad(idx.var->getType(), idx.antivaralloc);
1439 var = v.CreateAdd(var,
lookupM(idx.offset, v),
"",
true,
1443 indices.push_back(var);
1444 Value *lim = pair.second;
1446 if (limits.size() == 0) {
1447 limits.push_back(lim);
1449 limits.push_back(v.CreateMul(limits.back(), lim,
"",
1454 assert(indices.size() > 0);
1457 Value *idx = indices[0];
1458 for (
unsigned ind = 1; ind < indices.size(); ++ind) {
1459 idx = v.CreateAdd(idx,
1460 v.CreateMul(indices[ind], limits[ind - 1],
"",
1481 SmallVector<LoopContext, 4> contexts;
1490 auto subctx = ctx.
Block;
1491 auto zero = ConstantInt::get(Type::getInt64Ty(
newFunc->getContext()), 0);
1505 contexts.push_back(idx);
1508 for (BasicBlock *blk = ctx.
Block; blk !=
nullptr;) {
1513 contexts.emplace_back(std::move(idx));
1518 SmallVector<BasicBlock *, 4> allocationPreheaders(contexts.size(),
nullptr);
1520 SmallVector<Value *, 4> limits(contexts.size(),
nullptr);
1523 for (
int i = contexts.size() - 1; i >= 0; --i) {
1526 if ((
unsigned)i == contexts.size() - 1) {
1527 allocationPreheaders[i] = contexts[i].preheader;
1528 }
else if (!contexts[i].maxLimit) {
1531 allocationPreheaders[i] = contexts[i].preheader;
1535 allocationPreheaders[i] = allocationPreheaders[i + 1];
1541 if (!contexts[i].maxLimit) {
1543 ConstantInt::get(Type::getInt64Ty(ctx.
Block->getContext()), 1);
1547 ValueToValueMapTy prevMap;
1550 for (
int j = contexts.size() - 1;; --j) {
1556 if (allocationPreheaders[i] != contexts[j].preheader) {
1557 prevMap[contexts[j].var] = contexts[j].var;
1563 IRBuilder<> allocationBuilder(&allocationPreheaders[i]->back());
1564 Value *limitMinus1 =
nullptr;
1566 Value *limit = contexts[i].maxLimit;
1567 if (contexts[i].allocLimit)
1568 limit = contexts[i].allocLimit;
1572 limitMinus1 =
unwrapM(limit, allocationBuilder, prevMap,
1579 if (limitMinus1 ==
nullptr) {
1580 EmitWarning(
"NoOuterLimit", *cast<Instruction>(&*limit),
1581 "Could not compute outermost loop limit by moving value ",
1582 *limit,
" computed at block", contexts[i].header->getName(),
1583 " function ", contexts[i].header->getParent()->getName());
1584 allocationPreheaders[i] = contexts[i].preheader;
1585 allocationBuilder.SetInsertPoint(&allocationPreheaders[i]->back());
1586 limitMinus1 =
unwrapM(limit, allocationBuilder, prevMap,
1588 if (limitMinus1 ==
nullptr) {
1589 llvm::errs() << *contexts[i].preheader->getParent() <<
"\n";
1590 llvm::errs() <<
"block: " << *allocationPreheaders[i] <<
"\n";
1591 llvm::errs() <<
"limit: " << *limit <<
"\n";
1593 assert(limitMinus1 !=
nullptr);
1594 }
else if (i == 0 && extraSize &&
1595 unwrapM(extraSize, allocationBuilder, prevMap,
1598 "NoOuterLimit", *cast<Instruction>(extraSize),
newFunc,
1599 cast<Instruction>(extraSize)->getParent(),
1600 "Could not compute outermost loop limit by moving extraSize value ",
1601 *extraSize,
" computed at block", contexts[i].header->getName(),
1602 " function ", contexts[i].header->getParent()->getName());
1603 allocationPreheaders[i] = contexts[i].preheader;
1604 allocationBuilder.SetInsertPoint(&allocationPreheaders[i]->back());
1606 assert(limitMinus1 !=
nullptr);
1608 ValueToValueMapTy reverseMap;
1610 for (
int j = contexts.size() - 1;; --j) {
1616 if (allocationPreheaders[i] != contexts[j].preheader) {
1617 if (!inForwardPass) {
1618 reverseMap[contexts[j].var] = RB->CreateLoad(
1619 contexts[j].var->getType(), contexts[j].antivaralloc);
1628 if (inForwardPass) {
1632 auto &map = LimitCache[limitMinus1];
1633 auto found = map.find(allocationPreheaders[i]);
1634 if (found != map.end() && found->second !=
nullptr) {
1635 limits[i] = found->second;
1637 limits[i] = map[allocationPreheaders[i]] =
1638 allocationBuilder.CreateNSWAdd(
1639 limitMinus1, ConstantInt::get(limitMinus1->getType(), 1));
1642 Value *lim =
unwrapM(limitMinus1, *RB, reverseMap,
1644 allocationPreheaders[i]);
1646 llvm::errs() << *
newFunc <<
"\n";
1647 llvm::errs() << *limitMinus1 <<
"\n";
1650 limits[i] = RB->CreateNSWAdd(lim, ConstantInt::get(lim->getType(), 1));
1658 Value *size =
nullptr;
1660 SmallVector<std::pair<LoopContext, Value *>, 3> lims;
1663 for (
unsigned i = 0; i < contexts.size(); ++i) {
1664 IRBuilder<> allocationBuilder(&allocationPreheaders[i]->back());
1665 lims.push_back(std::make_pair(contexts[i], limits[i]));
1667 if (size ==
nullptr) {
1670 }
else if (!inForwardPass) {
1671 size = RB->CreateMul(size, limits[i],
"",
1675 auto cidx = std::make_tuple(size, limits[i], allocationPreheaders[i]);
1676 if (SizeCache.find(cidx) == SizeCache.end()) {
1678 allocationBuilder.CreateMul(size, limits[i],
"",
1681 size = SizeCache[cidx];
1686 if ((i + 1 < contexts.size()) &&
1687 (allocationPreheaders[i] != allocationPreheaders[i + 1])) {
1688 sublimits.push_back(std::make_pair(size, lims));
1695 if (size !=
nullptr) {
1696 sublimits.push_back(std::make_pair(size, lims));
1706 IRBuilder<> &BuilderM, Value *val,
1707 AllocaInst *cache, MDNode *TBAA) {
1708 assert(BuilderM.GetInsertBlock()->getParent() ==
newFunc);
1710 if (
auto inst = dyn_cast<Instruction>(val))
1711 assert(inst->getParent()->getParent() ==
newFunc);
1713 IRBuilder<> v(BuilderM.GetInsertBlock());
1714 v.SetInsertPoint(BuilderM.GetInsertBlock(), BuilderM.GetInsertPoint());
1715 v.setFastMathFlags(
getFast());
1726 if (BuilderM.GetInsertPoint() != BuilderM.GetInsertBlock()->end()) {
1727 for (
auto I = BuilderM.GetInsertBlock()->rbegin(),
1728 E = BuilderM.GetInsertBlock()->rend();
1730 if (&*I == &*BuilderM.GetInsertPoint())
1732 if (
auto si = dyn_cast<StoreInst>(&*I)) {
1734 if (ni !=
nullptr) {
1735 v.SetInsertPoint(ni);
1737 v.SetInsertPoint(si->getParent());
1743 bool isi1 = val->getType()->isIntegerTy() &&
1744 cast<IntegerType>(val->getType())->getBitWidth() == 1;
1746 true, v, ctx, cache,
1748 llvm::ValueToValueMapTy(),
1751 Value *tostore = val;
1757 if (
auto gep = dyn_cast<GetElementPtrInst>(loc)) {
1758 auto bo = cast<BinaryOperator>(*gep->idx_begin());
1759 assert(bo->getOpcode() == BinaryOperator::LShr);
1760 auto subidx = v.CreateAnd(
1761 v.CreateTrunc(bo->getOperand(0),
1762 Type::getInt8Ty(cache->getContext())),
1763 ConstantInt::get(Type::getInt8Ty(cache->getContext()), 7));
1764 auto mask = v.CreateNot(v.CreateShl(
1765 ConstantInt::get(Type::getInt8Ty(cache->getContext()), 1), subidx));
1767 Value *loadChunk = v.CreateLoad(mask->getType(), loc);
1768 auto cleared = v.CreateAnd(loadChunk, mask);
1770 auto toset = v.CreateShl(
1771 v.CreateZExt(val, Type::getInt8Ty(cache->getContext())), subidx);
1772 tostore = v.CreateOr(cleared, toset);
1773 assert(tostore->getType() == mask->getType());
1777#if LLVM_VERSION_MAJOR < 17
1778 if (tostore->getContext().supportsTypedPointers()) {
1779 if (tostore->getType() != loc->getType()->getPointerElementType()) {
1780 llvm::errs() <<
"val: " << *val <<
"\n";
1781 llvm::errs() <<
"tostore: " << *tostore <<
"\n";
1782 llvm::errs() <<
"loc: " << *loc <<
"\n";
1784 assert(tostore->getType() == loc->getType()->getPointerElementType());
1788 StoreInst *storeinst = v.CreateStore(tostore, loc);
1792 if (tostore == val) {
1793 if (ValueInvariantGroups.find(cache) == ValueInvariantGroups.end()) {
1794 MDNode *invgroup = MDNode::getDistinct(cache->getContext(), {});
1795 ValueInvariantGroups[cache] = invgroup;
1797 storeinst->setMetadata(LLVMContext::MD_invariant_group,
1798 ValueInvariantGroups[cache]);
1802 ConstantInt *byteSizeOfType =
1803 ConstantInt::get(Type::getInt64Ty(cache->getContext()),
1804 ctx.Block->getParent()
1807 .getTypeAllocSizeInBits(val->getType()) /
1810 storeinst->setMetadata(LLVMContext::MD_tbaa, TBAA);
1811 storeinst->setAlignment(Align(align));
1821 llvm::Instruction *inst,
1822 llvm::AllocaInst *cache,
1823 llvm::MDNode *TBAA) {
1829 IRBuilder<> v(inst->getParent());
1832 if (&*inst->getParent()->rbegin() != inst) {
1833 auto pn = dyn_cast<PHINode>(inst);
1834 Instruction *putafter = (pn && pn->getNumIncomingValues() > 0)
1838 v.SetInsertPoint(putafter);
1840 v.setFastMathFlags(
getFast());
1850 Value *cache,
bool storeInInstructionsMap,
1851 const ValueToValueMapTy &available,
1855 auto sublimits =
getSubLimits(inForwardPass, &BuilderM, ctx, extraSize);
1857 Value *next = cache;
1858 assert(next->getType()->isPointerTy());
1860 SmallVector<Type *, 4> types = {T};
1861 bool isi1 = T->isIntegerTy() && cast<IntegerType>(T)->getBitWidth() == 1;
1863 types[0] = Type::getInt8Ty(T->getContext());
1864 auto i64 = Type::getInt64Ty(T->getContext());
1865 for (
size_t i = 0; i < sublimits.size(); ++i) {
1871 auto P = B.CreatePHI(i64, 1);
1873 CallInst *malloccall;
1879 for (
auto &I : make_early_inc_range(reverse(*BB)))
1880 I.eraseFromParent();
1882 BB->eraseFromParent();
1884 types.push_back(allocType);
1888 for (
int i = sublimits.size() - 1; i >= 0; i--) {
1890 next = BuilderM.CreateLoad(types[i + 1], next);
1891 if (storeInInstructionsMap && isa<AllocaInst>(cache))
1893 cast<Instruction>(next));
1895 if (!next->getType()->isPointerTy()) {
1896 llvm::errs() << *
newFunc <<
"\n";
1897 llvm::errs() <<
"cache: " << *cache <<
"\n";
1898 llvm::errs() <<
"next: " << *next <<
"\n";
1899 assert(next->getType()->isPointerTy());
1903 if (CachePointerInvariantGroups.find(std::make_pair(cache, i)) ==
1904 CachePointerInvariantGroups.end()) {
1905 MDNode *invgroup = MDNode::getDistinct(cache->getContext(), {});
1906 CachePointerInvariantGroups[std::make_pair(cache, i)] = invgroup;
1908 cast<LoadInst>(next)->setMetadata(
1909 LLVMContext::MD_invariant_group,
1910 CachePointerInvariantGroups[std::make_pair(cache, i)]);
1913 ConstantInt *byteSizeOfType = ConstantInt::get(
1914 Type::getInt64Ty(cache->getContext()),
1915 newFunc->getParent()->getDataLayout().getTypeAllocSizeInBits(
1918 cast<LoadInst>(next)->setMetadata(
1919 LLVMContext::MD_dereferenceable,
1921 cache->getContext(),
1922 ArrayRef<Metadata *>(ConstantAsMetadata::get(byteSizeOfType))));
1925 cast<LoadInst>(next)->setAlignment(Align(align));
1927 const auto &containedloops = sublimits[i].second;
1929 if (containedloops.size() > 0) {
1930 Value *idx = computeIndexOfChunk(inForwardPass, BuilderM, containedloops,
1933 idx = BuilderM.CreateLShr(
1934 idx, ConstantInt::get(Type::getInt64Ty(
newFunc->getContext()), 3));
1935 if (i == 0 && extraSize) {
1936 Value *es =
lookupM(extraSize, BuilderM);
1938 idx = BuilderM.CreateMul(idx, es,
"",
true,
true);
1940 next = BuilderM.CreateGEP(types[i], next, idx);
1941 cast<GetElementPtrInst>(next)->setIsInBounds(
true);
1942 if (storeInInstructionsMap && isa<AllocaInst>(cache))
1944 cast<Instruction>(next));
1946 assert(next->getType()->isPointerTy());
1954 llvm::IRBuilder<> &BuilderM,
1956 llvm::Value *cache) {
1958 auto result = BuilderM.CreateLoad(T, cptr);
1961 if (ValueInvariantGroups.find(cache) == ValueInvariantGroups.end()) {
1962 MDNode *invgroup = MDNode::getDistinct(cache->getContext(), {});
1963 ValueInvariantGroups[cache] = invgroup;
1966 result->setMetadata(LLVMContext::MD_invariant_group,
1967 ValueInvariantGroups[cache]);
1968 ConstantInt *byteSizeOfType = ConstantInt::get(
1969 Type::getInt64Ty(cache->getContext()),
1970 newFunc->getParent()->getDataLayout().getTypeAllocSizeInBits(
1971 result->getType()) /
1974 result->setAlignment(Align(align));
1982 Type *T,
bool inForwardPass, IRBuilder<> &BuilderM,
LimitContext ctx,
1983 Value *cache,
bool isi1,
const ValueToValueMapTy &available,
1984 Value *extraSize, Value *extraOffset) {
1988 false, available, extraSize);
1992 cptr = BuilderM.CreateGEP(T, cptr, extraOffset);
1993 cast<GetElementPtrInst>(cptr)->setIsInBounds(
true);
2001 if (
auto gep = dyn_cast<GetElementPtrInst>(cptr)) {
2002 auto bo = cast<BinaryOperator>(*gep->idx_begin());
2003 assert(bo->getOpcode() == BinaryOperator::LShr);
2004 Value *res = BuilderM.CreateLShr(
2007 BuilderM.CreateTrunc(bo->getOperand(0),
2008 Type::getInt8Ty(cache->getContext())),
2009 ConstantInt::get(Type::getInt8Ty(cache->getContext()), 7)));
2010 return BuilderM.CreateTrunc(res, Type::getInt1Ty(result->getContext()));
static RegisterPass< ActivityAnalysisPrinter > X("print-activity-analysis", "Print Activity Analysis Results")
llvm::cl::opt< bool > EfficientMaxCache("enzyme-max-cache", cl::init(false), cl::Hidden, cl::desc("Avoid reallocs when possible by potentially overallocating cache"))
std::pair< PHINode *, Instruction * > InsertNewCanonicalIV(Loop *L, Type *Ty, const llvm::Twine &Name)
decltype(std::declval< const SCEVAddRecExpr & >().getNoWrapFlags()) NoWrapFlagsTy
static const SCEV * closedFormOfCountedAccumulator(PHINode *PN, Loop *L, const SCEV *IterationNumber, ScalarEvolution &SE)
PN is a header phi of L that scalar evolution could not classify.
static const SCEV * closedFormOfNegatingRecurrence(PHINode *PN, Loop *L, const SCEV *IterationNumber, ScalarEvolution &SE)
PN is a header phi of L that is negated on every iteration, x_{i+1} = -x_i, such as the alternating s...
void RemoveRedundantIVs(Loop *L, PHINode *CanonicalIV, Instruction *Increment, MustExitScalarEvolution &SE, llvm::function_ref< void(Instruction *, Value *)> replacer, llvm::function_ref< void(Instruction *)> eraser)
void CanonicalizeLatches(const Loop *L, BasicBlock *Header, BasicBlock *Preheader, PHINode *CanonicalIV, MustExitScalarEvolution &SE, CacheUtility &gutils, Instruction *Increment, ArrayRef< BasicBlock * > latches)
llvm::cl::opt< bool > EnzymeRewriteAccumulators("enzyme-rewrite-accumulators", cl::init(true), cl::Hidden, cl::desc("Rewrite a loop-carried counter whose step is an inner loop's " "trip count into a closed form of the induction variable"))
std::pair< PHINode *, Instruction * > FindCanonicalIV(Loop *L, Type *Ty)
llvm::cl::opt< bool > EnzymeZeroCache
llvm::cl::opt< bool > EfficientBoolCache
Pack 8 bools together in a single byte.
@ AttemptFullUnwrapWithLookup
static void getExitBlocks(const llvm::Loop *L, llvm::SmallPtrSetImpl< llvm::BasicBlock * > &ExitBlocks)
static llvm::SmallVector< llvm::BasicBlock *, 3 > getLatches(const llvm::Loop *L, const llvm::SmallPtrSetImpl< llvm::BasicBlock * > &ExitBlocks)
static std::string str(AugmentedStruct c)
llvm::Value * CreateReAllocation(llvm::IRBuilder<> &B, llvm::Value *prev, llvm::Type *T, llvm::Value *OuterCount, llvm::Value *InnerCount, const llvm::Twine &Name, llvm::CallInst **caller, bool ZeroMem)
llvm::SmallVector< llvm::Instruction *, 2 > PostCacheStore(llvm::StoreInst *SI, llvm::IRBuilder<> &B)
Value * CreateAllocation(IRBuilder<> &Builder, llvm::Type *T, Value *Count, const Twine &Name, CallInst **caller, Instruction **ZeroMem, bool isDefault)
LLVMValueRef(* CustomErrorHandler)(const char *, LLVMValueRef, ErrorType, const void *, LLVMValueRef, LLVMBuilderRef)
const SCEV * evaluateAtIterationWithoutExt(const SCEVAddRecExpr *AR, const SCEV *It, ScalarEvolution &SE)
llvm::FastMathFlags getFast()
Get LLVM fast math flags.
llvm::Constant * getUndefinedValueForType(llvm::Module &M, llvm::Type *T, bool forceZero)
static llvm::Instruction * getNextNonDebugInstructionOrNull(llvm::Instruction *Z)
Get the next non-debug instruction, if one exists.
static V * findInMap(std::map< K, V > &map, K key)
void EmitFailure(llvm::StringRef RemarkName, const llvm::DiagnosticLocation &Loc, const llvm::Instruction *CodeRegion, Args &...args)
static std::map< K, V >::iterator insert_or_assign2(std::map< K, V > &map, K key, V val)
Insert into a map.
void EmitWarning(llvm::StringRef RemarkName, const llvm::DiagnosticLocation &Loc, const llvm::BasicBlock *BB, const Args &...args)
static llvm::Instruction * getFirstNonPHI(llvm::BasicBlock *B)
static llvm::Instruction * getNextNonDebugInstruction(llvm::Instruction *Z)
Get the next non-debug instruction, erring if none exists.
static bool isConditionalBranch(const llvm::Value *V)
static llvm::Value * getBranchCondition(llvm::Value *V)
The condition of a branch isConditionalBranch says yes to.
llvm::cl::opt< bool > EnzymePrintPerf
Print additional debug info relevant to performance.
static llvm::Instruction * getFirstNonPHIOrDbg(llvm::BasicBlock *B)
static void moveBeforeInst(llvm::Instruction *I, llvm::Instruction *Before)
llvm::Function *const newFunc
The function whose instructions we are caching.
MustExitScalarEvolution SE
virtual llvm::Value * unwrapM(llvm::Value *const val, llvm::IRBuilder<> &BuilderM, const llvm::ValueToValueMapTy &available, UnwrapMode mode, llvm::BasicBlock *scope=nullptr, bool permitCache=true)=0
High-level utility to "unwrap" an instruction at a new location specified by BuilderM.
virtual llvm::CallInst * freeCache(llvm::BasicBlock *forwardPreheader, const SubLimitType &antimap, int i, llvm::AllocaInst *alloc, llvm::Type *myType, llvm::ConstantInt *byteSizeOfType, llvm::Value *storeInto, llvm::MDNode *InvariantMD)
If an allocation is requested to be freed, this subclass will be called to chose how and where to fre...
std::map< llvm::AllocaInst *, llvm::SmallVector< llvm::AssertingVH< llvm::CallInst >, 4 > > scopeAllocs
A map of allocations to a set of instructions which allocate memory as part of the cache.
std::pair< const llvm::SCEV *, const llvm::SCEV * > computeLoopLimit(llvm::Loop *L)
Compute the exact backedge-taken count of L (CouldNotCompute if it is not statically known) and the m...
llvm::AllocaInst * createCacheForScope(LimitContext ctx, llvm::Type *T, llvm::StringRef name, bool shouldFree, bool allocateInternal=true, llvm::Value *extraSize=nullptr)
Create a cache of Type T at the given LimitContext.
virtual void erase(llvm::Instruction *I)
Erase this instruction both from LLVM modules and any local data-structures.
llvm::Value * getCachePointer(llvm::Type *T, bool inForwardPass, llvm::IRBuilder<> &BuilderM, LimitContext ctx, llvm::Value *cache, bool storeInInstructionsMap, const llvm::ValueToValueMapTy &available, llvm::Value *extraSize)
Given an allocation specified by the LimitContext ctx and cache, compute a pointer that can hold the ...
llvm::Value * lookupValueFromCache(llvm::Type *T, bool inForwardPass, llvm::IRBuilder<> &BuilderM, LimitContext ctx, llvm::Value *cache, bool isi1, const llvm::ValueToValueMapTy &available, llvm::Value *extraSize=nullptr, llvm::Value *extraOffset=nullptr)
Given an allocation specified by the LimitContext ctx and cache, lookup the underlying cached value.
bool getContext(llvm::BasicBlock *BB, LoopContext &loopContext, bool ReverseLimit)
Given a BasicBlock BB in newFunc, set loopContext to the relevant contained loop and return true.
llvm::Value * loadFromCachePointer(llvm::Type *T, llvm::IRBuilder<> &BuilderM, llvm::Value *cptr, llvm::Value *cache)
Perform the final load from the cache, applying requisite invariant group and alignment.
std::map< llvm::AllocaInst *, std::set< llvm::AssertingVH< llvm::CallInst > > > scopeFrees
A map of allocations to a set of instructions which free memory as part of the cache.
std::map< llvm::Loop *, LoopContext > loopContexts
Map of Loop to requisite loop information needed for AD (forward/reverse induction/etc)
std::map< llvm::AllocaInst *, llvm::SmallVector< llvm::AssertingVH< llvm::Instruction >, 4 > > scopeInstructions
A map of allocations to a vector of instruction used to create by the allocation Keeping track of the...
llvm::BasicBlock * inversionAllocs
std::map< llvm::Value *, std::pair< llvm::AssertingVH< llvm::AllocaInst >, LimitContext > > scopeMap
A map of values being cached to their underlying allocation/limit context.
llvm::SmallVector< std::pair< llvm::Value *, llvm::SmallVector< std::pair< LoopContext, llvm::Value * >, 4 > >, 0 > SubLimitType
Given a LimitContext ctx, representing a location inside a loop nest, break each of the loops up into...
virtual void replaceAWithB(llvm::Value *A, llvm::Value *B, bool storeInCache=false)
Replace this instruction both in LLVM modules and any local data-structures.
unsigned getCacheAlignment(unsigned bsize) const
llvm::AllocaInst * getDynamicLoopLimit(llvm::Loop *L, bool ReverseLimit=true)
llvm::SmallPtrSet< llvm::LoadInst *, 10 > CacheLookups
SubLimitType getSubLimits(bool inForwardPass, llvm::IRBuilder<> *RB, LimitContext ctx, llvm::Value *extraSize=nullptr)
Given a LimitContext ctx, representing a location inside a loop nest, break each of the loops up into...
void storeInstructionInCache(LimitContext ctx, llvm::IRBuilder<> &BuilderM, llvm::Value *val, llvm::AllocaInst *cache, llvm::MDNode *TBAA=nullptr)
Given an allocation defined at a particular ctx, store the value val in the cache at the location def...
virtual llvm::Value * lookupM(llvm::Value *val, llvm::IRBuilder<> &BuilderM, const llvm::ValueToValueMapTy &incoming_availalble=llvm::ValueToValueMapTy(), bool tryLegalityCheck=true, llvm::BasicBlock *scope=nullptr)=0
High-level utility to get the value an instruction at a new location specified by BuilderM.
virtual bool assumeDynamicLoopOfSizeOne(llvm::Loop *L) const =0
llvm::SmallPtrSet< llvm::BasicBlock *, 4 > GuaranteedUnreachable
ScalarEvolution::ExitLimit computeExitLimit(const llvm::Loop *L, llvm::BasicBlock *ExitingBlock, bool AllowPredicates)
bool ForceSingleIteration
Container for all loop information to synthesize gradients.
llvm::Loop * parent
Parent loop of this loop.
llvm::BasicBlock * header
Header of this loop.
llvm::AssertingVH< llvm::Instruction > incvar
Increment of the induction.
bool dynamic
Whether this loop has a statically analyzable number of iterations.
llvm::SmallPtrSet< llvm::BasicBlock *, 8 > exitBlocks
All blocks this loop exits too.
llvm::AssertingVH< llvm::AllocaInst > antivaralloc
Allocation of induction variable of reverse pass.
llvm::AssertingVH< llvm::PHINode > var
Canonical induction variable of the loop.
AssertingReplacingVH offset
An offset to add to the index when getting the cache pointer.
llvm::BasicBlock * preheader
Preheader of this loop.
AssertingReplacingVH maxLimit
limit is last value of a canonical induction variable iters is number of times loop is run (thus iter...
AssertingReplacingVH allocLimit
An overriding allocation limit size.
AssertingReplacingVH trueLimit