[llvm] [Hexagon] Do not co-packetize scalar FP/mpy def with a consuming transfer of control (PR #227178)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Sep 28 19:56:08 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-hexagon
Author: Ikhlas Ajbar (iajbar)
<details>
<summary>Changes</summary>
A multi-cycle scalar producer on SLOT2/SLOT3 (TC3x scalar multiply such as M2_mpysip, or TC4x scalar floating-point such as F2_sfmpy) writes late in the packet. When it is bundled with a control-transfer that implicitly reads the same register (an ABI argument for a call/tail call/jumpr, or the ABI return-value register for a return), the consumer sees a stale value because the transfer of control happens before the write reaches the register file.
Introduce HexagonInstrInfo::hasMultiCycleDefLatency() which, for a given def MI, use MI and physical register, decides whether the pair may share a packet. It flags TC3x and TC4x scalar classes. Consult it from the packetizer so the bundle is refused uniformly for calls, tail calls (direct and indirect J2_jumpr) and returns (PS_jmpret / L4_return / J2_jumpr r31).
Update fp16-promote.ll, simple_addend.ll, bfloat.ll, fast-math-libcalls.ll, fptoi.sat.ll and tc_sched1.ll to reflect the split packets. Add scalar-fp-call-packet.ll as a regression test.
---
Full diff: https://github.com/llvm/llvm-project/pull/227178.diff
10 Files Affected:
- (modified) llvm/lib/Target/Hexagon/HexagonInstrInfo.cpp (+29)
- (modified) llvm/lib/Target/Hexagon/HexagonInstrInfo.h (+9)
- (modified) llvm/lib/Target/Hexagon/HexagonVLIWPacketizer.cpp (+17-1)
- (modified) llvm/test/CodeGen/Hexagon/bfloat.ll (+3-1)
- (modified) llvm/test/CodeGen/Hexagon/fast-math-libcalls.ll (+18)
- (modified) llvm/test/CodeGen/Hexagon/fp16-promote.ll (+6-2)
- (modified) llvm/test/CodeGen/Hexagon/fptoi.sat.ll (+4)
- (added) llvm/test/CodeGen/Hexagon/scalar-fp-call-packet.ll (+171)
- (modified) llvm/test/CodeGen/Hexagon/simple_addend.ll (+4-1)
- (modified) llvm/test/CodeGen/Hexagon/tc_sched1.ll (+1-1)
``````````diff
diff --git a/llvm/lib/Target/Hexagon/HexagonInstrInfo.cpp b/llvm/lib/Target/Hexagon/HexagonInstrInfo.cpp
index b31724f094ec7..427117382647f 100644
--- a/llvm/lib/Target/Hexagon/HexagonInstrInfo.cpp
+++ b/llvm/lib/Target/Hexagon/HexagonInstrInfo.cpp
@@ -4353,6 +4353,35 @@ unsigned HexagonInstrInfo::getInstrTimingClassLatency(
return ItinData->getStageLatency(MI.getDesc().getSchedClass());
}
+bool HexagonInstrInfo::hasMultiCycleDefLatency(
+ const InstrItineraryData *ItinData, const MachineInstr &DefMI,
+ const MachineInstr &UseMI, Register Reg) const {
+ const auto &HRI = *Subtarget.getRegisterInfo();
+ // Only meaningful when DefMI actually writes a register that overlaps Reg.
+ // Cover every orientation: exact match, super-reg def (paired def whose low
+ // half is the ABI arg register), and narrow def feeding a wider implicit
+ // use (e.g. sfmpy defining $r0 while the callee's implicit use is $d0).
+ bool DefsReg = false;
+ for (const MachineOperand &MO : DefMI.operands()) {
+ if (MO.isReg() && MO.isDef() && MO.getReg() &&
+ HRI.regsOverlap(MO.getReg(), Reg)) {
+ DefsReg = true;
+ break;
+ }
+ }
+ if (!DefsReg)
+ return false;
+ // Most scalar timing classes (TC1/TC2/TC3/loads/stores) commit their writes
+ // to the register file by the end of the packet, so the callee of a
+ // co-packetized call still observes the up-to-date value of an implicit
+ // argument register. Multi-cycle scalar producers on SLOT2/SLOT3 (TC3x
+ // scalar multiply and TC4x scalar floating-point) complete late enough that
+ // the callee can see a stale register when the def and the call are placed
+ // in the same packet. Refuse the bundle for those classes.
+ unsigned SchedClass = DefMI.getDesc().getSchedClass();
+ return is_TC3x(SchedClass) || is_TC4x(SchedClass);
+}
+
/// getOperandLatency - Compute and return the use operand latency of a given
/// pair of def and use.
/// In most cases, the static scheduling itinerary was enough to determine the
diff --git a/llvm/lib/Target/Hexagon/HexagonInstrInfo.h b/llvm/lib/Target/Hexagon/HexagonInstrInfo.h
index 7bcd2005af10d..8062af98c0067 100644
--- a/llvm/lib/Target/Hexagon/HexagonInstrInfo.h
+++ b/llvm/lib/Target/Hexagon/HexagonInstrInfo.h
@@ -474,6 +474,15 @@ class HexagonInstrInfo : public HexagonGenInstrInfo {
short getEquivalentHWInstr(const MachineInstr &MI) const;
unsigned getInstrTimingClassLatency(const InstrItineraryData *ItinData,
const MachineInstr &MI) const;
+ /// Return true if \p DefMI defines \p Reg (or a super-register of it) with
+ /// a scheduling class whose per-operand write latency prevents packetizing
+ /// the def with a consumer that reads \p Reg in the same packet (currently
+ /// scalar floating-point TC4x classes, whose writes commit after the point
+ /// at which a co-packetized call transfers control). \p UseMI is retained
+ /// in the signature for future refinement using operand-pair latencies.
+ bool hasMultiCycleDefLatency(const InstrItineraryData *ItinData,
+ const MachineInstr &DefMI,
+ const MachineInstr &UseMI, Register Reg) const;
bool getInvertedPredSense(SmallVectorImpl<MachineOperand> &Cond) const;
unsigned getInvertedPredicatedOpcode(const int Opc) const;
int getMaxValue(const MachineInstr &MI) const;
diff --git a/llvm/lib/Target/Hexagon/HexagonVLIWPacketizer.cpp b/llvm/lib/Target/Hexagon/HexagonVLIWPacketizer.cpp
index 8026a8a177e59..8ada7329c02d6 100644
--- a/llvm/lib/Target/Hexagon/HexagonVLIWPacketizer.cpp
+++ b/llvm/lib/Target/Hexagon/HexagonVLIWPacketizer.cpp
@@ -1429,8 +1429,24 @@ bool HexagonPacketizerList::isLegalToPacketizeTogether(SUnit *SUI, SUnit *SUJ) {
if (I.isCall() || HII->isJumpR(I) || I.isReturn() || HII->isTailCall(I)) {
if (!isRegDependence(DepType))
continue;
- if (!isCallDependent(I, DepType, SUJ->Succs[i].getReg()))
+ if (!isCallDependent(I, DepType, SUJ->Succs[i].getReg())) {
+ // The register dependence normally looks benign for a call (the
+ // implicit arg register is materialised in the same packet). But
+ // multi-cycle scalar producers (TC3x scalar multiply and TC4x scalar
+ // floating-point) commit their writes too late for the consumer to
+ // observe the up-to-date register at packet exit, so the def and the
+ // call must live in different packets. The same hazard applies to
+ // tail calls (jump-with-symbol), to indirect tail calls (J2_jumpr)
+ // and to returns (PS_jmpret / L4_return, which consume the ABI
+ // return-value register implicitly).
+ if (DepType == SDep::Data &&
+ HII->hasMultiCycleDefLatency(ResourceTracker->getInstrItins(), J, I,
+ SUJ->Succs[i].getReg())) {
+ Dependence = true;
+ return false;
+ }
continue;
+ }
}
if (DepType == SDep::Data) {
diff --git a/llvm/test/CodeGen/Hexagon/bfloat.ll b/llvm/test/CodeGen/Hexagon/bfloat.ll
index 550a2b54b2dea..52b37f77f59ed 100644
--- a/llvm/test/CodeGen/Hexagon/bfloat.ll
+++ b/llvm/test/CodeGen/Hexagon/bfloat.ll
@@ -166,9 +166,11 @@ define dso_local i32 @double_bf16(bfloat %a, bfloat %b) #0 {
; CHECK-NEXT: }
; CHECK-NEXT: {
; CHECK-NEXT: [[R0]] = convert_sf2w([[R0]]):chop
-; CHECK-NEXT: jumpr r31
; CHECK-NEXT: [[SP]] = add([[SP]],#16)
; CHECK-NEXT: }
+; CHECK-NEXT: {
+; CHECK-NEXT: jumpr r31
+; CHECK-NEXT: }
entry:
%c = alloca double, align 8
diff --git a/llvm/test/CodeGen/Hexagon/fast-math-libcalls.ll b/llvm/test/CodeGen/Hexagon/fast-math-libcalls.ll
index 831ab0a980368..5a9243c286a2f 100644
--- a/llvm/test/CodeGen/Hexagon/fast-math-libcalls.ll
+++ b/llvm/test/CodeGen/Hexagon/fast-math-libcalls.ll
@@ -37,6 +37,8 @@ define float @fast_add_f32(float %x, float %y) {
; CHECK-NEXT: // %bb.0:
; CHECK-NEXT: {
; CHECK-NEXT: r0 = sfadd(r0,r1)
+; CHECK-NEXT: }
+; CHECK-NEXT: {
; CHECK-NEXT: jumpr r31
; CHECK-NEXT: }
%result = fadd nnan ninf nsz afn float %x, %y
@@ -64,6 +66,8 @@ define float @fast_sub_f32(float %x, float %y) {
; CHECK-NEXT: // %bb.0:
; CHECK-NEXT: {
; CHECK-NEXT: r0 = sfsub(r0,r1)
+; CHECK-NEXT: }
+; CHECK-NEXT: {
; CHECK-NEXT: jumpr r31
; CHECK-NEXT: }
%result = fsub nnan ninf nsz afn float %x, %y
@@ -91,6 +95,8 @@ define float @fast_mul_f32(float %x, float %y) {
; CHECK-NEXT: // %bb.0:
; CHECK-NEXT: {
; CHECK-NEXT: r0 = sfmpy(r0,r1)
+; CHECK-NEXT: }
+; CHECK-NEXT: {
; CHECK-NEXT: jumpr r31
; CHECK-NEXT: }
%result = fmul nnan ninf nsz afn float %x, %y
@@ -149,6 +155,8 @@ define float @fast_div_f32(float %x, float %y) {
; CHECK-NEXT: }
; CHECK-NEXT: {
; CHECK-NEXT: r0 += sfmpy(r2,r4,p0):scale
+; CHECK-NEXT: }
+; CHECK-NEXT: {
; CHECK-NEXT: jumpr r31
; CHECK-NEXT: }
%result = fdiv nnan ninf nsz afn float %x, %y
@@ -237,6 +245,8 @@ define float @fadd_f32_afn(float %x, float %y) {
; CHECK-NEXT: // %bb.0:
; CHECK-NEXT: {
; CHECK-NEXT: r0 = sfadd(r0,r1)
+; CHECK-NEXT: }
+; CHECK-NEXT: {
; CHECK-NEXT: jumpr r31
; CHECK-NEXT: }
%result = fadd afn float %x, %y
@@ -249,6 +259,8 @@ define float @fadd_f32__afn_ninf(float %x, float %y) {
; CHECK-NEXT: // %bb.0:
; CHECK-NEXT: {
; CHECK-NEXT: r0 = sfadd(r0,r1)
+; CHECK-NEXT: }
+; CHECK-NEXT: {
; CHECK-NEXT: jumpr r31
; CHECK-NEXT: }
%result = fadd afn ninf float %x, %y
@@ -261,6 +273,8 @@ define float @fadd_f32__afn_nnan(float %x, float %y) {
; CHECK-NEXT: // %bb.0:
; CHECK-NEXT: {
; CHECK-NEXT: r0 = sfadd(r0,r1)
+; CHECK-NEXT: }
+; CHECK-NEXT: {
; CHECK-NEXT: jumpr r31
; CHECK-NEXT: }
%result = fadd afn nnan float %x, %y
@@ -273,6 +287,8 @@ define float @fadd_f32__nnan(float %x, float %y) {
; CHECK-NEXT: // %bb.0:
; CHECK-NEXT: {
; CHECK-NEXT: r0 = sfadd(r0,r1)
+; CHECK-NEXT: }
+; CHECK-NEXT: {
; CHECK-NEXT: jumpr r31
; CHECK-NEXT: }
%result = fadd nnan float %x, %y
@@ -285,6 +301,8 @@ define float @fadd_f32__nnan_ninf_afn(float %x, float %y) {
; CHECK-NEXT: // %bb.0:
; CHECK-NEXT: {
; CHECK-NEXT: r0 = sfadd(r0,r1)
+; CHECK-NEXT: }
+; CHECK-NEXT: {
; CHECK-NEXT: jumpr r31
; CHECK-NEXT: }
%result = fadd nnan ninf afn float %x, %y
diff --git a/llvm/test/CodeGen/Hexagon/fp16-promote.ll b/llvm/test/CodeGen/Hexagon/fp16-promote.ll
index 31bdb7a126e37..fbb8888185013 100644
--- a/llvm/test/CodeGen/Hexagon/fp16-promote.ll
+++ b/llvm/test/CodeGen/Hexagon/fp16-promote.ll
@@ -13,10 +13,12 @@ define half @freeze_half_undef() nounwind {
; CHECK-NEXT: call __extendhfsf2
; CHECK-NEXT: }
; CHECK-NEXT: {
-; CHECK-NEXT: call __truncsfhf2
; CHECK-NEXT: r0 = sfadd(r0,r0)
; CHECK-NEXT: }
; CHECK-NEXT: {
+; CHECK-NEXT: call __truncsfhf2
+; CHECK-NEXT: }
+; CHECK-NEXT: {
; CHECK-NEXT: r31:30 = dealloc_return(r30):raw
; CHECK-NEXT: }
%y1 = freeze half undef
@@ -32,10 +34,12 @@ define half @freeze_half_poison(half %maybe.poison) {
; CHECK-NEXT: allocframe(r29,#0):raw
; CHECK-NEXT: }
; CHECK-NEXT: {
-; CHECK-NEXT: call __truncsfhf2
; CHECK-NEXT: r0 = sfadd(r0,r0)
; CHECK-NEXT: }
; CHECK-NEXT: {
+; CHECK-NEXT: call __truncsfhf2
+; CHECK-NEXT: }
+; CHECK-NEXT: {
; CHECK-NEXT: r31:30 = dealloc_return(r30):raw
; CHECK-NEXT: }
%y1 = freeze half %maybe.poison
diff --git a/llvm/test/CodeGen/Hexagon/fptoi.sat.ll b/llvm/test/CodeGen/Hexagon/fptoi.sat.ll
index 864b3b62379b6..8308486f19063 100644
--- a/llvm/test/CodeGen/Hexagon/fptoi.sat.ll
+++ b/llvm/test/CodeGen/Hexagon/fptoi.sat.ll
@@ -49,6 +49,8 @@ define i16 @fptoui.sat.i16.f32(float %x) {
; CHECK-NEXT: }
; CHECK-NEXT: {
; CHECK-NEXT: r0 = convert_sf2uw(r0):chop
+; CHECK-NEXT: }
+; CHECK-NEXT: {
; CHECK-NEXT: jumpr r31
; CHECK-NEXT: }
%res = call i16 @llvm.fptoui.sat(float %x)
@@ -107,6 +109,8 @@ define i32 @fptoui.sat.i32.f64(double %x) {
; CHECK-NEXT: }
; CHECK-NEXT: {
; CHECK-NEXT: r0 = convert_df2uw(r1:0):chop
+; CHECK-NEXT: }
+; CHECK-NEXT: {
; CHECK-NEXT: jumpr r31
; CHECK-NEXT: }
%res = call i32 @llvm.fptoui.sat(double %x)
diff --git a/llvm/test/CodeGen/Hexagon/scalar-fp-call-packet.ll b/llvm/test/CodeGen/Hexagon/scalar-fp-call-packet.ll
new file mode 100644
index 0000000000000..e902477d0dda6
--- /dev/null
+++ b/llvm/test/CodeGen/Hexagon/scalar-fp-call-packet.ll
@@ -0,0 +1,171 @@
+; RUN: llc -mtriple=hexagon-- -mattr=+hvxv75,+hvx-length128b,+hvx-qfloat,+hvx-ieee-fp \
+; RUN: -O2 < %s | FileCheck %s
+
+; A multi-cycle scalar producer on SLOT2/SLOT3 (TC3x scalar multiply such as
+; M2_mpysip, or TC4x scalar floating-point such as F2_sfmpy / F2_dfmpyhh) must
+; not share a packet with a control-transfer instruction that implicitly reads
+; the same (or an overlapping) register. The multi-cycle write commits after
+; the transfer of control happens, so a co-packetized consumer would observe
+; a stale ABI argument or return-value register. The def and the transfer
+; must live in different packets. This applies uniformly to calls, tail calls
+; (direct and indirect), and returns (PS_jmpret / L4_return / J2_jumpr r31).
+
+; -----------------------------------------------------------------------------
+; Scalar single-precision FP def feeding a call that reads the same GPR.
+
+; CHECK-LABEL: mulredux_scalar_kernel:
+; CHECK: r0 = sfmpy(r0,r{{[0-9]+}})
+; CHECK-NEXT: }
+; CHECK-NEXT: {
+; CHECK-NEXT: call __truncsfhf2
+; CHECK-NEXT: }
+
+define <64 x half> @mulredux_scalar_kernel(half %s, <64 x half> %v) {
+._crit_edge:
+ %m = fmul half %s, 0xH0000
+ %b = bitcast half %m to <1 x half>
+ %splat = shufflevector <1 x half> %b, <1 x half> zeroinitializer,
+ <64 x i32> zeroinitializer
+ %r = fmul <64 x half> %splat, %v
+ ret <64 x half> %r
+}
+
+; -----------------------------------------------------------------------------
+; Double-precision FP def (paired reg r1:r0) feeding a call that reads r0
+; implicitly. The TC4x def of the pair overlaps the ABI argument register, so
+; the two must not be co-packetized.
+
+declare void @bar_i32(i32)
+
+; CHECK-LABEL: dfmpy_paired_def_call:
+; CHECK: dfmpyhh(r{{[0-9]+}}:{{[0-9]+}},r{{[0-9]+}}:{{[0-9]+}})
+; CHECK-NEXT: }
+; CHECK-NEXT: {
+; CHECK-NEXT: call bar_i32
+; CHECK-NEXT: }
+
+define void @dfmpy_paired_def_call(double %a, double %b) {
+entry:
+ %m = fmul double %a, %b
+ %bits = bitcast double %m to i64
+ %lo = trunc i64 %bits to i32
+ call void @bar_i32(i32 %lo)
+ ret void
+}
+
+; -----------------------------------------------------------------------------
+; Scalar FP def followed by a tail call. The tail call is emitted as a
+; jump-with-symbol and implicitly consumes the ABI argument register, so the
+; same hazard applies.
+
+declare void @bar_f32(float)
+
+; CHECK-LABEL: sfmpy_tailcall:
+; CHECK: r0 = sfmpy(r0,r{{[0-9]+}})
+; CHECK-NEXT: }
+; CHECK-NEXT: {
+; CHECK-NEXT: jump bar_f32
+; CHECK-NEXT: }
+
+define void @sfmpy_tailcall(float %a) {
+ %m = fmul float %a, %a
+ tail call void @bar_f32(float %m)
+ ret void
+}
+
+; -----------------------------------------------------------------------------
+; Scalar FP def of $r0 feeding a call whose implicit use is the wider $d0
+; (r1:r0) i64 argument register. The def and the call overlap through $r0 and
+; must not be co-packetized.
+
+declare void @bar_i64(i64)
+
+; CHECK-LABEL: sfmpy_narrow_def_wide_use:
+; CHECK: r0 = sfmpy(r0,r{{[0-9]+}})
+; CHECK: }
+; CHECK: {
+; CHECK: call bar_i64
+; CHECK-NEXT: }
+
+define void @sfmpy_narrow_def_wide_use(float %a, i32 %b) {
+ %m = fmul float %a, %a
+ %m_bits = bitcast float %m to i32
+ %m64 = zext i32 %m_bits to i64
+ %b64 = zext i32 %b to i64
+ %hi = shl i64 %b64, 32
+ %arg = or i64 %hi, %m64
+ call void @bar_i64(i64 %arg)
+ ret void
+}
+
+; -----------------------------------------------------------------------------
+; Scalar FP def followed by an indirect tail call (J2_jumpr). The indirect
+; branch consumes the ABI argument register implicitly and has the same
+; stale-register hazard as a direct call.
+
+; CHECK-LABEL: sfmpy_indirect_tailcall:
+; CHECK: r0 = sfmpy(r0,r{{[0-9]+}})
+; CHECK: }
+; CHECK: {
+; CHECK-NEXT: {{call|jump}}r r{{[0-9]+}}
+; CHECK-NEXT: }
+
+define void @sfmpy_indirect_tailcall(float %a, ptr %fp) {
+ %m = fmul float %a, %a
+ tail call void %fp(float %m)
+ ret void
+}
+
+; -----------------------------------------------------------------------------
+; Scalar TC3x def (M2_mpysip / +mpyi) feeding a call that reads the same GPR.
+; The TC3x write also completes late on real HW, so the multiply and the call
+; must live in different packets.
+
+declare void @bar_i32_2(i32)
+
+; CHECK-LABEL: mpyi_scalar_call:
+; CHECK: r0 = {{[+]?}}mpyi(r0,#3)
+; CHECK: }
+; CHECK: {
+; CHECK: call bar_i32_2
+; CHECK-NEXT: }
+
+define void @mpyi_scalar_call(i32 %a) {
+ %m = mul i32 %a, 3
+ call void @bar_i32_2(i32 %m)
+ ret void
+}
+
+; -----------------------------------------------------------------------------
+; Scalar FP def producing the return value in the same packet as a PS_jmpret
+; (which lowers to J2_jumpr r31 and implicitly reads $r0). Real HW would let
+; the caller observe a stale return-value register when the def and the return
+; are bundled, so they must live in different packets.
+
+; CHECK-LABEL: sfmpy_return:
+; CHECK: r0 = sfmpy(r0,r{{[0-9]+}})
+; CHECK-NEXT: }
+; CHECK-NEXT: {
+; CHECK-NEXT: jumpr r31
+; CHECK-NEXT: }
+
+define float @sfmpy_return(float %a, float %b) {
+ %m = fmul float %a, %b
+ ret float %m
+}
+
+; -----------------------------------------------------------------------------
+; TC3x scalar multiply feeding the return-value register: same hazard as
+; sfmpy_return, exercised for the TC3x path.
+
+; CHECK-LABEL: mpyi_return:
+; CHECK: r0 = {{[+]?}}mpyi(r0,#3)
+; CHECK-NEXT: }
+; CHECK-NEXT: {
+; CHECK-NEXT: jumpr r31
+; CHECK-NEXT: }
+
+define i32 @mpyi_return(i32 %a) {
+ %m = mul i32 %a, 3
+ ret i32 %m
+}
diff --git a/llvm/test/CodeGen/Hexagon/simple_addend.ll b/llvm/test/CodeGen/Hexagon/simple_addend.ll
index 909a43f6eac84..aaeed862ad661 100644
--- a/llvm/test/CodeGen/Hexagon/simple_addend.ll
+++ b/llvm/test/CodeGen/Hexagon/simple_addend.ll
@@ -7,4 +7,7 @@ define void @foo(i32 %a) {
call void @bar(i32 %b)
ret void
}
-; CHECK: 0x4 R_HEX_B22_PCREL bar 0x4
+; The scalar multiply on SLOT2/SLOT3 is a multi-cycle (TC3x) producer whose
+; write reaches the register file too late to be observed by a co-packetized
+; call, so the multiply and the call must live in separate packets.
+; CHECK: 0x8 R_HEX_B22_PCREL bar 0x0
diff --git a/llvm/test/CodeGen/Hexagon/tc_sched1.ll b/llvm/test/CodeGen/Hexagon/tc_sched1.ll
index 345665e34d0aa..dd9fe9c55f48d 100644
--- a/llvm/test/CodeGen/Hexagon/tc_sched1.ll
+++ b/llvm/test/CodeGen/Hexagon/tc_sched1.ll
@@ -13,7 +13,7 @@
; CHECK: memw
; CHECK: }
; CHECK: += mpyi
-; CHECK-NOT: }
+; CHECK: }
; CHECK: jumpr
; CHECK: }
``````````
</details>
https://github.com/llvm/llvm-project/pull/227178
More information about the llvm-commits
mailing list