390 lines · cpp
1// RUN: %clang_cc1 -fexperimental-strict-floating-point -DEXCEPT=1 \2// RUN: -fcxx-exceptions -triple x86_64-linux-gnu -emit-llvm -o - %s \3// RUN: | FileCheck -check-prefix=CHECK-NS %s4 5// RUN: %clang_cc1 -fexperimental-strict-floating-point \6// RUN: -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s \7// RUN: -check-prefixes=CHECK-DEFAULT,CHECK-CONST-ARGS8 9// RUN: %clang_cc1 -fexperimental-strict-floating-point -DFENV_ON=1 \10// RUN: -triple x86_64-linux-gnu -emit-llvm -o - %s \11// RUN: | FileCheck -check-prefix=CHECK-FENV %s12 13// RUN: %clang_cc1 -fexperimental-strict-floating-point -DNF128 \14// RUN: -triple %itanium_abi_triple -O3 -emit-llvm -o - %s \15// RUN: | FileCheck -check-prefix=CHECK-O3 %s16 17// RUN: %clang_cc1 -fexperimental-strict-floating-point \18// RUN: -triple x86_64-linux-gnu -emit-llvm -o - %s -ffp-eval-method=source \19// RUN: | FileCheck %s -check-prefixes=CHECK-SOURCE,CHECK-CONST-ARGS20 21// RUN: %clang_cc1 -fexperimental-strict-floating-point \22// RUN: -triple x86_64-linux-gnu -emit-llvm -o - %s -ffp-eval-method=double \23// RUN: | FileCheck %s -check-prefixes=CHECK-DOUBLE,CHECK-CONST-ARGS24 25// RUN: %clang_cc1 -fexperimental-strict-floating-point \26// RUN: -triple x86_64-linux-gnu -emit-llvm -o - %s -ffp-eval-method=extended \27// RUN: -mlong-double-80 | FileCheck %s \28// RUN: -check-prefixes=CHECK-EXTENDED,CHECK-CONST-ARGS29 30// RUN: %clang_cc1 -fexperimental-strict-floating-point \31// RUN: -triple i386-linux-gnu -emit-llvm -o - %s -ffp-eval-method=source \32// RUN: | FileCheck %s -check-prefix=CHECK-SOURCE33 34// RUN: %clang_cc1 -fexperimental-strict-floating-point -triple i386-linux-gnu \35// RUN: -emit-llvm -o - %s -ffp-eval-method=double | FileCheck %s \36// RUN: -check-prefix=CHECK-DOUBLE37 38// RUN: %clang_cc1 -fexperimental-strict-floating-point -triple i386-linux-gnu \39// RUN: -emit-llvm -o - %s -ffp-eval-method=extended -mlong-double-80 \40// RUN: | FileCheck %s -check-prefix=CHECK-EXTENDED41 42// RUN: %clang_cc1 -triple powerpc-unknown-aix -DNF128 -emit-llvm -o - %s \43// RUN: | FileCheck %s -check-prefix=CHECK-AIX44 45bool f() {46 // CHECK: define {{.*}}f{{.*}}47 return __FLT_EVAL_METHOD__ < 0 &&48 __FLT_EVAL_METHOD__ == -1;49 // CHECK: ret {{.*}} true50}51 52// Verify float_control(precise, off) enables fast math flags on fp operations.53float fp_precise_1(float a, float b, float c) {54// CHECK-O3: _Z12fp_precise_1fff55// CHECK-O3: %[[M:.+]] = fmul fast float{{.*}}56// CHECK-O3: fadd fast float %[[M]], %c57#pragma float_control(precise, off)58 return a * b + c;59}60 61// Is float_control state cleared on exiting compound statements?62float fp_precise_2(float a, float b, float c) {63 // CHECK-O3: _Z12fp_precise_2fff64 // CHECK-O3: %[[M:.+]] = fmul float{{.*}}65 // CHECK-O3: fadd float %[[M]], %c66 {67#pragma float_control(precise, off)68 }69 return a * b + c;70}71 72// Does float_control survive template instantiation?73class Foo {};74Foo operator+(Foo, Foo);75 76template <typename T>77T template_muladd(T a, T b, T c) {78#pragma float_control(precise, off)79 return a * b + c;80}81 82float fp_precise_3(float a, float b, float c) {83 // CHECK-O3: _Z12fp_precise_3fff84 // CHECK-O3: %[[M:.+]] = fmul fast float{{.*}}85 // CHECK-O3: fadd fast float %[[M]], %c86 return template_muladd<float>(a, b, c);87}88 89template <typename T>90class fp_precise_4 {91 float method(float a, float b, float c) {92#pragma float_control(precise, off)93 return a * b + c;94 }95};96 97template class fp_precise_4<int>;98// CHECK-O3: _ZN12fp_precise_4IiE6methodEfff99// CHECK-O3: %[[M:.+]] = fmul fast float{{.*}}100// CHECK-O3: fadd fast float %[[M]], %c101 102// Check file-scoped float_control103#pragma float_control(push)104#pragma float_control(precise, off)105float fp_precise_5(float a, float b, float c) {106 // CHECK-O3: _Z12fp_precise_5fff107 // CHECK-O3: %[[M:.+]] = fmul fast float{{.*}}108 // CHECK-O3: fadd fast float %[[M]], %c109 return a * b + c;110}111#pragma float_control(pop)112 113float fff(float x, float y) {114// CHECK-LABEL: define{{.*}} float @_Z3fffff{{.*}}115// CHECK: entry116#pragma float_control(except, on)117 float z;118 z = z * z;119 //CHECK: llvm.experimental.constrained.fmul{{.*}}120 {121 z = x * y;122 //CHECK: llvm.experimental.constrained.fmul{{.*}}123 }124 {125// This pragma has no effect since if there are any fp intrin in the126// function then all the operations need to be fp intrin127#pragma float_control(except, off)128 z = z + x * y;129 //CHECK: llvm.experimental.constrained.fmul{{.*}}130 }131 z = z * z;132 //CHECK: llvm.experimental.constrained.fmul{{.*}}133 return z;134}135float check_precise(float x, float y) {136 // CHECK-LABEL: define{{.*}} float @_Z13check_preciseff{{.*}}137 float z;138 {139#pragma float_control(precise, on)140 z = x * y + z;141 //CHECK: llvm.fmuladd{{.*}}142 }143 {144#pragma float_control(precise, off)145 z = x * y + z;146 //CHECK: fmul fast float147 //CHECK: fadd fast float148 }149 return z;150}151 152float fma_test2(float a, float b, float c) {153// CHECK-LABEL define{{.*}} float @_Z9fma_test2fff{{.*}}154#pragma float_control(precise, off)155 float x = a * b + c;156 //CHECK: fmuladd157 return x;158}159 160float fma_test1(float a, float b, float c) {161// CHECK-LABEL define{{.*}} float @_Z9fma_test1fff{{.*}}162#pragma float_control(precise, on)163 float x = a * b + c;164 //CHECK: fmuladd165 return x;166}167 168#pragma float_control(push)169#pragma float_control(precise, on)170struct Distance {};171Distance operator+(Distance, Distance);172 173template <class T>174T add(T lhs, T rhs) {175#pragma float_control(except, on)176 return lhs + rhs;177}178#pragma float_control(pop)179 180float test_OperatorCall() {181 return add(1.0f, 2.0f);182 //CHECK: llvm.experimental.constrained.fadd{{.*}}fpexcept.strict183}184// CHECK-LABEL define{{.*}} float {{.*}}test_OperatorCall{{.*}}185 186#if FENV_ON187#pragma STDC FENV_ACCESS ON188#endif189// CHECK-LABEL: define {{.*}}callt{{.*}}190 191void callt() {192 volatile float z;193 z = z * z;194 //CHECK-FENV: llvm.experimental.constrained.fmul{{.*}}195}196 197// CHECK-LABEL: define {{.*}}myAdd{{.*}}198float myAdd(int i, float f) {199 if (i<0)200 return 1.0 + 2.0;201 // Check that floating point constant folding doesn't occur if202 // #pragma STC FENV_ACCESS is enabled.203 //CHECK-FENV: llvm.experimental.constrained.fadd{{.*}}double 1.0{{.*}}double 2.0{{.*}}204 //CHECK: store float 3.0{{.*}}retval{{.*}}205 static double v = 1.0 / 3.0;206 //CHECK-FENV: llvm.experimental.constrained.fptrunc.f32.f64{{.*}}207 //CHECK-NOT: fdiv208 return v;209}210 211#if EXCEPT212namespace ns {213// Check that pragma float_control can appear in namespace.214#pragma float_control(except, on, push)215float exc_on(double x, float zero) {216// CHECK-NS: define {{.*}}exc_on{{.*}}217 {} try {218 x = 1.0 / zero; /* division by zero, the result unused */219//CHECK-NS: llvm.experimental.constrained.fdiv{{.*}}220 } catch (...) {}221 return zero;222}223}224 225// Check pragma is still effective after namespace closes226float exc_still_on(double x, float zero) {227// CHECK-NS: define {{.*}}exc_still_on{{.*}}228 {} try {229 x = 1.0 / zero; /* division by zero, the result unused */230//CHECK-NS: llvm.experimental.constrained.fdiv{{.*}}231 } catch (...) {}232 return zero;233}234 235#pragma float_control(pop)236float exc_off(double x, float zero) {237// CHECK-NS: define {{.*}}exc_off{{.*}}238 {} try {239 x = 1.0 / zero; /* division by zero, the result unused */240//CHECK-NS: fdiv double241 } catch (...) {}242 return zero;243}244 245namespace fc_template_namespace {246#pragma float_control(except, on, push)247template <class T>248T exc_on(double x, T zero) {249// CHECK-NS: define {{.*}}fc_template_namespace{{.*}}250 {} try {251 x = 1.0 / zero; /* division by zero, the result unused */252//CHECK-NS: llvm.experimental.constrained.fdiv{{.*}}253 } catch (...) {}254 return zero;255}256}257 258#pragma float_control(pop)259float xx(double x, float z) {260 return fc_template_namespace::exc_on<float>(x, z);261}262#endif // EXCEPT263 264float try_lam(float x, unsigned n) {265// CHECK: define {{.*}}try_lam{{.*}}class.anon{{.*}}266 float result;267 auto t =268 // Lambda expression begins269 [](float a, float b) {270#pragma float_control( except, on)271 return a * b;272//CHECK: llvm.experimental.constrained.fmul{{.*}}fpexcept.strict273 } // end of lambda expression274 (1.0f,2.0f);275 result = x + t;276 return result;277}278 279float mySub(float x, float y) {280 // CHECK: define {{.*}}float {{.*}}mySub{{.*}}281 // CHECK-NS: fsub float282 // CHECK-SOURCE: fsub float283 // CHECK-DOUBLE: fpext float284 // CHECK-DOUBLE: fpext float285 // CHECK-DOUBLE: fsub double286 // CHECK-DOUBLE: fptrunc double {{.*}} to float287 // CHECK-EXTENDED: fpext float288 // CHECK-EXTENDED: fpext float289 // CHECK-EXTENDED: fsub double290 // CHECK-EXTENDED: fptrunc double {{.*}} to float291 return x - y;292}293 294float mySubSource(float x, float y) {295// CHECK: define {{.*}}float {{.*}}mySubSource{{.*}}296#pragma clang fp eval_method(source)297 return x - y;298 // CHECK: fsub float299}300 301float mySubExtended(float x, float y) {302// CHECK: define {{.*}}float {{.*}}mySubExtended{{.*}}303#pragma clang fp eval_method(extended)304 return x - y;305 // CHECK: fpext float306 // CHECK: fpext float307 // CHECK: fsub x86_fp80308 // CHECK: fptrunc x86_fp80 {{.*}} to float309 // CHECK-AIX: fsub double310 // CHECK-AIX: fptrunc double311}312 313float mySubDouble(float x, float y) {314// CHECK: define {{.*}}float {{.*}}mySubDouble{{.*}}315#pragma clang fp eval_method(double)316 return x - y;317 // CHECK: fpext float318 // CHECK: fpext float319 // CHECK: fsub double320 // CHECK: fptrunc double {{.*}} to float321}322 323#ifndef NF128324__float128 mySub128(__float128 x, __float128 y) {325 // CHECK: define {{.*}}mySub128{{.*}}326 // Expect no fpext since fp128 is already widest327 // CHECK: load fp128328 // CHECK-NEXT: load fp128329 // CHECK-NEXT: fsub fp128330 // CHECK-NEXT: ret fp128331 return x - y;332}333#endif334 335void mySubfp16(__fp16 *res, __fp16 *x, __fp16 *y) {336 // CHECK: define {{.*}}mySubfp16{{.*}}337 *res = *x - *y;338 // CHECK: load half339 // CHECK-NEXT: load half340 // CHECK-NEXT: fpext half{{.*}}341 // CHECK-NEXT: load half342 // CHECK-NEXT: load half343 // CHECK-NS: fpext half{{.*}} to float344 // CHECK-DEFAULT: fpext half{{.*}} to float345 // CHECK-DOUBLE: fpext half{{.*}} to float346 // CHECK-EXTENDED: fpext half{{.*}} to float347 // CHECK-NEXT: fsub348 // CHECK-NEXT: fptrunc {{.*}}to half349 // CHECK-NS: fptrunc float {{.*}} to half350 // CHECK-DOUBLE: fptrunc float {{.*}} to half351 // CHECK-EXTENDED: fptrunc float {{.*}} to half352}353 354float Div(float x, float y, float z) {355 // CHECK: define{{.*}}float {{.*}}Div{{.*}}356 // CHECK-CONST-ARGS: fdiv float357 return x / (y / z);358}359 360float DivExtended(float x, float y, float z) {361// CHECK: define{{.*}}float {{.*}}DivExtended{{.*}}362#pragma clang fp eval_method(extended)363 // CHECK-CONST-ARGS: fdiv x86_fp80364 // CHECK-CONST-ARGS: fptrunc x86_fp80365 return x / (y / z);366}367 368float DivDouble(float x, float y, float z) {369// CHECK: define{{.*}}float {{.*}}DivDouble{{.*}}370#pragma clang fp eval_method(double)371 // CHECK-CONST-ARGS: fdiv double372 // CHECK-CONST-ARGS: fptrunc double373 return x / (y / z);374}375 376float DivSource(float x, float y, float z) {377// CHECK: define{{.*}}float {{.*}}DivSource{{.*}}378#pragma clang fp eval_method(source)379 // CHECK-CONST-ARGS: fdiv float380 return x / (y / z);381}382 383int main() {384 float f = Div(4.2f, 1.0f, 3.0f);385 float fextended = DivExtended(4.2f, 1.0f, 3.0f);386 float fdouble = DivDouble(4.2f, 1.0f, 3.0f);387 float fsource = DivSource(4.2f, 1.0f, 3.0f);388 // CHECK: store float389}390