[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