xref: /llvm-project/clang/test/CodeGen/fp-reassoc-pragma.cpp (revision a105877646d68e48cdeeeadd9d1e075dc3c5d68d)
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