Age | Commit message (Collapse) | Author | Files | Lines |
|
Consider this declaration:
`int foo();`
This function is described in LLVM with `clang::FunctionNoProtoType`
class. ([See
description](https://clang.llvm.org/doxygen/classclang_1_1FunctionNoProtoType.html))
Judging by [this
comment](https://github.com/llvm/llvm-project/blob/a1bf0d1394e48894be05d274d3942ff77c35ce87/clang/lib/CodeGen/CGCall.cpp#L159C11-L159C12)
all such functions are treated like functions with variadic number of
parameters.
When we want to [emit debug
info](https://github.com/llvm/llvm-project/blob/0a8ddd396546bec7eaa4c3b7ef2f495e52bca0b8/clang/lib/CodeGen/CGDebugInfo.cpp#L4808)
we have to know function that we calling.
In method
[getCalledFunction()](https://github.com/llvm/llvm-project/blob/0a8ddd396546bec7eaa4c3b7ef2f495e52bca0b8/llvm/include/llvm/IR/InstrTypes.h#L1348)
we compare two types of function:
1. Function that we deduce from calling operand, and
2. Function that we store locally
If they differ we get `nullptr` and can't emit appropriate debug info.
The only thing they differ is: lhs function is variadic, but rhs
function isn't
Reason of this difference is that under RISC-V there is no overridden
function that tells us about treating functions with no parameters.
[Default
function](https://github.com/llvm/llvm-project/blob/0a8ddd396546bec7eaa4c3b7ef2f495e52bca0b8/clang/lib/CodeGen/TargetInfo.cpp#L87)
always return `false`.
This patch overrides this function for RISC-V
|
|
CWD is queried in clang driver and passed to clang cc1 via flags when
needed. Respect the cc1 flags and do not repeated checking current
working directory in CodeGen.
|
|
(#151025)
The -gline-tables-only option emits minimal debug info for functions,
files and line numbers while omitting variables, parameters and most
type information. VTable debug symbols are emitted to facilitate a
debugger's ability to perform automatic type promotion on variables and
parameters. With variables and parameters being omitted, the VTable
symbols are unnecessary.
|
|
This patch adds a human readable trap category and message to UBSan
traps. The category and message are encoded in a fake frame in the debug
info where the function is a fake inline function where the name encodes
the trap category and message. This is the same mechanism used by
Clang’s `__builtin_verbose_trap()`.
This change allows consumers of binaries built with trapping UBSan to
more easily identify the reason for trapping. In particular LLDB already
has a frame recognizer that recognizes the fake function names emitted
in debug info by this patch. A patch testing this behavior in LLDB will
be added in a separately.
The human readable trap messages are based on the messages currently
emitted by the userspace runtime for UBSan in compiler-rt. Note the
wording is not identical because the userspace UBSan runtime has access
to dynamic information that is not available during Clang’s codegen.
Test cases for each UBSan trap kind are included.
This complements the [`-fsanitize-annotate-debug-info`
feature](https://github.com/llvm/llvm-project/pull/141997). While
`-fsanitize-annotate-debug-info` attempts to annotate all UBSan-added
instructions, this feature (`-fsanitize-debug-trap-reasons`) only
annotates the final trap instruction using SanitizerHandler information.
This work is part of a GSoc 2025 project.
|
|
This is one of the final remaining debug-intrinsic specific codepaths
out there, and pieces of cross-LLVM infrastructure to do with debug
intrinsics.
|
|
sugar types (#149613)
The checks for the 'z' and 't' format specifiers added in the original
PR #143653 had some issues and were overly strict, causing some build
failures and were consequently reverted at
https://github.com/llvm/llvm-project/commit/4c85bf2fe8042c855c9dd5be4b02191e9d071ffd.
In the latest commit
https://github.com/llvm/llvm-project/pull/149613/commits/27c58629ec76a703fde9c0b99b170573170b4a7a,
I relaxed the checks for the 'z' and 't' format specifiers, so warnings
are now only issued when they are used with mismatched types.
The original intent of these checks was to diagnose code that assumes
the underlying type of `size_t` is `unsigned` or `unsigned long`, for
example:
```c
printf("%zu", 1ul); // Not portable, but not an error when size_t is unsigned long
```
However, it produced a significant number of false positives. This was
partly because Clang does not treat the `typedef` `size_t` and
`__size_t` as having a common "sugar" type, and partly because a large
amount of existing code either assumes `unsigned` (or `unsigned long`)
is `size_t`, or they define the equivalent of size_t in their own way
(such as
sanitizer_internal_defs.h).https://github.com/llvm/llvm-project/blob/2e67dcfdcd023df2f06e0823eeea23990ce41534/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h#L203
|
|
This has been replaced by -fsanitize-annotate-debug-info
|
|
sugar types instead of built-in types (#143653)"
This reverts commit c27e283cfbca2bd22f34592430e98ee76ed60ad8.
A builbot failure has been reported:
https://lab.llvm.org/buildbot/#/builders/186/builds/10819/steps/10/logs/stdio
I'm also getting a large number of warnings related to %zu and %zx.
|
|
types instead of built-in types (#143653)
Including the results of `sizeof`, `sizeof...`, `__datasizeof`,
`__alignof`, `_Alignof`, `alignof`, `_Countof`, `size_t` literals, and
signed `size_t` literals, the results of pointer-pointer subtraction and
checks for standard library functions (and their calls).
The goal is to enable clang and downstream tools such as clangd and
clang-tidy to provide more portable hints and diagnostics.
The previous discussion can be found at #136542.
This PR implements this feature by introducing a new subtype of `Type`
called `PredefinedSugarType`, which was considered appropriate in
discussions. I tried to keep `PredefinedSugarType` simple enough yet not
limited to `size_t` and `ptrdiff_t` so that it can be used for other
purposes. `PredefinedSugarType` wraps a canonical `Type` and provides a
name, conceptually similar to a compiler internal `TypedefType` but
without depending on a `TypedefDecl` or a source file.
Additionally, checks for the `z` and `t` format specifiers in format
strings for `scanf` and `printf` were added. It will precisely match
expressions using `typedef`s or built-in expressions.
The affected tests indicates that it works very well.
Several code require that `SizeType` is canonical, so I kept `SizeType`
to its canonical form.
The failed tests in CI are allowed to fail. See the
[comment](https://github.com/llvm/llvm-project/pull/135386#issuecomment-3049426611)
in another PR #135386.
|
|
|
|
The verifier check was in the wrong place, meaning it wasn't actually
checking many instructions.
Fixing that causes a test failure (coro-dwarf-key-instrs.cpp) because
coros turn off the feature but still annotate instructions with the
metadata (which is a supported situation, but the verifier doesn't like
it, and it's hard to teach the verifier to like it).
Fix that by avoiding emitting any key instruction metadata if the
DISubprogram has opted out of key instructions.
|
|
Some `LangOptions` duplicate their `CodeGenOptions` counterparts. My
understanding is that this was done solely because some infrastructure
(like preprocessor initialization, serialization, module compatibility
checks, etc.) were only possible/convenient for `LangOptions`. This PR
implements the missing support for `CodeGenOptions`, which makes it
possible to remove some duplicate `LangOptions` fields and simplify the
logic. Motivated by https://github.com/llvm/llvm-project/pull/146342.
|
|
Clang can chose which sort of source-file hash is attached to a DIFile
metadata node. However, whenever hashing is possible, we /always/ attach
a hash. This patch permits users who want DWARF5 but don't want the file
hashes to opt out, by adding a "none" option to the -gsrc-hash option
that skips hash computation.
|
|
At this time (immediately prior to llvm21 branching) we haven't
instrumented coroutine generation to identify the "key" instructions of
things like co_return and similar. This will lead to worse stepping
behaviours, as there won't be any key instruction for those lines.
This patch removes the key-instructions flag from the DISubprograms for
coroutines, which will cause AsmPrinter to use the "old" / existing
linetable stepping behaviour, avoiding a regression until we can
instrument these constructs.
(I'm going to post on discourse about whether this is a good idea or not
in a moment)
|
|
RFC on discourse:
https://discourse.llvm.org/t/rfc-debug-info-for-coroutine-suspension-locations-take-2/86606
With this commit, we add `DILabel` debug infos to the resume points of a
coroutine. Those labels can be used by debugging scripts to figure out
the exact line and column at which a coroutine was suspended by looking
up current `__coro_index` value inside the coroutines frame, and then
searching for the corresponding label inside the coroutine's resume
function.
The DWARF information generated for such a label looks like:
```
0x00000f71: DW_TAG_label
DW_AT_name ("__coro_resume_1")
DW_AT_decl_file ("generator-example.cpp")
DW_AT_decl_line (5)
DW_AT_decl_column (3)
DW_AT_artificial (true)
DW_AT_LLVM_coro_suspend_idx (0x01)
DW_AT_low_pc (0x00000000000019be)
```
The labels can be mapped to their corresponding `__coro_idx` values
either via their naming convention `__coro_resume_<N>` or using the new
`DW_AT_LLVM_coro_suspend_idx` attribute. In gdb, those line numebrs can
be looked up using `info line -function my_coroutine -label
__coro_resume_1`. LLDB unfortunately does not understand DW_TAG_label
debug information, yet.
Given this is an artificial compiler-generated label, I did apply the
DW_AT_artificial tag to it. The DWARFv5 standard only allows that tag on
type and variable definitions, but this is a natural extension and was
also blessed in the RFC on discourse.
Also, this commit adds `DW_AT_decl_column` to labels, not only for
coroutines but also for normal C and C++ labels. While not strictly
necessary, I am doing so now because it would be harder to do so later
without breaking the binary LLVM-IR format
Drive-by fixes: While reading the existing test cases to understand how
to write my own test case, I did a couple of small typo fixes and
comment improvements
|
|
DISubroutineType (#130674)" (#145697)
This reverts commit cd826d6e840ed33ad88458c862da5f9fcc6e908c and relands
27c1aa9b9cf9e0b14211758ff8f7d3aaba24ffcf
This fixes #104765
I tweaked the code to avoid an OOB.
|
|
Patch 1/4 adding bitcode support.
Store whether or not a function is using Key Instructions in its DISubprogram so
that we don't need to rely on the -mllvm flag -dwarf-use-key-instructions to
determine whether or not to interpret Key Instructions metadata to decide
is_stmt placement at DWARF emission time. This makes bitcode support simple and
enables well defined mixing of non-key-instructions and key-instructions
functions in an LTO context.
This patch adds the bit (using DISubprogram::SubclassData1).
PR 144104 and 144103 use it during DWARF emission.
PR 44102 adds bitcode
support.
See pull request for overview of alternative attempts.
|
|
In Ada, a record type can have a non-constant size, and a field can
appear at a non-constant bit offset in a record.
To support this, this patch changes DIType to record the size and offset
using metadata, rather than plain integers. In addition to a constant
offset, both DIVariable and DIExpression are now supported here.
One thing of note in this patch is the choice of how exactly to
represent a non-constant bit offset, with the difficulty being that
DWARF 5 does not support this. DWARF 3 did have a way to support a
non-constant byte offset, combined with a constant bit offset within the
byte, but this was deprecated in DWARF 4 and removed from DWARF 5.
This patch takes a simple approach: a DWARF extension allowing the use
of an expression with DW_AT_data_bit_offset. There is a corresponding
DWARF issue, see https://dwarfstd.org/issues/250501.1.html. The main
reason for this approach is that it keeps API simplicity: just a single
value is needed, rather than having separate data describing the byte
offset and the bit within the byte.
|
|
The dependency from the type sugar of the underlying type of a Typedef
were not being considered for the dependency of the TypedefType itself.
A TypedefType should be instantiation dependent if it involves
non-instantiated template parameters, even if they don't contribute to
the canonical type.
Besides, a TypedefType should be instantiation dependent if it is
declared in a dependent context, but fixing that would have performance
consequences, as otherwise non-dependent typedef declarations would need
to be transformed during instantiation as well.
This removes the workaround added in
https://github.com/llvm/llvm-project/pull/90032
Fixes https://github.com/llvm/llvm-project/issues/89774
|
|
This extends https://github.com/llvm/llvm-project/pull/138577 to more UBSan checks, by changing SanitizerDebugLocation (formerly SanitizerScope) to add annotations if enabled for the specified ordinals.
Annotations will use the ordinal name if there is exactly one ordinal specified in the SanitizerDebugLocation; otherwise, it will use the handler name.
Updates the tests from https://github.com/llvm/llvm-project/pull/141814.
---------
Co-authored-by: Vitaly Buka <vitalybuka@google.com>
|
|
We have multiple different attributes in clang representing device
kernels for specific targets/languages. Refactor them into one attribute
with different spellings to make it more easily scalable for new
languages/targets.
---------
Signed-off-by: Sarnie, Nick <nick.sarnie@intel.com>
|
|
DIBuilder::finalize() (#139914)
DIBuilder began tracking definition subprograms and finalizing them in
`DIBuilder::finalize()` in eb1bb4e419.
Currently, `finalizeSubprogram()` attaches local variables, imported
entities, and labels to the `retainedNodes:` field of a corresponding
subprogram.
After 75819aedf, the definition and some declaration subprograms are
finalized in `DIBuilder::finalize()`:
`AllSubprograms` holds references to definition subprograms.
`AllRetainTypes` holds references to declaration subprograms.
For DISubprogram elements of both variables, `finalizeSubprogram()` was
called there.
However, `retainTypes()` is not necessarily called for every declaration
subprogram (as in 40a3fcb0).
DIBuilder clients may also want to attach DILocalVariables to
declaration subprograms, for example, in 58bdf8f9a8.
Thus, the `finalizeSubprogram()` function is called for all definition
subprograms in `DIBuilder::finalize()` because they are stored in the
`AllSubprograms` by the `CreateFunction(isDefinition: true)` call. But
for the declaration subprograms, it should be called manually.
With this commit, `AllSubprograms` is used for holding and finalizing all DISubprograms.
|
|
|
|
The IR now includes a global variable for the debugger that holds
the address of the vtable.
Now every class that contains virtual functions, has a static
member (marked as artificial) that identifies where that vtable
is loaded in memory. The unmangled name is '_vtable$'.
This new symbol will allow a debugger to easily associate
classes with the physical location of their VTables using
only the DWARF information. Previously, this had to be done
by searching for ELF symbols with matching names; something
that was time-consuming and error-prone in certain edge cases.
|
|
This implements the design proposed by [Representing SpirvType in
Clang's Type System](https://github.com/llvm/wg-hlsl/pull/181). It
creates `HLSLInlineSpirvType` as a new `Type` subclass, and
`__hlsl_spirv_type` as a new builtin type template to create such a
type.
This new type is lowered to the `spirv.Type` target extension type, as
described in [Target Extension Types for Inline SPIR-V and Decorated
Types](https://github.com/llvm/wg-hlsl/blob/main/proposals/0017-inline-spirv-and-decorated-types.md).
|
|
|
|
clang/lib/CodeGen/CGDebugInfo.cpp:153:2: error: extra ';' outside of a function is incompatible with C++98 [-Werror,-Wc++98-compat-extra-semi]
153 | };
| ^
1 error generated.
|
|
This is a scoped helper similar to ApplyDebugLocation that creates a new source
location atom group which instructions can be added to.
A source atom is a source construct that is "interesting" for debug stepping
purposes. We use an atom group number to track the instruction(s) that implement
the functionality for the atom, plus backup instructions/source locations.
This patch is part of a stack that teaches Clang to generate Key Instructions
metadata for C and C++.
RFC:
https://discourse.llvm.org/t/rfc-improving-is-stmt-placement-for-better-interactive-debugging/82668
The feature is only functional in LLVM if LLVM is built with CMake flag
LLVM_EXPERIMENTAL_KEY_INSTRUCTIONs. Eventually that flag will be removed.
|
|
|
|
In DWARF info RISC-V Vector types are presented as DW_TAG_array_type
with tags DW_AT_type (what elements does this array consist of) and
DW_TAG_subrange_type. DW_TAG_subrange_type have DW_AT_upper_bound tag
which contain upper bound value for this array.
For now, it's generate same DWARF info about length of segmented types
and their corresponding non-tuple types.
For example, vint32m4x2_t and vint32m4_t have DW_TAG_array_type with
same DW_AT_type and DW_TAG_subrange_type, it means that this types have
same length, which is not correct
(vint32m4x2_t length is twice as big as vint32m4_t)
|
|
(#130674)"
This reverts commit 27c1aa9b9cf9e0b14211758ff8f7d3aaba24ffcf.
See comments on PR. After this change, Clang now asserts like this:
clang: ../llvm/include/llvm/IR/Metadata.h:1435: const MDOperand &llvm::MDNode::getOperand(unsigned int) const: Assertion `I < getNumOperands() && "Out of range"' failed.
...
#8 0x000055f345c4e4cb clang::CodeGen::CGDebugInfo::getOrCreateInstanceMethodType()
#9 0x000055f345c5ba4f clang::CodeGen::CGDebugInfo::EmitFunctionDecl()
#10 0x000055f345b52519 clang::CodeGen::CodeGenModule::EmitExternalFunctionDeclaration()
This is due to pre-existing jankiness in the way BPF emits extra
declarations for debug info, but we should rollback and then fix forward.
|
|
Fixes issue #104765: When creating a virtual destructor with an
artificial "vtt" argument, the type of "vtt" was previously missing in
the `DISubroutineType` `types` array.
This commit fixes this behavior and adds a regression test.
|
|
The qualifier allows programmer to directly control how pointers are
signed when they are stored in a particular variable.
The qualifier takes three arguments: the signing key, a flag specifying
whether address discrimination should be used, and a non-negative
integer that is used for additional discrimination.
```
typedef void (*my_callback)(const void*);
my_callback __ptrauth(ptrauth_key_process_dependent_code, 1, 0xe27a) callback;
```
Co-Authored-By: John McCall rjmccall@apple.com
|
|
This patch extends the canonicalization printing policy to cover
expressions
and template names, and wires that up to the template argument printer,
covering expressions, and to the expression within a dependent decltype.
This is helpful for debugging, or if these expressions somehow end up
in diagnostics, as without this patch they can print as completely
unrelated
expressions, which can be quite confusing.
This is because expressions are not uniqued, unlike types, and
when a template specialization containing an expression is the first to
be
canonicalized, the expression ends up appearing in the canonical type of
subsequent equivalent specializations.
Fixes https://github.com/llvm/llvm-project/issues/92292
|
|
Finding operator delete[] is still problematic, without it the extension
is a security hazard, so reverting until the problem with operator
delete[] is figured out.
This reverts the following PRs:
Reland [MS][clang] Add support for vector deleting destructors (llvm#133451)
[MS][clang] Make sure vector deleting dtor calls correct operator delete (llvm#133950)
[MS][clang] Fix crash on deletion of array of pointers (llvm#134088)
[clang] Do not diagnose unused deleted operator delete[] (llvm#134357)
[MS][clang] Error about ambiguous operator delete[] only when required (llvm#135041)
|
|
This is an expensive header, only include it where needed. Move some
functions out of line to achieve that.
This reduces time to build clang by ~0.5% in terms of instructions
retired.
|
|
Whereas it is UB in terms of the standard to delete an array of objects
via pointer whose static type doesn't match its dynamic type, MSVC
supports an extension allowing to do it.
Aside from array deletion not working correctly in the mentioned case,
currently not having this extension implemented causes clang to generate
code that is not compatible with the code generated by MSVC, because
clang always puts scalar deleting destructor to the vftable. This PR
aims to resolve these problems.
It was reverted due to link time errors in chromium with sanitizer
coverage enabled,
which is fixed by https://github.com/llvm/llvm-project/pull/131929 .
The second commit of this PR also contains a fix for a runtime failure
in chromium reported
in
https://github.com/llvm/llvm-project/pull/126240#issuecomment-2730216384
.
Fixes https://github.com/llvm/llvm-project/issues/19772
|
|
With this, we can:
* use profilers to estimate how many cycles we spend on these checks
(subject to caveats),
* more easily see why we crashed.
|
|
|
|
Relands Original PR: https://github.com/llvm/llvm-project/pull/131965
Addresses
https://github.com/llvm/llvm-project/pull/131965#issuecomment-2741619498
* Fixes isIncompleteType for injected classes
This clears up some uses of getClass on MemberPointerType when
equivalent uses of getMostRecentCXXRecordDecl would be just as simple or
simpler.
This is split-off from a larger patch which removes getClass, in order
to facilitate review.
|
|
Reverts llvm/llvm-project#131965
Reverted due to issue reported here:
https://github.com/llvm/llvm-project/pull/131965#issuecomment-2741619498
|
|
|
|
This caused link errors when building with sancov. See comment on the PR.
> Whereas it is UB in terms of the standard to delete an array of objects
> via pointer whose static type doesn't match its dynamic type, MSVC
> supports an extension allowing to do it.
> Aside from array deletion not working correctly in the mentioned case,
> currently not having this extension implemented causes clang to generate
> code that is not compatible with the code generated by MSVC, because
> clang always puts scalar deleting destructor to the vftable. This PR
> aims to resolve these problems.
>
> Fixes https://github.com/llvm/llvm-project/issues/19772
This reverts commit d6942d54f677000cf713d2b0eba57b641452beb4.
|
|
i32. Add support for boolean swizzling. (#123977)
Make the memory representation of boolean vectors in HLSL, vectors of
i32.
Allow boolean swizzling for boolean vectors in HLSL.
Add tests for boolean vectors and boolean vector swizzling.
Closes #91639
|
|
Whereas it is UB in terms of the standard to delete an array of objects
via pointer whose static type doesn't match its dynamic type, MSVC
supports an extension allowing to do it.
Aside from array deletion not working correctly in the mentioned case,
currently not having this extension implemented causes clang to generate
code that is not compatible with the code generated by MSVC, because
clang always puts scalar deleting destructor to the vftable. This PR
aims to resolve these problems.
Fixes https://github.com/llvm/llvm-project/issues/19772
|
|
This patch adds a function attribute `riscv_vls_cc` for RISCV VLS
calling
convention which takes 0 or 1 argument, the argument is the `ABI_VLEN`
which is the `VLEN` for passing the fixed-vector arguments, it wraps the
argument as a scalable vector(VLA) using the `ABI_VLEN` and uses the
corresponding mechanism to handle it. The range of `ABI_VLEN` is [32,
65536],
if not specified, the default value is 128.
Here is an example of VLS argument passing:
Non-VLS call:
```
void original_call(__attribute__((vector_size(16))) int arg) {}
=>
define void @original_call(i128 noundef %arg) {
entry:
...
ret void
}
```
VLS call:
```
void __attribute__((riscv_vls_cc(256))) vls_call(__attribute__((vector_size(16))) int arg) {}
=>
define riscv_vls_cc void @vls_call(<vscale x 1 x i32> %arg) {
entry:
...
ret void
}
}
```
The first Non-VLS call passes generic vector argument of 16 bytes by
flattened integer.
On the contrary, the VLS call uses `ABI_VLEN=256` which wraps the
vector to <vscale x 1 x i32> where the number of scalable vector
elements
is calaulated by: `ORIG_ELTS * RVV_BITS_PER_BLOCK / ABI_VLEN`.
Note: ORIG_ELTS = Vector Size / Type Size = 128 / 32 = 4.
PsABI PR: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/418
C-API PR: https://github.com/riscv-non-isa/riscv-c-api-doc/pull/68
|
|
After #124287 updated several functions to return iterators rather than
Instruction *, it was no longer straightforward to pass their result to
DIBuilder. This commit updates DIBuilder methods to accept an
InsertPosition instead, so that they can be called with an iterator
(preferred), or with a deprecation warning an Instruction *, or a
BasicBlock *. This commit also updates the existing calls to the
DIBuilder methods to pass in iterators.
As a special exception, DIBuilder::insertDeclare() keeps a separate
overload accepting a BasicBlock *InsertAtEnd. This is because despite
the name, this method does not insert at the end of the block, therefore
this cannot be handled implicitly by using InsertPosition.
|
|
This reverts commit 3ec9f7494b31f2fe51d5ed0e07adcf4b7199def6.
|
|
After #124287 updated several functions to return iterators rather than
Instruction *, it was no longer straightforward to pass their result to
DIBuilder. This commit updates DIBuilder methods to accept an
InsertPosition instead, so that they can be called with an iterator
(preferred), or with a deprecation warning an Instruction *, or a
BasicBlock *. This commit also updates the existing calls to the
DIBuilder methods to pass in iterators.
|
|
This is the 2nd part to
https://github.com/llvm/llvm-project/pull/124752. Here we make sure to
set the `DICompositeType` `EnumKind` if the enum was declared with
`__attribute__((enum_extensibility(...)))`. In DWARF this will be
rendered as `DW_AT_APPLE_enum_kind` and will be used by LLDB when
creating `clang::EnumDecl`s from debug-info.
Depends on https://github.com/llvm/llvm-project/pull/126044
|