[llvm] [Hexagon] Disable pipelining of double-word memory loops (PR #226547)

Brian Cain via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 25 18:06:05 PDT 2026


https://github.com/androm3da updated https://github.com/llvm/llvm-project/pull/226547

>From d703936d59a0c8d4a42951a9a32a54f37da321aa Mon Sep 17 00:00:00 2001
From: Brian Cain <brian.cain at oss.qualcomm.com>
Date: Fri, 25 Sep 2026 12:15:06 -0500
Subject: [PATCH] [Hexagon] Disable pipelining of double-word memory loops

The modulo-schedule expander can miscompile a loop-carried double-word
memory recurrence by using a prolog value in place of a value from an earlier
iteration. Decline software pipelining for Hexagon loops with double-word
memory operands until the generic expander can preserve these dependences.

Fixes #209946
---
 llvm/lib/Target/Hexagon/HexagonInstrInfo.cpp |  15 +++
 llvm/test/CodeGen/Hexagon/swp-sha512.ll      | 123 +++++++++++++++++++
 2 files changed, 138 insertions(+)
 create mode 100644 llvm/test/CodeGen/Hexagon/swp-sha512.ll

diff --git a/llvm/lib/Target/Hexagon/HexagonInstrInfo.cpp b/llvm/lib/Target/Hexagon/HexagonInstrInfo.cpp
index b31724f094ec72..c9de09da303262 100644
--- a/llvm/lib/Target/Hexagon/HexagonInstrInfo.cpp
+++ b/llvm/lib/Target/Hexagon/HexagonInstrInfo.cpp
@@ -807,6 +807,21 @@ class HexagonPipelinerLoopInfo : public TargetInstrInfo::PipelinerLoopInfo {
 std::unique_ptr<TargetInstrInfo::PipelinerLoopInfo>
 HexagonInstrInfo::analyzeLoopForPipelining(MachineBasicBlock *LoopBB) const {
   // We really "analyze" only hardware loops right now.
+  const MachineRegisterInfo &MRI = LoopBB->getParent()->getRegInfo();
+  for (const MachineInstr &MI : *LoopBB) {
+    // Modulo variable expansion mishandles scalar 64-bit values written by a
+    // double-word store.  Vector stores and double-word loads are safe: they
+    // do not create the problematic recurrence.
+    if (!MI.mayStore())
+      continue;
+    for (const MachineOperand &MO : MI.operands())
+      if (MO.isReg() && MO.getReg().isVirtual() &&
+          Hexagon::DoubleRegsRegClass.hasSubClassEq(
+              MRI.getRegClass(MO.getReg())) &&
+          MRI.getType(MO.getReg()).isScalar(64))
+        return nullptr;
+  }
+
   MachineBasicBlock::iterator I = LoopBB->getFirstTerminator();
 
   if (I != LoopBB->end() && isEndLoopN(I->getOpcode())) {
diff --git a/llvm/test/CodeGen/Hexagon/swp-sha512.ll b/llvm/test/CodeGen/Hexagon/swp-sha512.ll
new file mode 100644
index 00000000000000..e0e02c9af43472
--- /dev/null
+++ b/llvm/test/CodeGen/Hexagon/swp-sha512.ll
@@ -0,0 +1,123 @@
+; RUN: llc -mtriple=hexagon -mcpu=hexagonv68 -O2 < %s | FileCheck %s
+; RUN: llc -mtriple=hexagon -mcpu=hexagonv68 -O2 -stats -o /dev/null < %s 2>&1 \
+; RUN:   | FileCheck --check-prefix=STATS %s
+
+; SHA-512 message-schedule recurrence from #209946.
+; CHECK-LABEL: schedule:
+; CHECK:       loop0(.LBB{{[0-9]+}}_1,#15)
+; CHECK:       .LBB{{[0-9]+}}_1:
+; CHECK:       memd(r{{[0-9]+}}+#48) = r{{[0-9]+}}:{{[0-9]+}}
+; CHECK:       memd(r{{[0-9]+}}+#56) = r{{[0-9]+}}:{{[0-9]+}}
+; CHECK:       memd(r{{[0-9]+}}+#64) = r{{[0-9]+}}:{{[0-9]+}}
+; CHECK:       memd(r{{[0-9]+}}+#72) = r{{[0-9]+}}:{{[0-9]+}}
+; CHECK:       } :endloop0
+
+; STATS-NOT: 1 pipeliner   - Number of loops software pipelined
+
+; ModuleID = 'swp-sha512.c'
+source_filename = "swp-sha512.c"
+target triple = "hexagon-unknown-linux-musl"
+
+define void @schedule(ptr %W) {
+entry:
+  br label %for.body
+
+for.cond.cleanup:                                 ; preds = %for.body
+  ret void
+
+for.body:                                         ; preds = %for.body, %entry
+  %i.066 = phi i32 [ 16, %entry ], [ %inc.3, %for.body ]
+  %0 = getelementptr i64, ptr %W, i32 %i.066
+  %arrayidx = getelementptr i8, ptr %0, i32 -120
+  %1 = load i64, ptr %arrayidx, align 8
+  %or = call i64 @llvm.fshl.i64(i64 %1, i64 %1, i64 63)
+  %or9 = call i64 @llvm.fshl.i64(i64 %1, i64 %1, i64 56)
+  %xor = xor i64 %or, %or9
+  %shr12 = lshr i64 %1, 7
+  %xor13 = xor i64 %xor, %shr12
+  %arrayidx15 = getelementptr i8, ptr %0, i32 -16
+  %2 = load i64, ptr %arrayidx15, align 8
+  %or20 = call i64 @llvm.fshl.i64(i64 %2, i64 %2, i64 45)
+  %or27 = call i64 @llvm.fshl.i64(i64 %2, i64 %2, i64 3)
+  %xor28 = xor i64 %or20, %or27
+  %shr31 = lshr i64 %2, 6
+  %xor32 = xor i64 %xor28, %shr31
+  %arrayidx34 = getelementptr i8, ptr %0, i32 -128
+  %3 = load i64, ptr %arrayidx34, align 8
+  %add = add i64 %xor13, %3
+  %arrayidx36 = getelementptr i8, ptr %0, i32 -56
+  %4 = load i64, ptr %arrayidx36, align 8
+  %add37 = add i64 %add, %4
+  %add38 = add i64 %add37, %xor32
+  store i64 %add38, ptr %0, align 8
+  %5 = getelementptr i64, ptr %W, i32 %i.066
+  %6 = getelementptr i8, ptr %5, i32 8
+  %arrayidx.1 = getelementptr i8, ptr %5, i32 -112
+  %7 = load i64, ptr %arrayidx.1, align 8
+  %or.1 = call i64 @llvm.fshl.i64(i64 %7, i64 %7, i64 63)
+  %or9.1 = call i64 @llvm.fshl.i64(i64 %7, i64 %7, i64 56)
+  %xor.1 = xor i64 %or.1, %or9.1
+  %shr12.1 = lshr i64 %7, 7
+  %xor13.1 = xor i64 %xor.1, %shr12.1
+  %arrayidx15.1 = getelementptr i8, ptr %5, i32 -8
+  %8 = load i64, ptr %arrayidx15.1, align 8
+  %or20.1 = call i64 @llvm.fshl.i64(i64 %8, i64 %8, i64 45)
+  %or27.1 = call i64 @llvm.fshl.i64(i64 %8, i64 %8, i64 3)
+  %xor28.1 = xor i64 %or20.1, %or27.1
+  %shr31.1 = lshr i64 %8, 6
+  %xor32.1 = xor i64 %xor28.1, %shr31.1
+  %add.1 = add i64 %xor13.1, %1
+  %arrayidx36.1 = getelementptr i8, ptr %5, i32 -48
+  %9 = load i64, ptr %arrayidx36.1, align 8
+  %add37.1 = add i64 %add.1, %9
+  %add38.1 = add i64 %add37.1, %xor32.1
+  store i64 %add38.1, ptr %6, align 8
+  %10 = getelementptr i64, ptr %W, i32 %i.066
+  %11 = getelementptr i8, ptr %10, i32 16
+  %arrayidx.2 = getelementptr i8, ptr %10, i32 -104
+  %12 = load i64, ptr %arrayidx.2, align 8
+  %or.2 = call i64 @llvm.fshl.i64(i64 %12, i64 %12, i64 63)
+  %or9.2 = call i64 @llvm.fshl.i64(i64 %12, i64 %12, i64 56)
+  %xor.2 = xor i64 %or.2, %or9.2
+  %shr12.2 = lshr i64 %12, 7
+  %xor13.2 = xor i64 %xor.2, %shr12.2
+  %13 = load i64, ptr %10, align 8
+  %or20.2 = call i64 @llvm.fshl.i64(i64 %13, i64 %13, i64 45)
+  %or27.2 = call i64 @llvm.fshl.i64(i64 %13, i64 %13, i64 3)
+  %xor28.2 = xor i64 %or20.2, %or27.2
+  %shr31.2 = lshr i64 %13, 6
+  %xor32.2 = xor i64 %xor28.2, %shr31.2
+  %add.2 = add i64 %xor13.2, %7
+  %arrayidx36.2 = getelementptr i8, ptr %10, i32 -40
+  %14 = load i64, ptr %arrayidx36.2, align 8
+  %add37.2 = add i64 %add.2, %14
+  %add38.2 = add i64 %add37.2, %xor32.2
+  store i64 %add38.2, ptr %11, align 8
+  %15 = getelementptr i64, ptr %W, i32 %i.066
+  %16 = getelementptr i8, ptr %15, i32 24
+  %arrayidx.3 = getelementptr i8, ptr %15, i32 -96
+  %17 = load i64, ptr %arrayidx.3, align 8
+  %or.3 = call i64 @llvm.fshl.i64(i64 %17, i64 %17, i64 63)
+  %or9.3 = call i64 @llvm.fshl.i64(i64 %17, i64 %17, i64 56)
+  %xor.3 = xor i64 %or.3, %or9.3
+  %shr12.3 = lshr i64 %17, 7
+  %xor13.3 = xor i64 %xor.3, %shr12.3
+  %arrayidx15.3 = getelementptr i8, ptr %15, i32 8
+  %18 = load i64, ptr %arrayidx15.3, align 8
+  %or20.3 = call i64 @llvm.fshl.i64(i64 %18, i64 %18, i64 45)
+  %or27.3 = call i64 @llvm.fshl.i64(i64 %18, i64 %18, i64 3)
+  %xor28.3 = xor i64 %or20.3, %or27.3
+  %shr31.3 = lshr i64 %18, 6
+  %xor32.3 = xor i64 %xor28.3, %shr31.3
+  %add.3 = add i64 %xor13.3, %12
+  %arrayidx36.3 = getelementptr i8, ptr %15, i32 -32
+  %19 = load i64, ptr %arrayidx36.3, align 8
+  %add37.3 = add i64 %add.3, %19
+  %add38.3 = add i64 %add37.3, %xor32.3
+  store i64 %add38.3, ptr %16, align 8
+  %inc.3 = add i32 %i.066, 4
+  %exitcond.not.3 = icmp eq i32 %inc.3, 80
+  br i1 %exitcond.not.3, label %for.cond.cleanup, label %for.body
+}
+
+declare i64 @llvm.fshl.i64(i64, i64, i64)



More information about the llvm-commits mailing list