[llvm] 297c739 - [SLP][NFC]Add a test with reassociated fmul/fadd/fsub missed in fma, NFC

via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 11 11:58:41 PDT 2026


Author: Alexey Bataev
Date: 2026-08-11T14:58:35-04:00
New Revision: 297c739709b51dfcd9bb447f8210b525cc4a0d49

URL: https://github.com/llvm/llvm-project/commit/297c739709b51dfcd9bb447f8210b525cc4a0d49
DIFF: https://github.com/llvm/llvm-project/commit/297c739709b51dfcd9bb447f8210b525cc4a0d49.diff

LOG: [SLP][NFC]Add a test with reassociated fmul/fadd/fsub missed in fma, NFC



Reviewers: 

Pull Request: https://github.com/llvm/llvm-project/pull/215642

Added: 
    llvm/test/Transforms/SLPVectorizer/X86/horizontal-fadd-with-sub.ll

Modified: 
    

Removed: 
    


################################################################################
diff  --git a/llvm/test/Transforms/SLPVectorizer/X86/horizontal-fadd-with-sub.ll b/llvm/test/Transforms/SLPVectorizer/X86/horizontal-fadd-with-sub.ll
new file mode 100644
index 0000000000000..8a66d57ef46b0
--- /dev/null
+++ b/llvm/test/Transforms/SLPVectorizer/X86/horizontal-fadd-with-sub.ll
@@ -0,0 +1,181 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt -S --passes=slp-vectorizer -mtriple=x86_64-unknown-linux-gnu -mcpu=znver4 < %s | FileCheck %s
+
+; An fadd reduction over an fsub/fneg chain is flattened with per-operand
+; signs, so subtracted leaves are vectorized and subtracted in the final
+; combine, forming per-lane fma.
+
+define double @fsub_fmul_2(ptr %x, ptr %y, ptr %z) {
+; CHECK-LABEL: define double @fsub_fmul_2(
+; CHECK-SAME: ptr [[X:%.*]], ptr [[Y:%.*]], ptr [[Z:%.*]]) #[[ATTR0:[0-9]+]] {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[Z8:%.*]] = getelementptr inbounds nuw i8, ptr [[Z]], i64 8
+; CHECK-NEXT:    [[Z0:%.*]] = load double, ptr [[Z]], align 8
+; CHECK-NEXT:    [[TMP2:%.*]] = load <2 x double>, ptr [[X]], align 8
+; CHECK-NEXT:    [[TMP1:%.*]] = load <2 x double>, ptr [[Y]], align 8
+; CHECK-NEXT:    [[TMP3:%.*]] = fmul reassoc nsz contract <2 x double> [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    [[Z1:%.*]] = load double, ptr [[Z8]], align 8
+; CHECK-NEXT:    [[ZSUM:%.*]] = fadd reassoc nsz contract double [[Z0]], [[Z1]]
+; CHECK-NEXT:    [[TMP5:%.*]] = extractelement <2 x double> [[TMP3]], i64 0
+; CHECK-NEXT:    [[SUB:%.*]] = fsub reassoc nsz contract double [[TMP5]], [[ZSUM]]
+; CHECK-NEXT:    [[TMP4:%.*]] = extractelement <2 x double> [[TMP3]], i64 1
+; CHECK-NEXT:    [[TMP6:%.*]] = fadd reassoc nsz contract double [[SUB]], [[TMP4]]
+; CHECK-NEXT:    ret double [[TMP6]]
+;
+entry:
+  %x8 = getelementptr inbounds nuw i8, ptr %x, i64 8
+  %y8 = getelementptr inbounds nuw i8, ptr %y, i64 8
+  %z8 = getelementptr inbounds nuw i8, ptr %z, i64 8
+  %x0 = load double, ptr %x, align 8
+  %y0 = load double, ptr %y, align 8
+  %mul = fmul reassoc nsz contract double %y0, %x0
+  %z0 = load double, ptr %z, align 8
+  %x1 = load double, ptr %x8, align 8
+  %y1 = load double, ptr %y8, align 8
+  %mul5 = fmul reassoc nsz contract double %y1, %x1
+  %z1 = load double, ptr %z8, align 8
+  %zsum = fadd reassoc nsz contract double %z0, %z1
+  %sub = fsub reassoc nsz contract double %mul, %zsum
+  %add = fadd reassoc nsz contract double %sub, %mul5
+  ret double %add
+}
+
+define double @fsub_fmul_4(ptr %x, ptr %y, ptr %z) {
+; CHECK-LABEL: define double @fsub_fmul_4(
+; CHECK-SAME: ptr [[X:%.*]], ptr [[Y:%.*]], ptr [[Z:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[X8:%.*]] = getelementptr inbounds nuw i8, ptr [[X]], i64 8
+; CHECK-NEXT:    [[Y8:%.*]] = getelementptr inbounds nuw i8, ptr [[Y]], i64 8
+; CHECK-NEXT:    [[X24:%.*]] = getelementptr inbounds nuw i8, ptr [[X]], i64 24
+; CHECK-NEXT:    [[Y24:%.*]] = getelementptr inbounds nuw i8, ptr [[Y]], i64 24
+; CHECK-NEXT:    [[X0:%.*]] = load double, ptr [[X]], align 8
+; CHECK-NEXT:    [[Y0:%.*]] = load double, ptr [[Y]], align 8
+; CHECK-NEXT:    [[MUL:%.*]] = fmul reassoc nsz contract double [[Y0]], [[X0]]
+; CHECK-NEXT:    [[TMP0:%.*]] = load <2 x double>, ptr [[X8]], align 8
+; CHECK-NEXT:    [[TMP1:%.*]] = load <2 x double>, ptr [[Y8]], align 8
+; CHECK-NEXT:    [[TMP2:%.*]] = fmul reassoc nsz contract <2 x double> [[TMP1]], [[TMP0]]
+; CHECK-NEXT:    [[X3:%.*]] = load double, ptr [[X24]], align 8
+; CHECK-NEXT:    [[Y3:%.*]] = load double, ptr [[Y24]], align 8
+; CHECK-NEXT:    [[MUL16:%.*]] = fmul reassoc nsz contract double [[Y3]], [[X3]]
+; CHECK-NEXT:    [[TMP3:%.*]] = load <4 x double>, ptr [[Z]], align 8
+; CHECK-NEXT:    [[TMP4:%.*]] = extractelement <2 x double> [[TMP2]], i64 0
+; CHECK-NEXT:    [[T1:%.*]] = fadd reassoc nsz contract double [[MUL]], [[TMP4]]
+; CHECK-NEXT:    [[TMP7:%.*]] = extractelement <2 x double> [[TMP2]], i64 1
+; CHECK-NEXT:    [[T3:%.*]] = fadd reassoc nsz contract double [[T1]], [[TMP7]]
+; CHECK-NEXT:    [[TMP6:%.*]] = call reassoc nsz contract double @llvm.vector.reduce.fadd.v4f64(double 0.000000e+00, <4 x double> [[TMP3]])
+; CHECK-NEXT:    [[ADD13:%.*]] = fsub reassoc nsz contract double [[T3]], [[TMP6]]
+; CHECK-NEXT:    [[TMP5:%.*]] = fadd reassoc nsz contract double [[ADD13]], [[MUL16]]
+; CHECK-NEXT:    ret double [[TMP5]]
+;
+entry:
+  %x8 = getelementptr inbounds nuw i8, ptr %x, i64 8
+  %y8 = getelementptr inbounds nuw i8, ptr %y, i64 8
+  %z8 = getelementptr inbounds nuw i8, ptr %z, i64 8
+  %x16 = getelementptr inbounds nuw i8, ptr %x, i64 16
+  %y16 = getelementptr inbounds nuw i8, ptr %y, i64 16
+  %z16 = getelementptr inbounds nuw i8, ptr %z, i64 16
+  %x24 = getelementptr inbounds nuw i8, ptr %x, i64 24
+  %y24 = getelementptr inbounds nuw i8, ptr %y, i64 24
+  %z24 = getelementptr inbounds nuw i8, ptr %z, i64 24
+  %x0 = load double, ptr %x, align 8
+  %y0 = load double, ptr %y, align 8
+  %mul = fmul reassoc nsz contract double %y0, %x0
+  %z0 = load double, ptr %z, align 8
+  %x1 = load double, ptr %x8, align 8
+  %y1 = load double, ptr %y8, align 8
+  %mul5 = fmul reassoc nsz contract double %y1, %x1
+  %z1 = load double, ptr %z8, align 8
+  %x2 = load double, ptr %x16, align 8
+  %y2 = load double, ptr %y16, align 8
+  %mul10 = fmul reassoc nsz contract double %y2, %x2
+  %z2 = load double, ptr %z16, align 8
+  %x3 = load double, ptr %x24, align 8
+  %y3 = load double, ptr %y24, align 8
+  %mul16 = fmul reassoc nsz contract double %y3, %x3
+  %z3 = load double, ptr %z24, align 8
+  %t0 = fadd reassoc nsz contract double %z0, %z1
+  %t1 = fadd reassoc nsz contract double %mul, %mul5
+  %t2 = fadd reassoc nsz contract double %t0, %z2
+  %t3 = fadd reassoc nsz contract double %t1, %mul10
+  %t4 = fadd reassoc nsz contract double %t2, %z3
+  %add13 = fsub reassoc nsz contract double %t3, %t4
+  %add19 = fadd reassoc nsz contract double %add13, %mul16
+  ret double %add19
+}
+
+; fneg leaves in the chain are flattened and subtracted too.
+define double @fneg_chain_2(ptr %x, ptr %y, ptr %z) {
+; CHECK-LABEL: define double @fneg_chain_2(
+; CHECK-SAME: ptr [[X:%.*]], ptr [[Y:%.*]], ptr [[Z:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[X8:%.*]] = getelementptr inbounds nuw i8, ptr [[X]], i64 8
+; CHECK-NEXT:    [[Y8:%.*]] = getelementptr inbounds nuw i8, ptr [[Y]], i64 8
+; CHECK-NEXT:    [[X0:%.*]] = load double, ptr [[X]], align 8
+; CHECK-NEXT:    [[Y0:%.*]] = load double, ptr [[Y]], align 8
+; CHECK-NEXT:    [[MUL:%.*]] = fmul reassoc nsz contract double [[Y0]], [[X0]]
+; CHECK-NEXT:    [[X1:%.*]] = load double, ptr [[X8]], align 8
+; CHECK-NEXT:    [[Y1:%.*]] = load double, ptr [[Y8]], align 8
+; CHECK-NEXT:    [[MUL5:%.*]] = fmul reassoc nsz contract double [[Y1]], [[X1]]
+; CHECK-NEXT:    [[TMP3:%.*]] = load <2 x double>, ptr [[Z]], align 8
+; CHECK-NEXT:    [[TMP4:%.*]] = fneg reassoc nsz contract <2 x double> [[TMP3]]
+; CHECK-NEXT:    [[TMP2:%.*]] = extractelement <2 x double> [[TMP4]], i64 0
+; CHECK-NEXT:    [[T:%.*]] = fadd reassoc nsz contract double [[MUL]], [[TMP2]]
+; CHECK-NEXT:    [[TMP6:%.*]] = extractelement <2 x double> [[TMP4]], i64 1
+; CHECK-NEXT:    [[T2:%.*]] = fadd reassoc nsz contract double [[T]], [[TMP6]]
+; CHECK-NEXT:    [[TMP5:%.*]] = fadd reassoc nsz contract double [[T2]], [[MUL5]]
+; CHECK-NEXT:    ret double [[TMP5]]
+;
+entry:
+  %x8 = getelementptr inbounds nuw i8, ptr %x, i64 8
+  %y8 = getelementptr inbounds nuw i8, ptr %y, i64 8
+  %z8 = getelementptr inbounds nuw i8, ptr %z, i64 8
+  %x0 = load double, ptr %x, align 8
+  %y0 = load double, ptr %y, align 8
+  %mul = fmul reassoc nsz contract double %y0, %x0
+  %z0 = load double, ptr %z, align 8
+  %x1 = load double, ptr %x8, align 8
+  %y1 = load double, ptr %y8, align 8
+  %mul5 = fmul reassoc nsz contract double %y1, %x1
+  %z1 = load double, ptr %z8, align 8
+  %negz0 = fneg reassoc nsz contract double %z0
+  %negz1 = fneg reassoc nsz contract double %z1
+  %t = fadd reassoc nsz contract double %mul, %negz0
+  %t2 = fadd reassoc nsz contract double %t, %negz1
+  %add = fadd reassoc nsz contract double %t2, %mul5
+  ret double %add
+}
+
+; A negated value used twice is scaled and negated.
+define double @negated_reused(ptr %x, ptr %y, ptr %z) {
+; CHECK-LABEL: define double @negated_reused(
+; CHECK-SAME: ptr [[X:%.*]], ptr [[Y:%.*]], ptr [[Z:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[X8:%.*]] = getelementptr inbounds nuw i8, ptr [[X]], i64 8
+; CHECK-NEXT:    [[Y8:%.*]] = getelementptr inbounds nuw i8, ptr [[Y]], i64 8
+; CHECK-NEXT:    [[X0:%.*]] = load double, ptr [[X]], align 8
+; CHECK-NEXT:    [[Y0:%.*]] = load double, ptr [[Y]], align 8
+; CHECK-NEXT:    [[MUL:%.*]] = fmul reassoc nsz contract double [[Y0]], [[X0]]
+; CHECK-NEXT:    [[Z0:%.*]] = load double, ptr [[Z]], align 8
+; CHECK-NEXT:    [[X1:%.*]] = load double, ptr [[X8]], align 8
+; CHECK-NEXT:    [[Y1:%.*]] = load double, ptr [[Y8]], align 8
+; CHECK-NEXT:    [[MUL5:%.*]] = fmul reassoc nsz contract double [[Y1]], [[X1]]
+; CHECK-NEXT:    [[TMP4:%.*]] = fsub reassoc nsz contract double [[MUL]], [[Z0]]
+; CHECK-NEXT:    [[TMP5:%.*]] = fsub reassoc nsz contract double [[MUL5]], [[Z0]]
+; CHECK-NEXT:    [[OP_RDX:%.*]] = fadd reassoc nsz contract double [[TMP4]], [[TMP5]]
+; CHECK-NEXT:    ret double [[OP_RDX]]
+;
+entry:
+  %x8 = getelementptr inbounds nuw i8, ptr %x, i64 8
+  %y8 = getelementptr inbounds nuw i8, ptr %y, i64 8
+  %x0 = load double, ptr %x, align 8
+  %y0 = load double, ptr %y, align 8
+  %mul = fmul reassoc nsz contract double %y0, %x0
+  %z0 = load double, ptr %z, align 8
+  %x1 = load double, ptr %x8, align 8
+  %y1 = load double, ptr %y8, align 8
+  %mul5 = fmul reassoc nsz contract double %y1, %x1
+  %sub = fsub reassoc nsz contract double %mul, %z0
+  %sub7 = fsub reassoc nsz contract double %mul5, %z0
+  %add = fadd reassoc nsz contract double %sub, %sub7
+  ret double %add
+}


        


More information about the llvm-commits mailing list