[llvm] [Reassociate] Add tests for linearizing through fadd,fmul pairs (NFC) (PR #218654)

Hari Limaye via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 25 03:21:25 PDT 2026


https://github.com/hazzlim created https://github.com/llvm/llvm-project/pull/218654

Assisted-by: OpenAI Codex

>From 4c9b26a58d9fa78874a12ebefbb50132667ff71f Mon Sep 17 00:00:00 2001
From: Hari Limaye <hari.limaye at arm.com>
Date: Sun, 23 Aug 2026 13:15:55 +0000
Subject: [PATCH] [Reassociate] Add tests for failure to linearize through
 fmul,fadd pairs (NFC)

---
 .../AArch64/reassociate-fma-pairs.ll          | 130 ++++++++++++++++++
 llvm/test/Transforms/Reassociate/fma-pairs.ll |  53 +++++++
 2 files changed, 183 insertions(+)
 create mode 100644 llvm/test/Transforms/PhaseOrdering/AArch64/reassociate-fma-pairs.ll

diff --git a/llvm/test/Transforms/PhaseOrdering/AArch64/reassociate-fma-pairs.ll b/llvm/test/Transforms/PhaseOrdering/AArch64/reassociate-fma-pairs.ll
new file mode 100644
index 0000000000000..63478d24837b0
--- /dev/null
+++ b/llvm/test/Transforms/PhaseOrdering/AArch64/reassociate-fma-pairs.ll
@@ -0,0 +1,130 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -S -passes='default<O3>' -mtriple=aarch64 < %s | FileCheck %s
+
+; This is derived from the calculations in a molecular dynamics benchmark. The
+; reassociation of the final expression affects whether SLP can vectorize the
+; shared coefficient products and the energy update.
+
+define double @md_vdw_energy(ptr nocapture readonly %coeffs, double %energy, double %scale, double %table.delta, i64 %n) {
+; CHECK-LABEL: define double @md_vdw_energy(
+; CHECK-SAME: ptr readonly captures(none) [[COEFFS:%.*]], double [[ENERGY:%.*]], double [[SCALE:%.*]], double [[TABLE_DELTA:%.*]], i64 [[N:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    [[TMP0:%.*]] = fmul fast double [[TABLE_DELTA]], [[TABLE_DELTA]]
+; CHECK-NEXT:    [[FACTOR_OP_FMUL:%.*]] = fmul fast double [[TMP0]], f0x3FC5555555555555
+; CHECK-NEXT:    [[FACTOR_OP_FMUL5:%.*]] = fmul fast double [[TABLE_DELTA]], -5.000000e-01
+; CHECK-NEXT:    [[TMP1:%.*]] = fneg fast double [[TABLE_DELTA]]
+; CHECK-NEXT:    [[FACTOR_OP_FMUL6:%.*]] = fmul fast double [[FACTOR_OP_FMUL]], [[TMP1]]
+; CHECK-NEXT:    [[FACTOR_OP_FMUL7:%.*]] = fmul fast double [[TMP0]], -2.500000e-01
+; CHECK-NEXT:    br label %[[LOOP:.*]]
+; CHECK:       [[LOOP]]:
+; CHECK-NEXT:    [[I:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[NEXT:%.*]], %[[LOOP]] ]
+; CHECK-NEXT:    [[ACC:%.*]] = phi double [ [[ENERGY]], %[[ENTRY]] ], [ [[RESULT:%.*]], %[[LOOP]] ]
+; CHECK-NEXT:    [[BASE:%.*]] = getelementptr inbounds [8 x i8], ptr [[COEFFS]], i64 [[I]]
+; CHECK-NEXT:    [[A:%.*]] = load double, ptr [[BASE]], align 8
+; CHECK-NEXT:    [[B_PTR:%.*]] = getelementptr inbounds nuw i8, ptr [[BASE]], i64 8
+; CHECK-NEXT:    [[B:%.*]] = load double, ptr [[B_PTR]], align 8
+; CHECK-NEXT:    [[AB:%.*]] = fmul fast double [[A]], [[SCALE]]
+; CHECK-NEXT:    [[BB:%.*]] = fmul fast double [[B]], [[SCALE]]
+; CHECK-NEXT:    [[C0_PTR:%.*]] = getelementptr inbounds nuw i8, ptr [[BASE]], i64 16
+; CHECK-NEXT:    [[C0:%.*]] = load double, ptr [[C0_PTR]], align 8
+; CHECK-NEXT:    [[C1_PTR:%.*]] = getelementptr inbounds nuw i8, ptr [[BASE]], i64 24
+; CHECK-NEXT:    [[C1:%.*]] = load double, ptr [[C1_PTR]], align 8
+; CHECK-NEXT:    [[P0:%.*]] = fmul fast double [[C0]], [[AB]]
+; CHECK-NEXT:    [[Q0:%.*]] = fmul fast double [[C1]], [[BB]]
+; CHECK-NEXT:    [[D0:%.*]] = fsub fast double [[P0]], [[Q0]]
+; CHECK-NEXT:    [[C2_PTR:%.*]] = getelementptr inbounds nuw i8, ptr [[BASE]], i64 32
+; CHECK-NEXT:    [[C2:%.*]] = load double, ptr [[C2_PTR]], align 8
+; CHECK-NEXT:    [[C3_PTR:%.*]] = getelementptr inbounds nuw i8, ptr [[BASE]], i64 40
+; CHECK-NEXT:    [[C3:%.*]] = load double, ptr [[C3_PTR]], align 8
+; CHECK-NEXT:    [[P1:%.*]] = fmul fast double [[C2]], [[AB]]
+; CHECK-NEXT:    [[Q1:%.*]] = fmul fast double [[C3]], [[BB]]
+; CHECK-NEXT:    [[D1:%.*]] = fsub fast double [[P1]], [[Q1]]
+; CHECK-NEXT:    [[C4_PTR:%.*]] = getelementptr inbounds nuw i8, ptr [[BASE]], i64 48
+; CHECK-NEXT:    [[C4:%.*]] = load double, ptr [[C4_PTR]], align 8
+; CHECK-NEXT:    [[C5_PTR:%.*]] = getelementptr inbounds nuw i8, ptr [[BASE]], i64 56
+; CHECK-NEXT:    [[C5:%.*]] = load double, ptr [[C5_PTR]], align 8
+; CHECK-NEXT:    [[P2:%.*]] = fmul fast double [[C4]], [[AB]]
+; CHECK-NEXT:    [[Q2:%.*]] = fmul fast double [[C5]], [[BB]]
+; CHECK-NEXT:    [[D2:%.*]] = fsub fast double [[P2]], [[Q2]]
+; CHECK-NEXT:    [[C6_PTR:%.*]] = getelementptr inbounds nuw i8, ptr [[BASE]], i64 64
+; CHECK-NEXT:    [[C6:%.*]] = load double, ptr [[C6_PTR]], align 8
+; CHECK-NEXT:    [[C7_PTR:%.*]] = getelementptr inbounds nuw i8, ptr [[BASE]], i64 72
+; CHECK-NEXT:    [[C7:%.*]] = load double, ptr [[C7_PTR]], align 8
+; CHECK-NEXT:    [[T1_REASS_REASS_REASS:%.*]] = fmul fast double [[FACTOR_OP_FMUL6]], [[D0]]
+; CHECK-NEXT:    [[T2_REASS_REASS_REASS:%.*]] = fmul fast double [[D1]], [[FACTOR_OP_FMUL7]]
+; CHECK-NEXT:    [[S0:%.*]] = fadd fast double [[T2_REASS_REASS_REASS]], [[T1_REASS_REASS_REASS]]
+; CHECK-NEXT:    [[T4_REASS_REASS:%.*]] = fmul fast double [[D2]], [[FACTOR_OP_FMUL5]]
+; CHECK-NEXT:    [[S1:%.*]] = fadd fast double [[S0]], [[T4_REASS_REASS]]
+; CHECK-NEXT:    [[Q3_NEG_NEG:%.*]] = fmul fast double [[C7]], [[BB]]
+; CHECK-NEXT:    [[TMP2:%.*]] = fmul fast double [[AB]], [[C6]]
+; CHECK-NEXT:    [[D3_NEG:%.*]] = fsub fast double [[ACC]], [[TMP2]]
+; CHECK-NEXT:    [[S2_NEG:%.*]] = fadd fast double [[Q3_NEG_NEG]], [[D3_NEG]]
+; CHECK-NEXT:    [[RESULT]] = fadd fast double [[S1]], [[S2_NEG]]
+; CHECK-NEXT:    [[NEXT]] = add nuw i64 [[I]], 10
+; CHECK-NEXT:    [[DONE_NOT:%.*]] = icmp ult i64 [[NEXT]], [[N]]
+; CHECK-NEXT:    br i1 [[DONE_NOT]], label %[[LOOP]], label %[[EXIT:.*]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    ret double [[RESULT]]
+;
+entry:
+  br label %loop
+
+loop:
+  %i = phi i64 [ 0, %entry ], [ %next, %loop ]
+  %acc = phi double [ %energy, %entry ], [ %result, %loop ]
+  %base = getelementptr inbounds double, ptr %coeffs, i64 %i
+  %a = load double, ptr %base, align 8
+  %b.ptr = getelementptr inbounds double, ptr %base, i64 1
+  %b = load double, ptr %b.ptr, align 8
+  %ab = fmul fast double %scale, %a
+  %bb = fmul fast double %scale, %b
+
+  %c0.ptr = getelementptr inbounds double, ptr %base, i64 2
+  %c0 = load double, ptr %c0.ptr, align 8
+  %c1.ptr = getelementptr inbounds double, ptr %base, i64 3
+  %c1 = load double, ptr %c1.ptr, align 8
+  %p0 = fmul fast double %ab, %c0
+  %q0 = fmul fast double %bb, %c1
+  %d0 = fsub fast double %p0, %q0
+
+  %c2.ptr = getelementptr inbounds double, ptr %base, i64 4
+  %c2 = load double, ptr %c2.ptr, align 8
+  %c3.ptr = getelementptr inbounds double, ptr %base, i64 5
+  %c3 = load double, ptr %c3.ptr, align 8
+  %p1 = fmul fast double %ab, %c2
+  %q1 = fmul fast double %bb, %c3
+  %d1 = fsub fast double %p1, %q1
+
+  %c4.ptr = getelementptr inbounds double, ptr %base, i64 6
+  %c4 = load double, ptr %c4.ptr, align 8
+  %c5.ptr = getelementptr inbounds double, ptr %base, i64 7
+  %c5 = load double, ptr %c5.ptr, align 8
+  %p2 = fmul fast double %ab, %c4
+  %q2 = fmul fast double %bb, %c5
+  %d2 = fsub fast double %p2, %q2
+
+  %c6.ptr = getelementptr inbounds double, ptr %base, i64 8
+  %c6 = load double, ptr %c6.ptr, align 8
+  %c7.ptr = getelementptr inbounds double, ptr %base, i64 9
+  %c7 = load double, ptr %c7.ptr, align 8
+  %p3 = fmul fast double %ab, %c6
+  %q3 = fmul fast double %bb, %c7
+  %d3 = fsub fast double %p3, %q3
+
+  %t0 = fmul fast double %table.delta, %d0
+  %t1 = fmul fast double %t0, 0x3FC5555555555555
+  %t2 = fmul fast double %d1, 2.500000e-01
+  %s0 = fadd fast double %t1, %t2
+  %t3 = fmul fast double %s0, %table.delta
+  %t4 = fmul fast double %d2, 5.000000e-01
+  %s1 = fadd fast double %t3, %t4
+  %t5 = fmul fast double %s1, %table.delta
+  %s2 = fadd fast double %t5, %d3
+  %result = fsub fast double %acc, %s2
+  %next = add nuw i64 %i, 10
+  %done = icmp uge i64 %next, %n
+  br i1 %done, label %exit, label %loop
+
+exit:
+  ret double %result
+}
diff --git a/llvm/test/Transforms/Reassociate/fma-pairs.ll b/llvm/test/Transforms/Reassociate/fma-pairs.ll
index 3c869168ff001..9eeb0f8e37b8a 100644
--- a/llvm/test/Transforms/Reassociate/fma-pairs.ll
+++ b/llvm/test/Transforms/Reassociate/fma-pairs.ll
@@ -405,3 +405,56 @@ define double @const_addend(ptr %x, ptr %y) {
   %r = fadd reassoc nsz contract double %a0, 2.0
   ret double %r
 }
+
+define double @hidden_fadd_tree(double %acc, double %a, double %b, double %c, double %d, double %e, double %f) {
+; CHECK-LABEL: define double @hidden_fadd_tree(
+; CHECK-SAME: double [[ACC:%.*]], double [[A:%.*]], double [[B:%.*]], double [[C:%.*]], double [[D:%.*]], double [[E:%.*]], double [[F:%.*]]) {
+; CHECK-NEXT:    [[ACC0:%.*]] = fadd fast double [[A]], [[B]]
+; CHECK-NEXT:    [[ACC1:%.*]] = fadd fast double [[C]], [[D]]
+; CHECK-NEXT:    [[ACC2:%.*]] = fadd fast double [[B]], [[C]]
+; CHECK-NEXT:    [[ACC3:%.*]] = fadd fast double [[A]], [[D]]
+; CHECK-NEXT:    [[ACC4:%.*]] = fadd fast double [[ACC0]], [[ACC1]]
+; CHECK-NEXT:    [[ACC5:%.*]] = fadd fast double [[ACC2]], [[ACC3]]
+; CHECK-NEXT:    [[ACC6:%.*]] = fadd fast double [[ACC4]], [[ACC5]]
+; CHECK-NEXT:    [[M0:%.*]] = fmul fast double [[F]], [[E]]
+; CHECK-NEXT:    [[ACC7:%.*]] = fadd fast double [[M0]], [[ACC6]]
+; CHECK-NEXT:    [[RESULT:%.*]] = fadd fast double [[ACC7]], [[ACC]]
+; CHECK-NEXT:    ret double [[RESULT]]
+;
+  %acc0 = fadd fast double %a, %b
+  %acc1 = fadd fast double %c, %d
+  %acc2 = fadd fast double %b, %c
+  %acc3 = fadd fast double %d, %a
+  %acc4 = fadd fast double %acc0, %acc1
+  %acc5 = fadd fast double %acc2, %acc3
+  %acc6 = fadd fast double %acc4, %acc5
+
+  %m0 = fmul fast double %e, %f
+  %acc7 = fadd fast double %m0, %acc6
+
+  %result = fadd fast double %acc, %acc7
+  ret double %result
+}
+
+define double @nested_fma_subtraction(double %acc, double %a, double %b, double %c, double %d, double %e, double %f) {
+; CHECK-LABEL: define double @nested_fma_subtraction(
+; CHECK-SAME: double [[ACC:%.*]], double [[A:%.*]], double [[B:%.*]], double [[C:%.*]], double [[D:%.*]], double [[E:%.*]], double [[F:%.*]]) {
+; CHECK-NEXT:    [[M0:%.*]] = fmul fast double [[B]], [[A]]
+; CHECK-NEXT:    [[M2:%.*]] = fmul fast double [[F]], [[E]]
+; CHECK-NEXT:    [[M0_NEG:%.*]] = fmul fast double [[M0]], -1.000000e+00
+; CHECK-NEXT:    [[M1_NEG_NEG:%.*]] = fmul fast double [[D]], [[C]]
+; CHECK-NEXT:    [[M2_NEG:%.*]] = fmul fast double [[M2]], -1.000000e+00
+; CHECK-NEXT:    [[SUB_NEG:%.*]] = fadd fast double [[ACC]], [[M0_NEG]]
+; CHECK-NEXT:    [[ADD_NEG:%.*]] = fadd fast double [[M1_NEG_NEG]], [[SUB_NEG]]
+; CHECK-NEXT:    [[RESULT:%.*]] = fadd fast double [[M2_NEG]], [[ADD_NEG]]
+; CHECK-NEXT:    ret double [[RESULT]]
+;
+  %m0 = fmul fast double %a, %b
+  %m1 = fmul fast double %c, %d
+  %sub = fsub fast double %m0, %m1
+  %m2 = fmul fast double %e, %f
+  %add = fadd fast double %m2, %sub
+  %result = fsub fast double %acc, %add
+  ret double %result
+}
+



More information about the llvm-commits mailing list