1280 SetVector<Value> potentialSources;
1282 if (!arg.getOwner()->isEntryBlock()) {
1283 for (Block *predecessor : arg.getOwner()->getPredecessors()) {
1284 Operation *terminator = predecessor->getTerminator();
1285 if (
auto iface = dyn_cast<BranchOpInterface>(terminator)) {
1286 for (
const auto &en : llvm::enumerate(predecessor->getSuccessors())) {
1287 if (en.value() != arg.getOwner())
1290 Value inflow = iface.getSuccessorOperands(en.index())
1291 .getForwardedOperands()[arg.getArgNumber()];
1292 potentialSources.insert(inflow);
1295 for (Value operand : terminator->getOperands())
1296 potentialSources.insert(operand);
1299 return potentialSources.takeVector();
1302 Operation *parent = arg.getOwner()->getParentOp();
1303 Region *parentRegion = arg.getOwner()->getParent();
1305 if (
auto iface = dyn_cast<ADDataFlowOpInterface>(parent)) {
1306 for (
auto val : iface.getPotentialIncomingValuesArg(arg))
1307 potentialSources.insert(val);
1308 return potentialSources.takeVector();
1309 }
else if (
auto iface = dyn_cast<RegionBranchOpInterface>(parent)) {
1310 auto isRegionSucessorOf = [arg](RegionBranchOpInterface iface,
1312 RegionBranchPoint predecessor,
1313 SetVector<Value> &potentialSources) {
1314 SmallVector<RegionSuccessor> successors;
1315 iface.getSuccessorRegions(predecessor, successors);
1316 for (
const RegionSuccessor &successor : successors) {
1317 if (successor.getSuccessor() != region)
1320 unsigned operandOffset =
static_cast<unsigned>(-1);
1321 for (
const auto &en :
1322 llvm::enumerate(iface.getSuccessorInputs(successor))) {
1323 if (en.value() != arg)
1325 operandOffset = en.index();
1327 assert(operandOffset !=
static_cast<unsigned>(-1) &&
1328 "could not locate the position of the argument in the "
1329 "successor input list");
1333 if (predecessor.isParent()) {
1336 assert(iface.getEntrySuccessorOperands(region).size() ==
1337 iface.getSuccessorInputs(successor).size());
1338 potentialSources.insert(
1339 iface.getEntrySuccessorOperands(region)[operandOffset]);
1344 for (Block &block : *predecessor.getTerminatorPredecessorOrNull()
1345 ->getParentRegion()) {
1347 if (
auto terminator = dyn_cast<RegionBranchTerminatorOpInterface>(
1348 block.getTerminator())) {
1352 assert(terminator.getSuccessorOperands(region).size() ==
1353 iface.getSuccessorInputs(successor).size());
1354 potentialSources.insert(
1355 terminator.getSuccessorOperands(region)[operandOffset]);
1357 for (Value v : block.getTerminator()->getOperands())
1358 potentialSources.insert(v);
1366 isRegionSucessorOf(iface, parentRegion, RegionBranchPoint::parent(),
1368 for (Region &childRegion : parent->getRegions())
1369 isRegionSucessorOf(iface, parentRegion,
1370 cast<RegionBranchTerminatorOpInterface>(
1371 childRegion.front().getTerminator()),
1377 for (Region ®ion : parent->getRegions()) {
1378 for (Block &block : region) {
1380 for (Value v : block.getTerminator()->getOperands())
1381 potentialSources.insert(v);
1386 for (
auto op : parent->getOperands())
1387 potentialSources.insert(op);
1390 return potentialSources.takeVector();
1520 if (isa<LLVM::LLVMVoidType>(Val.getType()))
1524 if (isa<mlir::TokenType>(Val.getType()))
1528 if (ConstantValues.find(Val) != ConstantValues.end()) {
1533 if (ActiveValues.find(Val) != ActiveValues.end()) {
1538 if (matchPattern(Val, m_Constant()))
1541 if (Operation *definingOp = Val.getDefiningOp()) {
1542 if (
auto ifaceOp = dyn_cast<enzyme::ActivityOpInterface>(definingOp)) {
1543 if (ifaceOp.isInactive()) {
1549 if (
auto arg = dyn_cast<BlockArgument>(Val)) {
1551 if (
auto funcIface = dyn_cast_or_null<FunctionOpInterface>(
1552 arg.getParentBlock()->getParentOp()))
1553 if (funcIface && arg.getOwner()->isEntryBlock() &&
1554 !funcIface.getArgAttr(arg.getArgNumber(),
1555 LLVM::LLVMDialect::getByValAttrName())) {
1556 llvm::errs() << funcIface <<
"\n";
1557 llvm::errs() << Val <<
"\n";
1558 assert(0 &&
"must've put arguments in constant/nonconstant");
1594 llvm::errs() <<
" Value const as integral " << (int)directions <<
" "
1597 InsertConstantValue(TR, Val);
1605 if (val->getType()->isPointerTy() &&
1606 cast<PointerType>(val->getType())->isIntOrIntVectorTy() &&
1607 TR.firstPointer(1, val,
false).isIntegral()) {
1609 llvm::errs() <<
" Value const as integral pointer" << (int)directions
1610 <<
" " << *val <<
"\n";
1611 InsertConstantValue(TR, Val);
1769 if (
auto CI = Val.getDefiningOp<CallOpInterface>()) {
1771 if (CI->hasAttr(
"enzyme_active")) {
1773 llvm::errs() <<
"forced active val " << Val <<
"\n";
1774 ActiveValues.insert(Val);
1777 if (CI->hasAttr(
"enzyme_inactive")) {
1779 llvm::errs() <<
"forced inactive val " << Val <<
"\n";
1780 InsertConstantValue(TR, Val);
1785 if (called->hasAttr(
"enzyme_active")) {
1787 llvm::errs() <<
"forced active val " << Val <<
"\n";
1788 ActiveValues.insert(Val);
1791 if (called->hasAttr(
"enzyme_inactive")) {
1793 llvm::errs() <<
"forced inactive val " << Val <<
"\n";
1794 InsertConstantValue(TR, Val);
1800 std::shared_ptr<mlir::enzyme::ActivityAnalyzer> UpHypothesis;
1809 bool containsPointer =
true;
1810 Type vectorTypeOrSelf =
1811 isa<mlir::VectorType>(Val.getType())
1812 ? cast<mlir::VectorType>(Val.getType()).getElementType()
1814 if (LLVM::isCompatibleFloatingPointType(vectorTypeOrSelf))
1815 containsPointer =
false;
1818 auto typeIface = dyn_cast<AutoDiffTypeInterface>(Val.getType());
1819 if (!typeIface || !typeIface.isMutable()) {
1820 containsPointer =
false;
1824 containsPointer =
false;
1832 if (containsPointer) {
1838 if (directions & UP) {
1842 if (!func.getArgAttr(cast<BlockArgument>(TmpOrig).getArgNumber(),
1843 LLVM::LLVMDialect::getByValAttrName())) {
1844 bool res = isConstantValue(TR, TmpOrig);
1847 llvm::errs() <<
" arg const from orig val=" << Val
1848 <<
" orig=" << TmpOrig <<
"\n";
1849 InsertConstantValue(TR, Val);
1852 llvm::errs() <<
" arg active from orig val=" << Val
1853 <<
" orig=" << TmpOrig <<
"\n";
1854 ActiveValues.insert(Val);
1860 if (
auto op = TmpOrig.getDefiningOp())
1861 if (
auto ifaceOp = dyn_cast<enzyme::ActivityOpInterface>(op)) {
1862 if (ifaceOp.isInactive()) {
1863 InsertConstantValue(TR, Val);
1864 if (TmpOrig != Val) {
1865 InsertConstantValue(TR, TmpOrig);
1871 UpHypothesis = std::shared_ptr<mlir::enzyme::ActivityAnalyzer>(
1873 UpHypothesis->ConstantValues.insert(Val);
1877 if (
auto blockArg = dyn_cast<BlockArgument>(TmpOrig)) {
1879 Value active =
nullptr;
1881 if (!UpHypothesis->isConstantValue(TR, V)) {
1887 InsertConstantValue(TR, Val);
1888 if (TmpOrig != Val) {
1889 InsertConstantValue(TR, TmpOrig);
1891 insertConstantsFrom(TR, *UpHypothesis);
1894 ReEvaluateValueIfInactiveValue[active].insert(Val);
1895 if (TmpOrig != Val) {
1896 ReEvaluateValueIfInactiveValue[active].insert(TmpOrig);
1899 }
else if (
auto LI = TmpOrig.getDefiningOp<LLVM::LoadOp>()) {
1900 if (directions == UP) {
1901 if (isConstantValue(TR, LI.getAddr())) {
1902 InsertConstantValue(TR, Val);
1906 if (UpHypothesis->isConstantValue(TR, LI.getAddr())) {
1907 InsertConstantValue(TR, Val);
1908 insertConstantsFrom(TR, *UpHypothesis);
1938 }
else if (
auto op = TmpOrig.getDefiningOp<CallOpInterface>()) {
1939 if (op->hasAttr(
"enzyme_inactive")) {
1940 InsertConstantValue(TR, Val);
1941 insertConstantsFrom(TR, *UpHypothesis);
1946 StringRef funcName =
1947 called ? cast<SymbolOpInterface>(called).getName() :
"";
1949 if (called && called->hasAttr(
"enzyme_inactive")) {
1950 InsertConstantValue(TR, Val);
1951 insertConstantsFrom(TR, *UpHypothesis);
1954 if (funcName ==
"free" || funcName ==
"_ZdlPv" ||
1955 funcName ==
"_ZdlPvm" || funcName ==
"munmap") {
1956 InsertConstantValue(TR, Val);
1957 insertConstantsFrom(TR, *UpHypothesis);
1961 auto dName = llvm::demangle(funcName.str());
1964 InsertConstantValue(TR, Val);
1965 insertConstantsFrom(TR, *UpHypothesis);
1972 InsertConstantValue(TR, Val);
1973 insertConstantsFrom(TR, *UpHypothesis);
1979 if (funcName.contains(FuncName)) {
1980 InsertConstantValue(TR, Val);
1981 insertConstantsFrom(TR, *UpHypothesis);
1989 InsertConstantValue(TR, Val);
1990 insertConstantsFrom(TR, *UpHypothesis);
2053 if (funcName ==
"jl_array_copy" || funcName ==
"ijl_array_copy" ||
2054 funcName ==
"jl_idtable_rehash" ||
2055 funcName ==
"ijl_idtable_rehash" ||
2056 funcName ==
"jl_genericmemory_copy_slice" ||
2057 funcName ==
"ijl_genericmemory_copy_slice") {
2060 if (directions & DOWN && directions & UP) {
2061 if (UpHypothesis->isConstantValue(TR, op->getOperand(0))) {
2062 auto DownHypothesis =
2063 std::shared_ptr<mlir::enzyme::ActivityAnalyzer>(
2065 DownHypothesis->ConstantValues.insert(TmpOrig);
2067 {UseActivity::OnlyLoads, UseActivity::OnlyNonPointerStores,
2068 UseActivity::AllStores, UseActivity::None}) {
2069 Operation *LoadReval =
nullptr;
2070 if (DownHypothesis->isValueInactiveFromUsers(TR, TmpOrig, UA,
2072 insertConstantsFrom(TR, *DownHypothesis);
2073 InsertConstantValue(TR, Val);
2076 if (LoadReval && UA != UseActivity::AllStores) {
2077 ReEvaluateValueIfInactiveOp[LoadReval].insert(TmpOrig);
2084 }
else if (Val.getDefiningOp<LLVM::AllocaOp>()) {
2090 if (directions == DOWN) {
2092 {UseActivity::OnlyLoads, UseActivity::OnlyNonPointerStores,
2093 UseActivity::AllStores, UseActivity::None}) {
2094 Operation *LoadReval =
nullptr;
2095 if (isValueInactiveFromUsers(TR, TmpOrig, UA, &LoadReval)) {
2096 InsertConstantValue(TR, Val);
2099 if (LoadReval && UA != UseActivity::AllStores) {
2100 ReEvaluateValueIfInactiveOp[LoadReval].insert(TmpOrig);
2103 }
else if (directions & DOWN) {
2104 auto DownHypothesis = std::shared_ptr<mlir::enzyme::ActivityAnalyzer>(
2106 DownHypothesis->ConstantValues.insert(TmpOrig);
2108 {UseActivity::OnlyLoads, UseActivity::OnlyNonPointerStores,
2109 UseActivity::AllStores, UseActivity::None}) {
2110 Operation *LoadReval =
nullptr;
2111 if (DownHypothesis->isValueInactiveFromUsers(TR, TmpOrig, UA,
2113 insertConstantsFrom(TR, *DownHypothesis);
2114 InsertConstantValue(TR, Val);
2117 if (LoadReval && UA != UseActivity::AllStores) {
2118 ReEvaluateValueIfInactiveOp[LoadReval].insert(TmpOrig);
2130 if (TmpOrig != Val) {
2131 if (isConstantValue(TR, TmpOrig)) {
2133 llvm::errs() <<
" Potential Pointer(" << (int)directions <<
") "
2134 << Val <<
" inactive from inactive origin " << TmpOrig
2136 InsertConstantValue(TR, Val);
2141 Operation *op = Val.getDefiningOp();
2145 if (directions == UP && !isa<BlockArgument>(Val)) {
2146 if (isValueInactiveFromOrigin(TR, Val)) {
2148 llvm::errs() <<
" Non-function value inactive from origin("
2149 << (int)directions <<
") " << Val <<
"\n";
2150 InsertConstantValue(TR, Val);
2154 if (UpHypothesis->isValueInactiveFromOrigin(TR, Val)) {
2156 llvm::errs() <<
" Non-function value_v2 inactive from origin("
2157 << (int)directions <<
") " << Val <<
"\n";
2158 InsertConstantValue(TR, Val);
2159 insertConstantsFrom(TR, *UpHypothesis);
2170 if (directions != (UP | DOWN)) {
2172 llvm::errs() <<
" <Potential Pointer assumed active at "
2173 << (int)directions <<
">" << Val <<
"\n";
2174 ActiveValues.insert(Val);
2184 bool potentiallyActiveStore =
false;
2185 bool potentialStore =
false;
2186 bool potentiallyActiveLoad =
false;
2191 std::shared_ptr<mlir::enzyme::ActivityAnalyzer> Hypothesis =
2192 std::shared_ptr<mlir::enzyme::ActivityAnalyzer>(
2194 Hypothesis->ActiveValues.insert(Val);
2196 for (Value V : DeducingPointers) {
2197 UpHypothesis->InsertConstantValue(TR, V);
2199 if (UpHypothesis->isValueInactiveFromOrigin(TR, Val)) {
2200 Hypothesis->DeducingPointers.insert(Val);
2202 llvm::errs() <<
" constant instruction hypothesis: " << Val <<
"\n";
2205 llvm::errs() <<
" cannot show constant instruction hypothesis: "
2210 auto checkActivity = [&](Operation *op) {
2211 if (notForAnalysis.count(op->getBlock()))
2214 if (
auto op = TmpOrig.getDefiningOp())
2215 if (
auto ifaceOp = dyn_cast<enzyme::ActivityOpInterface>(op)) {
2216 if (ifaceOp.isInactive()) {
2222 if (
auto CI = dyn_cast<CallOpInterface>(op)) {
2223 if (CI->hasAttr(
"enzyme_inactive"))
2227 StringRef funcName = F ? cast<SymbolOpInterface>(F).getName() :
"";
2229 if (F && F->hasAttr(
"enzyme_inactive")) {
2248 auto dName = llvm::demangle(funcName.str());
2261 if (funcName.contains(FuncName)) {
2266 if (funcName ==
"__cxa_guard_acquire" ||
2267 funcName ==
"__cxa_guard_release" ||
2268 funcName ==
"__cxa_guard_abort" || funcName ==
"posix_memalign") {
2317 llvm::ModRefInfo modRef =
2319 ? (mayWrite ? llvm::ModRefInfo::ModRef : llvm::ModRefInfo::Ref)
2320 : (mayWrite ? llvm::ModRefInfo::Mod : llvm::ModRefInfo::NoModRef);
2334 if (!potentiallyActiveLoad && isRefSet(modRef)) {
2336 llvm::errs() <<
"potential active load: " << *op <<
"\n";
2337 if (isa<memref::LoadOp, LLVM::LoadOp>(op)) {
2340 assert(op->getNumResults() == 1 &&
2341 "expected a load-like op to have one result");
2344 Value loadedValue = op->getResult(0);
2345 if (!Hypothesis->isConstantValue(TR, loadedValue)) {
2346 potentiallyActiveLoad =
true;
2348 std::function<bool(Value V, SmallPtrSetImpl<Value> &)> loadCheck =
2349 [&](Value V, SmallPtrSetImpl<Value> &Seen) {
2356 if (TR.
query(V)[{-1}].isPossiblePointer()) {
2357 for (Operation *user : V.getUsers()) {
2359 if (!Hypothesis->isConstantOperation(TR, user)) {
2361 llvm::errs() <<
"potential active store via "
2363 << *op <<
" of " << Val <<
" via "
2365 potentiallyActiveStore =
true;
2372 for (Value U : user->getResults()) {
2373 if (U != Val && !Hypothesis->isConstantValue(TR, U)) {
2374 if (loadCheck(U, Seen))
2382 SmallPtrSet<Value, 2> Seen;
2383 loadCheck(loadedValue, Seen);
2385 }
else if (isa<LLVM::MemcpyOp, LLVM::MemmoveOp, LLVM::MemcpyInlineOp>(
2387 if (!Hypothesis->isConstantValue(TR, op->getOperand(0))) {
2388 potentiallyActiveLoad =
true;
2397 potentiallyActiveStore =
true;
2412 if (!Hypothesis->isConstantOperation(TR, op) ||
2413 llvm::any_of(op->getResults(), [&](Value V) {
2416 return !Hypothesis->isConstantValue(TR, V);
2418 potentiallyActiveLoad =
true;
2424 if (TR.
query(Val)[{-1, -1}].isPossiblePointer()) {
2439 !Hypothesis->isConstantOperation(TR, op)) ||
2440 llvm::any_of(op->getResults(), [&](Value V) ->
bool {
2441 return !Hypothesis->DeducingPointers.count(V) &&
2442 !Hypothesis->isConstantValue(TR, V) &&
2443 TR.query(V)[{-1}].isPossiblePointer();
2446 llvm::errs() <<
"potential active store via pointer in "
2448 << *op <<
" of " << Val <<
"\n";
2449 potentiallyActiveStore =
true;
2455 if ((!potentiallyActiveStore || !potentialStore) && isModSet(modRef)) {
2457 llvm::errs() <<
"potential active store: " << *op <<
" Val=" << Val
2459 if (
auto SI = dyn_cast<enzyme::StoreLikeInterface>(op)) {
2460 bool cop = !Hypothesis->isConstantValue(TR, SI.getStoredValue());
2462 llvm::errs() <<
" -- store potential activity: " << (int)cop
2463 <<
" - " << *op <<
" of "
2464 <<
" Val=" << Val <<
"\n";
2465 potentialStore =
true;
2467 potentiallyActiveStore =
true;
2468 }
else if (isa<LLVM::MemcpyOp, LLVM::MemmoveOp, LLVM::MemcpyInlineOp>(
2470 bool cop = !Hypothesis->isConstantValue(TR, op->getOperand(1));
2471 potentialStore =
true;
2473 potentiallyActiveStore =
true;
2474 }
else if (isa<LLVM::MemsetOp>(op)) {
2475 potentialStore =
true;
2480 auto cop = !Hypothesis->isConstantOperation(TR, op);
2482 llvm::errs() <<
" -- unknown store potential activity: " << (int)cop
2483 <<
" - " << *op <<
" of "
2484 <<
" Val=" << Val <<
"\n";
2485 potentialStore =
true;
2487 potentiallyActiveStore =
true;
2490 if (potentiallyActiveStore && potentiallyActiveLoad)
2507 auto checkActivityWrapper = [checkActivity](Operation *op) {
2508 if (checkActivity(op))
2509 return WalkResult::interrupt();
2510 return WalkResult::advance();
2513 if (
auto VI = Val.getDefiningOp<LLVM::AllocaOp>()) {
2515 }
else if (
auto VI = Val.getDefiningOp<memref::AllocaOp>()) {
2532 Operation *func = Val.getParentBlock()->getParentOp();
2533 assert(func &&
"unexpected freestanding block");
2534 if (!isa<FunctionOpInterface>(func))
2535 func = func->getParentOfType<FunctionOpInterface>();
2537 WalkResult r = func->walk([checkActivity,
this](Operation *nested) {
2538 if (notForAnalysis.contains(nested->getBlock()))
2539 return WalkResult::skip();
2540 if (checkActivity(nested))
2541 return WalkResult::interrupt();
2542 return WalkResult::advance();
2544 if (r.wasInterrupted())
2545 goto activeLoadAndStore;
2548 activeLoadAndStore:;
2550 llvm::errs() <<
" </MEMSEARCH" << (int)directions <<
">" << Val
2551 <<
" potentiallyActiveLoad=" << potentiallyActiveLoad
2552 <<
" potentiallyActiveStore=" << potentiallyActiveStore
2553 <<
" potentialStore=" << potentialStore <<
"\n";
2554 if (potentiallyActiveLoad && potentiallyActiveStore) {
2555 insertAllFrom(TR, *Hypothesis, Val);
2558 ReEvaluateValueIfInactiveValue[TmpOrig].insert(Val);
2577 assert(UpHypothesis);
2579 if (DeducingPointers.size() == 0)
2580 UpHypothesis->insertConstantsFrom(TR, *Hypothesis);
2584 assert(directions & UP);
2586 !UpHypothesis->isValueInactiveFromOrigin(TR, Val);
2594 std::shared_ptr<mlir::enzyme::ActivityAnalyzer> DownHypothesis =
2595 std::shared_ptr<mlir::enzyme::ActivityAnalyzer>(
2597 DownHypothesis->ConstantValues.insert(Val);
2598 DownHypothesis->insertConstantsFrom(TR, *Hypothesis);
2600 DownHypothesis->isValueActivelyStoredOrReturned(TR, Val);
2603 if (!ActiveDown && TmpOrig != Val) {
2607 TmpOrig.getDefiningOp<LLVM::AllocaOp>() ||
2608 TmpOrig.getDefiningOp<memref::AllocaOp>()
2610 std::shared_ptr<mlir::enzyme::ActivityAnalyzer> DownHypothesis2 =
2611 std::shared_ptr<mlir::enzyme::ActivityAnalyzer>(
2613 DownHypothesis2->ConstantValues.insert(TmpOrig);
2614 if (DownHypothesis2->isValueActivelyStoredOrReturned(TR, TmpOrig)) {
2616 llvm::errs() <<
" active from ivasor: " << TmpOrig <<
"\n";
2622 llvm::errs() <<
" active from unknown origin: " << TmpOrig <<
"\n";
2635 bool ActiveMemory =
false;
2639 ActiveMemory |= (ActiveUp && ActiveDown);
2642 ActiveMemory |= (ActiveUp && potentiallyActiveLoad);
2646 ActiveMemory |= (ActiveUp && potentialStore);
2649 ActiveMemory |= (ActiveDown && potentialStore);
2654 ActiveMemory |= ActiveDown;
2660 llvm::errs() <<
" @@MEMSEARCH" << (int)directions <<
">" << Val
2661 <<
" potentiallyActiveLoad=" << potentiallyActiveLoad
2662 <<
" potentialStore=" << potentialStore
2663 <<
" ActiveUp=" << ActiveUp <<
" ActiveDown=" << ActiveDown
2664 <<
" ActiveMemory=" << ActiveMemory <<
"\n";
2667 ActiveValues.insert(Val);
2668 assert(Hypothesis->directions == directions);
2669 assert(Hypothesis->ActiveValues.count(Val));
2670 insertAllFrom(TR, *Hypothesis, Val);
2672 ReEvaluateValueIfInactiveValue[TmpOrig].insert(Val);
2675 InsertConstantValue(TR, Val);
2676 insertConstantsFrom(TR, *Hypothesis);
2677 if (DeducingPointers.size() == 0)
2678 insertConstantsFrom(TR, *UpHypothesis);
2679 insertConstantsFrom(TR, *DownHypothesis);
2693 if (directions & UP) {
2694 UpHypothesis = std::shared_ptr<mlir::enzyme::ActivityAnalyzer>(
2696 UpHypothesis->ConstantValues.insert(Val);
2697 SmallPtrSet<Value, 4> toredo;
2698 if (UpHypothesis->isValueInactiveFromOrigin(TR, Val, &toredo)) {
2699 insertConstantsFrom(TR, *UpHypothesis);
2700 InsertConstantValue(TR, Val);
2702 llvm::errs() <<
" Value constant from origin [" << (int)directions
2703 <<
"]" << Val <<
"\n";
2706 for (Value result : toredo) {
2708 ReEvaluateValueIfInactiveValue[result].insert(Val);
2713 if (directions & DOWN) {
2718 auto DownHypothesis = std::shared_ptr<mlir::enzyme::ActivityAnalyzer>(
2720 DownHypothesis->ConstantValues.insert(Val);
2721 if (DownHypothesis->isValueInactiveFromUsers(TR, Val, UseActivity::None)) {
2722 insertConstantsFrom(TR, *DownHypothesis);
2724 insertConstantsFrom(TR, *UpHypothesis);
2725 InsertConstantValue(TR, Val);
2731 llvm::errs() <<
" Value nonconstant (couldn't disprove)[" << (int)directions
2732 <<
"]" << Val <<
"\n";
2733 ActiveValues.insert(Val);
3037 assert(directions & DOWN);
3044 llvm::errs() <<
" <Value USESEARCH" << (int)directions <<
">" << val
3045 <<
" UA=" << (
int)PUA <<
"\n";
3047 bool seenuse =
false;
3049 std::deque<std::tuple<Operation *, Value, UseActivity>> todo;
3050 for (Operation *a : val.getUsers()) {
3051 todo.push_back(std::make_tuple(a, val, PUA));
3053 std::set<std::tuple<Operation *, Value, UseActivity>> done = {};
3055 llvm::SmallPtrSet<Value, 1> AllocaSet;
3057 if (val.getDefiningOp<LLVM::AllocaOp>())
3058 AllocaSet.insert(val);
3063 while (todo.size()) {
3067 auto tuple = todo.front();
3069 if (done.count(tuple))
3072 std::tie(a, parent, UA) = tuple;
3074 if (
auto LI = dyn_cast<LLVM::LoadOp>(a)) {
3075 if (UA == UseActivity::OnlyStores)
3084 if (UA != UseActivity::AllStores) {
3085 if (
auto ifaceOp = dyn_cast<enzyme::ActivityOpInterface>(a)) {
3086 bool allInactive =
true;
3087 for (OpOperand &operand : a->getOpOperands()) {
3088 if (parent == operand.get() &&
3089 !ifaceOp.isArgInactive(operand.getOperandNumber())) {
3090 allInactive =
false;
3100 llvm::errs() <<
" considering use of " << val <<
" - " << *a <<
"\n";
3104 if (
auto SI = dyn_cast<LLVM::StoreOp>(a)) {
3105 if (SI.getValue() != parent) {
3106 if (UA == UseActivity::OnlyLoads) {
3109 if (UA != UseActivity::AllStores &&
3110 (ConstantValues.count(SI.getValue()) ||
3113 (SI.getValue().getDefiningOp<LLVM::ConstantOp>() &&
3114 isa<IntegerType>(SI.getValue().getType()))))
3116 if (UA == UseActivity::None) {
3119 bool shouldContinue =
true;
3120 SmallVector<Value, 1> vtodo = {SI.getValue()};
3121 llvm::SmallPtrSet<Value, 1> seen;
3122 llvm::SmallPtrSet<Value, 1> newAllocaSet;
3123 while (vtodo.size()) {
3124 auto TmpOrig = vtodo.back();
3126 if (seen.count(TmpOrig))
3128 seen.insert(TmpOrig);
3129 if (AllocaSet.count(TmpOrig)) {
3132 if (TmpOrig.getDefiningOp<LLVM::AllocaOp>()) {
3133 newAllocaSet.insert(TmpOrig);
3140 if (isa_and_nonnull<LLVM::UndefOp, LLVM::ConstantOp>(
3141 TmpOrig.getDefiningOp())) {
3144 if (
auto LI = TmpOrig.getDefiningOp<LLVM::LoadOp>()) {
3145 vtodo.push_back(LI.getAddr());
3180 llvm::errs() <<
" -- cannot continuing indirect store from"
3181 << val <<
" due to " << TmpOrig <<
"\n";
3182 shouldContinue =
false;
3185 if (shouldContinue) {
3187 llvm::errs() <<
" -- continuing indirect store from " << val
3189 done.insert(std::make_tuple(SI.getOperation(), SI.getValue(), UA));
3190 for (Value TmpOrig : newAllocaSet) {
3192 for (Operation *a : TmpOrig.getUsers()) {
3193 todo.push_back(std::make_tuple(a, TmpOrig, UA));
3195 llvm::errs() <<
" ** " << *a <<
"\n";
3197 AllocaSet.insert(TmpOrig);
3198 shouldContinue =
true;
3204 if (SI.getAddr() != parent) {
3205 Value TmpOrig = SI.getAddr();
3208 bool shouldContinue =
false;
3210 if (AllocaSet.count(TmpOrig)) {
3211 shouldContinue =
true;
3214 if (TmpOrig.getDefiningOp<LLVM::AllocaOp>()) {
3215 done.insert(std::make_tuple(SI.getOperation(), SI.getAddr(), UA));
3216 for (
const auto a : TmpOrig.getUsers()) {
3217 todo.push_back(std::make_tuple(a, TmpOrig, UA));
3219 AllocaSet.insert(TmpOrig);
3220 shouldContinue =
true;
3223 if (PUA == UseActivity::None) {
3224 if (
auto LI = TmpOrig.getDefiningOp<LLVM::LoadOp>()) {
3225 TmpOrig = LI.getAddr();
3254 if (shouldContinue) {
3256 llvm::errs() <<
" -- continuing indirect store2 from " << val
3257 <<
" via " << TmpOrig <<
"\n";
3261 if (PUA == UseActivity::OnlyLoads) {
3294 if (isa<LLVM::AllocaOp>(a)) {
3296 llvm::errs() <<
"found constant(" << (int)directions
3297 <<
") allocainst use:" << val <<
" user " << *a <<
"\n";
3326 if (UA != UseActivity::AllStores) {
3328 for (
auto post : *termUsers) {
3329 for (Operation *postUser : post.getUsers()) {
3330 todo.push_back(std::make_tuple(postUser, post, UA));
3336 bool allConstant =
true;
3337 assert(a->getOperands().size() == ActiveReturns.size());
3338 for (
auto &&[retval, act] :
3339 llvm::zip(a->getOperands(), ActiveReturns)) {
3340 if (retval != parent)
3344 allConstant =
false;
3355 if (isa<LLVM::MemcpyOp, LLVM::MemmoveOp>(a)) {
3375 if (UA == UseActivity::OnlyLoads && a->getOperand(1) != parent)
3379 if (a->getOperand(0) != parent) {
3380 if (UA == UseActivity::OnlyStores)
3382 else if (UA == UseActivity::OnlyNonPointerStores ||
3383 UA == UseActivity::AllStores) {
3392 bool shouldContinue =
false;
3393 if (UA != UseActivity::AllStores)
3394 for (
int arg = 0; arg < 2; arg++)
3395 if (a->getOperand(arg) != parent &&
3396 (arg == 0 || (PUA == UseActivity::None))) {
3397 Value TmpOrig = a->getOperand(arg);
3399 if (AllocaSet.count(TmpOrig)) {
3400 shouldContinue =
true;
3403 if (TmpOrig.getDefiningOp<LLVM::AllocaOp>()) {
3404 done.insert(std::make_tuple(a, a->getOperand(arg), UA));
3405 for (Operation *a : TmpOrig.getUsers()) {
3406 todo.push_back(std::make_tuple(a, TmpOrig, UA));
3408 AllocaSet.insert(TmpOrig);
3409 shouldContinue =
true;
3412 if (PUA == UseActivity::None) {
3413 if (
auto LI = TmpOrig.getDefiningOp<LLVM::LoadOp>()) {
3414 TmpOrig = LI.getAddr();
3443 if (
auto call = dyn_cast<CallOpInterface>(a)) {
3444 bool ConstantArg = isFunctionArgumentConstant(call, parent);
3445 if (ConstantArg && UA != UseActivity::AllStores) {
3447 llvm::errs() <<
"Value found constant callinst use:" << val
3448 <<
" user " << *call <<
"\n";
3454 if (UA == UseActivity::AllStores &&
3455 cast<SymbolOpInterface>(F).getName() ==
"julia.write_barrier")
3458 }
else if (PUA == UseActivity::None || PUA == UseActivity::OnlyStores) {
3463 Value operand = dyn_cast<Value>(call.getCallableForCallee());
3466 bool toContinue =
false;
3467 if (operand.getDefiningOp<LLVM::LoadOp>()) {
3470 for (
unsigned i = 0; i < call.getArgOperands().size(); ++i) {
3471 Value a = call.getArgOperands()[i];
3475 llvm::APInt intValue;
3476 if (matchPattern(a, m_ConstantInt(&intValue)))
3480 bool subValue =
false;
3531 if (
auto gep = dyn_cast<LLVM::GEPOp>(a)) {
3542 if (Operation *I = a) {
3543 if (notForAnalysis.count(I->getBlock())) {
3546 llvm::errs() <<
"Value found constant unreachable inst use:" << val
3547 <<
" user " << *I <<
"\n";
3551 if (UA != UseActivity::AllStores && ConstantOperations.count(I)) {
3552 if (llvm::all_of(I->getResults(), [&](Value val) {
3553 return isa<LLVM::LLVMVoidType, mlir::TokenType>(val.getType()) ||
3554 ConstantValues.count(val);
3557 llvm::errs() <<
"Value found constant inst use:" << val <<
" user "
3563 if (UA == UseActivity::OnlyLoads || UA == UseActivity::OnlyStores ||
3564 UA == UseActivity::OnlyNonPointerStores) {
3567 ViewLikeOpInterface,
3599 NU = UseActivity::None;
3603 for (Value result : I->getResults()) {
3604 for (Operation *u : result.getUsers()) {
3605 todo.push_back(std::make_tuple(u, result, NU));
3616 if (UA == UseActivity::OnlyLoads || UA == UseActivity::OnlyStores ||
3617 UA == UseActivity::OnlyNonPointerStores) {
3620 NU = UseActivity::None;
3623 for (Value result : I->getResults()) {
3624 for (Operation *u : result.getUsers()) {
3625 todo.push_back(std::make_tuple(u, result, NU));
3636 llvm::errs() <<
"Value nonconstant inst (uses):" << val <<
" user " << *a
3643 llvm::errs() <<
" </Value USESEARCH" << (int)directions
3644 <<
" const=" << (!seenuse) <<
">" << val <<
"\n";