Enzyme main
Loading...
Searching...
No Matches
DifferentialUseAnalysis.cpp
Go to the documentation of this file.
1//===- DifferentialUseAnalysis.cpp - Determine values needed in reverse
2// pass-===//
3//
4// Enzyme Project
5//
6// Part of the Enzyme Project, under the Apache License v2.0 with LLVM
7// Exceptions. See https://llvm.org/LICENSE.txt for license information.
8// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
9//
10// If using this code in an academic setting, please cite the following:
11// @incollection{enzymeNeurips,
12// title = {Instead of Rewriting Foreign Code for Machine Learning,
13// Automatically Synthesize Fast Gradients},
14// author = {Moses, William S. and Churavy, Valentin},
15// booktitle = {Advances in Neural Information Processing Systems 33},
16// year = {2020},
17// note = {To appear in},
18// }
19//
20//===----------------------------------------------------------------------===//
21//
22// This file contains the declaration of Differential USe Analysis -- an
23// AD-specific analysis that deduces if a given value is needed in the reverse
24// pass.
25//
26//===----------------------------------------------------------------------===//
27
28#include <deque>
29#include <map>
30#include <set>
31
33#include "Utils.h"
34
35#include "llvm/IR/BasicBlock.h"
36#include "llvm/IR/Instruction.h"
37#include "llvm/IR/IntrinsicsX86.h"
38
39#include "llvm/ADT/ArrayRef.h"
40#include "llvm/ADT/SmallPtrSet.h"
41#include "llvm/ADT/SmallVector.h"
42
43#include "llvm/Support/Casting.h"
44#include "llvm/Support/ErrorHandling.h"
45
46#include "DiffeGradientUtils.h"
47#include "GradientUtils.h"
48#include "LibraryFuncs.h"
49
50using namespace llvm;
51
52StringMap<std::function<bool(const CallInst *, const GradientUtils *,
53 const Value *, bool, DerivativeMode, bool &)>>
55
57 const GradientUtils *gutils, const Value *val, DerivativeMode mode,
58 const Instruction *user,
59 const SmallPtrSetImpl<BasicBlock *> &oldUnreachable, QueryType qtype,
60 bool *recursiveUse) {
61 TypeResults const &TR = gutils->TR;
62#ifndef NDEBUG
63 if (auto ainst = dyn_cast<Instruction>(val)) {
64 assert(ainst->getParent()->getParent() == gutils->oldFunc);
65 }
66#endif
67
68 bool shadow =
70
71 /// Recursive use is only usable in shadow mode.
72 if (!shadow)
73 assert(recursiveUse == nullptr);
74 else
75 assert(recursiveUse != nullptr);
76
77 if (!shadow && isPointerArithmeticInst(user, /*includephi*/ true,
78 /*includebin*/ false)) {
79 return false;
80 }
81
82 // Floating point numbers cannot be used as a shadow pointer/etc
84 if (TR.query(const_cast<Value *>(val))[{-1}].isFloat())
85 return false;
86
87 if (!user) {
89 llvm::errs() << " Need: of " << *val << " in reverse as nullptr user\n";
90 return true;
91 }
92
93 assert(user->getParent()->getParent() == gutils->oldFunc);
94
95 if (oldUnreachable.count(user->getParent()))
96 return false;
97
98 if (auto SI = dyn_cast<StoreInst>(user)) {
99 if (!shadow) {
100
101 // We don't need any of the input operands to compute the adjoint of a
102 // store instance The one exception to this is stores to the loop bounds.
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";
116 return true;
117 }
118 }
119 }
120 }
121 }
122 }
123
124 // And runtime activity updates
125 if (gutils->runtimeActivity && SI->getPointerOperand() == val) {
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()))
130 .Lookup(storeSize, DL);
131 if (!vd.isKnown()) {
132 // It verbatim needs to replicate the same behavior as
133 // adjointgenerator. From reverse mode type analysis
134 // (https://github.com/EnzymeAD/Enzyme/blob/194875cbccd73d63cacfefbfa85c1f583c2fa1fe/enzyme/Enzyme/AdjointGenerator.h#L556)
135 if (looseTypeAnalysis || true) {
136 vd = defaultTypeTreeForLLVM(ET, const_cast<StoreInst *>(SI));
137 }
138 }
139 bool hasFloat = true;
140 for (ssize_t i = -1; i < (ssize_t)storeSize; ++i) {
141 if (vd[{(int)i}].isFloat()) {
142 hasFloat = true;
143 break;
144 }
145 }
146 if (hasFloat && !gutils->isConstantValue(const_cast<llvm::Value *>(
147 SI->getPointerOperand()))) {
149 llvm::errs() << " Need direct primal of " << *val
150 << " in reverse from runtime active store " << *user
151 << "\n";
152 return true;
153 }
154 }
155 } else {
156 bool backwardsShadow = false;
157 bool forwardsShadow = true;
158 for (auto pair : gutils->backwardsOnlyShadows) {
159 if (pair.second.stores.count(SI) &&
160 !gutils->isConstantValue(pair.first)) {
161 backwardsShadow = true;
162 forwardsShadow = pair.second.primalInitialize;
163 }
164 }
165
166 // Preserve any non-floating point values that are stored in an active
167 // backwards creation shadow.
168
169 if (SI->getValueOperand() == val) {
170 // storing an active pointer into a location
171 // doesn't require the shadow pointer for the
172 // reverse pass
173 // Unless the store is into a backwards store, which would
174 // would then be performed in the reverse if the stored value was
175 // a possible pointer.
176
177 if (!((mode == DerivativeMode::ReverseModePrimal && forwardsShadow) ||
179 backwardsShadow) ||
180 (mode == DerivativeMode::ForwardModeSplit && backwardsShadow) ||
182 (forwardsShadow || backwardsShadow)) ||
185 return false;
186 } else {
187 // Likewise, if not rematerializing in reverse pass, you
188 // don't need to keep the pointer operand for known pointers
189
190 auto ct = TR.query(const_cast<Value *>(SI->getValueOperand()))[{-1}];
191 if (ct == BaseType::Pointer || ct == BaseType::Integer) {
192
193 if (!((mode == DerivativeMode::ReverseModePrimal && forwardsShadow) ||
195 backwardsShadow) ||
196 (mode == DerivativeMode::ForwardModeSplit && backwardsShadow) ||
198 (forwardsShadow || backwardsShadow)) ||
201 return false;
202 }
203 }
204
205 if (!gutils->isConstantValue(
206 const_cast<Value *>(SI->getPointerOperand()))) {
208 llvm::errs() << " Need: shadow of " << *val
209 << " in reverse as shadow store " << *SI << "\n";
210 return true;
211 } else
212 return false;
213 }
214 return false;
215 }
216
217 if (!shadow)
218 if (auto LI = dyn_cast<LoadInst>(user)) {
219 if (gutils->runtimeActivity) {
220 auto vd = TR.query(const_cast<llvm::Instruction *>(user));
221 if (!vd.isKnown()) {
222 auto ET = LI->getType();
223 // It verbatim needs to replicate the same behavior as
224 // adjointgenerator. From reverse mode type analysis
225 // (https://github.com/EnzymeAD/Enzyme/blob/194875cbccd73d63cacfefbfa85c1f583c2fa1fe/enzyme/Enzyme/AdjointGenerator.h#L556)
226 if (looseTypeAnalysis || true) {
227 vd = defaultTypeTreeForLLVM(ET, const_cast<LoadInst *>(LI));
228 }
229 }
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()) {
235 hasFloat = true;
236 break;
237 }
238 }
239 if (hasFloat && !gutils->isConstantInstruction(
240 const_cast<llvm::Instruction *>(user))) {
242 llvm::errs() << " Need direct primal of " << *val
243 << " in reverse from runtime active load " << *user
244 << "\n";
245 return true;
246 }
247 }
248 return false;
249 }
250
251 if (auto MTI = dyn_cast<MemTransferInst>(user)) {
252 // If memtransfer, only the primal of the size is needed reverse pass
253 if (!shadow) {
254 // Unless we're storing into a backwards only shadow store
255 if (MTI->getArgOperand(1) == val || MTI->getArgOperand(2) == val) {
256 for (auto pair : gutils->backwardsOnlyShadows)
257 if (pair.second.stores.count(MTI)) {
259 llvm::errs() << " Need direct primal of " << *val
260 << " in reverse from remat memtransfer " << *user
261 << "\n";
262 return true;
263 }
264 }
265 // we also need the primal of all values if runtime activity is true
266 if (!gutils->runtimeActivity && MTI->getArgOperand(2) != val)
267 return false;
268 bool res = !gutils->isConstantValue(MTI->getArgOperand(0));
269 if (res) {
271 llvm::errs() << " Need direct primal of " << *val
272 << " in reverse from memtransfer " << *user << "\n";
273 }
274 return res;
275 } else {
276
277 if (MTI->getArgOperand(0) != val && MTI->getArgOperand(1) != val)
278 return false;
279
280 if (!gutils->isConstantValue(
281 const_cast<Value *>(MTI->getArgOperand(0)))) {
283 llvm::errs() << " Need: shadow of " << *val
284 << " in reverse as shadow MTI " << *MTI << "\n";
285 return true;
286 } else
287 return false;
288 }
289 }
290
291 if (auto MS = dyn_cast<MemSetInst>(user)) {
292 if (!shadow) {
293 // Preserve the primal of length of memsets of backward creation shadows,
294 // or if float-like and non constant value.
295 if (MS->getArgOperand(1) == val || MS->getArgOperand(2) == val) {
296 for (auto pair : gutils->backwardsOnlyShadows)
297 if (pair.second.stores.count(MS)) {
299 llvm::errs() << " Need direct primal of " << *val
300 << " in reverse from remat memset " << *user << "\n";
301 return true;
302 }
303 bool res = !gutils->isConstantValue(MS->getArgOperand(0));
304 if (res) {
306 llvm::errs() << " Need direct primal of " << *val
307 << " in reverse from memset " << *user << "\n";
308 }
309 return res;
310 }
311 } else {
312
313 if (MS->getArgOperand(0) != val)
314 return false;
315
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";
320 return true;
321 } else
322 return false;
323 }
324 }
325
326 if (!shadow)
327 if (isa<CmpInst>(user) || isAnyBranch(user) || isa<ReturnInst>(user) ||
328 isa<FPExtInst>(user) || isa<FPTruncInst>(user)
329 // isa<ExtractElement>(use) ||
330 // isa<InsertElementInst>(use) || isa<ShuffleVectorInst>(use) ||
331 // isa<ExtractValueInst>(use) || isa<AllocaInst>(use)
332 // || isa<StoreInst>(use)
333 ) {
334 return false;
335 }
336
337 if (!shadow)
338 if (auto IEI = dyn_cast<InsertElementInst>(user)) {
339 // Only need the index in the reverse, so if the value is not
340 // the index, short circuit and say we don't need
341 if (IEI->getOperand(2) != val) {
342 return false;
343 }
344 // The index is only needed in the reverse if the value being inserted
345 // is a possible active floating point value
346 if (gutils->isConstantValue(const_cast<InsertElementInst *>(IEI)) ||
347 TR.query(const_cast<InsertElementInst *>(IEI))[{-1}] ==
349 return false;
350 // Otherwise, we need the value.
352 llvm::errs() << " Need direct primal of " << *val
353 << " in reverse from non-pointer insertelem " << *user
354 << " "
355 << TR.query(const_cast<InsertElementInst *>(IEI)).str()
356 << "\n";
357 return true;
358 }
359
360 if (!shadow)
361 if (auto EEI = dyn_cast<ExtractElementInst>(user)) {
362 // Only need the index in the reverse, so if the value is not
363 // the index, short circuit and say we don't need
364 if (EEI->getIndexOperand() != val) {
365 return false;
366 }
367 // The index is only needed in the reverse if the value being inserted
368 // is a possible active floating point value
369 if (gutils->isConstantValue(const_cast<ExtractElementInst *>(EEI)) ||
370 TR.query(const_cast<ExtractElementInst *>(EEI))[{-1}] ==
372 return false;
373 // Otherwise, we need the value.
375 llvm::errs() << " Need direct primal of " << *val
376 << " in reverse from non-pointer extractelem " << *user
377 << " "
378 << TR.query(const_cast<ExtractElementInst *>(EEI)).str()
379 << "\n";
380 return true;
381 }
382
383 if (!shadow)
384 if (auto IVI = dyn_cast<InsertValueInst>(user)) {
385 // Only need the index in the reverse, so if the value is not
386 // the index, short circuit and say we don't need
387 bool valueIsIndex = false;
388 for (unsigned i = 2; i < IVI->getNumOperands(); ++i) {
389 if (IVI->getOperand(i) == val) {
390 valueIsIndex = true;
391 }
392 }
393
394 if (!valueIsIndex)
395 return false;
396
397 // The index is only needed in the reverse if the value being inserted
398 // is a possible active floating point value
399 if (gutils->isConstantValue(const_cast<InsertValueInst *>(IVI)) ||
400 TR.query(const_cast<InsertValueInst *>(IVI))[{-1}] ==
402 return false;
403 // Otherwise, we need the value.
405 llvm::errs() << " Need direct primal of " << *val
406 << " in reverse from non-pointer insertval " << *user
407 << " "
408 << TR.query(const_cast<InsertValueInst *>(IVI)).str()
409 << "\n";
410 return true;
411 }
412
413 if (!shadow)
414 if (auto EVI = dyn_cast<ExtractValueInst>(user)) {
415 // Only need the index in the reverse, so if the value is not
416 // the index, short circuit and say we don't need
417 bool valueIsIndex = false;
418 for (unsigned i = 2; i < EVI->getNumOperands(); ++i) {
419 if (EVI->getOperand(i) == val) {
420 valueIsIndex = true;
421 }
422 }
423
424 if (!valueIsIndex)
425 return false;
426
427 // The index is only needed in the reverse if the value being inserted
428 // is a possible active floating point value
429 if (gutils->isConstantValue(const_cast<ExtractValueInst *>(EVI)) ||
430 TR.query(const_cast<ExtractValueInst *>(EVI))[{-1}] ==
432 return false;
433 // Otherwise, we need the value.
435 llvm::errs() << " Need direct primal of " << *val
436 << " in reverse from non-pointer extractval " << *user
437 << " "
438 << TR.query(const_cast<ExtractValueInst *>(EVI)).str()
439 << "\n";
440 return true;
441 }
442
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)) {
447 StringRef funcName = getFuncNameFromCall(const_cast<CallInst *>(CI));
448 isMemFreeLibMFunction(funcName, &ID);
449 }
450
451 if (ID != Intrinsic::not_intrinsic) {
452 if (ID == Intrinsic::lifetime_start || ID == Intrinsic::lifetime_end ||
453 ID == Intrinsic::stacksave || ID == Intrinsic::stackrestore) {
454 return false;
455 }
456 }
457
458 if (!shadow)
459 if (auto si = dyn_cast<SelectInst>(user)) {
460 // Only would potentially need the condition
461 if (si->getCondition() != val) {
462 return false;
463 }
464
465 // only need the condition if select is active
466 bool needed = !gutils->isConstantValue(const_cast<SelectInst *>(si));
467 if (needed) {
469 llvm::errs() << " Need direct primal of " << *val
470 << " in reverse from select " << *user << "\n";
471 }
472 return needed;
473 }
474
475#include "BlasDiffUse.inc"
476
477 if (auto CI = dyn_cast<CallInst>(user)) {
478
479 {
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()) {
485 if (inp == val)
486 return true;
487 }
488 }
489 }
490
491 auto funcName = getFuncNameFromCall(CI);
492
493 {
494 auto found = customDiffUseHandlers.find(funcName);
495 if (found != customDiffUseHandlers.end()) {
496 bool useDefault = false;
497 bool result = found->second(CI, gutils, val, shadow, mode, useDefault);
498 if (!useDefault) {
499 if (result) {
501 llvm::errs() << " Need: " << to_string(qtype) << " of " << *val
502 << " from custom diff use handler of " << *CI
503 << "\n";
504 }
505 return result;
506 }
507 }
508 }
509
510 // Don't need shadow inputs for alloc function
511 if (shadow && isAllocationFunction(funcName, gutils->TLI))
512 return false;
513
514 // Even though inactive, keep the shadow pointer around in forward mode
515 // to perform the same memory free behavior on the shadow.
516 if (shadow &&
519 isDeallocationFunction(funcName, gutils->TLI)) {
521 llvm::errs() << " Need: shadow of " << *val
522 << " in reverse as shadow free " << *CI << "\n";
523 return true;
524 }
525
526 // Only need primal (and shadow) request for reverse, or shadow buffer
527 if (funcName == "MPI_Isend" || funcName == "MPI_Irecv" ||
528 funcName == "PMPI_Isend" || funcName == "PMPI_Irecv") {
529 if (gutils->isConstantInstruction(const_cast<Instruction *>(user)))
530 return false;
531
532 if (val == CI->getArgOperand(6)) {
534 llvm::errs() << " Need: " << to_string(qtype) << " request " << *val
535 << " in reverse for MPI " << *CI << "\n";
536 return true;
537 }
538 if (shadow && val == CI->getArgOperand(0)) {
539 if ((funcName == "MPI_Irecv" || funcName == "PMPI_Irecv") &&
541 // Need shadow buffer for forward pass of ireceive
543 llvm::errs() << " Need: shadow(" << to_string(qtype) << ") of "
544 << *val << " in reverse as shadow MPI " << *CI << "\n";
545 return true;
546 }
547 if (funcName == "MPI_Isend" || funcName == "PMPI_Isend") {
548 // Need shadow buffer for forward or reverse pass of isend
550 llvm::errs() << " Need: shadow(" << to_string(qtype) << ") of "
551 << *val << " in reverse as shadow MPI " << *CI << "\n";
552 return true;
553 }
554 }
555
556 return false;
557 }
558
559 if (!shadow) {
560
561 // Need the primal request in reverse.
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";
567 return true;
568 }
569
570 // Only need the primal request.
571 if (funcName == "MPI_Wait" || funcName == "PMPI_Wait")
572 if (val != CI->getArgOperand(0))
573 return false;
574
575 // Only need element count for reverse of waitall
576 if (funcName == "MPI_Waitall" || funcName == "PMPI_Waitall")
577 if (val != CI->getArgOperand(0) || val != CI->getOperand(1))
578 return false;
579
580 } else {
581 // Don't need shadow of anything (all via cache for reverse),
582 // but need shadow of request for primal.
583 if (funcName == "MPI_Wait" || funcName == "PMPI_Wait") {
584 if (gutils->isConstantInstruction(const_cast<Instruction *>(user)))
585 return false;
586 // Need shadow request in forward pass only
588 if (val == CI->getArgOperand(0)) {
590 llvm::errs() << " Need: shadow of " << *val
591 << " in reverse as shadow MPI " << *CI << "\n";
592 return true;
593 }
594 return false;
595 }
596 }
597
598 // Since adjoint of barrier is another barrier in reverse
599 // we still need even if instruction is inactive
600 if (!shadow)
601 if (funcName == "__kmpc_barrier" || funcName == "MPI_Barrier") {
603 llvm::errs() << " Need direct primal of " << *val
604 << " in reverse from barrier " << *user << "\n";
605 return true;
606 }
607
608 // Since adjoint of GC preserve is another preserve in reverse
609 // we still need even if instruction is inactive
610 if (!shadow)
611 if (funcName == "llvm.julia.gc_preserve_begin") {
613 llvm::errs() << " Need direct primal of " << *val
614 << " in reverse from gc " << *CI << "\n";
615 return true;
616 }
617
618 if (funcName == "julia.write_barrier" ||
619 funcName == "julia.write_barrier_binding") {
620 // Use in a write barrier requires the shadow in the forward, even
621 // though the instruction is active.
622 if (shadow && (mode != DerivativeMode::ReverseModeGradient &&
625 llvm::errs() << " Need: shadow of " << *val
626 << " in forward as shadow write_barrier " << *CI << "\n";
627 return true;
628 }
629 if (shadow) {
630 auto sz = CI->arg_size();
631 bool isStored = false;
632 // First pointer is the destination
633 for (size_t i = 1; i < sz; i++)
634 isStored |= val == CI->getArgOperand(i);
635 bool rematerialized = false;
636 if (isStored)
637 for (auto pair : gutils->backwardsOnlyShadows)
638 if (pair.second.stores.count(CI) &&
639 !gutils->isConstantValue(pair.first)) {
640 rematerialized = true;
641 break;
642 }
643
644 if (rematerialized) {
646 llvm::errs()
647 << " Need: shadow of " << *val
648 << " in rematerialized reverse as shadow write_barrier " << *CI
649 << "\n";
650 return true;
651 }
652 }
653 }
654
655 bool writeOnlyNoCapture = true;
656
657 if (shouldDisableNoWrite(CI)) {
658 writeOnlyNoCapture = false;
659 }
660 // Outside of forward mode, we don't need to keep a primal around in reverse
661 // just for the deallocation
662 if (!(mode == DerivativeMode::ForwardMode ||
664 isDeallocationFunction(funcName, gutils->TLI)) {
665 } else {
666 for (size_t i = 0; i < CI->arg_size(); i++) {
667 if (val == CI->getArgOperand(i)) {
668 if (!isNoCapture(CI, i)) {
669 writeOnlyNoCapture = false;
670 break;
671 }
672 if (!isWriteOnly(CI, i)) {
673 writeOnlyNoCapture = false;
674 break;
675 }
676 }
677 }
678 }
679
680 // Don't need the primal argument if it is write only and not captured
681 if (!shadow)
682 if (writeOnlyNoCapture) {
684 llvm::errs() << " No Need: primal of " << *val
685 << " per write-only no-capture use in " << *CI << "\n";
686 return false;
687 }
688
689 if (shadow) {
690 // Don't need the shadow argument if it is a pointer to pointers, which
691 // is only written since the shadow pointer store will have been
692 // completed in the forward pass.
693 if (writeOnlyNoCapture &&
694 TR.query(const_cast<Value *>(val))[{-1, -1}] == BaseType::Pointer &&
696 return false;
697
698 const Value *FV = CI->getCalledOperand();
699 if (FV == val) {
700 if (!gutils->isConstantInstruction(const_cast<Instruction *>(user)) ||
701 !gutils->isConstantValue(const_cast<Value *>((Value *)user))) {
703 llvm::errs() << " Need: shadow of " << *val
704 << " in reverse as shadow call " << *CI << "\n";
705 return true;
706 }
707 }
708 }
709 }
710
711 if (shadow) {
712 if (isa<ReturnInst>(user)) {
713 bool notrev = mode != DerivativeMode::ReverseModeGradient;
714 if (gutils->shadowReturnUsed && notrev) {
715
716 bool inst_cv = gutils->isConstantValue(const_cast<Value *>(val));
717
718 if ((qtype == QueryType::ShadowByConstPrimal && inst_cv) ||
719 (qtype == QueryType::Shadow && !inst_cv)) {
721 llvm::errs() << " Need: shadow(qtype=" << (int)qtype
722 << ",cv=" << inst_cv << ") of " << *val
723 << " in reverse as shadow return " << *user << "\n";
724 return true;
725 }
726 }
727 return false;
728 }
729
730 // With certain exceptions, assume active instructions require the
731 // shadow of the operand.
732 if (mode == DerivativeMode::ForwardMode ||
735 (!isa<ExtractValueInst>(user) && !isa<ExtractElementInst>(user) &&
736 !isa<InsertValueInst>(user) && !isa<InsertElementInst>(user) &&
737 !isPointerArithmeticInst(user, /*includephi*/ false,
738 /*includebin*/ false))) {
739
740 bool inst_cv = gutils->isConstantValue(const_cast<Value *>(val));
741
742 if (!inst_cv &&
743 !gutils->isConstantInstruction(const_cast<Instruction *>(user))) {
745 llvm::errs() << " Need: shadow of " << *val
746 << " in reverse as shadow inst " << *user << "\n";
747 return true;
748 }
749 }
750
751 // Now the remaining instructions are inactive, however note that
752 // a constant instruction may still require the use of the shadow
753 // in the forward pass, for example double* x = load double** y
754 // is a constant instruction, but needed in the forward. However,
755 // if the value [and from above also the instruction] is constant
756 // we don't need it.
757 if (gutils->isConstantValue(
758 const_cast<Value *>((const llvm::Value *)user))) {
759 return false;
760 }
761
762 // Now we don't need this value directly, but we may need it recursively
763 // in one the active value users
764 assert(recursiveUse);
765 *recursiveUse = true;
766 return false;
767 }
768
769 bool neededFB = false;
770 if (auto CB = dyn_cast<CallBase>(const_cast<Instruction *>(user))) {
771 neededFB = !callShouldNotUseDerivative(gutils, *CB, qtype, val);
772 } else {
773 neededFB = !gutils->isConstantInstruction(user) ||
774 !gutils->isConstantValue(const_cast<Instruction *>(user));
775 }
776 if (neededFB) {
778 llvm::errs() << " Need direct primal(" << mode << ") of " << *val
779 << " in reverse from fallback " << *user << "\n";
780 }
781 return neededFB;
782}
783
784void DifferentialUseAnalysis::dump(Graph &G) {
785 for (auto &pair : G) {
786 llvm::errs() << "[" << *pair.first.V << ", " << (int)pair.first.outgoing
787 << "]\n";
788 for (auto N : pair.second) {
789 llvm::errs() << "\t[" << *N.V << ", " << (int)N.outgoing << "]\n";
790 }
791 }
792}
793
794/* Returns true if there is a path from source 's' to sink 't' in
795 residual graph. Also fills parent[] to store the path */
796void DifferentialUseAnalysis::bfs(const Graph &G,
797 const SetVector<Value *> &Recompute,
798 std::map<Node, Node> &parent) {
799 std::deque<Node> q;
800 for (auto V : Recompute) {
801 Node N(V, false);
802 parent.emplace(N, Node(nullptr, true));
803 q.push_back(N);
804 }
805
806 // Standard BFS Loop
807 while (!q.empty()) {
808 auto u = q.front();
809 q.pop_front();
810 auto found = G.find(u);
811 if (found == G.end())
812 continue;
813 for (auto v : found->second) {
814 if (parent.find(v) == parent.end()) {
815 q.push_back(v);
816 parent.emplace(v, u);
817 }
818 }
819 }
820}
821
822// Return 1 if next is better
823// 0 if equal
824// -1 if prev is better, or unknown
825int DifferentialUseAnalysis::cmpLoopNest(Loop *prev, Loop *next) {
826 if (next == prev)
827 return 0;
828 if (next == nullptr)
829 return 1;
830 else if (prev == nullptr)
831 return -1;
832 for (Loop *L = prev; L != nullptr; L = L->getParentLoop()) {
833 if (L == next)
834 return 1;
835 }
836 return -1;
837}
838
839void DifferentialUseAnalysis::minCut(const DataLayout &DL, LoopInfo &OrigLI,
840 const SetVector<Value *> &Recomputes,
841 const SetVector<Value *> &Intermediates,
842 SetVector<Value *> &Required,
843 SetVector<Value *> &MinReq,
844 const GradientUtils *gutils,
845 llvm::TargetLibraryInfo &TLI) {
846 Graph G;
847 for (auto V : Intermediates) {
848 G[Node(V, false)].insert(Node(V, true));
849 forEachDifferentialUser(
850 [&](Value *U) {
851 if (Intermediates.count(U)) {
852 if (V != U)
853 G[Node(V, true)].insert(Node(U, false));
854 }
855 },
856 gutils, V);
857 }
858 for (auto pair : gutils->rematerializableAllocations) {
859 if (Intermediates.count(pair.first)) {
860 for (LoadInst *L : pair.second.loads) {
861 if (Intermediates.count(L)) {
862 if (L != pair.first)
863 G[Node(pair.first, true)].insert(Node(L, false));
864 }
865 }
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));
870 }
871 }
872 }
873 }
874#ifndef NDEBUG
875 for (auto R : Required) {
876 assert(Intermediates.count(R));
877 }
878 for (auto R : Recomputes) {
879 assert(Intermediates.count(R));
880 }
881#endif
882
883 Graph Orig = G;
884
885 // Augment the flow while there is a path from source to sink
886 while (1) {
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);
893 break;
894 }
895 }
896 if (end.V == nullptr)
897 break;
898 // update residual capacities of the edges and reverse edges
899 // along the path
900 Node v = end;
901 while (1) {
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);
907 G[u].erase(v);
908 G[v].insert(u);
909 if (Recomputes.count(u.V) && u.outgoing == false)
910 break;
911 v = u;
912 }
913 }
914
915 // Flow is maximum now, find vertices reachable from s
916
917 std::map<Node, Node> parent;
918 bfs(G, Recomputes, parent);
919
920 SetVector<Value *> todo;
921
922 // Print all edges that are from a reachable vertex to
923 // non-reachable vertex in the original graph
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);
930 MinReq.insert(N.V);
931 todo.insert(N.V);
932 }
933 }
934 }
935
936 while (todo.size()) {
937 auto V = todo.front();
938 todo.remove(V);
939 assert(MinReq.count(V));
940
941 // Fix up non-cacheable calls to use their operand(s) instead
942 if (hasNoCache(V)) {
943 MinReq.remove(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);
948 }
949 }
950 continue;
951 }
952
953 auto found = Orig.find(Node(V, true));
954 if (found != Orig.end()) {
955 const auto &mp = found->second;
956
957 // When ambiguous, push to cache the last value in a computation chain
958 // This should be considered in a cost for the max flow
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());
963 int moreOuterLoop =
964 cmpLoopNest(OrigLI.getLoopFor(cast<Instruction>(V)->getParent()),
965 OrigLI.getLoopFor(
966 cast<Instruction>(((*mp.begin()).V))->getParent()));
967 if (potentiallyRecursive)
968 continue;
969 if (moreOuterLoop == -1)
970 continue;
971 if (auto ASC = dyn_cast<AddrSpaceCastInst>((*mp.begin()).V)) {
972 if (ASC->getDestAddressSpace() == 11 ||
973 ASC->getDestAddressSpace() == 13)
974 continue;
975 if (ASC->getSrcAddressSpace() == 10 &&
976 ASC->getDestAddressSpace() == 0)
977 continue;
978 }
979 if (auto CI = dyn_cast<CastInst>((*mp.begin()).V)) {
980 if (CI->getType()->isPointerTy() &&
981 CI->getType()->getPointerAddressSpace() == 13)
982 continue;
983 }
984 if (auto G = dyn_cast<GetElementPtrInst>((*mp.begin()).V)) {
985 if (G->getType()->getPointerAddressSpace() == 13)
986 continue;
987 }
988 if (hasNoCache((*mp.begin()).V)) {
989 continue;
990 }
991 // If an allocation call, we cannot cache any "capturing" users
992 if (isAllocationCall(V, TLI) || isa<AllocaInst>(V)) {
993 auto next = (*mp.begin()).V;
994 bool noncapture = false;
995 if (isa<LoadInst>(next) || isNVLoad(next)) {
996 noncapture = true;
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)) {
1001 captures = true;
1002 break;
1003 }
1004 }
1005 noncapture = !captures;
1006 }
1007
1008 if (!noncapture)
1009 continue;
1010 }
1011
1012 if (moreOuterLoop == 1 ||
1013 (moreOuterLoop == 0 &&
1014 DL.getTypeSizeInBits(V->getType()) >=
1015 DL.getTypeSizeInBits((*mp.begin()).V->getType()))) {
1016 MinReq.remove(V);
1017 auto nnode = (*mp.begin()).V;
1018 MinReq.insert(nnode);
1019 if (Orig.find(Node(nnode, true)) != Orig.end())
1020 todo.insert(nnode);
1021 }
1022 }
1023 }
1024 }
1025
1026 // Fix up non-repeatable writing calls that chain within rematerialized
1027 // allocations. We could iterate from the keys of the valuemap, but that would
1028 // be a non-determinstic ordering.
1029 for (auto V : Intermediates) {
1030 auto found = gutils->rematerializableAllocations.find(V);
1031 if (found == gutils->rematerializableAllocations.end())
1032 continue;
1033 if (!found->second.nonRepeatableWritingCall)
1034 continue;
1035
1036 // We are already caching this allocation directly, we're fine
1037 if (MinReq.count(V))
1038 continue;
1039
1040 // If we are recomputing a load, we need to fix this.
1041 bool needsLoad = false;
1042 for (auto load : found->second.loads)
1043 if (Intermediates.count(load) && !MinReq.count(load)) {
1044 needsLoad = true;
1045 break;
1046 }
1047 for (auto load : found->second.loadLikeCalls)
1048 if (Intermediates.count(load.loadCall) && !MinReq.count(load.loadCall)) {
1049 needsLoad = true;
1050 break;
1051 }
1052
1053 if (!needsLoad)
1054 continue;
1055
1056 // Rewire the uses to cache the allocation directly.
1057 // TODO: as further optimization, we can remove potentially unnecessary
1058 // values that we are keeping for stores.
1059 MinReq.insert(V);
1060 }
1061
1062 return;
1063}
1064
1066 const GradientUtils *gutils, CallBase &call, QueryType qtype,
1067 const Value *val) {
1068 bool shadowReturnUsed = false;
1069 auto smode = gutils->mode;
1072 (void)gutils->getReturnDiffeType(&call, nullptr, &shadowReturnUsed, smode);
1073
1074 bool useConstantFallback =
1075 gutils->isConstantInstruction(&call) &&
1076 (gutils->isConstantValue(&call) || !shadowReturnUsed);
1077 if (useConstantFallback && gutils->mode != DerivativeMode::ForwardMode &&
1079
1080 // if there is an escaping allocation, which is deduced needed in
1081 // reverse pass, we need to do the recursive procedure to perform the
1082 // free.
1083 bool escapingNeededAllocation = false;
1084
1085 // First, some calls may be marked, non escaping. If that's the case, we
1086 // can avoid unnecessary work.
1087 if (!isNoEscapingAllocation(&call)) {
1088
1089 // If the function being called has a definition, check if any of the
1090 // subcalls can allocate.
1091 if (auto F = getFunctionFromCall(&call)) {
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))
1098 continue;
1099 done.insert(cur);
1100 // assume empty functions allocate.
1101 if (cur->empty()) {
1102 // unless they are marked
1103 if (isNoEscapingAllocation(cur))
1104 continue;
1105 seenAllocation = true;
1106 break;
1107 }
1108 auto UR = getGuaranteedUnreachable(cur);
1109 for (auto &BB : *cur) {
1110 if (UR.count(&BB))
1111 continue;
1112 for (auto &I : BB)
1113 if (auto CB = dyn_cast<CallBase>(&I)) {
1114 if (isNoEscapingAllocation(CB))
1115 continue;
1116 if (isAllocationCall(CB, gutils->TLI)) {
1117 seenAllocation = true;
1118 goto finish;
1119 }
1120 if (auto F = getFunctionFromCall(CB)) {
1121 todo.push_back(F);
1122 continue;
1123 }
1124 // Conservatively assume indirect functions allocate.
1125 seenAllocation = true;
1126 goto finish;
1127 }
1128 }
1129 finish:;
1130 if (!seenAllocation)
1131 goto doneEscapeCheck;
1132 }
1133
1134 // Next, test if any allocation could be stored into one of the
1135 // arguments.
1136 for (unsigned i = 0; i < call.arg_size(); ++i) {
1137 Value *a = call.getOperand(i);
1138
1139 if (EnzymeJuliaAddrLoad && isSpecialPtr(a->getType()))
1140 continue;
1141
1142 if (!gutils->TR.anyPointer(a))
1143 continue;
1144
1145 const auto &vd = gutils->TR.query(a);
1146
1147 if (!vd[{-1, -1}].isPossiblePointer())
1148 continue;
1149
1150 if (isReadOnly(&call, i))
1151 continue;
1152
1153 // An allocation could only be needed in the reverse pass if it
1154 // escapes into an argument. However, is the parameter by which it
1155 // escapes could capture the pointer, the rest of Enzyme's caching
1156 // mechanisms cannot assume that the allocation itself is
1157 // reloadable, since it may have been captured and overwritten
1158 // elsewhere.
1159 // TODO: this justification will need revisiting in the future as
1160 // the caching algorithm becomes increasingly sophisticated.
1161 if (!isNoCapture(&call, i))
1162 continue;
1163
1164 escapingNeededAllocation = true;
1165 goto doneEscapeCheck;
1166 break;
1167 }
1168
1169 // Finally, test if the return is a potential pointer, and needed for
1170 // the reverse pass.
1172 escapingNeededAllocation = true;
1173 goto doneEscapeCheck;
1174 }
1175
1176 // Not a pointer
1177 if (!gutils->TR.anyPointer(&call)) {
1178 goto doneEscapeCheck;
1179 }
1180 // GC'd pointer, not needed to be explicitly free'd
1181 if (EnzymeJuliaAddrLoad && isSpecialPtr(call.getType())) {
1182 goto doneEscapeCheck;
1183 }
1184
1185 std::map<UsageKey, bool> CacheResults =
1187 // to avoid an infinite loop, we assume this is needed by
1188 // marking the query that led us.
1189 if (val)
1190 CacheResults[UsageKey(val, qtype)] = true;
1191
1192 auto found = gutils->knownRecomputeHeuristic.find(&call);
1193 if (found != gutils->knownRecomputeHeuristic.end()) {
1194 if (!found->second) {
1195 CacheResults.erase(UsageKey(&call, QueryType::Primal));
1196 escapingNeededAllocation =
1198 QueryType::Primal>(gutils, &call,
1200 CacheResults, gutils->notForAnalysis);
1201 }
1202 } else {
1203 escapingNeededAllocation =
1205 QueryType::Primal>(gutils, &call,
1207 CacheResults, gutils->notForAnalysis);
1208 }
1209 }
1210 }
1211
1212 doneEscapeCheck:;
1213 if (escapingNeededAllocation)
1214 useConstantFallback = false;
1215 }
1216 return useConstantFallback;
1217}
1218
1220
1222 const llvm::PHINode *P0,
1223 const llvm::Value *incomingVal) {
1224 using namespace llvm;
1225 if (!gutils->OrigLI)
1226 return false;
1227 auto L = gutils->OrigLI->getLoopFor(P0->getParent());
1228 if (!L || L->getHeader() != P0->getParent())
1229 return false;
1230 BasicBlock *preheader = L->getLoopPreheader();
1231 if (!preheader)
1232 return false;
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);
1237 else
1238 break;
1239 }
1240 if (Pstart != incomingVal &&
1241 P0->getIncomingValueForBlock(preheader) != incomingVal)
1242 return false;
1243
1244 SmallVector<const Instruction *, 4> activeUses;
1245 for (auto u : P0->users()) {
1246 if (auto I = dyn_cast<Instruction>(u)) {
1247 if (!gutils->isConstantInstruction(const_cast<Instruction *>(I))) {
1248 activeUses.push_back(I);
1249 }
1250 }
1251 }
1252 if (activeUses.size() != 1)
1253 return false;
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 &&
1258 !gutils->isConstantValue(const_cast<BinaryOperator *>(BO))) {
1259 isLoopyReduction = true;
1260 }
1261 }
1262 // A select reduction (e.g. a running max) is differentiated through the
1263 // index of the last selecting iteration and never reads the start value's
1264 // primal, so only the division form needs it.
1265 if (!isLoopyReduction)
1266 return false;
1267
1268 SmallVector<BasicBlock *, 1> Latches;
1269 L->getLoopLatches(Latches);
1270 for (auto Latch : Latches) {
1271 if (userInst != P0->getIncomingValueForBlock(Latch)) {
1272 return false;
1273 }
1274 }
1275 SmallVector<BasicBlock *, 2> exitBlocks;
1276 L->getExitBlocks(exitBlocks);
1277 if (exitBlocks.size() != 1)
1278 return false;
1279
1280 return true;
1281}
1282
1283void pushLoopyPHIPreheader(const GradientUtils *gutils, llvm::Value *V,
1284 llvm::SetVector<llvm::Value *> &Intermediates,
1285 std::deque<llvm::Value *> &todo) {
1286 using namespace llvm;
1287 if (auto P0 = dyn_cast<PHINode>(V)) {
1288 if (!gutils->OrigLI)
1289 return;
1290 auto L = gutils->OrigLI->getLoopFor(P0->getParent());
1291 if (!L || L->getHeader() != P0->getParent())
1292 return;
1293 BasicBlock *preheader = L->getLoopPreheader();
1294 if (!preheader)
1295 return;
1296 Value *Pstart = P0->getIncomingValueForBlock(preheader);
1297 if (!Pstart)
1298 return;
1299 SmallVector<const Instruction *, 4> activeUses;
1300 for (auto u : P0->users()) {
1301 if (auto I = dyn_cast<Instruction>(u)) {
1302 if (!gutils->isConstantInstruction(const_cast<Instruction *>(I))) {
1303 activeUses.push_back(I);
1304 }
1305 }
1306 }
1307 if (activeUses.size() != 1)
1308 return;
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 &&
1313 !gutils->isConstantValue(const_cast<BinaryOperator *>(BO))) {
1314 isLoopyReduction = true;
1315 }
1316 }
1317 if (!isLoopyReduction)
1318 return;
1319
1320 SmallVector<BasicBlock *, 1> Latches;
1321 L->getLoopLatches(Latches);
1322 for (auto Latch : Latches) {
1323 if (userInst != P0->getIncomingValueForBlock(Latch)) {
1324 return;
1325 }
1326 }
1327 SmallVector<BasicBlock *, 2> exitBlocks;
1328 L->getExitBlocks(exitBlocks);
1329 if (exitBlocks.size() != 1)
1330 return;
1331
1332 while (Pstart) {
1333 // Constants and arguments are always available in the reverse pass, and
1334 // thus need not be added to the recompute graph (which only contains
1335 // instructions).
1336 if (!isa<Instruction>(Pstart))
1337 break;
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);
1343 else
1344 break;
1345 } else
1346 break;
1347 }
1348 }
1349}
1350
1351} // namespace DifferentialUseAnalysis
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.
@ ShadowByConstPrimal
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)
Definition Utils.cpp:4821
static bool isNoEscapingAllocation(const llvm::Function *F)
Definition Utils.h:2156
static bool isNoCapture(const llvm::CallBase *call, size_t idx)
Definition Utils.h:2109
static bool isPointerArithmeticInst(const llvm::Value *V, bool includephi=true, bool includebin=true)
Definition Utils.h:1660
static bool shouldDisableNoWrite(const llvm::CallInst *CI)
Definition Utils.h:1633
static bool isSpecialPtr(llvm::Type *Ty)
Definition Utils.h:2664
static bool hasNoCache(llvm::Value *op)
Definition Utils.h:1484
llvm::cl::opt< bool > EnzymeJuliaAddrLoad
static bool isAnyBranch(const llvm::Value *V)
Definition Utils.h:57
static llvm::StringRef getFuncNameFromCall(const llvm::CallBase *op)
Definition Utils.h:1470
static bool isWriteOnly(const llvm::Function *F, ssize_t arg=-1)
Definition Utils.h:2033
DerivativeMode
Definition Utils.h:524
llvm::Function *const newFunc
The function whose instructions we are caching.
llvm::TargetLibraryInfo & TLI
Various analysis results of newFunc.
DerivativeMode mode
TypeResults TR
std::map< const llvm::Value *, bool > knownRecomputeHeuristic
llvm::ValueMap< llvm::Value *, Rematerializer > rematerializableAllocations
std::map< UsageKey, bool > populateSeenFromKnownRecompute() const
llvm::Function * oldFunc
llvm::LoopInfo * OrigLI
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.
Definition TypeTree.h:595
std::string str() const
Returns a string representation of this TypeTree.
Definition TypeTree.h:1455
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)