1 // 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 2 // RUN: %clang_cc1 -fexperimental-strict-floating-point -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK-DEFAULT 3 // 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 4 // RUN: %clang_cc1 -fexperimental-strict-floating-point -triple %itanium_abi_triple -O3 -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-O3 %s 5 // RUN: %clang_cc1 -fexperimental-strict-floating-point -triple x86_64-linux-gnu -emit-llvm -o - %s -ffp-eval-method=source | FileCheck %s -check-prefix=CHECK-SOURCE 6 // RUN: %clang_cc1 -fexperimental-strict-floating-point -triple x86_64-linux-gnu -emit-llvm -o - %s -ffp-eval-method=double | FileCheck %s -check-prefix=CHECK-DOUBLE 7 // RUN: %clang_cc1 -fexperimental-strict-floating-point -triple x86_64-linux-gnu -emit-llvm -o - %s -ffp-eval-method=extended -mlong-double-80 | FileCheck %s -check-prefix=CHECK-EXTENDED 8 // RUN: %clang_cc1 -fexperimental-strict-floating-point -triple i386-linux-gnu -emit-llvm -o - %s -ffp-eval-method=source | FileCheck %s -check-prefix=CHECK-SOURCE 9 // RUN: %clang_cc1 -fexperimental-strict-floating-point -triple i386-linux-gnu -emit-llvm -o - %s -ffp-eval-method=double | FileCheck %s -check-prefix=CHECK-DOUBLE 10 // RUN: %clang_cc1 -fexperimental-strict-floating-point -triple i386-linux-gnu -emit-llvm -o - %s -ffp-eval-method=extended -mlong-double-80 | FileCheck %s -check-prefix=CHECK-EXTENDED 11 // RUN: %clang_cc1 -triple powerpc-unknown-aix -DPPC -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK-AIX 12 13 // Verify float_control(precise, off) enables fast math flags on fp operations. 14 float fp_precise_1(float a, float b, float c) { 15 // CHECK-O3: _Z12fp_precise_1fff 16 // CHECK-O3: %[[M:.+]] = fmul fast float{{.*}} 17 // CHECK-O3: fadd fast float %[[M]], %c 18 #pragma float_control(precise, off) 19 return a * b + c; 20 } 21 22 // Is float_control state cleared on exiting compound statements? 23 float fp_precise_2(float a, float b, float c) { 24 // CHECK-O3: _Z12fp_precise_2fff 25 // CHECK-O3: %[[M:.+]] = fmul float{{.*}} 26 // CHECK-O3: fadd float %[[M]], %c 27 { 28 #pragma float_control(precise, off) 29 } 30 return a * b + c; 31 } 32 33 // Does float_control survive template instantiation? 34 class Foo {}; 35 Foo operator+(Foo, Foo); 36 37 template <typename T> 38 T template_muladd(T a, T b, T c) { 39 #pragma float_control(precise, off) 40 return a * b + c; 41 } 42 43 float fp_precise_3(float a, float b, float c) { 44 // CHECK-O3: _Z12fp_precise_3fff 45 // CHECK-O3: %[[M:.+]] = fmul fast float{{.*}} 46 // CHECK-O3: fadd fast float %[[M]], %c 47 return template_muladd<float>(a, b, c); 48 } 49 50 template <typename T> 51 class fp_precise_4 { 52 float method(float a, float b, float c) { 53 #pragma float_control(precise, off) 54 return a * b + c; 55 } 56 }; 57 58 template class fp_precise_4<int>; 59 // CHECK-O3: _ZN12fp_precise_4IiE6methodEfff 60 // CHECK-O3: %[[M:.+]] = fmul fast float{{.*}} 61 // CHECK-O3: fadd fast float %[[M]], %c 62 63 // Check file-scoped float_control 64 #pragma float_control(push) 65 #pragma float_control(precise, off) 66 float fp_precise_5(float a, float b, float c) { 67 // CHECK-O3: _Z12fp_precise_5fff 68 // CHECK-O3: %[[M:.+]] = fmul fast float{{.*}} 69 // CHECK-O3: fadd fast float %[[M]], %c 70 return a * b + c; 71 } 72 #pragma float_control(pop) 73 74 float fff(float x, float y) { 75 // CHECK-LABEL: define{{.*}} float @_Z3fffff{{.*}} 76 // CHECK: entry 77 #pragma float_control(except, on) 78 float z; 79 z = z * z; 80 //CHECK: llvm.experimental.constrained.fmul{{.*}} 81 { 82 z = x * y; 83 //CHECK: llvm.experimental.constrained.fmul{{.*}} 84 } 85 { 86 // This pragma has no effect since if there are any fp intrin in the 87 // function then all the operations need to be fp intrin 88 #pragma float_control(except, off) 89 z = z + x * y; 90 //CHECK: llvm.experimental.constrained.fmul{{.*}} 91 } 92 z = z * z; 93 //CHECK: llvm.experimental.constrained.fmul{{.*}} 94 return z; 95 } 96 float check_precise(float x, float y) { 97 // CHECK-LABEL: define{{.*}} float @_Z13check_preciseff{{.*}} 98 float z; 99 { 100 #pragma float_control(precise, on) 101 z = x * y + z; 102 //CHECK: llvm.fmuladd{{.*}} 103 } 104 { 105 #pragma float_control(precise, off) 106 z = x * y + z; 107 //CHECK: fmul fast float 108 //CHECK: fadd fast float 109 } 110 return z; 111 } 112 113 float fma_test2(float a, float b, float c) { 114 // CHECK-LABEL define{{.*}} float @_Z9fma_test2fff{{.*}} 115 #pragma float_control(precise, off) 116 float x = a * b + c; 117 //CHECK: fmuladd 118 return x; 119 } 120 121 float fma_test1(float a, float b, float c) { 122 // CHECK-LABEL define{{.*}} float @_Z9fma_test1fff{{.*}} 123 #pragma float_control(precise, on) 124 float x = a * b + c; 125 //CHECK: fmuladd 126 return x; 127 } 128 129 #pragma float_control(push) 130 #pragma float_control(precise, on) 131 struct Distance {}; 132 Distance operator+(Distance, Distance); 133 134 template <class T> 135 T add(T lhs, T rhs) { 136 #pragma float_control(except, on) 137 return lhs + rhs; 138 } 139 #pragma float_control(pop) 140 141 float test_OperatorCall() { 142 return add(1.0f, 2.0f); 143 //CHECK: llvm.experimental.constrained.fadd{{.*}}fpexcept.strict 144 } 145 // CHECK-LABEL define{{.*}} float {{.*}}test_OperatorCall{{.*}} 146 147 #if FENV_ON 148 #pragma STDC FENV_ACCESS ON 149 #endif 150 // CHECK-LABEL: define {{.*}}callt{{.*}} 151 152 void callt() { 153 volatile float z; 154 z = z * z; 155 //CHECK-FENV: llvm.experimental.constrained.fmul{{.*}} 156 } 157 158 // CHECK-LABEL: define {{.*}}myAdd{{.*}} 159 float myAdd(int i, float f) { 160 if (i<0) 161 return 1.0 + 2.0; 162 // Check that floating point constant folding doesn't occur if 163 // #pragma STC FENV_ACCESS is enabled. 164 //CHECK-FENV: llvm.experimental.constrained.fadd{{.*}}double 1.0{{.*}}double 2.0{{.*}} 165 //CHECK: store float 3.0{{.*}}retval{{.*}} 166 static double v = 1.0 / 3.0; 167 //CHECK-FENV: llvm.experimental.constrained.fptrunc.f32.f64{{.*}} 168 //CHECK-NOT: fdiv 169 return v; 170 } 171 172 #if EXCEPT 173 namespace ns { 174 // Check that pragma float_control can appear in namespace. 175 #pragma float_control(except, on, push) 176 float exc_on(double x, float zero) { 177 // CHECK-NS: define {{.*}}exc_on{{.*}} 178 {} try { 179 x = 1.0 / zero; /* division by zero, the result unused */ 180 //CHECK-NS: llvm.experimental.constrained.fdiv{{.*}} 181 } catch (...) {} 182 return zero; 183 } 184 } 185 186 // Check pragma is still effective after namespace closes 187 float exc_still_on(double x, float zero) { 188 // CHECK-NS: define {{.*}}exc_still_on{{.*}} 189 {} try { 190 x = 1.0 / zero; /* division by zero, the result unused */ 191 //CHECK-NS: llvm.experimental.constrained.fdiv{{.*}} 192 } catch (...) {} 193 return zero; 194 } 195 196 #pragma float_control(pop) 197 float exc_off(double x, float zero) { 198 // CHECK-NS: define {{.*}}exc_off{{.*}} 199 {} try { 200 x = 1.0 / zero; /* division by zero, the result unused */ 201 //CHECK-NS: fdiv double 202 } catch (...) {} 203 return zero; 204 } 205 206 namespace fc_template_namespace { 207 #pragma float_control(except, on, push) 208 template <class T> 209 T exc_on(double x, T zero) { 210 // CHECK-NS: define {{.*}}fc_template_namespace{{.*}} 211 {} try { 212 x = 1.0 / zero; /* division by zero, the result unused */ 213 //CHECK-NS: llvm.experimental.constrained.fdiv{{.*}} 214 } catch (...) {} 215 return zero; 216 } 217 } 218 219 #pragma float_control(pop) 220 float xx(double x, float z) { 221 return fc_template_namespace::exc_on<float>(x, z); 222 } 223 #endif // EXCEPT 224 225 float try_lam(float x, unsigned n) { 226 // CHECK: define {{.*}}try_lam{{.*}}class.anon{{.*}} 227 float result; 228 auto t = 229 // Lambda expression begins 230 [](float a, float b) { 231 #pragma float_control( except, on) 232 return a * b; 233 //CHECK: llvm.experimental.constrained.fmul{{.*}}fpexcept.strict 234 } // end of lambda expression 235 (1.0f,2.0f); 236 result = x + t; 237 return result; 238 } 239 240 float mySub(float x, float y) { 241 // CHECK: define {{.*}}float {{.*}}mySub{{.*}} 242 // CHECK-NS: fsub float 243 // CHECK-SOURCE: fsub float 244 // CHECK-DOUBLE: fpext float 245 // CHECK-DOUBLE: fpext float 246 // CHECK-DOUBLE: fsub double 247 // CHECK-DOUBLE: fptrunc double {{.*}} to float 248 // CHECK-EXTENDED: fpext float 249 // CHECK-EXTENDED: fpext float 250 // CHECK-EXTENDED: fsub double 251 // CHECK-EXTENDED: fptrunc double {{.*}} to float 252 return x - y; 253 } 254 255 float mySubSource(float x, float y) { 256 // CHECK: define {{.*}}float {{.*}}mySubSource{{.*}} 257 #pragma float_control(source) 258 return x - y; 259 // CHECK: fsub float 260 } 261 262 float mySubExtended(float x, float y) { 263 // CHECK: define {{.*}}float {{.*}}mySubExtended{{.*}} 264 #pragma float_control(extended) 265 return x - y; 266 // CHECK: fpext float 267 // CHECK: fpext float 268 // CHECK: fsub x86_fp80 269 // CHECK: fptrunc x86_fp80 {{.*}} to float 270 } 271 272 float mySubDouble(float x, float y) { 273 // CHECK: define {{.*}}float {{.*}}mySubDouble{{.*}} 274 #pragma float_control(double) 275 return x - y; 276 // CHECK: fpext float 277 // CHECK: fpext float 278 // CHECK: fsub double 279 // CHECK: fptrunc double {{.*}} to float 280 } 281 282 #ifndef PPC 283 __float128 mySub128(__float128 x, __float128 y) { 284 // CHECK: define {{.*}}mySub128{{.*}} 285 // Expect no fpext since fp128 is already widest 286 // CHECK: load fp128 287 // CHECK-NEXT: load fp128 288 // CHECK-NEXT: fsub fp128 289 // CHECK-NEXT: ret fp128 290 return x - y; 291 } 292 #endif 293 294 void mySubfp16(__fp16 *res, __fp16 *x, __fp16 *y) { 295 // CHECK: define {{.*}}mySubfp16{{.*}} 296 *res = *x - *y; 297 // CHECK: load half 298 // CHECK-NEXT: load half 299 // CHECK-NEXT: fpext half{{.*}} 300 // CHECK-NEXT: load half 301 // CHECK-NEXT: load half 302 // CHECK-NS: fpext half{{.*}} to float 303 // CHECK-DEFAULT: fpext half{{.*}} to float 304 // CHECK-DOUBLE: fpext half{{.*}} to double 305 // CHECK-EXTENDED: fpext half{{.*}} to x86_fp80 306 // CHECK-NEXT: fsub 307 // CHECK-NEXT: fptrunc {{.*}}to half 308 // CHECK-NS: fptrunc float {{.*}} to half 309 // CHECK-DOUBLE: fptrunc double {{.*}} to half 310 // CHECK-EXTENDED: fptrunc x86_fp80 {{.*}} to half 311 } 312 313 int getFEM() { 314 // CHECK: define {{.*}}getFEM{{.*}} 315 return __FLT_EVAL_METHOD__; 316 // CHECK-NS: ret {{.*}} 0 317 // CHECK-AIX: ret {{.*}} 1 318 // CHECK-SOURCE: ret {{.*}} 0 319 // CHECK-DOUBLE: ret {{.*}} 1 320 // CHECK-EXTENDED: ret {{.*}} 2 321 } 322