[llvm] [SLP][NFC]Add a test for mixed fma/fmuladd scalars, NFC (PR #211280)

Alexey Bataev via llvm-commits llvm-commits at lists.llvm.org
Wed Jul 22 07:52:32 PDT 2026


https://github.com/alexey-bataev created https://github.com/llvm/llvm-project/pull/211280

None

>From 9868ad39ba740f9d636c4c5f82ca8d341cf53043 Mon Sep 17 00:00:00 2001
From: Alexey Bataev <a.bataev at outlook.com>
Date: Wed, 22 Jul 2026 07:52:20 -0700
Subject: [PATCH] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20initia?=
 =?UTF-8?q?l=20version?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Created using spr 1.3.7
---
 .../SLPVectorizer/X86/fma-fmuladd-mix.ll      | 126 ++++++++++++++++++
 1 file changed, 126 insertions(+)
 create mode 100644 llvm/test/Transforms/SLPVectorizer/X86/fma-fmuladd-mix.ll

diff --git a/llvm/test/Transforms/SLPVectorizer/X86/fma-fmuladd-mix.ll b/llvm/test/Transforms/SLPVectorizer/X86/fma-fmuladd-mix.ll
new file mode 100644
index 0000000000000..3179f53823941
--- /dev/null
+++ b/llvm/test/Transforms/SLPVectorizer/X86/fma-fmuladd-mix.ll
@@ -0,0 +1,126 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -mtriple=x86_64-unknown -passes=slp-vectorizer -S | FileCheck %s --check-prefix=NO-FMA
+; RUN: opt < %s -mtriple=x86_64-unknown -mcpu=core-avx2 -passes=slp-vectorizer -S | FileCheck %s --check-prefix=FMA
+
+ at srcA64 = common global [8 x double] zeroinitializer, align 64
+ at srcB64 = common global [8 x double] zeroinitializer, align 64
+ at srcC64 = common global [8 x double] zeroinitializer, align 64
+ at dst64 = common global [8 x double] zeroinitializer, align 64
+
+declare double @llvm.fma.f64(double, double, double)
+declare double @llvm.fmuladd.f64(double, double, double)
+
+; A bundle mixing fma and fmuladd widens to a single vector fma on an FMA
+; target; the fmuladd lane is fused, which is one of its permitted lowerings.
+define void @fma_fmuladd_2f64() {
+; NO-FMA-LABEL: @fma_fmuladd_2f64(
+; NO-FMA-NEXT:    [[A0:%.*]] = load double, ptr @srcA64, align 8
+; NO-FMA-NEXT:    [[A1:%.*]] = load double, ptr getelementptr inbounds ([8 x double], ptr @srcA64, i32 0, i64 1), align 8
+; NO-FMA-NEXT:    [[B0:%.*]] = load double, ptr @srcB64, align 8
+; NO-FMA-NEXT:    [[B1:%.*]] = load double, ptr getelementptr inbounds ([8 x double], ptr @srcB64, i32 0, i64 1), align 8
+; NO-FMA-NEXT:    [[C0:%.*]] = load double, ptr @srcC64, align 8
+; NO-FMA-NEXT:    [[C1:%.*]] = load double, ptr getelementptr inbounds ([8 x double], ptr @srcC64, i32 0, i64 1), align 8
+; NO-FMA-NEXT:    [[FMA0:%.*]] = call double @llvm.fma.f64(double [[A0]], double [[B0]], double [[C0]])
+; NO-FMA-NEXT:    [[FMA1:%.*]] = call double @llvm.fmuladd.f64(double [[A1]], double [[B1]], double [[C1]])
+; NO-FMA-NEXT:    store double [[FMA0]], ptr @dst64, align 8
+; NO-FMA-NEXT:    store double [[FMA1]], ptr getelementptr inbounds ([8 x double], ptr @dst64, i32 0, i64 1), align 8
+; NO-FMA-NEXT:    ret void
+;
+; FMA-LABEL: @fma_fmuladd_2f64(
+; FMA-NEXT:    [[A0:%.*]] = load double, ptr @srcA64, align 8
+; FMA-NEXT:    [[A1:%.*]] = load double, ptr getelementptr inbounds ([8 x double], ptr @srcA64, i32 0, i64 1), align 8
+; FMA-NEXT:    [[B0:%.*]] = load double, ptr @srcB64, align 8
+; FMA-NEXT:    [[B1:%.*]] = load double, ptr getelementptr inbounds ([8 x double], ptr @srcB64, i32 0, i64 1), align 8
+; FMA-NEXT:    [[C0:%.*]] = load double, ptr @srcC64, align 8
+; FMA-NEXT:    [[C1:%.*]] = load double, ptr getelementptr inbounds ([8 x double], ptr @srcC64, i32 0, i64 1), align 8
+; FMA-NEXT:    [[FMA0:%.*]] = call double @llvm.fma.f64(double [[A0]], double [[B0]], double [[C0]])
+; FMA-NEXT:    [[FMA1:%.*]] = call double @llvm.fmuladd.f64(double [[A1]], double [[B1]], double [[C1]])
+; FMA-NEXT:    store double [[FMA0]], ptr @dst64, align 8
+; FMA-NEXT:    store double [[FMA1]], ptr getelementptr inbounds ([8 x double], ptr @dst64, i32 0, i64 1), align 8
+; FMA-NEXT:    ret void
+;
+  %a0 = load double, ptr @srcA64, align 8
+  %a1 = load double, ptr getelementptr inbounds ([8 x double], ptr @srcA64, i32 0, i64 1), align 8
+  %b0 = load double, ptr @srcB64, align 8
+  %b1 = load double, ptr getelementptr inbounds ([8 x double], ptr @srcB64, i32 0, i64 1), align 8
+  %c0 = load double, ptr @srcC64, align 8
+  %c1 = load double, ptr getelementptr inbounds ([8 x double], ptr @srcC64, i32 0, i64 1), align 8
+  %fma0 = call double @llvm.fma.f64(double %a0, double %b0, double %c0)
+  %fma1 = call double @llvm.fmuladd.f64(double %a1, double %b1, double %c1)
+  store double %fma0, ptr @dst64, align 8
+  store double %fma1, ptr getelementptr inbounds ([8 x double], ptr @dst64, i32 0, i64 1), align 8
+  ret void
+}
+
+; Reversed lane order: the fmuladd appears first, so the representative must be
+; switched to the fma to emit the always-fused vector form.
+define void @fmuladd_fma_2f64() {
+; NO-FMA-LABEL: @fmuladd_fma_2f64(
+; NO-FMA-NEXT:    [[A0:%.*]] = load double, ptr @srcA64, align 8
+; NO-FMA-NEXT:    [[A1:%.*]] = load double, ptr getelementptr inbounds ([8 x double], ptr @srcA64, i32 0, i64 1), align 8
+; NO-FMA-NEXT:    [[B0:%.*]] = load double, ptr @srcB64, align 8
+; NO-FMA-NEXT:    [[B1:%.*]] = load double, ptr getelementptr inbounds ([8 x double], ptr @srcB64, i32 0, i64 1), align 8
+; NO-FMA-NEXT:    [[C0:%.*]] = load double, ptr @srcC64, align 8
+; NO-FMA-NEXT:    [[C1:%.*]] = load double, ptr getelementptr inbounds ([8 x double], ptr @srcC64, i32 0, i64 1), align 8
+; NO-FMA-NEXT:    [[FMA0:%.*]] = call double @llvm.fmuladd.f64(double [[A0]], double [[B0]], double [[C0]])
+; NO-FMA-NEXT:    [[FMA1:%.*]] = call double @llvm.fma.f64(double [[A1]], double [[B1]], double [[C1]])
+; NO-FMA-NEXT:    store double [[FMA0]], ptr @dst64, align 8
+; NO-FMA-NEXT:    store double [[FMA1]], ptr getelementptr inbounds ([8 x double], ptr @dst64, i32 0, i64 1), align 8
+; NO-FMA-NEXT:    ret void
+;
+; FMA-LABEL: @fmuladd_fma_2f64(
+; FMA-NEXT:    [[A0:%.*]] = load double, ptr @srcA64, align 8
+; FMA-NEXT:    [[A1:%.*]] = load double, ptr getelementptr inbounds ([8 x double], ptr @srcA64, i32 0, i64 1), align 8
+; FMA-NEXT:    [[B0:%.*]] = load double, ptr @srcB64, align 8
+; FMA-NEXT:    [[B1:%.*]] = load double, ptr getelementptr inbounds ([8 x double], ptr @srcB64, i32 0, i64 1), align 8
+; FMA-NEXT:    [[C0:%.*]] = load double, ptr @srcC64, align 8
+; FMA-NEXT:    [[C1:%.*]] = load double, ptr getelementptr inbounds ([8 x double], ptr @srcC64, i32 0, i64 1), align 8
+; FMA-NEXT:    [[FMA0:%.*]] = call double @llvm.fmuladd.f64(double [[A0]], double [[B0]], double [[C0]])
+; FMA-NEXT:    [[FMA1:%.*]] = call double @llvm.fma.f64(double [[A1]], double [[B1]], double [[C1]])
+; FMA-NEXT:    store double [[FMA0]], ptr @dst64, align 8
+; FMA-NEXT:    store double [[FMA1]], ptr getelementptr inbounds ([8 x double], ptr @dst64, i32 0, i64 1), align 8
+; FMA-NEXT:    ret void
+;
+  %a0 = load double, ptr @srcA64, align 8
+  %a1 = load double, ptr getelementptr inbounds ([8 x double], ptr @srcA64, i32 0, i64 1), align 8
+  %b0 = load double, ptr @srcB64, align 8
+  %b1 = load double, ptr getelementptr inbounds ([8 x double], ptr @srcB64, i32 0, i64 1), align 8
+  %c0 = load double, ptr @srcC64, align 8
+  %c1 = load double, ptr getelementptr inbounds ([8 x double], ptr @srcC64, i32 0, i64 1), align 8
+  %fma0 = call double @llvm.fmuladd.f64(double %a0, double %b0, double %c0)
+  %fma1 = call double @llvm.fma.f64(double %a1, double %b1, double %c1)
+  store double %fma0, ptr @dst64, align 8
+  store double %fma1, ptr getelementptr inbounds ([8 x double], ptr @dst64, i32 0, i64 1), align 8
+  ret void
+}
+
+; Control: a pure fmuladd bundle stays fmuladd, keeping the freedom to split.
+define void @fmuladd_2f64() {
+; NO-FMA-LABEL: @fmuladd_2f64(
+; NO-FMA-NEXT:    [[TMP1:%.*]] = load <2 x double>, ptr @srcA64, align 8
+; NO-FMA-NEXT:    [[TMP2:%.*]] = load <2 x double>, ptr @srcB64, align 8
+; NO-FMA-NEXT:    [[TMP3:%.*]] = load <2 x double>, ptr @srcC64, align 8
+; NO-FMA-NEXT:    [[TMP4:%.*]] = call <2 x double> @llvm.fmuladd.v2f64(<2 x double> [[TMP1]], <2 x double> [[TMP2]], <2 x double> [[TMP3]])
+; NO-FMA-NEXT:    store <2 x double> [[TMP4]], ptr @dst64, align 8
+; NO-FMA-NEXT:    ret void
+;
+; FMA-LABEL: @fmuladd_2f64(
+; FMA-NEXT:    [[TMP1:%.*]] = load <2 x double>, ptr @srcA64, align 8
+; FMA-NEXT:    [[TMP2:%.*]] = load <2 x double>, ptr @srcB64, align 8
+; FMA-NEXT:    [[TMP3:%.*]] = load <2 x double>, ptr @srcC64, align 8
+; FMA-NEXT:    [[TMP4:%.*]] = call <2 x double> @llvm.fmuladd.v2f64(<2 x double> [[TMP1]], <2 x double> [[TMP2]], <2 x double> [[TMP3]])
+; FMA-NEXT:    store <2 x double> [[TMP4]], ptr @dst64, align 8
+; FMA-NEXT:    ret void
+;
+  %a0 = load double, ptr @srcA64, align 8
+  %a1 = load double, ptr getelementptr inbounds ([8 x double], ptr @srcA64, i32 0, i64 1), align 8
+  %b0 = load double, ptr @srcB64, align 8
+  %b1 = load double, ptr getelementptr inbounds ([8 x double], ptr @srcB64, i32 0, i64 1), align 8
+  %c0 = load double, ptr @srcC64, align 8
+  %c1 = load double, ptr getelementptr inbounds ([8 x double], ptr @srcC64, i32 0, i64 1), align 8
+  %fma0 = call double @llvm.fmuladd.f64(double %a0, double %b0, double %c0)
+  %fma1 = call double @llvm.fmuladd.f64(double %a1, double %b1, double %c1)
+  store double %fma0, ptr @dst64, align 8
+  store double %fma1, ptr getelementptr inbounds ([8 x double], ptr @dst64, i32 0, i64 1), align 8
+  ret void
+}



More information about the llvm-commits mailing list