35#include "llvm/IR/BasicBlock.h"
36#include "llvm/IR/Instruction.h"
37#include "llvm/IR/IntrinsicsX86.h"
39#include "llvm/ADT/ArrayRef.h"
40#include "llvm/ADT/SmallPtrSet.h"
41#include "llvm/ADT/SmallVector.h"
43#include "llvm/Support/Casting.h"
44#include "llvm/Support/ErrorHandling.h"
47#include "GradientUtils.h"
52StringMap<std::function<bool(
const CallInst *,
const GradientUtils *,
58 const Instruction *user,
59 const SmallPtrSetImpl<BasicBlock *> &oldUnreachable,
QueryType qtype,
63 if (
auto ainst = dyn_cast<Instruction>(val)) {
64 assert(ainst->getParent()->getParent() == gutils->
oldFunc);
73 assert(recursiveUse ==
nullptr);
75 assert(recursiveUse !=
nullptr);
84 if (TR.
query(
const_cast<Value *
>(val))[{-1}].isFloat())
89 llvm::errs() <<
" Need: of " << *val <<
" in reverse as nullptr user\n";
93 assert(user->getParent()->getParent() == gutils->
oldFunc);
95 if (oldUnreachable.count(user->getParent()))
98 if (
auto SI = dyn_cast<StoreInst>(user)) {
103 if (SI->getValueOperand() == val) {
104 for (
auto U : SI->getPointerOperand()->users()) {
105 if (
auto CI = dyn_cast<CallInst>(U)) {
106 if (
auto F = CI->getCalledFunction()) {
107 if (F->getName() ==
"__kmpc_for_static_init_4" ||
108 F->getName() ==
"__kmpc_for_static_init_4u" ||
109 F->getName() ==
"__kmpc_for_static_init_8" ||
110 F->getName() ==
"__kmpc_for_static_init_8u") {
111 if (CI->getArgOperand(4) == val ||
112 CI->getArgOperand(5) == val || CI->getArgOperand(6)) {
114 llvm::errs() <<
" Need direct primal of " << *val
115 <<
" in reverse from omp " << *user <<
"\n";
126 auto &DL = gutils->
newFunc->getParent()->getDataLayout();
127 auto ET = SI->getValueOperand()->getType();
128 auto storeSize = (DL.getTypeSizeInBits(ET) + 7) / 8;
129 auto vd = TR.
query(
const_cast<Value *
>(SI->getPointerOperand()))
139 bool hasFloat =
true;
140 for (ssize_t i = -1; i < (ssize_t)storeSize; ++i) {
141 if (vd[{(int)i}].isFloat()) {
147 SI->getPointerOperand()))) {
149 llvm::errs() <<
" Need direct primal of " << *val
150 <<
" in reverse from runtime active store " << *user
156 bool backwardsShadow =
false;
157 bool forwardsShadow =
true;
159 if (pair.second.stores.count(SI) &&
161 backwardsShadow =
true;
162 forwardsShadow = pair.second.primalInitialize;
169 if (SI->getValueOperand() == val) {
182 (forwardsShadow || backwardsShadow)) ||
190 auto ct = TR.
query(
const_cast<Value *
>(SI->getValueOperand()))[{-1}];
198 (forwardsShadow || backwardsShadow)) ||
206 const_cast<Value *
>(SI->getPointerOperand()))) {
208 llvm::errs() <<
" Need: shadow of " << *val
209 <<
" in reverse as shadow store " << *SI <<
"\n";
218 if (
auto LI = dyn_cast<LoadInst>(user)) {
220 auto vd = TR.
query(
const_cast<llvm::Instruction *
>(user));
222 auto ET = LI->getType();
230 auto &DL = gutils->
newFunc->getParent()->getDataLayout();
231 auto LoadSize = (DL.getTypeSizeInBits(LI->getType()) + 1) / 8;
232 bool hasFloat =
true;
233 for (ssize_t i = -1; i < (ssize_t)LoadSize; ++i) {
234 if (vd[{(int)i}].isFloat()) {
240 const_cast<llvm::Instruction *
>(user))) {
242 llvm::errs() <<
" Need direct primal of " << *val
243 <<
" in reverse from runtime active load " << *user
251 if (
auto MTI = dyn_cast<MemTransferInst>(user)) {
255 if (MTI->getArgOperand(1) == val || MTI->getArgOperand(2) == val) {
257 if (pair.second.stores.count(MTI)) {
259 llvm::errs() <<
" Need direct primal of " << *val
260 <<
" in reverse from remat memtransfer " << *user
271 llvm::errs() <<
" Need direct primal of " << *val
272 <<
" in reverse from memtransfer " << *user <<
"\n";
277 if (MTI->getArgOperand(0) != val && MTI->getArgOperand(1) != val)
281 const_cast<Value *
>(MTI->getArgOperand(0)))) {
283 llvm::errs() <<
" Need: shadow of " << *val
284 <<
" in reverse as shadow MTI " << *MTI <<
"\n";
291 if (
auto MS = dyn_cast<MemSetInst>(user)) {
295 if (MS->getArgOperand(1) == val || MS->getArgOperand(2) == val) {
297 if (pair.second.stores.count(MS)) {
299 llvm::errs() <<
" Need direct primal of " << *val
300 <<
" in reverse from remat memset " << *user <<
"\n";
306 llvm::errs() <<
" Need direct primal of " << *val
307 <<
" in reverse from memset " << *user <<
"\n";
313 if (MS->getArgOperand(0) != val)
316 if (!gutils->
isConstantValue(
const_cast<Value *
>(MS->getArgOperand(0)))) {
318 llvm::errs() <<
" Need: shadow of " << *val
319 <<
" in reverse as shadow MS " << *MS <<
"\n";
327 if (isa<CmpInst>(user) ||
isAnyBranch(user) || isa<ReturnInst>(user) ||
328 isa<FPExtInst>(user) || isa<FPTruncInst>(user)
338 if (
auto IEI = dyn_cast<InsertElementInst>(user)) {
341 if (IEI->getOperand(2) != val) {
347 TR.
query(
const_cast<InsertElementInst *
>(IEI))[{-1}] ==
352 llvm::errs() <<
" Need direct primal of " << *val
353 <<
" in reverse from non-pointer insertelem " << *user
355 << TR.
query(
const_cast<InsertElementInst *
>(IEI)).
str()
361 if (
auto EEI = dyn_cast<ExtractElementInst>(user)) {
364 if (EEI->getIndexOperand() != val) {
370 TR.
query(
const_cast<ExtractElementInst *
>(EEI))[{-1}] ==
375 llvm::errs() <<
" Need direct primal of " << *val
376 <<
" in reverse from non-pointer extractelem " << *user
378 << TR.
query(
const_cast<ExtractElementInst *
>(EEI)).
str()
384 if (
auto IVI = dyn_cast<InsertValueInst>(user)) {
387 bool valueIsIndex =
false;
388 for (
unsigned i = 2; i < IVI->getNumOperands(); ++i) {
389 if (IVI->getOperand(i) == val) {
400 TR.
query(
const_cast<InsertValueInst *
>(IVI))[{-1}] ==
405 llvm::errs() <<
" Need direct primal of " << *val
406 <<
" in reverse from non-pointer insertval " << *user
408 << TR.
query(
const_cast<InsertValueInst *
>(IVI)).
str()
414 if (
auto EVI = dyn_cast<ExtractValueInst>(user)) {
417 bool valueIsIndex =
false;
418 for (
unsigned i = 2; i < EVI->getNumOperands(); ++i) {
419 if (EVI->getOperand(i) == val) {
430 TR.
query(
const_cast<ExtractValueInst *
>(EVI))[{-1}] ==
435 llvm::errs() <<
" Need direct primal of " << *val
436 <<
" in reverse from non-pointer extractval " << *user
438 << TR.
query(
const_cast<ExtractValueInst *
>(EVI)).
str()
443 Intrinsic::ID ID = Intrinsic::not_intrinsic;
444 if (
auto II = dyn_cast<IntrinsicInst>(user)) {
445 ID = II->getIntrinsicID();
446 }
else if (
auto CI = dyn_cast<CallInst>(user)) {
451 if (ID != Intrinsic::not_intrinsic) {
452 if (ID == Intrinsic::lifetime_start || ID == Intrinsic::lifetime_end ||
453 ID == Intrinsic::stacksave || ID == Intrinsic::stackrestore) {
459 if (
auto si = dyn_cast<SelectInst>(user)) {
461 if (si->getCondition() != val) {
469 llvm::errs() <<
" Need direct primal of " << *val
470 <<
" in reverse from select " << *user <<
"\n";
475#include "BlasDiffUse.inc"
477 if (
auto CI = dyn_cast<CallInst>(user)) {
480 SmallVector<OperandBundleDef, 2> OrigDefs;
481 CI->getOperandBundlesAsDefs(OrigDefs);
482 SmallVector<OperandBundleDef, 2> Defs;
483 for (
auto bund : OrigDefs) {
484 for (
auto inp : bund.inputs()) {
496 bool useDefault =
false;
497 bool result = found->second(CI, gutils, val, shadow, mode, useDefault);
501 llvm::errs() <<
" Need: " <<
to_string(qtype) <<
" of " << *val
502 <<
" from custom diff use handler of " << *CI
521 llvm::errs() <<
" Need: shadow of " << *val
522 <<
" in reverse as shadow free " << *CI <<
"\n";
527 if (funcName ==
"MPI_Isend" || funcName ==
"MPI_Irecv" ||
528 funcName ==
"PMPI_Isend" || funcName ==
"PMPI_Irecv") {
532 if (val == CI->getArgOperand(6)) {
534 llvm::errs() <<
" Need: " <<
to_string(qtype) <<
" request " << *val
535 <<
" in reverse for MPI " << *CI <<
"\n";
538 if (shadow && val == CI->getArgOperand(0)) {
539 if ((funcName ==
"MPI_Irecv" || funcName ==
"PMPI_Irecv") &&
543 llvm::errs() <<
" Need: shadow(" <<
to_string(qtype) <<
") of "
544 << *val <<
" in reverse as shadow MPI " << *CI <<
"\n";
547 if (funcName ==
"MPI_Isend" || funcName ==
"PMPI_Isend") {
550 llvm::errs() <<
" Need: shadow(" <<
to_string(qtype) <<
") of "
551 << *val <<
" in reverse as shadow MPI " << *CI <<
"\n";
562 if (funcName ==
"cuStreamSynchronize")
563 if (val == CI->getArgOperand(0)) {
565 llvm::errs() <<
" Need: primal(" <<
to_string(qtype) <<
") of "
566 << *val <<
" in reverse for cuda sync " << *CI <<
"\n";
571 if (funcName ==
"MPI_Wait" || funcName ==
"PMPI_Wait")
572 if (val != CI->getArgOperand(0))
576 if (funcName ==
"MPI_Waitall" || funcName ==
"PMPI_Waitall")
577 if (val != CI->getArgOperand(0) || val != CI->getOperand(1))
583 if (funcName ==
"MPI_Wait" || funcName ==
"PMPI_Wait") {
588 if (val == CI->getArgOperand(0)) {
590 llvm::errs() <<
" Need: shadow of " << *val
591 <<
" in reverse as shadow MPI " << *CI <<
"\n";
601 if (funcName ==
"__kmpc_barrier" || funcName ==
"MPI_Barrier") {
603 llvm::errs() <<
" Need direct primal of " << *val
604 <<
" in reverse from barrier " << *user <<
"\n";
611 if (funcName ==
"llvm.julia.gc_preserve_begin") {
613 llvm::errs() <<
" Need direct primal of " << *val
614 <<
" in reverse from gc " << *CI <<
"\n";
618 if (funcName ==
"julia.write_barrier" ||
619 funcName ==
"julia.write_barrier_binding") {
625 llvm::errs() <<
" Need: shadow of " << *val
626 <<
" in forward as shadow write_barrier " << *CI <<
"\n";
630 auto sz = CI->arg_size();
631 bool isStored =
false;
633 for (
size_t i = 1; i < sz; i++)
634 isStored |= val == CI->getArgOperand(i);
635 bool rematerialized =
false;
638 if (pair.second.stores.count(CI) &&
640 rematerialized =
true;
644 if (rematerialized) {
647 <<
" Need: shadow of " << *val
648 <<
" in rematerialized reverse as shadow write_barrier " << *CI
655 bool writeOnlyNoCapture =
true;
658 writeOnlyNoCapture =
false;
666 for (
size_t i = 0; i < CI->arg_size(); i++) {
667 if (val == CI->getArgOperand(i)) {
669 writeOnlyNoCapture =
false;
673 writeOnlyNoCapture =
false;
682 if (writeOnlyNoCapture) {
684 llvm::errs() <<
" No Need: primal of " << *val
685 <<
" per write-only no-capture use in " << *CI <<
"\n";
693 if (writeOnlyNoCapture &&
698 const Value *FV = CI->getCalledOperand();
703 llvm::errs() <<
" Need: shadow of " << *val
704 <<
" in reverse as shadow call " << *CI <<
"\n";
712 if (isa<ReturnInst>(user)) {
721 llvm::errs() <<
" Need: shadow(qtype=" << (int)qtype
722 <<
",cv=" << inst_cv <<
") of " << *val
723 <<
" in reverse as shadow return " << *user <<
"\n";
735 (!isa<ExtractValueInst>(user) && !isa<ExtractElementInst>(user) &&
736 !isa<InsertValueInst>(user) && !isa<InsertElementInst>(user) &&
745 llvm::errs() <<
" Need: shadow of " << *val
746 <<
" in reverse as shadow inst " << *user <<
"\n";
758 const_cast<Value *
>((
const llvm::Value *)user))) {
764 assert(recursiveUse);
765 *recursiveUse =
true;
769 bool neededFB =
false;
770 if (
auto CB = dyn_cast<CallBase>(
const_cast<Instruction *
>(user))) {
771 neededFB = !callShouldNotUseDerivative(gutils, *CB, qtype, val);
778 llvm::errs() <<
" Need direct primal(" << mode <<
") of " << *val
779 <<
" in reverse from fallback " << *user <<
"\n";
785 for (
auto &pair : G) {
786 llvm::errs() <<
"[" << *pair.first.V <<
", " << (int)pair.first.outgoing
788 for (
auto N : pair.second) {
789 llvm::errs() <<
"\t[" << *N.V <<
", " << (int)N.outgoing <<
"]\n";
797 const SetVector<Value *> &Recompute,
798 std::map<Node, Node> &parent) {
800 for (
auto V : Recompute) {
802 parent.emplace(N, Node(
nullptr,
true));
810 auto found = G.find(u);
811 if (found == G.end())
813 for (
auto v : found->second) {
814 if (parent.find(v) == parent.end()) {
816 parent.emplace(v, u);
830 else if (prev ==
nullptr)
832 for (Loop *L = prev; L !=
nullptr; L = L->getParentLoop()) {
840 const SetVector<Value *> &Recomputes,
841 const SetVector<Value *> &Intermediates,
842 SetVector<Value *> &Required,
843 SetVector<Value *> &MinReq,
845 llvm::TargetLibraryInfo &TLI) {
847 for (
auto V : Intermediates) {
848 G[Node(V,
false)].insert(Node(V,
true));
849 forEachDifferentialUser(
851 if (Intermediates.count(U)) {
853 G[Node(V,
true)].insert(Node(U,
false));
859 if (Intermediates.count(pair.first)) {
860 for (LoadInst *L : pair.second.loads) {
861 if (Intermediates.count(L)) {
863 G[Node(pair.first,
true)].insert(Node(L,
false));
866 for (
auto L : pair.second.loadLikeCalls) {
867 if (Intermediates.count(L.loadCall)) {
868 if (L.loadCall != pair.first)
869 G[Node(pair.first,
true)].insert(Node(L.loadCall,
false));
875 for (
auto R : Required) {
876 assert(Intermediates.count(R));
878 for (
auto R : Recomputes) {
879 assert(Intermediates.count(R));
887 std::map<Node, Node> parent;
888 bfs(G, Recomputes, parent);
889 Node end(
nullptr,
false);
890 for (
auto req : Required) {
891 if (parent.find(Node(req,
true)) != parent.end()) {
892 end = Node(req,
true);
896 if (end.V ==
nullptr)
902 assert(parent.find(v) != parent.end());
903 Node u = parent.find(v)->second;
904 assert(u.V !=
nullptr);
905 assert(G[u].count(v) == 1);
906 assert(G[v].count(u) == 0);
909 if (Recomputes.count(u.V) && u.outgoing ==
false)
917 std::map<Node, Node> parent;
918 bfs(G, Recomputes, parent);
920 SetVector<Value *> todo;
924 for (
auto &pair : Orig) {
925 if (parent.find(pair.first) != parent.end())
926 for (
auto N : pair.second) {
927 if (parent.find(N) == parent.end()) {
928 assert(pair.first.outgoing == 0 && N.outgoing == 1);
929 assert(pair.first.V == N.V);
936 while (todo.size()) {
937 auto V = todo.front();
939 assert(MinReq.count(V));
944 for (
auto &pair : Orig) {
945 if (pair.second.count(Node(V,
false))) {
946 MinReq.insert(pair.first.V);
947 todo.insert(pair.first.V);
953 auto found = Orig.find(Node(V,
true));
954 if (found != Orig.end()) {
955 const auto &mp = found->second;
959 if (mp.size() == 1 && !Required.count(V)) {
960 bool potentiallyRecursive =
961 isa<PHINode>((*mp.begin()).V) &&
962 OrigLI.isLoopHeader(cast<PHINode>((*mp.begin()).V)->getParent());
964 cmpLoopNest(OrigLI.getLoopFor(cast<Instruction>(V)->getParent()),
966 cast<Instruction>(((*mp.begin()).V))->getParent()));
967 if (potentiallyRecursive)
969 if (moreOuterLoop == -1)
971 if (
auto ASC = dyn_cast<AddrSpaceCastInst>((*mp.begin()).V)) {
972 if (ASC->getDestAddressSpace() == 11 ||
973 ASC->getDestAddressSpace() == 13)
975 if (ASC->getSrcAddressSpace() == 10 &&
976 ASC->getDestAddressSpace() == 0)
979 if (
auto CI = dyn_cast<CastInst>((*mp.begin()).V)) {
980 if (CI->getType()->isPointerTy() &&
981 CI->getType()->getPointerAddressSpace() == 13)
984 if (
auto G = dyn_cast<GetElementPtrInst>((*mp.begin()).V)) {
985 if (G->getType()->getPointerAddressSpace() == 13)
993 auto next = (*mp.begin()).V;
994 bool noncapture =
false;
995 if (isa<LoadInst>(next) ||
isNVLoad(next)) {
997 }
else if (
auto CI = dyn_cast<CallInst>(next)) {
998 bool captures =
false;
999 for (
size_t i = 0; i < CI->arg_size(); i++) {
1000 if (CI->getArgOperand(i) == V && !
isNoCapture(CI, i)) {
1005 noncapture = !captures;
1012 if (moreOuterLoop == 1 ||
1013 (moreOuterLoop == 0 &&
1014 DL.getTypeSizeInBits(V->getType()) >=
1015 DL.getTypeSizeInBits((*mp.begin()).V->getType()))) {
1017 auto nnode = (*mp.begin()).V;
1018 MinReq.insert(nnode);
1019 if (Orig.find(Node(nnode,
true)) != Orig.end())
1029 for (
auto V : Intermediates) {
1033 if (!found->second.nonRepeatableWritingCall)
1037 if (MinReq.count(V))
1041 bool needsLoad =
false;
1042 for (
auto load : found->second.loads)
1043 if (Intermediates.count(load) && !MinReq.count(load)) {
1047 for (
auto load : found->second.loadLikeCalls)
1048 if (Intermediates.count(load.loadCall) && !MinReq.count(load.loadCall)) {
1068 bool shadowReturnUsed =
false;
1069 auto smode = gutils->
mode;
1074 bool useConstantFallback =
1083 bool escapingNeededAllocation =
false;
1092 SmallVector<Function *, 1> todo = {F};
1093 SmallPtrSet<Function *, 1> done;
1094 bool seenAllocation =
false;
1095 while (todo.size() && !seenAllocation) {
1096 auto cur = todo.pop_back_val();
1097 if (done.count(cur))
1105 seenAllocation =
true;
1109 for (
auto &BB : *cur) {
1113 if (
auto CB = dyn_cast<CallBase>(&I)) {
1117 seenAllocation =
true;
1125 seenAllocation =
true;
1130 if (!seenAllocation)
1131 goto doneEscapeCheck;
1136 for (
unsigned i = 0; i < call.arg_size(); ++i) {
1137 Value *a = call.getOperand(i);
1145 const auto &vd = gutils->
TR.
query(a);
1147 if (!vd[{-1, -1}].isPossiblePointer())
1164 escapingNeededAllocation =
true;
1165 goto doneEscapeCheck;
1172 escapingNeededAllocation =
true;
1173 goto doneEscapeCheck;
1178 goto doneEscapeCheck;
1182 goto doneEscapeCheck;
1185 std::map<UsageKey, bool> CacheResults =
1190 CacheResults[
UsageKey(val, qtype)] =
true;
1194 if (!found->second) {
1196 escapingNeededAllocation =
1200 CacheResults, gutils->notForAnalysis);
1203 escapingNeededAllocation =
1207 CacheResults, gutils->notForAnalysis);
1213 if (escapingNeededAllocation)
1214 useConstantFallback =
false;
1216 return useConstantFallback;
1222 const llvm::PHINode *P0,
1223 const llvm::Value *incomingVal) {
1224 using namespace llvm;
1227 auto L = gutils->
OrigLI->getLoopFor(P0->getParent());
1228 if (!L || L->getHeader() != P0->getParent())
1230 BasicBlock *preheader = L->getLoopPreheader();
1233 Value *Pstart = P0->getIncomingValueForBlock(preheader);
1234 while (
auto phi = dyn_cast_or_null<PHINode>(Pstart)) {
1235 if (phi->getNumIncomingValues() == 1)
1236 Pstart = phi->getIncomingValue(0);
1240 if (Pstart != incomingVal &&
1241 P0->getIncomingValueForBlock(preheader) != incomingVal)
1244 SmallVector<const Instruction *, 4> activeUses;
1245 for (
auto u : P0->users()) {
1246 if (
auto I = dyn_cast<Instruction>(u)) {
1248 activeUses.push_back(I);
1252 if (activeUses.size() != 1)
1254 const Instruction *userInst = activeUses[0];
1255 bool isLoopyReduction =
false;
1256 if (
auto BO = dyn_cast<BinaryOperator>(userInst)) {
1257 if (BO->getOpcode() == Instruction::FDiv && BO->getOperand(0) == P0 &&
1259 isLoopyReduction =
true;
1265 if (!isLoopyReduction)
1268 SmallVector<BasicBlock *, 1> Latches;
1269 L->getLoopLatches(Latches);
1270 for (
auto Latch : Latches) {
1271 if (userInst != P0->getIncomingValueForBlock(Latch)) {
1275 SmallVector<BasicBlock *, 2> exitBlocks;
1276 L->getExitBlocks(exitBlocks);
1277 if (exitBlocks.size() != 1)
1284 llvm::SetVector<llvm::Value *> &Intermediates,
1285 std::deque<llvm::Value *> &todo) {
1286 using namespace llvm;
1287 if (
auto P0 = dyn_cast<PHINode>(V)) {
1290 auto L = gutils->
OrigLI->getLoopFor(P0->getParent());
1291 if (!L || L->getHeader() != P0->getParent())
1293 BasicBlock *preheader = L->getLoopPreheader();
1296 Value *Pstart = P0->getIncomingValueForBlock(preheader);
1299 SmallVector<const Instruction *, 4> activeUses;
1300 for (
auto u : P0->users()) {
1301 if (
auto I = dyn_cast<Instruction>(u)) {
1303 activeUses.push_back(I);
1307 if (activeUses.size() != 1)
1309 const Instruction *userInst = activeUses[0];
1310 bool isLoopyReduction =
false;
1311 if (
auto BO = dyn_cast<BinaryOperator>(userInst)) {
1312 if (BO->getOpcode() == Instruction::FDiv && BO->getOperand(0) == P0 &&
1314 isLoopyReduction =
true;
1317 if (!isLoopyReduction)
1320 SmallVector<BasicBlock *, 1> Latches;
1321 L->getLoopLatches(Latches);
1322 for (
auto Latch : Latches) {
1323 if (userInst != P0->getIncomingValueForBlock(Latch)) {
1327 SmallVector<BasicBlock *, 2> exitBlocks;
1328 L->getExitBlocks(exitBlocks);
1329 if (exitBlocks.size() != 1)
1336 if (!isa<Instruction>(Pstart))
1338 Intermediates.insert(Pstart);
1339 todo.push_back(Pstart);
1340 if (
auto phi = dyn_cast<PHINode>(Pstart)) {
1341 if (phi->getNumIncomingValues() == 1)
1342 Pstart = phi->getIncomingValue(0);
StringMap< std::function< bool(const CallInst *, const GradientUtils *, const Value *, bool, DerivativeMode, bool &)> > customDiffUseHandlers
llvm::cl::opt< bool > EnzymePrintDiffUse
static llvm::SmallPtrSet< llvm::BasicBlock *, 4 > getGuaranteedUnreachable(llvm::Function *F)
static bool isDeallocationFunction(const llvm::StringRef name, const llvm::TargetLibraryInfo &TLI)
Return whether a given function is a known C/C++ memory deallocation function For updating below one ...
static bool isAllocationFunction(const llvm::StringRef name, const llvm::TargetLibraryInfo &TLI)
Return whether a given function is a known C/C++ memory allocation function For updating below one sh...
static bool isAllocationCall(const llvm::Value *TmpOrig, llvm::TargetLibraryInfo &TLI)
static bool isReadOnly(Operation *op)
static Operation * getFunctionFromCall(CallOpInterface iface)
llvm::cl::opt< bool > EnzymeGlobalActivity
constexpr const char * to_string(ActivityAnalyzer::UseActivity UA)
llvm::cl::opt< bool > looseTypeAnalysis
QueryType
Classification of what type of use is requested.
std::pair< const llvm::Value *, QueryType > UsageKey
TypeTree defaultTypeTreeForLLVM(llvm::Type *ET, llvm::Instruction *I, bool intIsPointer)
static bool isMemFreeLibMFunction(llvm::StringRef str, llvm::Intrinsic::ID *ID=nullptr)
bool isNVLoad(const llvm::Value *V)
static bool isNoEscapingAllocation(const llvm::Function *F)
static bool isNoCapture(const llvm::CallBase *call, size_t idx)
static bool isPointerArithmeticInst(const llvm::Value *V, bool includephi=true, bool includebin=true)
static bool shouldDisableNoWrite(const llvm::CallInst *CI)
static bool isSpecialPtr(llvm::Type *Ty)
static bool hasNoCache(llvm::Value *op)
llvm::cl::opt< bool > EnzymeJuliaAddrLoad
static bool isAnyBranch(const llvm::Value *V)
static llvm::StringRef getFuncNameFromCall(const llvm::CallBase *op)
static bool isWriteOnly(const llvm::Function *F, ssize_t arg=-1)
llvm::Function *const newFunc
The function whose instructions we are caching.
llvm::TargetLibraryInfo & TLI
Various analysis results of newFunc.
std::map< const llvm::Value *, bool > knownRecomputeHeuristic
llvm::ValueMap< llvm::Value *, Rematerializer > rematerializableAllocations
std::map< UsageKey, bool > populateSeenFromKnownRecompute() const
DIFFE_TYPE getReturnDiffeType(llvm::Value *orig, bool *primalReturnUsedP, bool *shadowReturnUsedP, DerivativeMode cmode) const
bool isConstantInstruction(const llvm::Instruction *inst) const
llvm::ValueMap< llvm::Value *, ShadowRematerializer > backwardsOnlyShadows
Only loaded from and stored to (not captured), mapped to the stores (and memset).
bool isConstantValue(llvm::Value *val) const
A holder class representing the results of running TypeAnalysis on a given function.
bool anyPointer(llvm::Value *val) const
Whether any part of the top level register can contain a pointer e.g.
const TypeTree & query(llvm::Value *val) const
The TypeTree of a particular Value.
TypeTree Lookup(size_t len, const llvm::DataLayout &dl) const
Select all submappings whose first index is in range [0, len) and remove the first index.
std::string str() const
Returns a string representation of this TypeTree.
void minCut(const llvm::DataLayout &DL, llvm::LoopInfo &OrigLI, const llvm::SetVector< llvm::Value * > &Recomputes, const llvm::SetVector< llvm::Value * > &Intermediates, llvm::SetVector< llvm::Value * > &Required, llvm::SetVector< llvm::Value * > &MinReq, const GradientUtils *gutils, llvm::TargetLibraryInfo &TLI)
bool callShouldNotUseDerivative(const GradientUtils *gutils, llvm::CallBase &orig, QueryType qtype, const llvm::Value *val)
Return whether or not this is a constant and should use reverse pass.
bool is_value_needed_in_reverse(const GradientUtils *gutils, const llvm::Value *inst, DerivativeMode mode, std::map< UsageKey, bool > &seen, const llvm::SmallPtrSetImpl< llvm::BasicBlock * > &oldUnreachable)
void bfs(const std::map< Node, std::set< Node > > &G, const llvm::SetVector< llvm::Value * > &Recompute, std::map< Node, Node > &parent)
void dump(std::map< Node, std::set< Node > > &G)
void pushLoopyPHIPreheader(const GradientUtils *gutils, llvm::Value *V, llvm::SetVector< llvm::Value * > &Intermediates, std::deque< llvm::Value * > &todo)
bool is_use_directly_needed_in_reverse(const GradientUtils *gutils, const llvm::Value *val, DerivativeMode mode, const llvm::Instruction *user, const llvm::SmallPtrSetImpl< llvm::BasicBlock * > &oldUnreachable, QueryType shadow, bool *recursiveUse=nullptr)
Determine if a value is needed directly to compute the adjoint of the given instruction user.
bool checkLoopyReductionPHI(const GradientUtils *gutils, const llvm::PHINode *P0, const llvm::Value *incomingVal)
int cmpLoopNest(llvm::Loop *prev, llvm::Loop *next)