1 // RUN: %clang_cc1 -O3 -triple %itanium_abi_triple -emit-llvm -o - %s | FileCheck %s 2 // Simple case 3 float fp_reassoc_simple(float a, float b, float c) { 4 // CHECK: _Z17fp_reassoc_simplefff 5 // CHECK: %[[A:.+]] = fadd reassoc float %b, %c 6 // CHECK: %[[M:.+]] = fmul reassoc float %b, %[[A]] 7 // CHECK-NEXT: fadd reassoc float %c, %[[M]] 8 #pragma clang fp reassociate(on) 9 a = b + c; 10 return a * b + c; 11 } 12 13 // Reassoc pragma should only apply to its scope 14 float fp_reassoc_scoped(float a, float b, float c) { 15 // CHECK: _Z17fp_reassoc_scopedfff 16 // CHECK: %[[M:.+]] = fmul float %a, %b 17 // CHECK-NEXT: fadd float %[[M]], %c 18 { 19 #pragma clang fp reassociate(on) 20 } 21 return a * b + c; 22 } 23 24 // Reassoc pragma should apply to templates as well 25 class Foo {}; 26 Foo operator+(Foo, Foo); 27 template <typename T> 28 T template_reassoc(T a, T b, T c) { 29 #pragma clang fp reassociate(on) 30 return ((a + b) - c) + c; 31 } 32 33 float fp_reassoc_template(float a, float b, float c) { 34 // CHECK: _Z19fp_reassoc_templatefff 35 // CHECK: %[[A1:.+]] = fadd reassoc float %a, %b 36 // CHECK-NEXT: %[[A2:.+]] = fsub reassoc float %[[A1]], %c 37 // CHECK-NEXT: fadd reassoc float %c, %[[A2]] 38 return template_reassoc<float>(a, b, c); 39 } 40 41 // File Scoping should work across functions 42 #pragma clang fp reassociate(on) 43 float fp_file_scope_on(float a, float b, float c) { 44 // CHECK: _Z16fp_file_scope_onfff 45 // CHECK: %[[M1:.+]] = fmul reassoc float %a, %c 46 // CHECK-NEXT: %[[M2:.+]] = fmul reassoc float %b, %c 47 // CHECK-NEXT: fadd reassoc float %[[M1]], %[[M2]] 48 return (a * c) + (b * c); 49 } 50 51 // Inner pragma has precedence 52 float fp_file_scope_stop(float a, float b, float c) { 53 // CHECK: _Z18fp_file_scope_stopfff 54 // CHECK: %[[A:.+]] = fadd reassoc float %a, %a 55 // CHECK: %[[M1:.+]] = fmul float %[[A]], %c 56 // CHECK-NEXT: %[[M2:.+]] = fmul float %b, %c 57 // CHECK-NEXT: fsub float %[[M1]], %[[M2]] 58 a = a + a; 59 { 60 #pragma clang fp reassociate(off) 61 return (a * c) - (b * c); 62 } 63 } 64 65 #pragma clang fp reassociate(off) 66 float fp_reassoc_off(float a, float b, float c) { 67 // CHECK: _Z14fp_reassoc_offfff 68 // CHECK: %[[D1:.+]] = fdiv float %a, %c 69 // CHECK-NEXT: %[[D2:.+]] = fdiv float %b, %c 70 // CHECK-NEXT: fadd float %[[D1]], %[[D2]] 71 return (a / c) + (b / c); 72 } 73 74 // Takes latest flag 75 float fp_reassoc_many(float a, float b, float c) { 76 // CHECK: _Z15fp_reassoc_manyfff 77 // CHECK: %[[D1:.+]] = fdiv reassoc float %a, %c 78 // CHECK-NEXT: %[[D2:.+]] = fdiv reassoc float %b, %c 79 // CHECK-NEXT: fadd reassoc float %[[D1]], %[[D2]] 80 #pragma clang fp reassociate(off) reassociate(on) 81 return (a / c) + (b / c); 82 } 83 84 // Pragma does not propagate through called functions 85 float helper_func(float a, float b, float c) { return a + b + c; } 86 float fp_reassoc_call_helper(float a, float b, float c) { 87 // CHECK: _Z22fp_reassoc_call_helperfff 88 // CHECK: %[[S1:.+]] = fadd float %a, %b 89 // CHECK-NEXT: fadd float %[[S1]], %c 90 #pragma clang fp reassociate(on) 91 return helper_func(a, b, c); 92 } 93