blob: ef29d24de1dbca5b443d31787415dca1748692ab [file] [log] [blame]
// RUN: %clang_cc1 -fexperimental-strict-floating-point -DEXCEPT=1 -fcxx-exceptions -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-NS %s
// RUN: %clang_cc1 -fexperimental-strict-floating-point -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s
// RUN: %clang_cc1 -fexperimental-strict-floating-point -DFENV_ON=1 -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-FENV %s
// RUN: %clang_cc1 -fexperimental-strict-floating-point -triple %itanium_abi_triple -O3 -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-O3 %s
// Verify float_control(precise, off) enables fast math flags on fp operations.
float fp_precise_1(float a, float b, float c) {
// CHECK-O3: _Z12fp_precise_1fff
// CHECK-O3: %[[M:.+]] = fmul fast float{{.*}}
// CHECK-O3: fadd fast float %[[M]], %c
#pragma float_control(precise, off)
return a * b + c;
}
// Is float_control state cleared on exiting compound statements?
float fp_precise_2(float a, float b, float c) {
// CHECK-O3: _Z12fp_precise_2fff
// CHECK-O3: %[[M:.+]] = fmul float{{.*}}
// CHECK-O3: fadd float %[[M]], %c
{
#pragma float_control(precise, off)
}
return a * b + c;
}
// Does float_control survive template instantiation?
class Foo {};
Foo operator+(Foo, Foo);
template <typename T>
T template_muladd(T a, T b, T c) {
#pragma float_control(precise, off)
return a * b + c;
}
float fp_precise_3(float a, float b, float c) {
// CHECK-O3: _Z12fp_precise_3fff
// CHECK-O3: %[[M:.+]] = fmul fast float{{.*}}
// CHECK-O3: fadd fast float %[[M]], %c
return template_muladd<float>(a, b, c);
}
template <typename T>
class fp_precise_4 {
float method(float a, float b, float c) {
#pragma float_control(precise, off)
return a * b + c;
}
};
template class fp_precise_4<int>;
// CHECK-O3: _ZN12fp_precise_4IiE6methodEfff
// CHECK-O3: %[[M:.+]] = fmul fast float{{.*}}
// CHECK-O3: fadd fast float %[[M]], %c
// Check file-scoped float_control
#pragma float_control(push)
#pragma float_control(precise, off)
float fp_precise_5(float a, float b, float c) {
// CHECK-O3: _Z12fp_precise_5fff
// CHECK-O3: %[[M:.+]] = fmul fast float{{.*}}
// CHECK-O3: fadd fast float %[[M]], %c
return a * b + c;
}
#pragma float_control(pop)
float fff(float x, float y) {
// CHECK-LABEL: define{{.*}} float @_Z3fffff{{.*}}
// CHECK: entry
#pragma float_control(except, on)
float z;
z = z * z;
//CHECK: llvm.experimental.constrained.fmul{{.*}}
{
z = x * y;
//CHECK: llvm.experimental.constrained.fmul{{.*}}
}
{
// This pragma has no effect since if there are any fp intrin in the
// function then all the operations need to be fp intrin
#pragma float_control(except, off)
z = z + x * y;
//CHECK: llvm.experimental.constrained.fmul{{.*}}
}
z = z * z;
//CHECK: llvm.experimental.constrained.fmul{{.*}}
return z;
}
float check_precise(float x, float y) {
// CHECK-LABEL: define{{.*}} float @_Z13check_preciseff{{.*}}
float z;
{
#pragma float_control(precise, on)
z = x * y + z;
//CHECK: llvm.fmuladd{{.*}}
}
{
#pragma float_control(precise, off)
z = x * y + z;
//CHECK: fmul fast float
//CHECK: fadd fast float
}
return z;
}
float fma_test2(float a, float b, float c) {
// CHECK-LABEL define{{.*}} float @_Z9fma_test2fff{{.*}}
#pragma float_control(precise, off)
float x = a * b + c;
//CHECK: fmuladd
return x;
}
float fma_test1(float a, float b, float c) {
// CHECK-LABEL define{{.*}} float @_Z9fma_test1fff{{.*}}
#pragma float_control(precise, on)
float x = a * b + c;
//CHECK: fmuladd
return x;
}
#pragma float_control(push)
#pragma float_control(precise, on)
struct Distance {};
Distance operator+(Distance, Distance);
template <class T>
T add(T lhs, T rhs) {
#pragma float_control(except, on)
return lhs + rhs;
}
#pragma float_control(pop)
float test_OperatorCall() {
return add(1.0f, 2.0f);
//CHECK: llvm.experimental.constrained.fadd{{.*}}fpexcept.strict
}
// CHECK-LABEL define{{.*}} float {{.*}}test_OperatorCall{{.*}}
#if FENV_ON
#pragma STDC FENV_ACCESS ON
#endif
// CHECK-LABEL: define {{.*}}callt{{.*}}
void callt() {
volatile float z;
z = z * z;
//CHECK-FENV: llvm.experimental.constrained.fmul{{.*}}
}
// CHECK-LABEL: define {{.*}}myAdd{{.*}}
float myAdd(int i, float f) {
if (i<0)
return 1.0 + 2.0;
// Check that floating point constant folding doesn't occur if
// #pragma STC FENV_ACCESS is enabled.
//CHECK-FENV: llvm.experimental.constrained.fadd{{.*}}double 1.0{{.*}}double 2.0{{.*}}
//CHECK: store float 3.0{{.*}}retval{{.*}}
static double v = 1.0 / 3.0;
//CHECK-FENV: llvm.experimental.constrained.fptrunc.f32.f64{{.*}}
//CHECK-NOT: fdiv
return v;
}
#if EXCEPT
namespace ns {
// Check that pragma float_control can appear in namespace.
#pragma float_control(except, on, push)
float exc_on(double x, float zero) {
// CHECK-NS: define {{.*}}exc_on{{.*}}
{} try {
x = 1.0 / zero; /* division by zero, the result unused */
//CHECK-NS: llvm.experimental.constrained.fdiv{{.*}}
} catch (...) {}
return zero;
}
}
// Check pragma is still effective after namespace closes
float exc_still_on(double x, float zero) {
// CHECK-NS: define {{.*}}exc_still_on{{.*}}
{} try {
x = 1.0 / zero; /* division by zero, the result unused */
//CHECK-NS: llvm.experimental.constrained.fdiv{{.*}}
} catch (...) {}
return zero;
}
#pragma float_control(pop)
float exc_off(double x, float zero) {
// CHECK-NS: define {{.*}}exc_off{{.*}}
{} try {
x = 1.0 / zero; /* division by zero, the result unused */
//CHECK-NS: fdiv double
} catch (...) {}
return zero;
}
namespace fc_template_namespace {
#pragma float_control(except, on, push)
template <class T>
T exc_on(double x, T zero) {
// CHECK-NS: define {{.*}}fc_template_namespace{{.*}}
{} try {
x = 1.0 / zero; /* division by zero, the result unused */
//CHECK-NS: llvm.experimental.constrained.fdiv{{.*}}
} catch (...) {}
return zero;
}
}
#pragma float_control(pop)
float xx(double x, float z) {
return fc_template_namespace::exc_on<float>(x, z);
}
#endif // EXCEPT
float try_lam(float x, unsigned n) {
// CHECK: define {{.*}}try_lam{{.*}}class.anon{{.*}}
float result;
auto t =
// Lambda expression begins
[](float a, float b) {
#pragma float_control( except, on)
return a * b;
//CHECK: llvm.experimental.constrained.fmul{{.*}}fpexcept.strict
} // end of lambda expression
(1.0f,2.0f);
result = x + t;
return result;
}