1096 SetVector<Value> potentialSources;
1098 if (!arg.getOwner()->isEntryBlock()) {
1099 for (Block *predecessor : arg.getOwner()->getPredecessors()) {
1100 Operation *terminator = predecessor->getTerminator();
1101 if (
auto iface = dyn_cast<BranchOpInterface>(terminator)) {
1102 for (
const auto &en : llvm::enumerate(predecessor->getSuccessors())) {
1103 if (en.value() != arg.getOwner())
1106 Value inflow = iface.getSuccessorOperands(en.index())
1107 .getForwardedOperands()[arg.getArgNumber()];
1108 potentialSources.insert(inflow);
1111 for (Value operand : terminator->getOperands())
1112 potentialSources.insert(operand);
1115 return potentialSources.takeVector();
1118 Operation *parent = arg.getOwner()->getParentOp();
1119 Region *parentRegion = arg.getOwner()->getParent();
1121 if (
auto iface = dyn_cast<ADDataFlowOpInterface>(parent)) {
1122 for (
auto val : iface.getPotentialIncomingValuesArg(arg))
1123 potentialSources.insert(val);
1124 return potentialSources.takeVector();
1125 }
else if (
auto iface = dyn_cast<RegionBranchOpInterface>(parent)) {
1126 auto isRegionSucessorOf = [arg](RegionBranchOpInterface iface,
1128 RegionBranchPoint predecessor,
1129 SetVector<Value> &potentialSources) {
1130 SmallVector<RegionSuccessor> successors;
1131 iface.getSuccessorRegions(predecessor, successors);
1132 for (
const RegionSuccessor &successor : successors) {
1133 if (successor.getSuccessor() != region)
1136 unsigned operandOffset =
static_cast<unsigned>(-1);
1137 for (
const auto &en :
1138 llvm::enumerate(iface.getSuccessorInputs(successor))) {
1139 if (en.value() != arg)
1141 operandOffset = en.index();
1143 assert(operandOffset !=
static_cast<unsigned>(-1) &&
1144 "could not locate the position of the argument in the "
1145 "successor input list");
1149 if (predecessor.isParent()) {
1152 assert(iface.getEntrySuccessorOperands(region).size() ==
1153 iface.getSuccessorInputs(successor).size());
1154 potentialSources.insert(
1155 iface.getEntrySuccessorOperands(region)[operandOffset]);
1160 for (Block &block : *predecessor.getTerminatorPredecessorOrNull()
1161 ->getParentRegion()) {
1163 if (
auto terminator = dyn_cast<RegionBranchTerminatorOpInterface>(
1164 block.getTerminator())) {
1168 assert(terminator.getSuccessorOperands(region).size() ==
1169 iface.getSuccessorInputs(successor).size());
1170 potentialSources.insert(
1171 terminator.getSuccessorOperands(region)[operandOffset]);
1173 for (Value v : block.getTerminator()->getOperands())
1174 potentialSources.insert(v);
1182 isRegionSucessorOf(iface, parentRegion, RegionBranchPoint::parent(),
1184 for (Region &childRegion : parent->getRegions())
1185 isRegionSucessorOf(iface, parentRegion,
1186 cast<RegionBranchTerminatorOpInterface>(
1187 childRegion.front().getTerminator()),
1193 for (Region ®ion : parent->getRegions()) {
1194 for (Block &block : region) {
1196 for (Value v : block.getTerminator()->getOperands())
1197 potentialSources.insert(v);
1202 for (
auto op : parent->getOperands())
1203 potentialSources.insert(op);
1206 return potentialSources.takeVector();
1336 if (isa<LLVM::LLVMVoidType>(Val.getType()))
1340 if (isa<LLVM::LLVMTokenType>(Val.getType()))
1344 if (ConstantValues.find(Val) != ConstantValues.end()) {
1349 if (ActiveValues.find(Val) != ActiveValues.end()) {
1354 if (matchPattern(Val, m_Constant()))
1357 if (Operation *definingOp = Val.getDefiningOp()) {
1358 if (
auto ifaceOp = dyn_cast<enzyme::ActivityOpInterface>(definingOp)) {
1359 if (ifaceOp.isInactive()) {
1365 if (
auto arg = dyn_cast<BlockArgument>(Val)) {
1367 if (
auto funcIface = dyn_cast_or_null<FunctionOpInterface>(
1368 arg.getParentBlock()->getParentOp()))
1369 if (funcIface && arg.getOwner()->isEntryBlock() &&
1370 !funcIface.getArgAttr(arg.getArgNumber(),
1371 LLVM::LLVMDialect::getByValAttrName())) {
1372 llvm::errs() << funcIface <<
"\n";
1373 llvm::errs() << Val <<
"\n";
1374 assert(0 &&
"must've put arguments in constant/nonconstant");
1410 llvm::errs() <<
" Value const as integral " << (int)directions <<
" "
1413 InsertConstantValue(TR, Val);
1421 if (val->getType()->isPointerTy() &&
1422 cast<PointerType>(val->getType())->isIntOrIntVectorTy() &&
1423 TR.firstPointer(1, val,
false).isIntegral()) {
1425 llvm::errs() <<
" Value const as integral pointer" << (int)directions
1426 <<
" " << *val <<
"\n";
1427 InsertConstantValue(TR, Val);
1585 if (
auto CI = Val.getDefiningOp<CallOpInterface>()) {
1587 if (CI->hasAttr(
"enzyme_active")) {
1589 llvm::errs() <<
"forced active val " << Val <<
"\n";
1590 ActiveValues.insert(Val);
1593 if (CI->hasAttr(
"enzyme_inactive")) {
1595 llvm::errs() <<
"forced inactive val " << Val <<
"\n";
1596 InsertConstantValue(TR, Val);
1601 if (called->hasAttr(
"enzyme_active")) {
1603 llvm::errs() <<
"forced active val " << Val <<
"\n";
1604 ActiveValues.insert(Val);
1607 if (called->hasAttr(
"enzyme_inactive")) {
1609 llvm::errs() <<
"forced inactive val " << Val <<
"\n";
1610 InsertConstantValue(TR, Val);
1616 std::shared_ptr<mlir::enzyme::ActivityAnalyzer> UpHypothesis;
1625 bool containsPointer =
true;
1626 Type vectorTypeOrSelf =
1627 isa<mlir::VectorType>(Val.getType())
1628 ? cast<mlir::VectorType>(Val.getType()).getElementType()
1630 if (LLVM::isCompatibleFloatingPointType(vectorTypeOrSelf))
1631 containsPointer =
false;
1635 if (!isa<LLVM::LLVMPointerType, MemRefType>(Val.getType()))
1636 containsPointer =
false;
1639 containsPointer =
false;
1647 if (containsPointer) {
1653 if (directions & UP) {
1657 if (!func.getArgAttr(cast<BlockArgument>(TmpOrig).getArgNumber(),
1658 LLVM::LLVMDialect::getByValAttrName())) {
1659 bool res = isConstantValue(TR, TmpOrig);
1662 llvm::errs() <<
" arg const from orig val=" << Val
1663 <<
" orig=" << TmpOrig <<
"\n";
1664 InsertConstantValue(TR, Val);
1667 llvm::errs() <<
" arg active from orig val=" << Val
1668 <<
" orig=" << TmpOrig <<
"\n";
1669 ActiveValues.insert(Val);
1675 if (
auto op = TmpOrig.getDefiningOp())
1676 if (
auto ifaceOp = dyn_cast<enzyme::ActivityOpInterface>(op)) {
1677 if (ifaceOp.isInactive()) {
1678 InsertConstantValue(TR, Val);
1679 if (TmpOrig != Val) {
1680 InsertConstantValue(TR, TmpOrig);
1686 UpHypothesis = std::shared_ptr<mlir::enzyme::ActivityAnalyzer>(
1688 UpHypothesis->ConstantValues.insert(Val);
1692 if (
auto blockArg = dyn_cast<BlockArgument>(TmpOrig)) {
1694 Value active =
nullptr;
1696 if (!UpHypothesis->isConstantValue(TR, V)) {
1702 InsertConstantValue(TR, Val);
1703 if (TmpOrig != Val) {
1704 InsertConstantValue(TR, TmpOrig);
1706 insertConstantsFrom(TR, *UpHypothesis);
1709 ReEvaluateValueIfInactiveValue[active].insert(Val);
1710 if (TmpOrig != Val) {
1711 ReEvaluateValueIfInactiveValue[active].insert(TmpOrig);
1714 }
else if (
auto LI = TmpOrig.getDefiningOp<LLVM::LoadOp>()) {
1715 if (directions == UP) {
1716 if (isConstantValue(TR, LI.getAddr())) {
1717 InsertConstantValue(TR, Val);
1721 if (UpHypothesis->isConstantValue(TR, LI.getAddr())) {
1722 InsertConstantValue(TR, Val);
1723 insertConstantsFrom(TR, *UpHypothesis);
1753 }
else if (
auto op = TmpOrig.getDefiningOp<CallOpInterface>()) {
1754 if (op->hasAttr(
"enzyme_inactive")) {
1755 InsertConstantValue(TR, Val);
1756 insertConstantsFrom(TR, *UpHypothesis);
1761 StringRef funcName =
1762 called ? cast<SymbolOpInterface>(called).getName() :
"";
1764 if (called && called->hasAttr(
"enzyme_inactive")) {
1765 InsertConstantValue(TR, Val);
1766 insertConstantsFrom(TR, *UpHypothesis);
1769 if (funcName ==
"free" || funcName ==
"_ZdlPv" ||
1770 funcName ==
"_ZdlPvm" || funcName ==
"munmap") {
1771 InsertConstantValue(TR, Val);
1772 insertConstantsFrom(TR, *UpHypothesis);
1776 auto dName = llvm::demangle(funcName.str());
1779 InsertConstantValue(TR, Val);
1780 insertConstantsFrom(TR, *UpHypothesis);
1787 InsertConstantValue(TR, Val);
1788 insertConstantsFrom(TR, *UpHypothesis);
1794 if (funcName.contains(FuncName)) {
1795 InsertConstantValue(TR, Val);
1796 insertConstantsFrom(TR, *UpHypothesis);
1804 InsertConstantValue(TR, Val);
1805 insertConstantsFrom(TR, *UpHypothesis);
1868 if (funcName ==
"jl_array_copy" || funcName ==
"ijl_array_copy" ||
1869 funcName ==
"jl_idtable_rehash" ||
1870 funcName ==
"ijl_idtable_rehash" ||
1871 funcName ==
"jl_genericmemory_copy_slice" ||
1872 funcName ==
"ijl_genericmemory_copy_slice") {
1875 if (directions & DOWN && directions & UP) {
1876 if (UpHypothesis->isConstantValue(TR, op->getOperand(0))) {
1877 auto DownHypothesis =
1878 std::shared_ptr<mlir::enzyme::ActivityAnalyzer>(
1880 DownHypothesis->ConstantValues.insert(TmpOrig);
1882 {UseActivity::OnlyLoads, UseActivity::OnlyNonPointerStores,
1883 UseActivity::AllStores, UseActivity::None}) {
1884 Operation *LoadReval =
nullptr;
1885 if (DownHypothesis->isValueInactiveFromUsers(TR, TmpOrig, UA,
1887 insertConstantsFrom(TR, *DownHypothesis);
1888 InsertConstantValue(TR, Val);
1891 if (LoadReval && UA != UseActivity::AllStores) {
1892 ReEvaluateValueIfInactiveOp[LoadReval].insert(TmpOrig);
1899 }
else if (Val.getDefiningOp<LLVM::AllocaOp>()) {
1905 if (directions == DOWN) {
1907 {UseActivity::OnlyLoads, UseActivity::OnlyNonPointerStores,
1908 UseActivity::AllStores, UseActivity::None}) {
1909 Operation *LoadReval =
nullptr;
1910 if (isValueInactiveFromUsers(TR, TmpOrig, UA, &LoadReval)) {
1911 InsertConstantValue(TR, Val);
1914 if (LoadReval && UA != UseActivity::AllStores) {
1915 ReEvaluateValueIfInactiveOp[LoadReval].insert(TmpOrig);
1918 }
else if (directions & DOWN) {
1919 auto DownHypothesis = std::shared_ptr<mlir::enzyme::ActivityAnalyzer>(
1921 DownHypothesis->ConstantValues.insert(TmpOrig);
1923 {UseActivity::OnlyLoads, UseActivity::OnlyNonPointerStores,
1924 UseActivity::AllStores, UseActivity::None}) {
1925 Operation *LoadReval =
nullptr;
1926 if (DownHypothesis->isValueInactiveFromUsers(TR, TmpOrig, UA,
1928 insertConstantsFrom(TR, *DownHypothesis);
1929 InsertConstantValue(TR, Val);
1932 if (LoadReval && UA != UseActivity::AllStores) {
1933 ReEvaluateValueIfInactiveOp[LoadReval].insert(TmpOrig);
1945 if (TmpOrig != Val) {
1946 if (isConstantValue(TR, TmpOrig)) {
1948 llvm::errs() <<
" Potential Pointer(" << (int)directions <<
") "
1949 << Val <<
" inactive from inactive origin " << TmpOrig
1951 InsertConstantValue(TR, Val);
1956 Operation *op = Val.getDefiningOp();
1960 if (directions == UP && !isa<BlockArgument>(Val)) {
1961 if (isValueInactiveFromOrigin(TR, Val)) {
1963 llvm::errs() <<
" Non-function value inactive from origin("
1964 << (int)directions <<
") " << Val <<
"\n";
1965 InsertConstantValue(TR, Val);
1969 if (UpHypothesis->isValueInactiveFromOrigin(TR, Val)) {
1971 llvm::errs() <<
" Non-function value_v2 inactive from origin("
1972 << (int)directions <<
") " << Val <<
"\n";
1973 InsertConstantValue(TR, Val);
1974 insertConstantsFrom(TR, *UpHypothesis);
1985 if (directions != (UP | DOWN)) {
1987 llvm::errs() <<
" <Potential Pointer assumed active at "
1988 << (int)directions <<
">" << Val <<
"\n";
1989 ActiveValues.insert(Val);
1999 bool potentiallyActiveStore =
false;
2000 bool potentialStore =
false;
2001 bool potentiallyActiveLoad =
false;
2006 std::shared_ptr<mlir::enzyme::ActivityAnalyzer> Hypothesis =
2007 std::shared_ptr<mlir::enzyme::ActivityAnalyzer>(
2009 Hypothesis->ActiveValues.insert(Val);
2011 for (Value V : DeducingPointers) {
2012 UpHypothesis->InsertConstantValue(TR, V);
2014 if (UpHypothesis->isValueInactiveFromOrigin(TR, Val)) {
2015 Hypothesis->DeducingPointers.insert(Val);
2017 llvm::errs() <<
" constant instruction hypothesis: " << Val <<
"\n";
2020 llvm::errs() <<
" cannot show constant instruction hypothesis: "
2025 auto checkActivity = [&](Operation *op) {
2026 if (notForAnalysis.count(op->getBlock()))
2029 if (
auto op = TmpOrig.getDefiningOp())
2030 if (
auto ifaceOp = dyn_cast<enzyme::ActivityOpInterface>(op)) {
2031 if (ifaceOp.isInactive()) {
2037 if (
auto CI = dyn_cast<CallOpInterface>(op)) {
2038 if (CI->hasAttr(
"enzyme_inactive"))
2042 StringRef funcName = F ? cast<SymbolOpInterface>(F).getName() :
"";
2044 if (F && F->hasAttr(
"enzyme_inactive")) {
2063 auto dName = llvm::demangle(funcName.str());
2076 if (funcName.contains(FuncName)) {
2081 if (funcName ==
"__cxa_guard_acquire" ||
2082 funcName ==
"__cxa_guard_release" ||
2083 funcName ==
"__cxa_guard_abort" || funcName ==
"posix_memalign") {
2132 llvm::ModRefInfo modRef =
2134 ? (mayWrite ? llvm::ModRefInfo::ModRef : llvm::ModRefInfo::Ref)
2135 : (mayWrite ? llvm::ModRefInfo::Mod : llvm::ModRefInfo::NoModRef);
2149 if (!potentiallyActiveLoad && isRefSet(modRef)) {
2151 llvm::errs() <<
"potential active load: " << *op <<
"\n";
2152 if (isa<memref::LoadOp, LLVM::LoadOp>(op)) {
2155 assert(op->getNumResults() == 1 &&
2156 "expected a load-like op to have one result");
2159 Value loadedValue = op->getResult(0);
2160 if (!Hypothesis->isConstantValue(TR, loadedValue)) {
2161 potentiallyActiveLoad =
true;
2163 std::function<bool(Value V, SmallPtrSetImpl<Value> &)> loadCheck =
2164 [&](Value V, SmallPtrSetImpl<Value> &Seen) {
2171 if (TR.
query(V)[{-1}].isPossiblePointer()) {
2172 for (Operation *user : V.getUsers()) {
2174 if (!Hypothesis->isConstantOperation(TR, user)) {
2176 llvm::errs() <<
"potential active store via "
2178 << *op <<
" of " << Val <<
" via "
2180 potentiallyActiveStore =
true;
2187 for (Value U : user->getResults()) {
2188 if (U != Val && !Hypothesis->isConstantValue(TR, U)) {
2189 if (loadCheck(U, Seen))
2197 SmallPtrSet<Value, 2> Seen;
2198 loadCheck(loadedValue, Seen);
2200 }
else if (isa<LLVM::MemcpyOp, LLVM::MemmoveOp, LLVM::MemcpyInlineOp>(
2202 if (!Hypothesis->isConstantValue(TR, op->getOperand(0))) {
2203 potentiallyActiveLoad =
true;
2212 potentiallyActiveStore =
true;
2227 if (!Hypothesis->isConstantOperation(TR, op) ||
2228 llvm::any_of(op->getResults(), [&](Value V) {
2231 return !Hypothesis->isConstantValue(TR, V);
2233 potentiallyActiveLoad =
true;
2239 if (TR.
query(Val)[{-1, -1}].isPossiblePointer()) {
2254 !Hypothesis->isConstantOperation(TR, op)) ||
2255 llvm::any_of(op->getResults(), [&](Value V) ->
bool {
2256 return !Hypothesis->DeducingPointers.count(V) &&
2257 !Hypothesis->isConstantValue(TR, V) &&
2258 TR.query(V)[{-1}].isPossiblePointer();
2261 llvm::errs() <<
"potential active store via pointer in "
2263 << *op <<
" of " << Val <<
"\n";
2264 potentiallyActiveStore =
true;
2270 if ((!potentiallyActiveStore || !potentialStore) && isModSet(modRef)) {
2272 llvm::errs() <<
"potential active store: " << *op <<
" Val=" << Val
2274 if (
auto SI = dyn_cast<LLVM::StoreOp>(op)) {
2275 bool cop = !Hypothesis->isConstantValue(TR, SI.getValue());
2277 llvm::errs() <<
" -- store potential activity: " << (int)cop
2278 <<
" - " << *SI <<
" of "
2279 <<
" Val=" << Val <<
"\n";
2280 potentialStore =
true;
2282 potentiallyActiveStore =
true;
2283 }
else if (
auto SI = dyn_cast<memref::StoreOp>(op)) {
2285 bool cop = !Hypothesis->isConstantValue(TR, SI.getValueToStore());
2287 llvm::errs() <<
" -- store potential activity: " << (int)cop
2288 <<
" - " << *SI <<
" of "
2289 <<
" Val=" << Val <<
"\n";
2290 potentialStore =
true;
2292 potentiallyActiveStore =
true;
2293 }
else if (isa<LLVM::MemcpyOp, LLVM::MemmoveOp, LLVM::MemcpyInlineOp>(
2295 bool cop = !Hypothesis->isConstantValue(TR, op->getOperand(1));
2296 potentialStore =
true;
2298 potentiallyActiveStore =
true;
2299 }
else if (isa<LLVM::MemsetOp>(op)) {
2300 potentialStore =
true;
2305 auto cop = !Hypothesis->isConstantOperation(TR, op);
2307 llvm::errs() <<
" -- unknown store potential activity: " << (int)cop
2308 <<
" - " << *op <<
" of "
2309 <<
" Val=" << Val <<
"\n";
2310 potentialStore =
true;
2312 potentiallyActiveStore =
true;
2315 if (potentiallyActiveStore && potentiallyActiveLoad)
2332 auto checkActivityWrapper = [checkActivity](Operation *op) {
2333 if (checkActivity(op))
2334 return WalkResult::interrupt();
2335 return WalkResult::advance();
2338 if (
auto VI = Val.getDefiningOp<LLVM::AllocaOp>()) {
2340 }
else if (
auto VI = Val.getDefiningOp<memref::AllocaOp>()) {
2357 Operation *func = Val.getParentBlock()->getParentOp();
2358 assert(func &&
"unexpected freestanding block");
2359 if (!isa<FunctionOpInterface>(func))
2360 func = func->getParentOfType<FunctionOpInterface>();
2362 WalkResult r = func->walk([checkActivity,
this](Operation *nested) {
2363 if (notForAnalysis.contains(nested->getBlock()))
2364 return WalkResult::skip();
2365 if (checkActivity(nested))
2366 return WalkResult::interrupt();
2367 return WalkResult::advance();
2369 if (r.wasInterrupted())
2370 goto activeLoadAndStore;
2373 activeLoadAndStore:;
2375 llvm::errs() <<
" </MEMSEARCH" << (int)directions <<
">" << Val
2376 <<
" potentiallyActiveLoad=" << potentiallyActiveLoad
2377 <<
" potentiallyActiveStore=" << potentiallyActiveStore
2378 <<
" potentialStore=" << potentialStore <<
"\n";
2379 if (potentiallyActiveLoad && potentiallyActiveStore) {
2380 insertAllFrom(TR, *Hypothesis, Val);
2383 ReEvaluateValueIfInactiveValue[TmpOrig].insert(Val);
2402 assert(UpHypothesis);
2404 if (DeducingPointers.size() == 0)
2405 UpHypothesis->insertConstantsFrom(TR, *Hypothesis);
2409 assert(directions & UP);
2411 !UpHypothesis->isValueInactiveFromOrigin(TR, Val);
2419 std::shared_ptr<mlir::enzyme::ActivityAnalyzer> DownHypothesis =
2420 std::shared_ptr<mlir::enzyme::ActivityAnalyzer>(
2422 DownHypothesis->ConstantValues.insert(Val);
2423 DownHypothesis->insertConstantsFrom(TR, *Hypothesis);
2425 DownHypothesis->isValueActivelyStoredOrReturned(TR, Val);
2428 if (!ActiveDown && TmpOrig != Val) {
2432 TmpOrig.getDefiningOp<LLVM::AllocaOp>() ||
2433 TmpOrig.getDefiningOp<memref::AllocaOp>()
2435 std::shared_ptr<mlir::enzyme::ActivityAnalyzer> DownHypothesis2 =
2436 std::shared_ptr<mlir::enzyme::ActivityAnalyzer>(
2438 DownHypothesis2->ConstantValues.insert(TmpOrig);
2439 if (DownHypothesis2->isValueActivelyStoredOrReturned(TR, TmpOrig)) {
2441 llvm::errs() <<
" active from ivasor: " << TmpOrig <<
"\n";
2447 llvm::errs() <<
" active from unknown origin: " << TmpOrig <<
"\n";
2460 bool ActiveMemory =
false;
2464 ActiveMemory |= (ActiveUp && ActiveDown);
2467 ActiveMemory |= (ActiveUp && potentiallyActiveLoad);
2471 ActiveMemory |= (ActiveUp && potentialStore);
2474 ActiveMemory |= (ActiveDown && potentialStore);
2479 ActiveMemory |= ActiveDown;
2485 llvm::errs() <<
" @@MEMSEARCH" << (int)directions <<
">" << Val
2486 <<
" potentiallyActiveLoad=" << potentiallyActiveLoad
2487 <<
" potentialStore=" << potentialStore
2488 <<
" ActiveUp=" << ActiveUp <<
" ActiveDown=" << ActiveDown
2489 <<
" ActiveMemory=" << ActiveMemory <<
"\n";
2492 ActiveValues.insert(Val);
2493 assert(Hypothesis->directions == directions);
2494 assert(Hypothesis->ActiveValues.count(Val));
2495 insertAllFrom(TR, *Hypothesis, Val);
2497 ReEvaluateValueIfInactiveValue[TmpOrig].insert(Val);
2500 InsertConstantValue(TR, Val);
2501 insertConstantsFrom(TR, *Hypothesis);
2502 if (DeducingPointers.size() == 0)
2503 insertConstantsFrom(TR, *UpHypothesis);
2504 insertConstantsFrom(TR, *DownHypothesis);
2518 if (directions & UP) {
2519 UpHypothesis = std::shared_ptr<mlir::enzyme::ActivityAnalyzer>(
2521 UpHypothesis->ConstantValues.insert(Val);
2522 SmallPtrSet<Value, 4> toredo;
2523 if (UpHypothesis->isValueInactiveFromOrigin(TR, Val, &toredo)) {
2524 insertConstantsFrom(TR, *UpHypothesis);
2525 InsertConstantValue(TR, Val);
2527 llvm::errs() <<
" Value constant from origin [" << (int)directions
2528 <<
"]" << Val <<
"\n";
2531 for (Value result : toredo) {
2533 ReEvaluateValueIfInactiveValue[result].insert(Val);
2538 if (directions & DOWN) {
2543 auto DownHypothesis = std::shared_ptr<mlir::enzyme::ActivityAnalyzer>(
2545 DownHypothesis->ConstantValues.insert(Val);
2546 if (DownHypothesis->isValueInactiveFromUsers(TR, Val, UseActivity::None)) {
2547 insertConstantsFrom(TR, *DownHypothesis);
2549 insertConstantsFrom(TR, *UpHypothesis);
2550 InsertConstantValue(TR, Val);
2556 llvm::errs() <<
" Value nonconstant (couldn't disprove)[" << (int)directions
2557 <<
"]" << Val <<
"\n";
2558 ActiveValues.insert(Val);
2860 assert(directions & DOWN);
2867 llvm::errs() <<
" <Value USESEARCH" << (int)directions <<
">" << val
2868 <<
" UA=" << (
int)PUA <<
"\n";
2870 bool seenuse =
false;
2872 std::deque<std::tuple<Operation *, Value, UseActivity>> todo;
2873 for (Operation *a : val.getUsers()) {
2874 todo.push_back(std::make_tuple(a, val, PUA));
2876 std::set<std::tuple<Operation *, Value, UseActivity>> done = {};
2878 llvm::SmallPtrSet<Value, 1> AllocaSet;
2880 if (val.getDefiningOp<LLVM::AllocaOp>())
2881 AllocaSet.insert(val);
2886 while (todo.size()) {
2890 auto tuple = todo.front();
2892 if (done.count(tuple))
2895 std::tie(a, parent, UA) = tuple;
2897 if (
auto LI = dyn_cast<LLVM::LoadOp>(a)) {
2898 if (UA == UseActivity::OnlyStores)
2907 if (UA != UseActivity::AllStores) {
2908 if (
auto ifaceOp = dyn_cast<enzyme::ActivityOpInterface>(a)) {
2909 bool allInactive =
true;
2910 for (OpOperand &operand : a->getOpOperands()) {
2911 if (parent == operand.get() &&
2912 !ifaceOp.isArgInactive(operand.getOperandNumber())) {
2913 allInactive =
false;
2923 llvm::errs() <<
" considering use of " << val <<
" - " << *a <<
"\n";
2927 if (
auto SI = dyn_cast<LLVM::StoreOp>(a)) {
2928 if (SI.getValue() != parent) {
2929 if (UA == UseActivity::OnlyLoads) {
2932 if (UA != UseActivity::AllStores &&
2933 (ConstantValues.count(SI.getValue()) ||
2936 (SI.getValue().getDefiningOp<LLVM::ConstantOp>() &&
2937 isa<IntegerType>(SI.getValue().getType()))))
2939 if (UA == UseActivity::None) {
2942 bool shouldContinue =
true;
2943 SmallVector<Value, 1> vtodo = {SI.getValue()};
2944 llvm::SmallPtrSet<Value, 1> seen;
2945 llvm::SmallPtrSet<Value, 1> newAllocaSet;
2946 while (vtodo.size()) {
2947 auto TmpOrig = vtodo.back();
2949 if (seen.count(TmpOrig))
2951 seen.insert(TmpOrig);
2952 if (AllocaSet.count(TmpOrig)) {
2955 if (TmpOrig.getDefiningOp<LLVM::AllocaOp>()) {
2956 newAllocaSet.insert(TmpOrig);
2963 if (isa_and_nonnull<LLVM::UndefOp, LLVM::ConstantOp>(
2964 TmpOrig.getDefiningOp())) {
2967 if (
auto LI = TmpOrig.getDefiningOp<LLVM::LoadOp>()) {
2968 vtodo.push_back(LI.getAddr());
3003 llvm::errs() <<
" -- cannot continuing indirect store from"
3004 << val <<
" due to " << TmpOrig <<
"\n";
3005 shouldContinue =
false;
3008 if (shouldContinue) {
3010 llvm::errs() <<
" -- continuing indirect store from " << val
3012 done.insert(std::make_tuple(SI.getOperation(), SI.getValue(), UA));
3013 for (Value TmpOrig : newAllocaSet) {
3015 for (Operation *a : TmpOrig.getUsers()) {
3016 todo.push_back(std::make_tuple(a, TmpOrig, UA));
3018 llvm::errs() <<
" ** " << *a <<
"\n";
3020 AllocaSet.insert(TmpOrig);
3021 shouldContinue =
true;
3027 if (SI.getAddr() != parent) {
3028 Value TmpOrig = SI.getAddr();
3031 bool shouldContinue =
false;
3033 if (AllocaSet.count(TmpOrig)) {
3034 shouldContinue =
true;
3037 if (TmpOrig.getDefiningOp<LLVM::AllocaOp>()) {
3038 done.insert(std::make_tuple(SI.getOperation(), SI.getAddr(), UA));
3039 for (
const auto a : TmpOrig.getUsers()) {
3040 todo.push_back(std::make_tuple(a, TmpOrig, UA));
3042 AllocaSet.insert(TmpOrig);
3043 shouldContinue =
true;
3046 if (PUA == UseActivity::None) {
3047 if (
auto LI = TmpOrig.getDefiningOp<LLVM::LoadOp>()) {
3048 TmpOrig = LI.getAddr();
3077 if (shouldContinue) {
3079 llvm::errs() <<
" -- continuing indirect store2 from " << val
3080 <<
" via " << TmpOrig <<
"\n";
3084 if (PUA == UseActivity::OnlyLoads) {
3117 if (isa<LLVM::AllocaOp>(a)) {
3119 llvm::errs() <<
"found constant(" << (int)directions
3120 <<
") allocainst use:" << val <<
" user " << *a <<
"\n";
3149 if (UA != UseActivity::AllStores) {
3151 for (
auto post : *termUsers) {
3152 for (Operation *postUser : post.getUsers()) {
3153 todo.push_back(std::make_tuple(postUser, post, UA));
3159 bool allConstant =
true;
3160 assert(a->getOperands().size() == ActiveReturns.size());
3161 for (
auto &&[retval, act] :
3162 llvm::zip(a->getOperands(), ActiveReturns)) {
3163 if (retval != parent)
3167 allConstant =
false;
3178 if (isa<LLVM::MemcpyOp, LLVM::MemmoveOp>(a)) {
3198 if (UA == UseActivity::OnlyLoads && a->getOperand(1) != parent)
3202 if (a->getOperand(0) != parent) {
3203 if (UA == UseActivity::OnlyStores)
3205 else if (UA == UseActivity::OnlyNonPointerStores ||
3206 UA == UseActivity::AllStores) {
3215 bool shouldContinue =
false;
3216 if (UA != UseActivity::AllStores)
3217 for (
int arg = 0; arg < 2; arg++)
3218 if (a->getOperand(arg) != parent &&
3219 (arg == 0 || (PUA == UseActivity::None))) {
3220 Value TmpOrig = a->getOperand(arg);
3222 if (AllocaSet.count(TmpOrig)) {
3223 shouldContinue =
true;
3226 if (TmpOrig.getDefiningOp<LLVM::AllocaOp>()) {
3227 done.insert(std::make_tuple(a, a->getOperand(arg), UA));
3228 for (Operation *a : TmpOrig.getUsers()) {
3229 todo.push_back(std::make_tuple(a, TmpOrig, UA));
3231 AllocaSet.insert(TmpOrig);
3232 shouldContinue =
true;
3235 if (PUA == UseActivity::None) {
3236 if (
auto LI = TmpOrig.getDefiningOp<LLVM::LoadOp>()) {
3237 TmpOrig = LI.getAddr();
3266 if (
auto call = dyn_cast<CallOpInterface>(a)) {
3267 bool ConstantArg = isFunctionArgumentConstant(call, parent);
3268 if (ConstantArg && UA != UseActivity::AllStores) {
3270 llvm::errs() <<
"Value found constant callinst use:" << val
3271 <<
" user " << *call <<
"\n";
3277 if (UA == UseActivity::AllStores &&
3278 cast<SymbolOpInterface>(F).getName() ==
"julia.write_barrier")
3281 }
else if (PUA == UseActivity::None || PUA == UseActivity::OnlyStores) {
3286 Value operand = dyn_cast<Value>(call.getCallableForCallee());
3289 bool toContinue =
false;
3290 if (operand.getDefiningOp<LLVM::LoadOp>()) {
3293 for (
unsigned i = 0; i < call.getArgOperands().size(); ++i) {
3294 Value a = call.getArgOperands()[i];
3298 llvm::APInt intValue;
3299 if (matchPattern(a, m_ConstantInt(&intValue)))
3303 bool subValue =
false;
3354 if (
auto gep = dyn_cast<LLVM::GEPOp>(a)) {
3365 if (Operation *I = a) {
3366 if (notForAnalysis.count(I->getBlock())) {
3369 llvm::errs() <<
"Value found constant unreachable inst use:" << val
3370 <<
" user " << *I <<
"\n";
3374 if (UA != UseActivity::AllStores && ConstantOperations.count(I)) {
3375 if (llvm::all_of(I->getResults(), [&](Value val) {
3376 return isa<LLVM::LLVMVoidType, LLVM::LLVMTokenType>(
3378 ConstantValues.count(val);
3381 llvm::errs() <<
"Value found constant inst use:" << val <<
" user "
3387 if (UA == UseActivity::OnlyLoads || UA == UseActivity::OnlyStores ||
3388 UA == UseActivity::OnlyNonPointerStores) {
3415 LLVM::AddrSpaceCastOp,
3425 NU = UseActivity::None;
3429 for (Value result : I->getResults()) {
3430 for (Operation *u : result.getUsers()) {
3431 todo.push_back(std::make_tuple(u, result, NU));
3442 if (UA == UseActivity::OnlyLoads || UA == UseActivity::OnlyStores ||
3443 UA == UseActivity::OnlyNonPointerStores) {
3446 NU = UseActivity::None;
3449 for (Value result : I->getResults()) {
3450 for (Operation *u : result.getUsers()) {
3451 todo.push_back(std::make_tuple(u, result, NU));
3462 llvm::errs() <<
"Value nonconstant inst (uses):" << val <<
" user " << *a
3469 llvm::errs() <<
" </Value USESEARCH" << (int)directions
3470 <<
" const=" << (!seenuse) <<
">" << val <<
"\n";