From 123ddd98310228a8afd9a5f93b0a7b482df8e93e Mon Sep 17 00:00:00 2001 From: Warren Ristow Date: Wed, 8 Oct 2025 13:52:37 -0700 Subject: [PATCH] Always honor fp-contract pragmas on PlayStation The pragma: #pragma clang fp contract (off) can be used to disable FMA, but when cross-statement FMA is enabled in `fast` fp contract mode (via `-ffast-math`, for example), the effect of that pragma is suppressed. To have Clang honor that pragma in 'fast' fp contract mode in C/C++, an additional switch: -ffp-contract=fast-honor-pragmas must be applied. On PlayStation, we want to always honor that pragma, without requiring the additional switch to be specified. This commit does that. --- clang/lib/CodeGen/BackendUtil.cpp | 6 ++- clang/test/CodeGen/X86/fma-fast-pragma.cpp | 53 ++++++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 clang/test/CodeGen/X86/fma-fast-pragma.cpp diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index 2d959827d6972..0840c7348c18b 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -406,7 +406,11 @@ static bool initTargetOptions(const CompilerInstance &CI, Options.AllowFPOpFusion = llvm::FPOpFusion::Standard; break; case LangOptions::FPM_Fast: - Options.AllowFPOpFusion = llvm::FPOpFusion::Fast; + // We always honor fp-contract pragmas for PlayStation. + if (CI.getASTContext().getTargetInfo().getTriple().isPS()) + Options.AllowFPOpFusion = llvm::FPOpFusion::Standard; + else + Options.AllowFPOpFusion = llvm::FPOpFusion::Fast; break; } diff --git a/clang/test/CodeGen/X86/fma-fast-pragma.cpp b/clang/test/CodeGen/X86/fma-fast-pragma.cpp new file mode 100644 index 0000000000000..9d38e245b5f64 --- /dev/null +++ b/clang/test/CodeGen/X86/fma-fast-pragma.cpp @@ -0,0 +1,53 @@ +// REQUIRES: x86-registered-target + +// With the pragma in place, generic targets leave FMA enabled unless the +// switch '-ffp-contract=fast-honor-pragmas' is used to disable it; whereas +// for PlayStation, the pragma is always honored, so FMA is disabled even in +// plain 'fast' mode: +// RUN: %clang_cc1 -S -triple x86_64-unknown-unknown -target-feature +fma \ +// RUN: -O2 -ffp-contract=fast -o - %s | \ +// RUN: FileCheck --check-prefix=CHECK-YES-FMA %s +// RUN: %clang_cc1 -S -triple x86_64-unknown-unknown -target-feature +fma \ +// RUN: -O2 -ffp-contract=fast-honor-pragmas -o - %s | \ +// RUN: FileCheck --check-prefix=CHECK-NO-FMA %s +// RUN: %clang_cc1 -S -triple x86_64-unknown-unknown -target-feature +fma \ +// RUN: -O2 -ffp-contract=fast -ffp-contract=fast-honor-pragmas -o - %s | \ +// RUN: FileCheck --check-prefix=CHECK-NO-FMA %s +// RUN: %clang_cc1 -S -triple x86_64-sie-ps5 -target-feature +fma \ +// RUN: -O2 -ffp-contract=fast -o - %s | \ +// RUN: FileCheck --check-prefix=CHECK-NO-FMA %s +// RUN: %clang_cc1 -S -triple x86_64-sie-ps5 -target-feature +fma \ +// RUN: -O2 -ffp-contract=fast-honor-pragmas -o - %s | \ +// RUN: FileCheck --check-prefix=CHECK-NO-FMA %s +// +// With the pragma suppressed, FMA happens in 'fast' or 'fast-honor-pragmas' +// modes (for generic targets and for PlayStation): +// RUN: %clang_cc1 -S -DSUPPRESS_PRAGMA \ +// RUN: -triple x86_64-unknown-unknown -target-feature +fma \ +// RUN: -O2 -ffp-contract=fast -o - %s | \ +// RUN: FileCheck --check-prefix=CHECK-YES-FMA %s +// RUN: %clang_cc1 -S -DSUPPRESS_PRAGMA \ +// RUN: -triple x86_64-unknown-unknown -target-feature +fma \ +// RUN: -O2 -ffp-contract=fast-honor-pragmas -o - %s | \ +// RUN: FileCheck --check-prefix=CHECK-YES-FMA %s +// RUN: %clang_cc1 -S -DSUPPRESS_PRAGMA \ +// RUN: -triple x86_64-sie-ps5 -target-feature +fma \ +// RUN: -O2 -ffp-contract=fast -o - %s | \ +// RUN: FileCheck --check-prefix=CHECK-YES-FMA %s +// RUN: %clang_cc1 -S -DSUPPRESS_PRAGMA \ +// RUN: -triple x86_64-sie-ps5 -target-feature +fma \ +// RUN: -O2 -ffp-contract=fast-honor-pragmas -o - %s | \ +// RUN: FileCheck --check-prefix=CHECK-YES-FMA %s +// +float compute(float a, float b, float c) { +#if !defined(SUPPRESS_PRAGMA) +#pragma clang fp contract (off) +#endif + float product = a * b; + return product + c; +} + +// CHECK-NO-FMA: vmulss +// CHECK-NO-FMA-NEXT: vaddss + +// CHECK-YES-FMA: vfmadd213ss