94 std::map<UsageKey, bool> &seen,
95 const llvm::SmallPtrSetImpl<llvm::BasicBlock *> &oldUnreachable) {
102 if (seen.find(idx) != seen.end())
104 if (
auto ainst = dyn_cast<Instruction>(inst)) {
105 assert(ainst->getParent()->getParent() == gutils->
oldFunc);
112 if (
auto op = dyn_cast<BinaryOperator>(inst)) {
113 if (op->getOpcode() == Instruction::FDiv) {
117 llvm::errs() <<
" Need: " <<
to_string(VT) <<
" of " << *inst
118 <<
" in reverse as is active div\n";
119 return seen[idx] =
true;
127 <<
" Need: " <<
to_string(VT) <<
" of " << *inst
128 <<
" in reverse as forward mode error always needs result\n";
129 return seen[idx] =
true;
133 if (
auto CI = dyn_cast<CallInst>(inst)) {
135 if (funcName ==
"julia.get_pgcstack" || funcName ==
"julia.ptls_states")
136 return seen[idx] =
true;
142 for (
auto use : inst->users()) {
146 const Instruction *user = dyn_cast<Instruction>(use);
154 bool recursiveUse =
false;
156 gutils, inst, mode, user, oldUnreachable,
160 return seen[idx] =
true;
163 if (recursiveUse && !OneLevel) {
167 gutils, user, mode, seen, oldUnreachable);
170 gutils, user, mode, seen, oldUnreachable);
173 llvm::errs() <<
" Need: " <<
to_string(VT) <<
" of " << *inst
174 <<
" in reverse as shadow sub-need " << *user <<
"\n";
175 return seen[idx] =
true;
179 if (!TR.
allFloat(
const_cast<Value *
>(inst)))
180 if (
auto IVI = dyn_cast<Instruction>(user)) {
181 bool inserted =
false;
182 if (
auto II = dyn_cast<InsertValueInst>(IVI))
183 inserted = II->getInsertedValueOperand() == inst ||
184 II->getAggregateOperand() == inst;
185 if (
auto II = dyn_cast<ExtractValueInst>(IVI))
186 inserted = II->getAggregateOperand() == inst;
187 if (
auto II = dyn_cast<InsertElementInst>(IVI))
188 inserted = II->getOperand(1) == inst || II->getOperand(0) == inst;
189 if (
auto II = dyn_cast<ExtractElementInst>(IVI))
190 inserted = II->getOperand(0) == inst;
192 SmallVector<const Instruction *, 1> todo;
194 while (todo.size()) {
195 auto cur = todo.pop_back_val();
196 for (
auto u : cur->users()) {
197 if (
auto IVI2 = dyn_cast<InsertValueInst>(u)) {
198 todo.push_back(IVI2);
201 if (
auto IVI2 = dyn_cast<ExtractValueInst>(u)) {
202 todo.push_back(IVI2);
205 if (
auto IVI2 = dyn_cast<InsertElementInst>(u)) {
206 todo.push_back(IVI2);
209 if (
auto IVI2 = dyn_cast<ExtractElementInst>(u)) {
210 todo.push_back(IVI2);
214 bool partial =
false;
215 if (
auto UI = dyn_cast<Instruction>(u)) {
217 const_cast<Instruction *
>(cur))) {
218 bool recursiveUse =
false;
220 gutils, cur, mode, UI, oldUnreachable,
223 }
else if (recursiveUse && !OneLevel) {
225 gutils, UI, mode, seen, oldUnreachable);
228 bool recursiveUse =
false;
230 gutils, cur, mode, UI, oldUnreachable,
233 }
else if (recursiveUse && !OneLevel) {
236 seen, oldUnreachable);
245 <<
" Need (partial) direct " <<
to_string(VT) <<
" of "
246 << *inst <<
" in reverse from insertelem " << *user
247 <<
" via " << *cur <<
" in " << *u <<
"\n";
248 return seen[idx] =
true;
261 if (
auto P0 = dyn_cast<PHINode>(user)) {
264 llvm::errs() <<
" Need: " <<
to_string(VT) <<
"(" << mode <<
") of "
266 <<
" in reverse as loopy reduction preheader of "
268 return seen[idx] =
true;
270 if (P0->getNumIncomingValues() == 1) {
271 for (
auto u2 : P0->users()) {
272 if (
auto P1 = dyn_cast<PHINode>(u2)) {
277 <<
" Need: " <<
to_string(VT) <<
"(" << mode <<
") of "
279 <<
" in reverse via LCSSA loopy reduction preheader of "
281 return seen[idx] =
true;
292 llvm::errs() <<
" Need: " <<
to_string(VT) <<
"(" << mode <<
") of "
293 << *inst <<
" in reverse as sub-need " << *user <<
"\n";
294 return seen[idx] =
true;
300 bool isStored =
false;
301 if (
auto SI = dyn_cast<StoreInst>(user))
302 isStored = inst == SI->getValueOperand();
303 else if (
auto MTI = dyn_cast<MemTransferInst>(user)) {
304 isStored = inst == MTI->getSource() || inst == MTI->getLength();
305 }
else if (
auto MS = dyn_cast<MemSetInst>(user)) {
306 isStored = inst == MS->getLength() || inst == MS->getValue();
307 }
else if (
auto CB = dyn_cast<CallBase>(user)) {
309 if (name ==
"julia.write_barrier" ||
310 name ==
"julia.write_barrier_binding") {
311 auto sz = CB->arg_size();
313 for (
size_t i = 1; i < sz; i++)
314 isStored |= inst == CB->getArgOperand(i);
329 if (found != seen.end() && !found->second) {
338 if (pair.second.stores.count(user)) {
343 llvm::errs() <<
" Need: " <<
to_string(VT) <<
" of " << *inst
344 <<
" in reverse from rematerialized alloc "
345 << *pair.first <<
"\n";
346 return seen[idx] =
true;
348 for (LoadInst *L : pair.second.loads)
352 llvm::errs() <<
" Need: " <<
to_string(VT) <<
" of " << *inst
353 <<
" in reverse as rematload " << *L <<
"\n";
354 return seen[idx] =
true;
356 for (
auto &pair : pair.second.loadLikeCalls)
358 gutils, pair.operand, mode, pair.loadCall, oldUnreachable,
361 seen, oldUnreachable)) {
363 llvm::errs() <<
" Need: " <<
to_string(VT) <<
" of " << *inst
364 <<
" in reverse as rematloadcall "
365 << *pair.loadCall <<
"\n";
366 return seen[idx] =
true;
373 <<
" Need: " <<
to_string(VT) <<
" of " << *inst
374 <<
" in reverse as rematalloc " << *pair.first <<
"\n";
375 return seen[idx] =
true;
399 for (
auto suc : successors(cast<Instruction>(use)->getParent())) {
400 if (!oldUnreachable.count(suc)) {
407 llvm::errs() <<
" Need: " <<
to_string(VT) <<
" of " << *inst
408 <<
" in reverse as control-flow " << *user <<
"\n";
409 return seen[idx] =
true;
412 if (
auto CI = dyn_cast<CallInst>(use)) {
413 if (
auto F = CI->getCalledFunction()) {
414 if (F->getName() ==
"__kmpc_for_static_init_4" ||
415 F->getName() ==
"__kmpc_for_static_init_4u" ||
416 F->getName() ==
"__kmpc_for_static_init_8" ||
417 F->getName() ==
"__kmpc_for_static_init_8u") {
419 llvm::errs() <<
" Need: " <<
to_string(VT) <<
" of " << *inst
420 <<
" in reverse as omp init " << *user <<
"\n";
421 return seen[idx] =
true;
431 bool primalUsedInShadowPointer =
true;
432 if (isa<CastInst>(user) || isa<LoadInst>(user))
433 primalUsedInShadowPointer =
false;
434 if (
auto CI = dyn_cast<CallInst>(user)) {
436 if (funcName ==
"julia.pointer_from_objref") {
437 primalUsedInShadowPointer =
false;
439 if (funcName ==
"julia.gc_loaded") {
440 primalUsedInShadowPointer =
false;
442 if (funcName.contains(
"__enzyme_todense")) {
443 primalUsedInShadowPointer =
false;
445 if (funcName.contains(
"__enzyme_ignore_derivatives")) {
446 primalUsedInShadowPointer =
false;
449 if (
auto GEP = dyn_cast<GetElementPtrInst>(user)) {
450 bool idxUsed =
false;
451 for (
auto &idx : GEP->indices()) {
452 if (idx.get() == inst)
456 primalUsedInShadowPointer =
false;
458 if (
auto II = dyn_cast<IntrinsicInst>(user)) {
460 const std::array<size_t, 4> idxArgsIndices{{0, 1, 2, 4}};
461 bool idxUsed =
false;
462 for (
auto i : idxArgsIndices) {
463 if (II->getOperand(i) == inst)
467 primalUsedInShadowPointer =
false;
472 if (isa<InsertValueInst>(user) || isa<ExtractValueInst>(user))
473 primalUsedInShadowPointer =
false;
475 if (primalUsedInShadowPointer)
476 if (!user->getType()->isVoidTy() &&
477 TR.
anyPointer(
const_cast<Instruction *
>(user))) {
479 gutils, user, mode, seen, oldUnreachable)) {
481 llvm::errs() <<
" Need: " <<
to_string(VT) <<
" of " << *inst
482 <<
" in reverse as used to compute shadow ptr "
484 return seen[idx] =
true;
493 if (inst->getType()->isTokenTy()) {
494 llvm::errs() <<
" need " << *inst <<
" via " << *user <<
"\n";
496 assert(!inst->getType()->isTokenTy());
498 return seen[idx] =
true;
553forEachDirectInsertUser(llvm::function_ref<
void(llvm::Instruction *)> f,
555 llvm::Value *val,
bool useCheck) {
556 using namespace llvm;
559 bool inserted =
false;
560 if (
auto II = dyn_cast<InsertValueInst>(IVI))
561 inserted = II->getInsertedValueOperand() == val ||
562 II->getAggregateOperand() == val;
563 if (
auto II = dyn_cast<ExtractValueInst>(IVI))
564 inserted = II->getAggregateOperand() == val;
565 if (
auto II = dyn_cast<InsertElementInst>(IVI))
566 inserted = II->getOperand(1) == val || II->getOperand(0) == val;
567 if (
auto II = dyn_cast<ExtractElementInst>(IVI))
568 inserted = II->getOperand(0) == val;
570 SmallVector<Instruction *, 1> todo;
572 while (todo.size()) {
573 auto cur = todo.pop_back_val();
574 for (
auto u : cur->users()) {
575 if (isa<InsertValueInst>(u) || isa<InsertElementInst>(u) ||
576 isa<ExtractValueInst>(u) || isa<ExtractElementInst>(u)) {
577 auto I2 = cast<Instruction>(u);
578 bool subCheck = useCheck;