// RUN: %clang_cc1 -triple x86_64-linux-gnu -ffp-contract=on -DDEFAULT=1 -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-DDEFAULT %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -ffp-contract=on -DEBSTRICT=1 -ffp-exception-behavior=strict -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-DEBSTRICT %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -DFAST=1 -ffast-math -ffp-contract=fast -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-FAST %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -ffp-contract=on -DNOHONOR=1 -ffinite-math-only -menable-no-infs -menable-no-nans -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-NOHONOR %s
#define FUN(n) \
(float z) { return n * z + n; }
// CHECK-DDEFAULT: Function Attrs: mustprogress noinline nounwind optnone{{$$}}
// CHECK-DEBSTRICT: Function Attrs: mustprogress noinline nounwind optnone strictfp{{$$}}
// CHECK-FAST: Function Attrs: mustprogress noinline nounwind optnone{{$$}}
// CHECK-NOHONOR: Function Attrs: mustprogress noinline nounwind optnone{{$$}}
float fun_default FUN(1)
//CHECK-LABEL: define {{.*}} @_Z11fun_defaultf{{.*}}
#if DEFAULT
//CHECK-DDEFAULT: call float @llvm.fmuladd{{.*}}
#endif
#if EBSTRICT
// Note that backend wants constrained intrinsics used
// throughout the function if they are needed anywhere in the function.
// In that case, operations are built with constrained intrinsics operator
// but using default settings for exception behavior and rounding mode.
//CHECK-DEBSTRICT: llvm.experimental.constrained.fmul{{.*}}tonearest{{.*}}strict
#endif
#if FAST
//CHECK-FAST: fmul fast float
//CHECK-FAST: fadd fast float
#endif
#pragma float_control(push)
#ifndef FAST
// Rule: precise must be enabled
#pragma float_control(except, on)
#endif
// CHECK-FAST: Function Attrs: mustprogress noinline nounwind optnone{{$$}}
// CHECK-DDEFAULT: Function Attrs: mustprogress noinline nounwind optnone strictfp{{$$}}
// CHECK-DEBSTRICT: Function Attrs: mustprogress noinline nounwind optnone strictfp{{$$}}
// CHECK-NOHONOR: Function Attrs: mustprogress noinline nounwind optnone strictfp{{$$}}
float exc_on FUN(2)
//CHECK-LABEL: define {{.*}} @_Z6exc_onf{{.*}}
#if DEFAULT
//CHECK-DDEFAULT: llvm.experimental.constrained.fmul{{.*}}
#endif
#if EBSTRICT
//CHECK-DEBSTRICT: llvm.experimental.constrained.fmuladd{{.*}}tonearest{{.*}}strict
#endif
#if NOHONOR
//CHECK-NOHONOR: nnan ninf float {{.*}}llvm.experimental.constrained.fmuladd{{.*}}tonearest{{.*}}strict
#endif
#if FAST
//Not possible to enable float_control(except) in FAST mode.
//CHECK-FAST: fmul fast float
//CHECK-FAST: fadd fast float
#endif
#pragma float_control(pop)
// CHECK-DDEFAULT: Function Attrs: mustprogress noinline nounwind optnone{{$$}}
// CHECK-DEBSTRICT: Function Attrs: mustprogress noinline nounwind optnone strictfp{{$$}}
// CHECK-FAST: Function Attrs: mustprogress noinline nounwind optnone{{$$}}
// CHECK-NOHONOR: Function Attrs: mustprogress noinline nounwind optnone{{$$}}
float exc_pop FUN(5)
//CHECK-LABEL: define {{.*}} @_Z7exc_popf{{.*}}
#if DEFAULT
//CHECK-DDEFAULT: call float @llvm.fmuladd{{.*}}
#endif
#if EBSTRICT
//CHECK-DEBSTRICT: llvm.experimental.constrained.fmuladd{{.*}}tonearest{{.*}}strict
#endif
#if NOHONOR
//CHECK-NOHONOR: call nnan ninf float @llvm.fmuladd{{.*}}
#endif
#if FAST
//CHECK-FAST: fmul fast float
//CHECK-FAST: fadd fast float
#endif
#pragma float_control(except, off)
float exc_off FUN(5)
//CHECK-LABEL: define {{.*}} @_Z7exc_offf{{.*}}
#if DEFAULT
//CHECK-DDEFAULT: call float @llvm.fmuladd{{.*}}
#endif
#if EBSTRICT
//CHECK-DEBSTRICT: call float @llvm.fmuladd{{.*}}
#endif
#if NOHONOR
//CHECK-NOHONOR: call nnan ninf float @llvm.fmuladd{{.*}}
#endif
#if FAST
//CHECK-FAST: fmul fast float
//CHECK-FAST: fadd fast float
#endif
#pragma float_control(precise, on, push)
float precise_on FUN(3)
//CHECK-LABEL: define {{.*}} @_Z10precise_onf{{.*}}
#if DEFAULT
//CHECK-DDEFAULT: float {{.*}}llvm.fmuladd{{.*}}
#endif
#if EBSTRICT
//CHECK-DEBSTRICT: float {{.*}}llvm.fmuladd{{.*}}
#endif
#if NOHONOR
// If precise is pushed then all fast-math should be off!
//CHECK-NOHONOR: call float {{.*}}llvm.fmuladd{{.*}}
#endif
#if FAST
//CHECK-FAST: float {{.*}}llvm.fmuladd{{.*}}
#endif
#pragma float_control(pop)
float precise_pop FUN(3)
//CHECK-LABEL: define {{.*}} @_Z11precise_popf{{.*}}
#if DEFAULT
//CHECK-DDEFAULT: float {{.*}}llvm.fmuladd{{.*}}
#endif
#if EBSTRICT
//CHECK-DEBSTRICT: float {{.*}}llvm.fmuladd{{.*}}
#endif
#if NOHONOR
//CHECK-NOHONOR: call nnan ninf float @llvm.fmuladd{{.*}}
#endif
#if FAST
//CHECK-FAST: fmul fast float
//CHECK-FAST: fadd fast float
#endif
#pragma float_control(precise, off)
float precise_off FUN(4)
//CHECK-LABEL: define {{.*}} @_Z11precise_offf{{.*}}
#if DEFAULT
// Note: precise_off enables fp_contract=fast and the instructions
// generated do not include the contract flag, although it was enabled
// in IRBuilder.
//CHECK-DDEFAULT: fmul fast float
//CHECK-DDEFAULT: fadd fast float
#endif
#if EBSTRICT
//CHECK-DEBSTRICT: fmul fast float
//CHECK-DEBSTRICT: fadd fast float
#endif
#if NOHONOR
// fast math should be enabled, and contract should be fast
//CHECK-NOHONOR: fmul fast float
//CHECK-NOHONOR: fadd fast float
#endif
#if FAST
//CHECK-FAST: fmul fast float
//CHECK-FAST: fadd fast float
#endif
#pragma float_control(precise, on)
float precise_on2 FUN(3)
//CHECK-LABEL: define {{.*}} @_Z11precise_on2f{{.*}}
#if DEFAULT
//CHECK-DDEFAULT: llvm.fmuladd{{.*}}
#endif
#if EBSTRICT
//CHECK-DEBSTRICT: float {{.*}}llvm.fmuladd{{.*}}
#endif
#if NOHONOR
// fast math should be off, and contract should be on
//CHECK-NOHONOR: float {{.*}}llvm.fmuladd{{.*}}
#endif
#if FAST
//CHECK-FAST: float {{.*}}llvm.fmuladd{{.*}}
#endif
#pragma float_control(push)
float precise_push FUN(3)
//CHECK-LABEL: define {{.*}} @_Z12precise_pushf{{.*}}
#if DEFAULT
//CHECK-DDEFAULT: llvm.fmuladd{{.*}}
#endif
#if EBSTRICT
//CHECK-DEBSTRICT: float {{.*}}llvm.fmuladd{{.*}}
#endif
#if NOHONOR
//CHECK-NOHONOR: float {{.*}}llvm.fmuladd{{.*}}
#endif
#if FAST
//CHECK-FAST: float {{.*}}llvm.fmuladd{{.*}}
#endif
#pragma float_control(precise, off)
float precise_off2 FUN(4)
//CHECK-LABEL: define {{.*}} @_Z12precise_off2f{{.*}}
#if DEFAULT
//CHECK-DDEFAULT: fmul fast float
//CHECK-DDEFAULT: fadd fast float
#endif
#if EBSTRICT
//CHECK-DEBSTRICT: fmul fast float
//CHECK-DEBSTRICT: fadd fast float
#endif
#if NOHONOR
// fast math settings since precise is off
//CHECK-NOHONOR: fmul fast float
//CHECK-NOHONOR: fadd fast float
#endif
#if FAST
//CHECK-FAST: fmul fast float
//CHECK-FAST: fadd fast float
#endif
#pragma float_control(pop)
float precise_pop2 FUN(3)
//CHECK-LABEL: define {{.*}} @_Z12precise_pop2f{{.*}}
#if DEFAULT
//CHECK-DDEFAULT: llvm.fmuladd{{.*}}
#endif
#if EBSTRICT
//CHECK-DEBSTRICT: float {{.*}}llvm.fmuladd{{.*}}
#endif
#if NOHONOR
//CHECK-NOHONOR: float {{.*}}llvm.fmuladd{{.*}}
#endif
#if FAST
//CHECK-FAST: float {{.*}}llvm.fmuladd{{.*}}
#endif
#ifndef FAST
// Rule: precise must be enabled
#pragma float_control(except, on)
#endif
float y();
// CHECK-DDEFAULT: Function Attrs: mustprogress noinline nounwind optnone{{$$}}
// CHECK-DEBSTRICT: Function Attrs: mustprogress noinline nounwind optnone strictfp{{$$}}
// CHECK-FAST: Function Attrs: mustprogress noinline nounwind optnone{{$$}}
// CHECK-NOHONOR: Function Attrs: mustprogress noinline nounwind optnone{{$$}}
class ON {
// Settings for top level class initializer use program source setting.
float z = 2 + y() * 7;
//CHECK-LABEL: define {{.*}} void @_ZN2ONC2Ev{{.*}}
#if DEFAULT
// CHECK-DDEFAULT: llvm.experimental.constrained.fmul{{.*}}tonearest{{.*}}strict
#endif
#if EBSTRICT
// CHECK-DEBSTRICT: llvm.experimental.constrained.fmul{{.*}}tonearest{{.*}}strict
#endif
#if NOHONOR
// CHECK-NOHONOR: llvm.experimental.constrained.fmul{{.*}}tonearest{{.*}}strict
#endif
#if FAST
// CHECK-FAST: float {{.*}}llvm.fmuladd{{.*}}
#endif
};
ON on;
#pragma float_control(except, off)
// CHECK-DDEFAULT: Function Attrs: mustprogress noinline nounwind optnone{{$$}}
// CHECK-DEBSTRICT: Function Attrs: mustprogress noinline nounwind optnone{{$$}}
// CHECK-FAST: Function Attrs: mustprogress noinline nounwind optnone{{$$}}
// CHECK-NOHONOR: Function Attrs: mustprogress noinline nounwind optnone{{$$}}
class OFF {
float w = 2 + y() * 7;
// CHECK-LABEL: define {{.*}} void @_ZN3OFFC2Ev{{.*}}
// CHECK: call float {{.*}}llvm.fmuladd
};
OFF off;
#pragma clang fp reassociate(on)
struct MyComplex {
float xx;
float yy;
MyComplex(float x, float y) {
xx = x;
yy = y;
}
MyComplex() {}
const MyComplex operator+(const MyComplex other) const {
// CHECK-LABEL: define {{.*}} @_ZNK9MyComplexplES_
// CHECK: fadd reassoc float
// CHECK: fadd reassoc float
return MyComplex(xx + other.xx, yy + other.yy);
}
};
MyComplex useAdd() {
MyComplex a (1, 3);
MyComplex b (2, 4);
return a + b;
}
// CHECK-DDEFAULT: Function Attrs: noinline nounwind{{$$}}
// CHECK-DEBSTRICT: Function Attrs: noinline nounwind strictfp{{$$}}
// CHECK-FAST: Function Attrs: noinline nounwind{{$$}}
// CHECK-NOHONOR: Function Attrs: noinline nounwind{{$$}}
// CHECK-LABEL: define{{.*}} @_GLOBAL__sub_I_fp_floatcontrol_stack
// CHECK-DEBSTRICT: {{[ ]}}strictfp{{[ ]}}
// CHECK-DEBSTRICT-NOT: "strictfp"