[llvm] [TTI][TLI] Support scalable immediates with isLegalAddImmediate (PR #84173)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Mar 6 06:13:58 PST 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-systemz
Author: Graham Hunter (huntergr-arm)
<details>
<summary>Changes</summary>
Adds a second parameter (default to 0) to isLegalAddImmediate, to represent a scalable immediate.
Extends the AArch64 implementation to match immediates based on vscale * base_register_size * immediate in the range [-32,31].
See the vscale-aware LSR RFC for reference: https://discourse.llvm.org/t/rfc-vscale-aware-loopstrengthreduce/77131
---
Full diff: https://github.com/llvm/llvm-project/pull/84173.diff
21 Files Affected:
- (modified) llvm/include/llvm/Analysis/TargetTransformInfo.h (+4-4)
- (modified) llvm/include/llvm/Analysis/TargetTransformInfoImpl.h (+3-1)
- (modified) llvm/include/llvm/CodeGen/BasicTTIImpl.h (+2-2)
- (modified) llvm/include/llvm/CodeGen/TargetLowering.h (+2-2)
- (modified) llvm/lib/Analysis/TargetTransformInfo.cpp (+3-2)
- (modified) llvm/lib/Target/AArch64/AArch64ISelLowering.cpp (+19-1)
- (modified) llvm/lib/Target/AArch64/AArch64ISelLowering.h (+1-1)
- (modified) llvm/lib/Target/ARM/ARMISelLowering.cpp (+2-1)
- (modified) llvm/lib/Target/ARM/ARMISelLowering.h (+2-1)
- (modified) llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp (+2-1)
- (modified) llvm/lib/Target/LoongArch/LoongArchISelLowering.h (+1-1)
- (modified) llvm/lib/Target/PowerPC/PPCISelLowering.cpp (+2-1)
- (modified) llvm/lib/Target/PowerPC/PPCISelLowering.h (+2-1)
- (modified) llvm/lib/Target/RISCV/RISCVISelLowering.cpp (+3-2)
- (modified) llvm/lib/Target/RISCV/RISCVISelLowering.h (+1-1)
- (modified) llvm/lib/Target/SystemZ/SystemZISelLowering.cpp (+2-1)
- (modified) llvm/lib/Target/SystemZ/SystemZISelLowering.h (+1-1)
- (modified) llvm/lib/Target/X86/X86ISelLowering.cpp (+2-1)
- (modified) llvm/lib/Target/X86/X86ISelLowering.h (+2-1)
- (modified) llvm/unittests/Target/AArch64/CMakeLists.txt (+1)
- (added) llvm/unittests/Target/AArch64/Immediates.cpp (+75)
``````````diff
diff --git a/llvm/include/llvm/Analysis/TargetTransformInfo.h b/llvm/include/llvm/Analysis/TargetTransformInfo.h
index 4eab357f1b33b6..f9dd7bbc3dcec8 100644
--- a/llvm/include/llvm/Analysis/TargetTransformInfo.h
+++ b/llvm/include/llvm/Analysis/TargetTransformInfo.h
@@ -694,7 +694,7 @@ class TargetTransformInfo {
/// Return true if the specified immediate is legal add immediate, that
/// is the target has add instructions which can add a register with the
/// immediate without having to materialize the immediate into a register.
- bool isLegalAddImmediate(int64_t Imm) const;
+ bool isLegalAddImmediate(int64_t Imm, int64_t ScalableImm = 0) const;
/// Return true if the specified immediate is legal icmp immediate,
/// that is the target has icmp instructions which can compare a register
@@ -1834,7 +1834,7 @@ class TargetTransformInfo::Concept {
APInt &UndefElts, APInt &UndefElts2, APInt &UndefElts3,
std::function<void(Instruction *, unsigned, APInt, APInt &)>
SimplifyAndSetOp) = 0;
- virtual bool isLegalAddImmediate(int64_t Imm) = 0;
+ virtual bool isLegalAddImmediate(int64_t Imm, int64_t ScalableImm) = 0;
virtual bool isLegalICmpImmediate(int64_t Imm) = 0;
virtual bool isLegalAddressingMode(Type *Ty, GlobalValue *BaseGV,
int64_t BaseOffset, bool HasBaseReg,
@@ -2292,8 +2292,8 @@ class TargetTransformInfo::Model final : public TargetTransformInfo::Concept {
IC, II, DemandedElts, UndefElts, UndefElts2, UndefElts3,
SimplifyAndSetOp);
}
- bool isLegalAddImmediate(int64_t Imm) override {
- return Impl.isLegalAddImmediate(Imm);
+ bool isLegalAddImmediate(int64_t Imm, int64_t ScalableImm) override {
+ return Impl.isLegalAddImmediate(Imm, ScalableImm);
}
bool isLegalICmpImmediate(int64_t Imm) override {
return Impl.isLegalICmpImmediate(Imm);
diff --git a/llvm/include/llvm/Analysis/TargetTransformInfoImpl.h b/llvm/include/llvm/Analysis/TargetTransformInfoImpl.h
index 95fb13d1c97154..7fbdfe3fc68437 100644
--- a/llvm/include/llvm/Analysis/TargetTransformInfoImpl.h
+++ b/llvm/include/llvm/Analysis/TargetTransformInfoImpl.h
@@ -214,7 +214,9 @@ class TargetTransformInfoImplBase {
void getPeelingPreferences(Loop *, ScalarEvolution &,
TTI::PeelingPreferences &) const {}
- bool isLegalAddImmediate(int64_t Imm) const { return false; }
+ bool isLegalAddImmediate(int64_t Imm, int64_t ScalableImm) const {
+ return false;
+ }
bool isLegalICmpImmediate(int64_t Imm) const { return false; }
diff --git a/llvm/include/llvm/CodeGen/BasicTTIImpl.h b/llvm/include/llvm/CodeGen/BasicTTIImpl.h
index 61f6564e8cd79b..ac8cd28689d35a 100644
--- a/llvm/include/llvm/CodeGen/BasicTTIImpl.h
+++ b/llvm/include/llvm/CodeGen/BasicTTIImpl.h
@@ -324,8 +324,8 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
return nullptr;
}
- bool isLegalAddImmediate(int64_t imm) {
- return getTLI()->isLegalAddImmediate(imm);
+ bool isLegalAddImmediate(int64_t Imm, int64_t ScalableImm) {
+ return getTLI()->isLegalAddImmediate(Imm, ScalableImm);
}
bool isLegalICmpImmediate(int64_t imm) {
diff --git a/llvm/include/llvm/CodeGen/TargetLowering.h b/llvm/include/llvm/CodeGen/TargetLowering.h
index 2f164a460db843..57844dd82d6410 100644
--- a/llvm/include/llvm/CodeGen/TargetLowering.h
+++ b/llvm/include/llvm/CodeGen/TargetLowering.h
@@ -2766,8 +2766,8 @@ class TargetLoweringBase {
/// Return true if the specified immediate is legal add immediate, that is the
/// target has add instructions which can add a register with the immediate
/// without having to materialize the immediate into a register.
- virtual bool isLegalAddImmediate(int64_t) const {
- return true;
+ virtual bool isLegalAddImmediate(int64_t, int64_t ScalableImm = 0) const {
+ return !ScalableImm;
}
/// Return true if the specified immediate is legal for the value input of a
diff --git a/llvm/lib/Analysis/TargetTransformInfo.cpp b/llvm/lib/Analysis/TargetTransformInfo.cpp
index 15311be4dba277..8791ae4c3744e5 100644
--- a/llvm/lib/Analysis/TargetTransformInfo.cpp
+++ b/llvm/lib/Analysis/TargetTransformInfo.cpp
@@ -391,8 +391,9 @@ void TargetTransformInfo::getPeelingPreferences(Loop *L, ScalarEvolution &SE,
return TTIImpl->getPeelingPreferences(L, SE, PP);
}
-bool TargetTransformInfo::isLegalAddImmediate(int64_t Imm) const {
- return TTIImpl->isLegalAddImmediate(Imm);
+bool TargetTransformInfo::isLegalAddImmediate(int64_t Imm,
+ int64_t ScalableImm) const {
+ return TTIImpl->isLegalAddImmediate(Imm, ScalableImm);
}
bool TargetTransformInfo::isLegalICmpImmediate(int64_t Imm) const {
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 2290223a06f8ef..e53e8ce6a3d227 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -16559,7 +16559,25 @@ LLT AArch64TargetLowering::getOptimalMemOpLLT(
}
// 12-bit optionally shifted immediates are legal for adds.
-bool AArch64TargetLowering::isLegalAddImmediate(int64_t Immed) const {
+bool AArch64TargetLowering::isLegalAddImmediate(int64_t Immed,
+ int64_t ScalableImm) const {
+ if (ScalableImm) {
+ // Scalable immediates require SVE support; mixed fixed + scalable
+ // immediates are not supported by the current instructions.
+ if (Immed || !Subtarget->hasSVE())
+ return false;
+
+ // addvl's immediates are in terms of the number of bytes in a register.
+ // Since there are 16 in the base supported size (128bits), we need to
+ // divide the immediate by that much to give us a useful immediate to
+ // multiply by vscale. We can't have a remainder as a result of this.
+ if (ScalableImm % 16 != 0)
+ return false;
+ int64_t Imm = ScalableImm / 16;
+
+ return Imm >= -32 && Imm <= 31;
+ }
+
if (Immed == std::numeric_limits<int64_t>::min()) {
LLVM_DEBUG(dbgs() << "Illegal add imm " << Immed
<< ": avoid UB for INT64_MIN\n");
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.h b/llvm/lib/Target/AArch64/AArch64ISelLowering.h
index 68341c199e0a2a..adec93d7e6aea1 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.h
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.h
@@ -688,7 +688,7 @@ class AArch64TargetLowering : public TargetLowering {
bool lowerInterleaveIntrinsicToStore(IntrinsicInst *II,
StoreInst *SI) const override;
- bool isLegalAddImmediate(int64_t) const override;
+ bool isLegalAddImmediate(int64_t Imm, int64_t ScalableImm = 0) const override;
bool isLegalICmpImmediate(int64_t) const override;
bool isMulAddWithConstProfitable(SDValue AddNode,
diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp
index dc81178311b6d8..65a15f959ff4d9 100644
--- a/llvm/lib/Target/ARM/ARMISelLowering.cpp
+++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp
@@ -19722,7 +19722,8 @@ bool ARMTargetLowering::isLegalICmpImmediate(int64_t Imm) const {
/// *or sub* immediate, that is the target has add or sub instructions which can
/// add a register with the immediate without having to materialize the
/// immediate into a register.
-bool ARMTargetLowering::isLegalAddImmediate(int64_t Imm) const {
+bool ARMTargetLowering::isLegalAddImmediate(int64_t Imm,
+ int64_t ScalableImm) const {
// Same encoding for add/sub, just flip the sign.
int64_t AbsImm = std::abs(Imm);
if (!Subtarget->isThumb())
diff --git a/llvm/lib/Target/ARM/ARMISelLowering.h b/llvm/lib/Target/ARM/ARMISelLowering.h
index b13ddf697cb806..70bbb15a1772f8 100644
--- a/llvm/lib/Target/ARM/ARMISelLowering.h
+++ b/llvm/lib/Target/ARM/ARMISelLowering.h
@@ -494,7 +494,8 @@ class VectorType;
/// add immediate, that is the target has add instructions which can
/// add a register and the immediate without having to materialize
/// the immediate into a register.
- bool isLegalAddImmediate(int64_t Imm) const override;
+ bool isLegalAddImmediate(int64_t Imm,
+ int64_t ScalableImm = 0) const override;
/// getPreIndexedAddressParts - returns true by value, base pointer and
/// offset pointer and addressing mode by reference if the node's address
diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
index c8e955a23336d7..f975fc52b2f774 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
@@ -4933,7 +4933,8 @@ bool LoongArchTargetLowering::isLegalICmpImmediate(int64_t Imm) const {
return isInt<12>(Imm);
}
-bool LoongArchTargetLowering::isLegalAddImmediate(int64_t Imm) const {
+bool LoongArchTargetLowering::isLegalAddImmediate(int64_t Imm,
+ int64_t ScalableImm) const {
return isInt<12>(Imm);
}
diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h
index 9e9ac0b8269291..b59a4dfcd9ead3 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h
+++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h
@@ -222,7 +222,7 @@ class LoongArchTargetLowering : public TargetLowering {
Instruction *I = nullptr) const override;
bool isLegalICmpImmediate(int64_t Imm) const override;
- bool isLegalAddImmediate(int64_t Imm) const override;
+ bool isLegalAddImmediate(int64_t Imm, int64_t ScalableImm = 0) const override;
bool isZExtFree(SDValue Val, EVT VT2) const override;
bool isSExtCheaperThanZExt(EVT SrcVT, EVT DstVT) const override;
diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
index 68c80dd9aa5c76..2aaf7b24d52544 100644
--- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
+++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
@@ -17300,7 +17300,8 @@ bool PPCTargetLowering::isLegalICmpImmediate(int64_t Imm) const {
return isInt<16>(Imm) || isUInt<16>(Imm);
}
-bool PPCTargetLowering::isLegalAddImmediate(int64_t Imm) const {
+bool PPCTargetLowering::isLegalAddImmediate(int64_t Imm,
+ int64_t ScalableImm) const {
return isInt<16>(Imm) || isUInt<16>(Imm);
}
diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.h b/llvm/lib/Target/PowerPC/PPCISelLowering.h
index 0bdfdcd15441f4..a1b404bd655b36 100644
--- a/llvm/lib/Target/PowerPC/PPCISelLowering.h
+++ b/llvm/lib/Target/PowerPC/PPCISelLowering.h
@@ -1023,7 +1023,8 @@ namespace llvm {
/// add immediate, that is the target has add instructions which can
/// add a register and the immediate without having to materialize
/// the immediate into a register.
- bool isLegalAddImmediate(int64_t Imm) const override;
+ bool isLegalAddImmediate(int64_t Imm,
+ int64_t ScalableImm = 0) const override;
/// isTruncateFree - Return true if it's free to truncate a value of
/// type Ty1 to type Ty2. e.g. On PPC it's free to truncate a i64 value in
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 4c3dc63afd878d..c6b02b8b26856b 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -1783,8 +1783,9 @@ bool RISCVTargetLowering::isLegalICmpImmediate(int64_t Imm) const {
return isInt<12>(Imm);
}
-bool RISCVTargetLowering::isLegalAddImmediate(int64_t Imm) const {
- return isInt<12>(Imm);
+bool RISCVTargetLowering::isLegalAddImmediate(int64_t Imm,
+ int64_t ScalableImm) const {
+ return !ScalableImm && isInt<12>(Imm);
}
// On RV32, 64-bit integers are split into their high and low parts and held
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.h b/llvm/lib/Target/RISCV/RISCVISelLowering.h
index f90cb4df604761..61fb5809c9b8dd 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.h
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.h
@@ -475,7 +475,7 @@ class RISCVTargetLowering : public TargetLowering {
unsigned AS,
Instruction *I = nullptr) const override;
bool isLegalICmpImmediate(int64_t Imm) const override;
- bool isLegalAddImmediate(int64_t Imm) const override;
+ bool isLegalAddImmediate(int64_t Imm, int64_t ScalableImm = 0) const override;
bool isTruncateFree(Type *SrcTy, Type *DstTy) const override;
bool isTruncateFree(EVT SrcVT, EVT DstVT) const override;
bool isZExtFree(SDValue Val, EVT VT2) const override;
diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
index 3b85a6ac0371ed..a2aa33ff059489 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
@@ -944,7 +944,8 @@ bool SystemZTargetLowering::isLegalICmpImmediate(int64_t Imm) const {
return isInt<32>(Imm) || isUInt<32>(Imm);
}
-bool SystemZTargetLowering::isLegalAddImmediate(int64_t Imm) const {
+bool SystemZTargetLowering::isLegalAddImmediate(int64_t Imm,
+ int64_t ScalableImm) const {
// We can use ALGFI or SLGFI.
return isUInt<32>(Imm) || isUInt<32>(-Imm);
}
diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.h b/llvm/lib/Target/SystemZ/SystemZISelLowering.h
index baf4ba41654879..274b23b4d28935 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.h
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.h
@@ -477,7 +477,7 @@ class SystemZTargetLowering : public TargetLowering {
AtomicExpansionKind
shouldExpandAtomicRMWInIR(AtomicRMWInst *RMW) const override;
bool isLegalICmpImmediate(int64_t Imm) const override;
- bool isLegalAddImmediate(int64_t Imm) const override;
+ bool isLegalAddImmediate(int64_t Imm, int64_t ScalableImm = 0) const override;
bool isLegalAddressingMode(const DataLayout &DL, const AddrMode &AM, Type *Ty,
unsigned AS,
Instruction *I = nullptr) const override;
diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index 6eaaec407dbb08..d5f5ef24e56d5d 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -33882,7 +33882,8 @@ bool X86TargetLowering::isLegalICmpImmediate(int64_t Imm) const {
return isInt<32>(Imm);
}
-bool X86TargetLowering::isLegalAddImmediate(int64_t Imm) const {
+bool X86TargetLowering::isLegalAddImmediate(int64_t Imm,
+ int64_t ScalableImm) const {
// Can also use sub to handle negated immediates.
return isInt<32>(Imm);
}
diff --git a/llvm/lib/Target/X86/X86ISelLowering.h b/llvm/lib/Target/X86/X86ISelLowering.h
index fe1943b5760844..b3cccee0e67bf1 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.h
+++ b/llvm/lib/Target/X86/X86ISelLowering.h
@@ -1329,7 +1329,8 @@ namespace llvm {
/// add immediate, that is the target has add instructions which can
/// add a register and the immediate without having to materialize
/// the immediate into a register.
- bool isLegalAddImmediate(int64_t Imm) const override;
+ bool isLegalAddImmediate(int64_t Imm,
+ int64_t ScalableImm = 0) const override;
bool isLegalStoreImmediate(int64_t Imm) const override;
diff --git a/llvm/unittests/Target/AArch64/CMakeLists.txt b/llvm/unittests/Target/AArch64/CMakeLists.txt
index dacd919ba1e33b..64ab991ac479a4 100644
--- a/llvm/unittests/Target/AArch64/CMakeLists.txt
+++ b/llvm/unittests/Target/AArch64/CMakeLists.txt
@@ -29,6 +29,7 @@ add_llvm_target_unittest(AArch64Tests
MatrixRegisterAliasing.cpp
SMEAttributesTest.cpp
AArch64SVESchedPseudoTest.cpp
+ Immediates.cpp
)
set_property(TARGET AArch64Tests PROPERTY FOLDER "Tests/UnitTests/TargetTests")
diff --git a/llvm/unittests/Target/AArch64/Immediates.cpp b/llvm/unittests/Target/AArch64/Immediates.cpp
new file mode 100644
index 00000000000000..5f5895e44c6110
--- /dev/null
+++ b/llvm/unittests/Target/AArch64/Immediates.cpp
@@ -0,0 +1,75 @@
+#include "AArch64Subtarget.h"
+#include "AArch64TargetMachine.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/MC/TargetRegistry.h"
+#include "llvm/Support/TargetSelect.h"
+
+#include "gtest/gtest.h"
+#include <initializer_list>
+#include <memory>
+
+using namespace llvm;
+
+namespace {
+
+struct TestCase {
+ int64_t FixedImm;
+ int64_t ScalableImm;
+ bool Result;
+};
+
+const std::initializer_list<TestCase> Tests = {
+ // FixedImm, ScalableImm, Result
+ // No change, easily 'supported'
+ {0, 0, true},
+
+ // Simple fixed immediate cases
+ // +8
+ {8, 0, true},
+ // -16
+ {-16, 0, true},
+
+ // Scalable; addvl increments by whole registers, range [-32,31]
+ // +(16 * vscale), one register's worth
+ {0, 16, true},
+ // +(8 * vscale), half a register's worth
+ {0, 8, false},
+ // -(32 * 16 * vscale)
+ {0, -512, true},
+ // -(33 * 16 * vscale)
+ {0, -528, false},
+ // +(31 * 16 * vscale)
+ {0, 496, true},
+ // +(32 * 16 * vscale)
+ {0, 512, false},
+
+ // Mixed; not supported.
+ // +(16 + (16 * vscale)) -- one register's worth + 16
+ {16, 16, false},
+};
+} // namespace
+
+TEST(Immediates, Immediates) {
+ LLVMInitializeAArch64TargetInfo();
+ LLVMInitializeAArch64Target();
+ LLVMInitializeAArch64TargetMC();
+
+ std::string Error;
+ auto TT = Triple::normalize("aarch64");
+ const Target *T = TargetRegistry::lookupTarget(TT, Error);
+
+ std::unique_ptr<TargetMachine> TM(
+ T->createTargetMachine(TT, "generic", "+sve", TargetOptions(),
+ std::nullopt, std::nullopt,
+ CodeGenOptLevel::Default));
+ AArch64Subtarget ST(TM->getTargetTriple(), TM->getTargetCPU(),
+ TM->getTargetCPU(), TM->getTargetFeatureString(), *TM,
+ true);
+
+ auto *TLI = ST.getTargetLowering();
+
+ for (const auto &Test : Tests) {
+ ASSERT_EQ(TLI->isLegalAddImmediate(Test.FixedImm, Test.ScalableImm),
+ Test.Result);
+ }
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/84173
More information about the llvm-commits
mailing list