aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Analysis/VectorUtils.cpp
AgeCommit message (Collapse)AuthorFilesLines
2025-09-01[LoopVectorize] Generate wide active lane masks (#147535)Kerry McLaughlin1-0/+2
This patch adds a new flag (-enable-wide-lane-mask) which allows LoopVectorize to generate wider-than-VF active lane masks when it is safe to do so (i.e. the mask is used for data and control flow). The transform in extractFromWideActiveLaneMask creates vector extracts from the first active lane mask in the header & loop body, modifying the active lane mask phi operands to use the extracts. An additional operand is passed to the ActiveLaneMask instruction, the value of which is used as a multiplier of VF when generating the mask. By default this is 1, and is updated to UF by extractFromWideActiveLaneMask. The motivation for this change is to improve interleaved loops when SVE2.1 is available, where we can make use of the whilelo instruction which returns a predicate pair. This is based on a PR that was created by @momchil-velikov (#81140) and contains tests which were added there.
2025-08-07Reland [VectorUtils] Trivially vectorize ldexp, [l]lround (#152476)Ramkumar Ramachandra1-0/+6
Changes: The original patch, landed as 1336675, was reverted due to a bug in LoopVectorize resulting in a crash. The bug has now been fixed by 95c32bf ([VPlan] Return invalid cost if any skeleton block has invalid costs), and this reland is identical to the original patch.
2025-08-01Revert "[VectorUtils] Trivially vectorize ldexp, [l]lround (#145545)"Muhammad Omair Javaid1-6/+0
This reverts commit 13366759c3b9db9366659d870cc73c938422b020. This broke various LLVM testsuite buildbots for AArch64 SVE, but the problem got masked because relevant buildbots were already failing due to other breakage. It has broken llvm-test-suite test: gfortran-regression-compile-regression__vect__pr106253_f.test https://lab.llvm.org/buildbot/#/builders/4/builds/8164 https://lab.llvm.org/buildbot/#/builders/17/builds/9858 https://lab.llvm.org/buildbot/#/builders/41/builds/8067 https://lab.llvm.org/buildbot/#/builders/143/builds/9607
2025-07-31[VectorUtils] Simplify the code by new function InterleaveGroup::isFull. nfc ↵Mel Chen1-3/+3
(#151112)
2025-07-29[VectorUtils] Trivially vectorize ldexp, [l]lround (#145545)Ramkumar Ramachandra1-0/+6
2025-07-29[IR] Add new CreateVectorInterleave interface (#150931)David Sherwood1-24/+0
This PR adds a new interface to IRBuilder called CreateVectorInterleave, which can be used to create vector.interleave intrinsics of factors 2-8. For convenience I have also moved getInterleaveIntrinsicID and getDeinterleaveIntrinsicID from VectorUtils.cpp to Intrinsics.cpp where it can be used by IRBuilder.
2025-07-16[IA] Relax the requirement of having ExtractValue users on deinterleave ↵Min-Yih Hsu1-0/+9
intrinsic (#148716) There are cases where InstCombine / InstSimplify might sink extractvalue instructions that use a deinterleave intrinsic into successor blocks, which prevents InterleavedAccess from kicking in because the current pattern requires deinterleave intrinsic to be used by extractvalue. However, this requirement is bit too strict while we could have just replaced the users of deinterleave intrinsic with whatever generated by the target TLI hooks.
2025-07-14[IA][NFC] Factoring out helper functions that extract (de)interleaving ↵Min-Yih Hsu1-0/+42
factors (#148689) Factoring out and combining `isInterleaveIntrinsic`, `isDeinterleaveIntrinsic`, and `getIntrinsicFactor` into `getInterleaveIntrinsicFactor` and `getDeinterleaveIntrinsicFactor` inside VectorUtils. NFC.
2025-06-12[LV] Support scalable interleave groups for factors 3,5,6 and 7 (#141865)Luke Lau1-0/+24
Currently the loop vectorizer can only vectorize interleave groups for power-of-2 factors at scalable VFs by recursively interleaving [de]interleave2 intrinsics. However after https://github.com/llvm/llvm-project/pull/124825 and #139893, we now have [de]interleave intrinsics for all factors up to 8, which is enough to support all types of segmented loads and stores on RISC-V. Now that the interleaved access pass has been taught to lower these in #139373 and #141512, this patch teaches the loop vectorizer to emit these intrinsics for factors up to 8, which enables scalable vectorization for non-power-of-2 factors. As far as I'm aware, no in-tree target will vectorize a scalable interelave group above factor 8 because the maximum interleave factor is capped at 4 on AArch64 and 8 on RISC-V, and the `-max-interleave-group-factor` CLI option defaults to 8, so the recursive [de]interleaving code has been removed for now. Factors of 3 with scalable VFs are also turned off in AArch64 since there's no lowering for [de]interleave3 just yet either.
2025-05-01[VectorUtils][VPlan] Consolidate VPWidenIntrinsicRecipe::onlyFirstLaneUsed ↵Luke Lau1-1/+5
and isVectorIntrinsicWithScalarOpAtArg (#137497) We can reuse isVectorIntrinsicWithScalarOpAtArg in VectorUtils to determine if only the first lane will be used for a VPWidenIntrinsicRecipe, provided that we also move the VP EVL operand check into it. This was needed by a local patch I was working on that created a VPWidenIntrinsicRecipe with a VP intrinsic, and prevents the need to update the scalar arguments in two places.
2025-04-29[VectorUtils] Improve computeMinimumValueSizes (NFC) (#137692)Ramkumar Ramachandra1-14/+10
The Worklist used by computeMinimumValueSizes is wastefully a Value-vector, when the top of the loop attempts to cast the popped value to an Instruction anyway. Improve the algorithm by cutting this wasteful work, refining the type of Worklist, Visited, and Roots from Value-vectors to Instruction-vectors.
2025-04-29[LV] Fix MinBWs in WidenIntrinsic case (#137005)Ramkumar Ramachandra1-1/+8
There is a bug in the computation and handling of MinBWs in the case of VPWidenIntrinsicRecipe: a crash is observed in VPlanTransforms::truncateToMinimalBitwidths due to a mismatch between the number of recipes processed and the number of entries in MinBWs. Fix handling of calls in llvm::computeMinimumValueSizes, and handle VPWidenIntrinsicRecipe in truncateToMinimalBitwidths, fixing the bug. Fixes #87407.
2025-04-16[llvm] Construct SmallVector with iterator ranges (NFC) (#136064)Kazu Hirata1-3/+1
2025-04-15Vectorize: Support fminimumnum and fmaximumnum (#131781)YunQiang Su1-0/+2
Support auto-vectorize for fminimum_num and fmaximum_num. For ARM64 with SVE, scalable vector cannot support yet. --------- Co-authored-by: Your Name <you@example.com>
2025-04-09[VPlan] Remove no-op addMetadata for VPWidenGEP/VPWidenIntOrFPInd (NFC).Florian Hahn1-1/+1
GEPs and truncates should not have any metadata that can be propgated at the moment, so addMetadata is a no-op. Remove the calls. This patch also adds assertions to the recipes' constructors, to ensure no metadata is accidentially dropped.
2025-04-09[VectorUtils] Add helper to get list of metadata to propagate (NFC). (#135003)Florian Hahn1-9/+28
Split off the logic to filter out metadata that should not be propagated to a helper that populates a list with metadata kinds that should be preserved. The current version just uses is_contained on an array to check if a metadata kind is supported. Given that most instructions will only have a small number of metadata kinds to start with, this shouldn't be worse than iterating over all kinds once and querying the instruction for individual metadata kinds, which involves quite a bit of indirection. I plan ot use this utility in a follow-up patch in other places as well. PR: https://github.com/llvm/llvm-project/pull/135003
2025-04-04[EquivClasses] Shorten members_{begin,end} idiom (#134373)Ramkumar Ramachandra1-3/+3
Introduce members() iterator-helper to shorten the members_{begin,end} idiom. A previous attempt of this patch was #130319, which had to be reverted due to unit-test failures when attempting to call members() on the end iterator. In this patch, members() accepts either an ECValue or an ElemTy, which is more intuitive and doesn't suffer from the same issue.
2025-04-02[EquivalenceClasses] Use SmallVector for deterministic iteration order. ↵Florian Hahn1-4/+4
(#134075) Currently iterators over EquivalenceClasses will iterate over std::set, which guarantees the order specified by the comperator. Unfortunately in many cases, EquivalenceClasses are used with pointers, so iterating over std::set of pointers will not be deterministic across runs. There are multiple places that explicitly try to sort the equivalence classes before using them to try to get a deterministic order (LowerTypeTests, SplitModule), but there are others that do not at the moment and this can result at least in non-determinstic value naming in Float2Int. This patch updates EquivalenceClasses to keep track of all members via a extra SmallVector and removes code from LowerTypeTests and SplitModule to sort the classes before processing. Overall it looks like compile-time slightly decreases in most cases, but close to noise: https://llvm-compile-time-tracker.com/compare.php?from=7d441d9892295a6eb8aaf481e1715f039f6f224f&to=b0c2ac67a88d3ef86987e2f82115ea0170675a17&stat=instructions PR: https://github.com/llvm/llvm-project/pull/134075
2025-04-01[EquivalenceClasses] Update member_begin to take ECValue (NFC).Florian Hahn1-4/+6
Remove a level of indirection and update code to use range-based for loops.
2025-03-07Revert "Reland [EquivClasses] Introduce members iterator-helper" (#130380)Vitaly Buka1-3/+3
Reverts llvm/llvm-project#130319 Multiple bot failures.
2025-03-07Reland [EquivClasses] Introduce members iterator-helper (#130319)Ramkumar Ramachandra1-3/+3
Changes: Fix the expectations in EquivalenceClassesTest.MemberIterator, also fixing a build failure.
2025-03-07Revert "[EquivClasses] Introduce members iterator-helper" (#130313)Ramkumar Ramachandra1-3/+3
This reverts commit 259624bf6d, as it causes a build failure.
2025-03-07[EquivClasses] Introduce members iterator-helper (#130139)Ramkumar Ramachandra1-3/+3
2025-03-03[LV][EVL] Support fixed-order recurrence idiom with EVL tail folding. (#124093)Mel Chen1-0/+2
This patch converts the llvm.vector.splice intrinsic to llvm.experimental.vp.splice, ensuring that fixed-order recurrences execute correctly when tail folding by EVL is enable. Due to the non-VFxUF penultimate EVL issue, the EVL from the previous iteration will be preserved and used in llvm.experimental.vp.splice.
2025-02-28Reapply "[RISCV][TTI] Add shuffle costing for masked slide lowering (#128537)"Philip Reames1-0/+30
With a fix for fully undef masks. These can't reach the lowering code, but can reach the costing code via e.g. SLP. This change adds the TTI costing corresponding to the recently added isMaskedSlidePair lowering for vector shuffles. However, since the existing costing code hadn't covered either slideup, slidedown, or the (now removed) isElementRotate, the impact is larger in scope than just that new lowering. --------- Co-authored-by: Alexey Bataev <a.bataev@gmx.com> Co-authored-by: Luke Lau <luke_lau@icloud.com>
2025-02-28[LV] Teach the vectorizer to cost and vectorize modf and sincospi intrinsics ↵Benjamin Maxwell1-0/+4
(#129064) Follow on to #128035. It is a small extension to support vectorizing `llvm.modf.*` and `llvm.sincospi.*` too. This renames the test files from `sincos.ll` -> `multiple-result-intrinsics.ll` to group together the similar tests (which make up most of this PR).
2025-02-27Revert "[RISCV][TTI] Add shuffle costing for masked slide lowering (#128537)"Philip Reames1-30/+0
This reverts commit 4904728cab8596320a77a895cb712fba07ea7bb1. Downstream test failed, reverting during investigation.
2025-02-27[RISCV][TTI] Add shuffle costing for masked slide lowering (#128537)Philip Reames1-0/+30
This change adds the TTI costing corresponding to the recently added isMaskedSlidePair lowering for vector shuffles. However, since the existing costing code hadn't covered either slideup, slidedown, or the (now removed) isElementRotate, the impact is larger in scope than just that new lowering. --------- Co-authored-by: Alexey Bataev <a.bataev@gmx.com> Co-authored-by: Luke Lau <luke_lau@icloud.com>
2025-02-27[LV] Teach the loop vectorizer llvm.sincos is trivially vectorizable (#128035)Benjamin Maxwell1-0/+2
Depends on #123210
2025-02-13[Scalarizer] Make `*_with_overflow` intrinsics scalarizable (#126815)Deric Cheung1-0/+6
Addresses issue #126809 - Made `uadd_with_overflow`, `sadd_with_overflow`, `usub_with_overflow`, `ssub_with_overflow`, `umul_with_overflow`, and `smul_with_overflow` trivially scalarizable in `isTriviallyScalarizable()` from `VectorUtils.cpp` - Renamed and updated the test `Scalarizer/uadd_overflow.ll` to `Scalarizer/uadd_with_overflow.ll` to check that `uadd_with_overflow` gets scalarized - Added a test `Scalarizer/sincos.ll` to ensure the bug fix #113625 still works
2025-01-13[RISCV][CG]Use processShuffleMasks for per-register shufflesAlexey Bataev1-3/+7
Patch adds usage of processShuffleMasks in in codegen in lowerShuffleViaVRegSplitting. This function is already used for X86 shuffles estimations and in DAGTypeLegalizer::SplitVecRes_VECTOR_SHUFFLE functions, unifies the code. Reviewers: topperc, wangpc-pp, lukel97, preames Reviewed By: preames Pull Request: https://github.com/llvm/llvm-project/pull/121765
2025-01-10[RISCV] Attempt to widen SEW before generic shuffle lowering (#122311)Philip Reames1-0/+35
This takes inspiration from AArch64 which does the same thing to assist with zip/trn/etc.. Doing this recursion unconditionally when the mask allows is slightly questionable, but seems to work out okay in practice. As a bit of context, it's helpful to realize that we have existing logic in both DAGCombine and InstCombine which mutates the element width of in an analogous manner. However, that code has two restriction which prevent it from handling the motivating cases here. First, it only triggers if there is a bitcast involving a different element type. Second, the matcher used considers a partially undef wide element to be a non-match. I considered trying to relax those assumptions, but the information loss for undef in mid-level opt seemed more likely to open a can of worms than I wanted.
2024-12-19[NFC][TargetTransformInfo][VectorUtils] Consolidate `isVectorIntrinsic...` ↵Finn Plummer1-4/+30
api (#117635) - update `VectorUtils:isVectorIntrinsicWithScalarOpAtArg` to use TTI for all uses, to allow specifiction of target specific intrinsics - add TTI to the `isVectorIntrinsicWithStructReturnOverloadAtField` api - update TTI api to provide `isTargetIntrinsicWith...` functions and consistently name them - move `isTriviallyScalarizable` to VectorUtils - update all uses of the api and provide the TTI parameter Resolves #117030
2024-12-11[LV][EVL] Support cast instruction with EVL-vectorization (#108351)LiqinWeng1-0/+3
2024-12-06[TTI][X86]Fix detection of the shuffles from the second shuffle operand onlyAlexey Bataev1-6/+7
If the shuffle mask uses only indices from the second shuffle operand, processShuffleMasks function misses it currently, which prevents correct cost estimation in this corner case. To fix this, need to raise the limit to 2 * VF rather than just VF and adjust processing correspondingly. Will allow future improvements for 2 sources permutations. Reviewers: RKSimon Reviewed By: RKSimon Pull Request: https://github.com/llvm/llvm-project/pull/118972
2024-11-28[LV][EVL] Support call instruction with EVL-vectorization (#110412)LiqinWeng1-0/+7
2024-11-21[NFC][VectorUtils][TargetTransformInfo] Add ↵Finn Plummer1-2/+5
`isVectorIntrinsicWithOverloadTypeAtArg` api (#114849) This changes allows target intrinsics to specify and overwrite overloaded types. - Updates `ReplaceWithVecLib` to not provide TTI as there most probably won't be a use-case - Updates `SLPVectorizer` to use available TTI - Updates `VPTransformState` to pass down TTI - Updates `VPlanRecipe` to use passed-down TTI This change will let us add scalarization for `asdouble`: #114847
2024-11-08[Analysis] atan2: isTriviallyVectorizable; add to massv and accelerate ↵Tex Riddell1-0/+1
veclibs (#113637) This change is part of this proposal: https://discourse.llvm.org/t/rfc-all-the-math-intrinsics/78294 - Return true for atan2 from isTriviallyVectorizable - Add atan2 to VecFuncs.def for massv and accelerate libraries. - Add atan2 to hasOptimizedCodeGen - Add atan2 support in llvm/lib/Analysis/ValueTracking.cpp llvm::getIntrinsicForCallSite and update vectorization tests - Add atan2 name check to isLoweredToCall in llvm/include/llvm/Analysis/TargetTransformInfoImpl.h - Note: there's no test coverage for these names in isLoweredToCall, except that Transforms/TailCallElim/inf-recursion.ll is impacted by the "fabs" case Thanks to @jroelofs for the atan2 accelerate veclib and associated test additions, plus the hasOptimizedCodeGen addition. Part of: Implement the atan2 HLSL Function #70096.
2024-10-29Adding more vector calls for -fveclib=AMDLIBM (#109662)Rohit Aggarwal1-0/+1
AMD has it's own implementation of vector calls. New vector calls are introduced in the library for exp10, log10, sincos and finite asin/acos Please refer [https://github.com/amd/aocl-libm-ose] --------- Co-authored-by: Rohit Aggarwal <Rohit.Aggarwal@amd.com>
2024-10-21[Scalarizer][DirectX] support structs return types (#111569)Farzon Lotfi1-0/+10
Based on this RFC: https://discourse.llvm.org/t/rfc-allow-the-scalarizer-pass-to-scalarize-vectors-returned-in-structs/82306 LLVM intrinsics do not support out params. To get around this limitation implementers will make intrinsics return structs to capture a return type and an out param. This implementation detail should not impact scalarization since these cases should be elementwise operations. ## Three changes are needed. - The CallInst visitor needs to be updated to handle Structs - A new visitor is needed for `ExtractValue` instructions - finsh needs to be update to handle structs so that insert elements are properly propogated. ## Testing changes - Add support for `llvm.frexp` - Add support for `llvm.dx.splitdouble` fixes https://github.com/llvm/llvm-project/issues/111437
2024-10-16[LLVM][NFC] Reduce copying of parameter in lambda (#110299)Amr Hesham1-6/+5
Reduce redundant copy parameter in lambda Fixes #95642
2024-09-24[NFC] Fix typos in comments (#109765)Piotr Fusik1-1/+1
2024-09-02[SLP] Add vectorization support for [u|s]cmp (#106747)Yingwei Zheng1-0/+4
This patch adds vectorization support for [u|s]cmp intrinsic calls.
2024-08-30[Analysis] isTriviallyVectorizable - add vectorization support for ↵Simon Pilgrim1-0/+6
acos/asin/atan and cosh/sinh/tanh intrinsics (#106584) Show fallback cases in amdlibm tests where it doesn't have that specific op
2024-07-16[ValueTracking][X86] Compute KnownBits for phadd/phsub (#92429)mskamp1-0/+28
Add KnownBits computations to ValueTracking and X86 DAG lowering. These instructions add/subtract adjacent vector elements in their operands. Example: phadd [X1, X2] [Y1, Y2] = [X1 + X2, Y1 + Y2]. This means that, in this example, we can compute the KnownBits of the operation by computing the KnownBits of [X1, X2] + [X1, X2] and [Y1, Y2] + [Y1, Y2] and intersecting the results. This approach also generalizes to all x86 vector types. There are also the operations phadd.sw and phsub.sw, which perform saturating addition/subtraction. Use sadd_sat and ssub_sat to compute the KnownBits of these operations. Also adjust the existing test case pr53247.ll because it can be transformed to a constant using the new KnownBits computation. Fixes #82516.
2024-06-27[IR] Add getDataLayout() helpers to BasicBlock and Instruction (#96902)Nikita Popov1-1/+1
This is a helper to avoid writing `getModule()->getDataLayout()`. I regularly try to use this method only to remember it doesn't exist... `getModule()->getDataLayout()` is also a common (the most common?) reason why code has to include the Module.h header.
2024-06-26[VectorUtils] Use SmallPtrSet::remove_if() (NFC)Nikita Popov1-6/+5
2024-06-26[VectorUtils] Add llvm::scaleShuffleMaskElts wrapper for ↵Simon Pilgrim1-0/+25
narrowShuffleMaskElts/widenShuffleMaskElts, NFC. (#96646) Using the target number of vector elements, scaleShuffleMaskElts will try to use narrowShuffleMaskElts/widenShuffleMaskElts to scale the shuffle mask accordingly. Working on #58895 I didn't want to create yet another case where we have to handle both re-scaling cases.
2024-06-24[VectorUtils] Use poison instead of undef in findScalarElement()Nikita Popov1-3/+3
Out-of-range extractelement returns poison, and so do poison elements in the shufflevector mask.
2024-06-05[x86] Add tan intrinsic part 4 (#90503)Farzon Lotfi1-0/+1
This change is an implementation of #87367's investigation on supporting IEEE math operations as intrinsics. Which was discussed in this RFC: https://discourse.llvm.org/t/rfc-all-the-math-intrinsics/78294 Much of this change was following how G_FSIN and G_FCOS were used. Changes: - `llvm/docs/GlobalISel/GenericOpcode.rst` - Document the `G_FTAN` opcode - `llvm/docs/LangRef.rst` - Document the tan intrinsic - `llvm/include/llvm/Analysis/VecFuncs.def` - Associate the tan intrinsic as a vector function similar to the tanf libcall. - `llvm/include/llvm/CodeGen/BasicTTIImpl.h` - Map the tan intrinsic to `ISD::FTAN` - `llvm/include/llvm/CodeGen/ISDOpcodes.h` - Define ISD opcodes for `FTAN` and `STRICT_FTAN` - `llvm/include/llvm/IR/Intrinsics.td` - Create the tan intrinsic - `llvm/include/llvm/IR/RuntimeLibcalls.def` - Define tan libcall mappings - `llvm/include/llvm/Target/GenericOpcodes.td` - Define the `G_FTAN` Opcode - `llvm/include/llvm/Support/TargetOpcodes.def` - Create a `G_FTAN` Opcode handler - `llvm/include/llvm/Target/GlobalISel/SelectionDAGCompat.td` - Map `G_FTAN` to `ftan` - `llvm/include/llvm/Target/TargetSelectionDAG.td` - Define `ftan`, `strict_ftan`, and `any_ftan` and map them to the ISD opcodes for `FTAN` and `STRICT_FTAN` - `llvm/lib/Analysis/VectorUtils.cpp` - Associate the tan intrinsic as a vector intrinsic - `llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp` Map the tan intrinsic to `G_FTAN` Opcode - `llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp` - Add `G_FTAN` to the list of floating point math operations also associate `G_FTAN` with the `TAN_F` runtime lib. - `llvm/lib/CodeGen/GlobalISel/Utils.cpp` - More floating point math operation common behaviors. - llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp - List the function expansion operations for `FTAN` and `STRICT_FTAN`. Also define both opcodes in `PromoteNode`. - `llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp` - More `FTAN` and `STRICT_FTAN` handling in the legalizer - `llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h` - Define `SoftenFloatRes_FTAN` and `ExpandFloatRes_FTAN`. - `llvm/lib/CodeGen/SelectionDAG/LegalizeVectorOps.cpp` - Define `FTAN` as a legal vector operation. - `llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp` - Define `FTAN` as a legal vector operation. - `llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp` - define tan as an intrinsic that doesn't return NaN. - `llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp` Map `LibFunc_tan`, `LibFunc_tanf`, and `LibFunc_tanl` to `ISD::FTAN`. Map `Intrinsic::tan` to `ISD::FTAN` and add selection dag handling for `Intrinsic::tan`. - `llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp` - Define `ftan` and `strict_ftan` names for the equivalent ISD opcodes. - `llvm/lib/CodeGen/TargetLoweringBase.cpp` -Define a Tan128 libcall and ISD::FTAN as a target lowering action. - `llvm/lib/Target/X86/X86ISelLowering.cpp` - Add x86_64 lowering for tan intrinsic resolves https://github.com/llvm/llvm-project/issues/70082