llvm/clang/test/CodeGen/fp-floatcontrol-stack.cpp

// 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"