// RUN: %clang_cc1 -emit-llvm -triple i386-linux -std=c++2a -Wno-unknown-pragmas %s -o - | FileCheck %s // nextUp(1.F) == 0x1.000002p0F constexpr float add_round_down(float x, float y) { #pragma STDC FENV_ROUND FE_DOWNWARD float res = x; res += y; return res; } constexpr float add_round_up(float x, float y) { #pragma STDC FENV_ROUND FE_UPWARD float res = x; res += y; return res; } float V1 = add_round_down(1.0F, 0x0.000001p0F); float V2 = add_round_up(1.0F, 0x0.000001p0F); // CHECK: @V1 = {{.*}} float 1.000000e+00 // CHECK: @V2 = {{.*}} float 0x3FF0000020000000 constexpr float add_cast_round_down(float x, double y) { #pragma STDC FENV_ROUND FE_DOWNWARD float res = x; res += y; return res; } constexpr float add_cast_round_up(float x, double y) { #pragma STDC FENV_ROUND FE_UPWARD float res = x; res += y; return res; } float V3 = add_cast_round_down(1.0F, 0x0.000001p0F); float V4 = add_cast_round_up(1.0F, 0x0.000001p0F); // CHECK: @V3 = {{.*}} float 1.000000e+00 // CHECK: @V4 = {{.*}} float 0x3FF0000020000000 // The next three variables use the same function as initializer, only rounding // modes differ. float V5 = []() -> float { return [](float x, float y)->float { #pragma STDC FENV_ROUND FE_UPWARD return x + y; }([](float x, float y) -> float { #pragma STDC FENV_ROUND FE_UPWARD return x + y; }(1.0F, 0x0.000001p0F), 0x0.000001p0F); }(); // CHECK: @V5 = {{.*}} float 0x3FF0000040000000 float V6 = []() -> float { return [](float x, float y)->float { #pragma STDC FENV_ROUND FE_DOWNWARD return x + y; }([](float x, float y) -> float { #pragma STDC FENV_ROUND FE_UPWARD return x + y; }(1.0F, 0x0.000001p0F), 0x0.000001p0F); }(); // CHECK: @V6 = {{.*}} float 0x3FF0000020000000 float V7 = []() -> float { return [](float x, float y)->float { #pragma STDC FENV_ROUND FE_DOWNWARD return x + y; }([](float x, float y) -> float { #pragma STDC FENV_ROUND FE_DOWNWARD return x + y; }(1.0F, 0x0.000001p0F), 0x0.000001p0F); }(); // CHECK: @V7 = {{.*}} float 1.000000e+00 #pragma STDC FENV_ROUND FE_DYNAMIC template struct L { constexpr L() : value(V) {} float value; }; #pragma STDC FENV_ROUND FE_DOWNWARD L<0.1F> val_d; // CHECK: @val_d = {{.*}} { float 0x3FB9999980000000 } #pragma STDC FENV_ROUND FE_UPWARD L<0.1F> val_u; // CHECK: @val_u = {{.*}} { float 0x3FB99999A0000000 } // Check literals in macros. #pragma STDC FENV_ROUND FE_DOWNWARD #define CONSTANT_0_1 0.1F #pragma STDC FENV_ROUND FE_UPWARD float C1_ru = CONSTANT_0_1; // CHECK: @C1_ru = {{.*}} float 0x3FB99999A0000000 #pragma STDC FENV_ROUND FE_DOWNWARD float C1_rd = CONSTANT_0_1; // CHECK: @C1_rd = {{.*}} float 0x3FB9999980000000 #pragma STDC FENV_ROUND FE_DOWNWARD #define PRAGMA(x) _Pragma(#x) #define CONSTANT_0_1_RM(v, rm) ([](){ PRAGMA(STDC FENV_ROUND rm); return v; }()) #pragma STDC FENV_ROUND FE_UPWARD float C2_rd = CONSTANT_0_1_RM(0.1F, FE_DOWNWARD); float C2_ru = CONSTANT_0_1_RM(0.1F, FE_UPWARD); // CHECK: @C2_rd = {{.*}} float 0x3FB9999980000000 // CHECK: @C2_ru = {{.*}} float 0x3FB99999A0000000 #pragma STDC FENV_ROUND FE_DOWNWARD float C3_rd = CONSTANT_0_1_RM(0.1F, FE_DOWNWARD); float C3_ru = CONSTANT_0_1_RM(0.1F, FE_UPWARD); // CHECK: @C3_rd = {{.*}} float 0x3FB9999980000000 // CHECK: @C3_ru = {{.*}} float 0x3FB99999A0000000 // Check literals in template instantiations. #pragma STDC FENV_ROUND FE_DYNAMIC template constexpr T foo() { return C; } #pragma STDC FENV_ROUND FE_DOWNWARD float var_d = foo(); // CHECK: @var_d = {{.*}} float 0x3FB9999980000000 #pragma STDC FENV_ROUND FE_UPWARD float var_u = foo(); // CHECK: @var_u = {{.*}} float 0x3FB99999A0000000 #pragma STDC FENV_ROUND FE_DYNAMIC template void foo2() { T Val = f; } void func_01() { #pragma STDC FENV_ROUND FE_DOWNWARD foo2(); } void func_02() { #pragma STDC FENV_ROUND FE_UPWARD foo2(); } // CHECK-LABEL: define {{.*}} void @_Z4foo2IfTnT_Lf3dccccccEEvv() // CHECK: store float 0x3FB9999980000000, ptr // CHECK-LABEL: define {{.*}} void @_Z4foo2IfTnT_Lf3dcccccdEEvv() // CHECK: store float 0x3FB99999A0000000, ptr #pragma STDC FENV_ROUND FE_DOWNWARD template float tfunc_01() { return 0.1F; // Must be 0x3FB9999980000000 in all instantiations. } template float tfunc_01<0>(); // CHECK-LABEL: define {{.*}} float @_Z8tfunc_01ILi0EEfv() // CHECK: ret float 0x3FB9999980000000 #pragma STDC FENV_ROUND FE_UPWARD template float tfunc_01<1>(); // CHECK-LABEL: define {{.*}} float @_Z8tfunc_01ILi1EEfv() // CHECK: ret float 0x3FB9999980000000 template<> float tfunc_01<2>() { return 0.1F; } // CHECK-LABEL: define {{.*}} float @_Z8tfunc_01ILi2EEfv() // CHECK: ret float 0x3FB99999A0000000