Commit Graph

11993 Commits

Author SHA1 Message Date
Nikita Popov
4d97a914d7 [SCEV] Use umin_seq for symbolic max BE count
We were using umin_seq when computing the exact BE count, but not
when computing the symbolic max BE count.
2022-12-07 15:32:49 +01:00
Max Kazantsev
07de5d18c9 [SCEV] Remember blocks for which we know symbolic exit count but not exact
The old code didn't bother to memoize blocks for which exact exit count is not
known. As result, in situation when exact isn't known but symbolic is known, this
info was lost. This patch fixes the situation: now we memoize when symbolic is
known (exact always implies symbolic, so this is a strict superset of what was before).

Differential Revision: https://reviews.llvm.org/D139515
Reviewed By: nikic
2022-12-07 17:51:30 +07:00
Max Kazantsev
49e928bee8 [SCEV][NFC] Sink initialization of SymbolicMaxNotTaken from ExitLimit constructor to its callers
Preserves current behavior (always select Exact if known, otherwise select Constant Max).
This is the final preparation step before letting each particular computation way to decide
how exactly it should be computed. Functional improvement is coming shortly as follow-up.

Differential Revision: https://reviews.llvm.org/D139402
Reviewed By: nikic, fhahn
2022-12-07 15:33:03 +07:00
Kazu Hirata
1f421b6d7e [llvm] Use std::nullopt instead of None in comments (NFC)
This is part of an effort to migrate from llvm::Optional to
std::optional:

https://discourse.llvm.org/t/deprecating-llvm-optional-x-hasvalue-getvalue-getvalueor/63716
2022-12-06 22:45:17 -08:00
Kazu Hirata
405fc404bf [ADT] Don't including None.h (NFC)
These source files no longer use None, so they do not need to include
None.h.

This is part of an effort to migrate from llvm::Optional to
std::optional:

https://discourse.llvm.org/t/deprecating-llvm-optional-x-hasvalue-getvalue-getvalueor/63716
2022-12-06 20:14:51 -08:00
Krzysztof Parzyszek
c589730ad5 [YAML] Convert Optional to std::optional 2022-12-06 12:49:32 -08:00
Mircea Trofin
4c97745bf0 Reapply "[mlgo] Dependency-free training mode logger"
This reverts commit 8abe7b11f7.

Added the missing cast which was causing a build problem on certain compilers.
2022-12-06 10:29:50 -08:00
Roman Lebedev
46db90cc71 [SCEV] MatchBinaryOp(): try to recognize or as add-in-disguise (w/ no common bits set)
LLVM *loves* to convert `add` of operands with no common bits
into an `or`. But SCEV really doesn't deal with `or` that well,
so try extra hard to recognize this `or` as an `add`.

I believe, previously this wasn't being done because of the recursive
of this, but now that the `createSCEV()` is not recursive,
this should be fine. Unless this is *too* costly compile-time wise...

https://alive2.llvm.org/ce/z/EfapCo
2022-12-06 20:26:53 +03:00
Florian Hahn
8abe7b11f7 Revert "[mlgo] Dependency-free training mode logger"
This reverts commit c5ff6f7234.

This breaks building on macOS:

FAILED: lib/Analysis/CMakeFiles/LLVMAnalysis.dir/TensorSpec.cpp.o
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++ -DBUILD_EXAMPLES -DGTEST_HAS_RTTI=0 -D_DEBUG -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -I/Users/buildslave/jenkins/workspace/clang-stage1-cmake-RA-incremental/clang-build/lib/Analysis -I/Users/buildslave/jenkins/workspace/clang-stage1-cmake-RA-incremental/llvm-project/llvm/lib/Analysis -I/Users/buildslave/jenkins/workspace/clang-stage1-cmake-RA-incremental/clang-build/include -I/Users/buildslave/jenkins/workspace/clang-stage1-cmake-RA-incremental/llvm-project/llvm/include -fPIC -fvisibility-inlines-hidden -Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -pedantic -Wno-long-long -Wc++98-compat-extra-semi -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wstring-conversion -Wmisleading-indentation -Wctad-maybe-unsupported -fdiagnostics-color -O3 -DNDEBUG -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.1.sdk -mmacosx-version-min=10.14  -fno-exceptions -fno-rtti -UNDEBUG -std=c++17 -MD -MT lib/Analysis/CMakeFiles/LLVMAnalysis.dir/TensorSpec.cpp.o -MF lib/Analysis/CMakeFiles/LLVMAnalysis.dir/TensorSpec.cpp.o.d -o lib/Analysis/CMakeFiles/LLVMAnalysis.dir/TensorSpec.cpp.o -c /Users/buildslave/jenkins/workspace/clang-stage1-cmake-RA-incremental/llvm-project/llvm/lib/Analysis/TensorSpec.cpp
In file included from /Users/buildslave/jenkins/workspace/clang-stage1-cmake-RA-incremental/llvm-project/llvm/lib/Analysis/TensorSpec.cpp:16:
In file included from /Users/buildslave/jenkins/workspace/clang-stage1-cmake-RA-incremental/llvm-project/llvm/include/llvm/Analysis/TensorSpec.h:16:
/Users/buildslave/jenkins/workspace/clang-stage1-cmake-RA-incremental/llvm-project/llvm/include/llvm/Support/JSON.h:354:29: error: non-constant-expression cannot be narrowed from type 'unsigned long' to 'int64_t' (aka 'long long') in initializer list [-Wc++11-narrowing]
    create<int64_t>(int64_t{I});
                            ^
/Users/buildslave/jenkins/workspace/clang-stage1-cmake-RA-incremental/llvm-project/llvm/lib/Analysis/TensorSpec.cpp:55:18: note: in instantiation of function template specialization 'llvm::json::Value::Value<unsigned long, void, void, void>' requested here
        OS.value(D);
                 ^
/Users/buildslave/jenkins/workspace/clang-stage1-cmake-RA-incremental/llvm-project/llvm/include/llvm/Support/JSON.h:354:29: note: insert an explicit cast to silence this issue
    create<int64_t>(int64_t{I});
                            ^
                            static_cast<int64_t>( )
1 error generated.

https://green.lab.llvm.org/green/job/clang-stage1-cmake-RA-incremental/33120/consoleFull#-145995569149ba4694-19c4-4d7e-bec5-911270d8a58c
2022-12-06 17:24:55 +00:00
Mircea Trofin
c5ff6f7234 [mlgo] Dependency-free training mode logger
This is the next step in dropping the dependency on protobuf.

The simple logger produces an output consisting of lines of json
strings. Tensor values - which should constitute the bulk of the data -
are serialized as raw byte buffers. This allows for light-weight reading
of the values.

The next step is to switch the training logic to the new logging format,
following which the protobuf-based logger will be dropped, together with
the training dependency on protobuf.

Subsequent changes will also stop buffering and stream, instead - the
buffering model is just as a convenient point-in-time.

Differential Revision: https://reviews.llvm.org/D139370
2022-12-06 08:12:45 -08:00
Nikita Popov
fa4b518f1d [BasicAA] Guard against empty successors list (PR59360)
Succs can be empty here if a phi predecessor is unreachable.

Fixes https://github.com/llvm/llvm-project/issues/59360
2022-12-06 16:59:00 +01:00
Matt Arsenault
7f4429c0e4 ValueTracking: Teach CannotBeOrderedLessThanZero about copysign 2022-12-06 09:01:39 -05:00
Nikita Popov
48edb906d5 [MemorySSA] Use BatchAA for clobber walker
While MemorySSA use optimization was already using BatchAA, the
publicly exposed MSSA walkers were using plain AAResults. This is
not great, because it is expected that clobber walking will make
repeated AA queries.

This patch makes the clobber API accept a BatchAAResults instance.
The plain APIs are kept as wrappers and will create a BatchAAResults
instance for the duration of the query. In the future, the explicit
BatchAAResults arguments will be used to share AA results across
queries, not just within one query.

Differential Revision: https://reviews.llvm.org/D136164
2022-12-06 08:29:11 +01:00
Paul Walker
6e26ddbc7e [NFC][PatternMatch] Add helper for m_Intrinsic<Intrinsic::experimental_vector_reverse>. 2022-12-05 16:36:08 +00:00
Matt Arsenault
51af4ddfc2 ValueTracking: Teach canCreateUndefOrPoison about more intrinsics
I tried to test the fallthrough to noundef callsite return attribute
case, but it seems that folds out as-is.
2022-12-05 10:04:13 -05:00
Matt Arsenault
dbca874faa ValueTracking: Teach CannotBeOrderedLessThanZero about trivial ops
Handle canonicalize and arithmetic.fence
2022-12-05 08:39:07 -05:00
Matt Arsenault
db0f258479 ValueTracking: Teach isKnownNeverNaN about arithmetic_fence 2022-12-05 08:39:07 -05:00
Matt Arsenault
dac496fb1f ValueTracking: Teach isKnownNeverInfinity about arithmetic.fence 2022-12-05 08:39:07 -05:00
Max Kazantsev
0c7910eab9 [NFC] Rename variable MaxBECount -> ConstantMaxBECount
Just to distinguish it from symbolic max which we plan to compute
here as well.
2022-12-05 17:48:36 +07:00
Nikita Popov
4de3184f07 [LAA] Use cross-iteration alias analysis
LAA analyzes cross-iteration memory dependencies, as such AA should
not make assumptions about equality of values inside the loop, as
they may come from different iterations.

Fix this by exposing the MayBeCrossIteration AA flag and enabling
it for LAA.

Differential Revision: https://reviews.llvm.org/D137958
2022-12-05 09:27:13 +01:00
Nikita Popov
e95ca5bb05 [AST] Make AliasSetTracker work on BatchAA
D138014 restricted AST to work on immutable IR. This means it is
also safe to use a single BatchAA instance for the entire AST
lifetime, instead of only batching parts of individual queries.

The primary motivation for this is not compile-time, but rather
having a central place to control cross-iteration AA, which will
be used by D137958.

Differential Revision: https://reviews.llvm.org/D137955
2022-12-05 08:12:26 +01:00
Fangrui Song
a996cc217c Remove unused #include "llvm/ADT/Optional.h" 2022-12-05 06:31:11 +00:00
Fangrui Song
89fae41ef1 [IR] llvm::Optional => std::optional
Many llvm/IR/* files have been migrated by other contributors.
This migrates most remaining files.
2022-12-05 04:13:11 +00:00
Kazu Hirata
9f252e5567 [llvm] Use std::nullopt instead of None in comments (NFC)
This is part of an effort to migrate from llvm::Optional to
std::optional:

https://discourse.llvm.org/t/deprecating-llvm-optional-x-hasvalue-getvalue-getvalueor/63716
2022-12-04 17:31:17 -08:00
Kazu Hirata
3c09ed006a [llvm] Use std::nullopt instead of None in comments (NFC)
This is part of an effort to migrate from llvm::Optional to
std::optional:

https://discourse.llvm.org/t/deprecating-llvm-optional-x-hasvalue-getvalue-getvalueor/63716
2022-12-04 17:12:44 -08:00
Benjamin Kramer
856f7937c7 Compress a few pairs using PointerIntPairs
Use the uniform structured bindings interface where possible. NFCI.
2022-12-04 16:55:16 +01:00
Krzysztof Parzyszek
ab672e9173 FPEnv: convert Optional to std::optional 2022-12-03 13:55:56 -06:00
David Green
16a72a0f87 [AArch64] Enable the select optimize pass for AArch64
This enabled the select optimize patch for ARM Out of order AArch64
cores. It is trying to solve a problem that is difficult for the
compiler to fix. The criteria for when a csel is better or worse than a
branch depends heavily on whether the branch is well predicted and the
amount of ILP in the loop (as well as other criteria like the core in
question and the relative performance of the branch predictor).  The
pass seems to do a decent job though, with the inner loop heuristics
being well implemented and doing a better job than I had expected in
general, even without PGO information.

I've been doing quite a bit of benchmarking. The headline numbers are
these for SPEC2017 on a Neoverse N1:
  500.perlbench_r   -0.12%
  502.gcc_r         0.02%
  505.mcf_r         6.02%
  520.omnetpp_r     0.32%
  523.xalancbmk_r   0.20%
  525.x264_r        0.02%
  531.deepsjeng_r   0.00%
  541.leela_r       -0.09%
  548.exchange2_r   0.00%
  557.xz_r          -0.20%

Running benchmarks with a combination of the llvm-test-suite plus
several versions of SPEC gave between a 0.2% and 0.4% geomean
improvement depending on the core/run. The instruction count went down
by 0.1% too, which is a good sign, but the results can be a little
noisy.  Some issues from other benchmarks I had ran were improved in
rGca78b5601466f8515f5f958ef8e63d787d9d812e. In summary well predicted
branches will see in improvement, badly predicted branches may get
worse, and on average performance seems to be a little better overall.

This patch enables the pass for AArch64 under -O3 for cores that will
benefit for it. i.e. not in-order cores that do not fit into the "Assume
infinite resources that allow to fully exploit the available
instruction-level parallelism" cost model. It uses a subtarget feature
for specifying when the pass will be enabled, which I have enabled under
cpu=generic as the performance increases for out of order cores seems
larger than any decreases for inorder, which were minor.

Differential Revision: https://reviews.llvm.org/D138990
2022-12-03 16:08:58 +00:00
Kazu Hirata
19aff0f37d [Analysis] Use std::nullopt instead of None (NFC)
This patch mechanically replaces None with std::nullopt where the
compiler would warn if None were deprecated.  The intent is to reduce
the amount of manual work required in migrating from Optional to
std::optional.

This is part of an effort to migrate from llvm::Optional to
std::optional:

https://discourse.llvm.org/t/deprecating-llvm-optional-x-hasvalue-getvalue-getvalueor/63716
2022-12-02 19:43:04 -08:00
Jan Svoboda
abf0c6c0c0 Use CTAD on llvm::SaveAndRestore
Reviewed By: dblaikie

Differential Revision: https://reviews.llvm.org/D139229
2022-12-02 15:36:12 -08:00
Kazu Hirata
2d6ec146dd [ModuleInliner] Add MLPriority
This patch adds MLPriority as the first step toward the ML-based
function inlining with the module inliner.

For now, MLPriority is completely identical to CostPriority.

Once this patch lands, I'm planning to:

- integrate NoInferenceModelRunner,

- memoize the priority computation so that the priority remains the
  same for given values of metrics even with the noise injected during
  training, and

- port/take more features into account.

Differential Revision: https://reviews.llvm.org/D139140
2022-12-02 14:25:13 -08:00
Kazu Hirata
ba7cf9d18a [ModuleInliner] Initialize variables (NFC)
This patch initializes all class variables in InlineOrder.cpp for
safety just in case we miss them in constructors.  Currently, all
these variables are properly initialized in their respective
constructors.

Differential Revision: https://reviews.llvm.org/D139225
2022-12-02 13:31:13 -08:00
Krzysztof Parzyszek
86fe4dfdb6 TargetTransformInfo: convert Optional to std::optional
Recommit: added missing "#include <cstdint>".
2022-12-02 11:42:15 -08:00
Krzysztof Parzyszek
4e12d1836a Revert "TargetTransformInfo: convert Optional to std::optional"
This reverts commit b83711248c.

Some buildbots are failing.
2022-12-02 11:34:04 -08:00
Krzysztof Parzyszek
b83711248c TargetTransformInfo: convert Optional to std::optional 2022-12-02 11:27:12 -08:00
Krzysztof Parzyszek
26424c96c0 Attributes: convert Optional to std::optional 2022-12-02 08:15:45 -06:00
tentzen
db6a979ae8 Revert "[Windows SEH]: HARDWARE EXCEPTION HANDLING (MSVC -EHa) - Part 2"
This reverts commit 1a949c871a.
2022-12-02 02:44:18 -08:00
tentzen
1a949c871a [Windows SEH]: HARDWARE EXCEPTION HANDLING (MSVC -EHa) - Part 2
This patch is the Part-2 (BE LLVM) implementation of HW Exception handling.
Part-1 (FE Clang) was committed in 797ad70152.

This new feature adds the support of Hardware Exception for Microsoft Windows
SEH (Structured Exception Handling).

Compiler options:
  For clang-cl.exe, the option is -EHa, the same as MSVC.
  For clang.exe, the extra option is -fasync-exceptions,
  plus -triple x86_64-windows -fexceptions and -fcxx-exceptions as usual.

NOTE:: Without the -EHa or -fasync-exceptions, this patch is a NO-DIFF change.

The rules for C code:
For C-code, one way (MSVC approach) to achieve SEH -EHa semantic is to follow three rules:
  First, no exception can move in or out of _try region., i.e., no "potential faulty
    instruction can be moved across _try boundary.
  Second, the order of exceptions for instructions 'directly' under a _try must be preserved
    (not applied to those in callees).
  Finally, global states (local/global/heap variables) that can be read outside of _try region
    must be updated in memory (not just in register) before the subsequent exception occurs.

The impact to C++ code:
  Although SEH is a feature for C code, -EHa does have a profound effect on C++
  side. When a C++ function (in the same compilation unit with option -EHa ) is
  called by a SEH C function, a hardware exception occurs in C++ code can also
  be handled properly by an upstream SEH _try-handler or a C++ catch(...).
  As such, when that happens in the middle of an object's life scope, the dtor
  must be invoked the same way as C++ Synchronous Exception during unwinding process.

Design:
A natural way to achieve the rules above in LLVM today is to allow an EH edge
added on memory/computation instruction (previous iload/istore idea) so that
exception path is modeled in Flow graph preciously. However, tracking every
single memory instruction and potential faulty instruction can create many
Invokes, complicate flow graph and possibly result in negative performance
impact for downstream optimization and code generation. Making all
optimizations be aware of the new semantic is also substantial.

This design does not intend to model exception path at instruction level.
Instead, the proposed design tracks and reports EH state at BLOCK-level to
reduce the complexity of flow graph and minimize the performance-impact on CPP
code under -EHa option.
One key element of this design is the ability to compute State number at
block-level. Our algorithm is based on the following rationales:

A _try scope is always a SEME (Single Entry Multiple Exits) region as jumping
into a _try is not allowed. The single entry must start with a seh_try_begin()
invoke with a correct State number that is the initial state of the SEME.
Through control-flow, state number is propagated into all blocks. Side exits
marked by seh_try_end() will unwind to parent state based on existing SEHUnwindMap[].
Note side exits can ONLY jump into parent scopes (lower state number).
Thus, when a block succeeds various states from its predecessors, the lowest
State triumphs others.  If some exits flow to unreachable, propagation on those
paths terminate, not affecting remaining blocks.
For CPP code, object lifetime region is usually a SEME as SEH _try.
However there is one rare exception: jumping into a lifetime that has Dtor but
has no Ctor is warned, but allowed:

Warning: jump bypasses variable with a non-trivial destructor

In that case, the region is actually a MEME (multiple entry multiple exits).
Our solution is to inject a eha_scope_begin() invoke in the side entry block to
ensure a correct State.
Implementation:
Part-1: Clang implementation (already in):
Please see commit 797ad70152).

Part-2 : LLVM implementation described below.

For both C++ & C-code, the state of each block is computed at the same place in
BE (WinEHPreparing pass) where all other EH tables/maps are calculated.
In addition to _scope_begin & _scope_end, the computation of block state also
rely on the existing State tracking code (UnwindMap and InvokeStateMap).

For both C++ & C-code, the state of each block with potential trap instruction
is marked and reported in DAG Instruction Selection pass, the same place where
the state for -EHsc (synchronous exceptions) is done.
If the first instruction in a reported block scope can trap, a Nop is injected
before this instruction. This nop is needed to accommodate LLVM Windows EH
implementation, in which the address in IPToState table is offset by +1.
(note the purpose of that is to ensure the return address of a call is in the
same scope as the call address.

The handler for catch(...) for -EHa must handle HW exception. So it is
'adjective' flag is reset (it cannot be IsStdDotDot (0x40) that only catches
C++ exceptions).
Suppress push/popTerminate() scope (from noexcept/noTHrow) so that HW
exceptions can be passed through.

Original llvm-dev [RFC] discussions can be found in these two threads below:
https://lists.llvm.org/pipermail/llvm-dev/2020-March/140541.html
https://lists.llvm.org/pipermail/llvm-dev/2020-April/141338.html

Differential Revision: https://reviews.llvm.org/D102817/new/
2022-12-01 23:44:25 -08:00
Mircea Trofin
f291667d61 [mlgo][nfc] Virtualize Logger implementation
This is in preparation for dropping the dependency on protobuf. This
first step allows us to subsequently introduce the non-protobuf
implementation behind a flag. After that we can update the training side
to ingest the new format, after which we can drop the protobuf
implementation and de-virtualize everything.

Differential Revision: https://reviews.llvm.org/D139062
2022-12-01 16:03:08 -08:00
Krzysztof Parzyszek
467432899b MemoryLocation: convert Optional to std::optional 2022-12-01 15:36:20 -08:00
Mircea Trofin
1ee3bb17c3 [mlgo][nfc] Make LoggedFeatureSpec an implementation detail
It's an artifact very specific to using TFAgents during training, so it
belongs with ModelUnderTrainingRunner.

Differential Revision: https://reviews.llvm.org/D139031
2022-11-30 15:57:58 -08:00
Sanjay Patel
47f5da47f5 [InstSimplify] (X && Y) ? X : Y --> Y
Similar to the recent fold that was added for 'or' in D138815:
https://alive2.llvm.org/ce/z/PBapTJ
2022-11-30 15:44:48 -05:00
David Stuttard
62498962e4 ConstantFolding: Guard use of getFunction
Add additional guards for a use of getFunction on an Instruction
In some cases constanfFoldCanonicalize can be called with a cloned instruction
that doesn't have a parent (or associated function), causing a seg fault.

Differential Revision: https://reviews.llvm.org/D138642
2022-11-30 14:09:40 +00:00
chenglin.bi
f297332749 [InstSimplify] Fold (X || Y) ? X : Y --> X
(X || Y) ? X : Y --> X
https://alive2.llvm.org/ce/z/oRQJee

Reviewed By: spatel

Differential Revision: https://reviews.llvm.org/D138815
2022-11-30 10:14:17 +08:00
Vasileios Porpodas
8a1ccb8ae0 [NFC] Removed call to getInstList() from range loops on BBs.
Differential Revision: https://reviews.llvm.org/D138605
2022-11-29 17:33:10 -08:00
chenglin.bi
1fd4d91fa6 [InstSimplify] Fold !(X || Y) && X --> false
!(X || Y) && X --> false
https://alive2.llvm.org/ce/z/693Jgv

Fix: [56654](https://github.com/llvm/llvm-project/issues/56654)
Fix: [56780](https://github.com/llvm/llvm-project/issues/56780)

Reviewed By: spatel

Differential Revision: https://reviews.llvm.org/D138853
2022-11-29 22:45:24 +08:00
chenglin.bi
0752fb57e4 [InstSimplify] Fold (X || Y) ? false : X --> false
(X || Y) ? false : X --> false
https://alive2.llvm.org/ce/z/y93yUm

Reviewed By: spatel

Differential Revision: https://reviews.llvm.org/D138700
2022-11-29 22:08:50 +08:00
Kazu Hirata
55378ae87c [Analysis] Remove unused fields in MemorySSA.cpp (NFC)
The last uses of AR were removed on July 28, 2022 in commit
f96ea53e89.

Differential Revision: https://reviews.llvm.org/D138730
2022-11-28 15:39:32 -08:00
Slava Zakharin
5bd8175dd7 [AA] A global cannot escape through nocapture/nocallback call.
When an internal global is passed to a 'nocallback' call as
a 'nocapture' pointer, it cannot escape through this call and
be indirectly referenced in this module.
So it must not alias with any pointer in the module.

This may provide some remedy for Fortran module-private array descriptors
that are usually passed by address to some runtime functions
(e.g. to allocation/deallocation functions). In general, a good aliasing
information derived from Fortran language rules would solve the same issue,
but I think this change may be beneficial as-is (given that nocapture,
nocallback attributes are properly set).

Reviewed By: jdoerfert

Differential Revision: https://reviews.llvm.org/D138336
2022-11-28 12:50:31 -08:00
Max Kazantsev
0b74cb4231 [SCEV] Introduce field for storing SymbolicMaxNotTaken. NFCI
ritht is initialized with either exact (if available) or
with constant max exit count. In the future, this can be improved.

Hypothetically this is not an NFC (it is possible that exact is not
known and max is known for a particular exit), but for how we use
it now it seems be an NFC (or at least I could not find an example
where it differs). constant max exit count. In the future, this can
be improved.

Differential Revision: https://reviews.llvm.org/D138699
Reviewed By: lebedev.ri
2022-11-28 17:07:33 +07:00