raising the head after a three-weeks refactoring
[m6w6/ext-psi] / src / calc.c
1 /*******************************************************************************
2 Copyright (c) 2016, Michael Wallner <mike@php.net>.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7
8 * Redistributions of source code must retain the above copyright notice,
9 this list of conditions and the following disclaimer.
10 * Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
13
14 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
18 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *******************************************************************************/
25
26 #include "php_psi_stdinc.h"
27
28 #include "token.h"
29 #include "calc.h"
30
31 #define PRIfval "f"
32 #define PRIdval "lf"
33 #define PRIldval "Lf"
34
35 #define PSI_CALC_OP(var) do { \
36 const char *fmt = "calc %" PRI##var ", %" PRI##var ": %" PRI##var "\n"; \
37 res->var = PSI_CALC(v1->var, v2->var); \
38 if (!res->var && (v1->var || v2->var)) fprintf(stderr, fmt, v1->var, v2->var, res->var); \
39 } while (0)
40 #define PSI_CALC_OP2(vres, var1, var2) do { \
41 const char *fmt = "calc %" PRI##var1 ", %" PRI##var2 ": %" PRI##vres "\n"; \
42 res->vres = PSI_CALC(v1->var1, v2->var2); \
43 if (!res->vres && (v1->var1 || v2->var2)) fprintf(stderr, fmt, v1->var1, v2->var2, res->vres); \
44 } while(0)
45
46 #ifdef HAVE_LONG_DOUBLE
47 # define PSI_CALC_NO_LD
48 # define PSI_CALC_OP_LD PSI_CALC_OP(ldval)
49 # define PSI_CALC_OP2_LD2(var1) PSI_CALC_OP2(ldval, var1, ldval)
50 # define PSI_CALC_OP2_LD1(var2) PSI_CALC_OP2(ldval, ldval, var2)
51 #else
52 # define PSI_CALC_NO_LD abort()
53 # define PSI_CALC_OP_LD PSI_CALC_NO_LD
54 # define PSI_CALC_OP2_LD2(var) PSI_CALC_NO_LD
55 # define PSI_CALC_OP2_LD1(var) PSI_CALC_NO_LD
56 #endif
57
58 #define PSI_CALC_FN(op) token_t psi_calc_##op(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res) \
59 { \
60 if (t1 == t2) { \
61 switch (t1) { \
62 case PSI_T_FLOAT: PSI_CALC_OP(fval); break; \
63 case PSI_T_DOUBLE: PSI_CALC_OP(dval); break; \
64 case PSI_T_LONG_DOUBLE: PSI_CALC_OP_LD; break; \
65 case PSI_T_INT8: PSI_CALC_OP(i8); break; \
66 case PSI_T_UINT8: PSI_CALC_OP(u8); break; \
67 case PSI_T_INT16: PSI_CALC_OP(i16); break; \
68 case PSI_T_UINT16: PSI_CALC_OP(u16); break; \
69 case PSI_T_INT32: PSI_CALC_OP(i32); break; \
70 case PSI_T_UINT32: PSI_CALC_OP(u32); break; \
71 case PSI_T_INT64: PSI_CALC_OP(i64); break; \
72 case PSI_T_UINT64: PSI_CALC_OP(u64); break; \
73 EMPTY_SWITCH_DEFAULT_CASE(); \
74 } \
75 return t1; \
76 } else if (t1 == PSI_T_DOUBLE) { \
77 switch (t2) { \
78 case PSI_T_LONG_DOUBLE: PSI_CALC_OP2_LD2(dval); return t2; \
79 case PSI_T_FLOAT: PSI_CALC_OP2(dval, dval, fval); break; \
80 case PSI_T_INT8: PSI_CALC_OP2(dval, dval, i8); break; \
81 case PSI_T_UINT8: PSI_CALC_OP2(dval, dval, u8); break; \
82 case PSI_T_INT16: PSI_CALC_OP2(dval, dval, i16); break; \
83 case PSI_T_UINT16: PSI_CALC_OP2(dval, dval, u16); break; \
84 case PSI_T_INT32: PSI_CALC_OP2(dval, dval, i32); break; \
85 case PSI_T_UINT32: PSI_CALC_OP2(dval, dval, u32); break; \
86 case PSI_T_INT64: PSI_CALC_OP2(dval, dval, i64); break; \
87 case PSI_T_UINT64: PSI_CALC_OP2(dval, dval, u64); break; \
88 EMPTY_SWITCH_DEFAULT_CASE(); \
89 } \
90 return t1; \
91 } else if (t2 == PSI_T_DOUBLE) { \
92 switch (t1) { \
93 case PSI_T_LONG_DOUBLE: PSI_CALC_OP2_LD1(dval); return t1; \
94 case PSI_T_FLOAT: PSI_CALC_OP2(dval, fval, dval); break; \
95 case PSI_T_INT8: PSI_CALC_OP2(dval, i8, dval); break; \
96 case PSI_T_UINT8: PSI_CALC_OP2(dval, u8, dval); break; \
97 case PSI_T_INT16: PSI_CALC_OP2(dval, i16, dval); break; \
98 case PSI_T_UINT16: PSI_CALC_OP2(dval, u16, dval); break; \
99 case PSI_T_INT32: PSI_CALC_OP2(dval, i32, dval); break; \
100 case PSI_T_UINT32: PSI_CALC_OP2(dval, u32, dval); break; \
101 case PSI_T_INT64: PSI_CALC_OP2(dval, i64, dval); break; \
102 case PSI_T_UINT64: PSI_CALC_OP2(dval, u64, dval); break; \
103 EMPTY_SWITCH_DEFAULT_CASE(); \
104 } \
105 return t2; \
106 } else if (t1 == PSI_T_LONG_DOUBLE) { \
107 PSI_CALC_NO_LD; \
108 switch (t2) { \
109 case PSI_T_DOUBLE: PSI_CALC_OP2_LD1(dval); break; \
110 case PSI_T_FLOAT: PSI_CALC_OP2_LD1(fval); break; \
111 case PSI_T_INT8: PSI_CALC_OP2_LD1(i8); break; \
112 case PSI_T_UINT8: PSI_CALC_OP2_LD1(u8); break; \
113 case PSI_T_INT16: PSI_CALC_OP2_LD1(i16); break; \
114 case PSI_T_UINT16: PSI_CALC_OP2_LD1(u16); break; \
115 case PSI_T_INT32: PSI_CALC_OP2_LD1(i32); break; \
116 case PSI_T_UINT32: PSI_CALC_OP2_LD1(u32); break; \
117 case PSI_T_INT64: PSI_CALC_OP2_LD1(i64); break; \
118 case PSI_T_UINT64: PSI_CALC_OP2_LD1(u64); break; \
119 EMPTY_SWITCH_DEFAULT_CASE(); \
120 } \
121 return t1; \
122 } else if (t2 == PSI_T_LONG_DOUBLE) { \
123 PSI_CALC_NO_LD; \
124 switch (t1) { \
125 case PSI_T_DOUBLE: PSI_CALC_OP2_LD2(dval); break; \
126 case PSI_T_FLOAT: PSI_CALC_OP2_LD2(fval); break; \
127 case PSI_T_INT8: PSI_CALC_OP2_LD2(i8); break; \
128 case PSI_T_UINT8: PSI_CALC_OP2_LD2(u8); break; \
129 case PSI_T_INT16: PSI_CALC_OP2_LD2(i16); break; \
130 case PSI_T_UINT16: PSI_CALC_OP2_LD2(u16); break; \
131 case PSI_T_INT32: PSI_CALC_OP2_LD2(i32); break; \
132 case PSI_T_UINT32: PSI_CALC_OP2_LD2(u32); break; \
133 case PSI_T_INT64: PSI_CALC_OP2_LD2(i64); break; \
134 case PSI_T_UINT64: PSI_CALC_OP2_LD2(u64); break; \
135 EMPTY_SWITCH_DEFAULT_CASE(); \
136 } \
137 return t2; \
138 } else if (t1 == PSI_T_FLOAT) { \
139 switch (t2) { \
140 case PSI_T_LONG_DOUBLE: PSI_CALC_OP2_LD2(fval); return t2; \
141 case PSI_T_DOUBLE: PSI_CALC_OP2(dval, fval, dval); return t2; \
142 case PSI_T_INT8: PSI_CALC_OP2(fval, fval, i8); break; \
143 case PSI_T_UINT8: PSI_CALC_OP2(fval, fval, u8); break; \
144 case PSI_T_INT16: PSI_CALC_OP2(fval, fval, i16); break; \
145 case PSI_T_UINT16: PSI_CALC_OP2(fval, fval, u16); break; \
146 case PSI_T_INT32: PSI_CALC_OP2(fval, fval, i32); break; \
147 case PSI_T_UINT32: PSI_CALC_OP2(fval, fval, u32); break; \
148 case PSI_T_INT64: PSI_CALC_OP2(fval, fval, i64); break; \
149 case PSI_T_UINT64: PSI_CALC_OP2(fval, fval, u64); break; \
150 EMPTY_SWITCH_DEFAULT_CASE(); \
151 } \
152 return t1; \
153 } else if (t2 == PSI_T_FLOAT) { \
154 switch (t1) { \
155 case PSI_T_LONG_DOUBLE: PSI_CALC_OP2_LD1(fval); return t1; \
156 case PSI_T_DOUBLE: PSI_CALC_OP2(dval, dval, fval); return t1; \
157 case PSI_T_INT8: PSI_CALC_OP2(fval, i8, fval); break; \
158 case PSI_T_UINT8: PSI_CALC_OP2(fval, u8, fval); break; \
159 case PSI_T_INT16: PSI_CALC_OP2(fval, i16, fval); break; \
160 case PSI_T_UINT16: PSI_CALC_OP2(fval, u16, fval); break; \
161 case PSI_T_INT32: PSI_CALC_OP2(fval, i32, fval); break; \
162 case PSI_T_UINT32: PSI_CALC_OP2(fval, u32, fval); break; \
163 case PSI_T_INT64: PSI_CALC_OP2(fval, i64, fval); break; \
164 case PSI_T_UINT64: PSI_CALC_OP2(fval, u64, fval); break; \
165 EMPTY_SWITCH_DEFAULT_CASE(); \
166 } \
167 return t2; \
168 } else { \
169 int64_t sval1 = v1->i64, sval2 = v2->i64; \
170 uint64_t uval1 = v1->u64, uval2 = v2->u64; \
171 switch (t1) { \
172 case PSI_T_INT8: sval1 >>= 8; \
173 case PSI_T_INT16: sval1 >>= 8; \
174 case PSI_T_INT32: sval1 >>= 8; \
175 case PSI_T_INT64: \
176 switch (t2) { \
177 case PSI_T_INT8: sval2 >>= 8; \
178 case PSI_T_INT16: sval2 >>= 8; \
179 case PSI_T_INT32: sval2 >>= 8; \
180 case PSI_T_INT64: \
181 res->i64 = PSI_CALC(sval1 , sval2); \
182 return PSI_T_INT64; \
183 case PSI_T_UINT8: uval2 >>= 8; \
184 case PSI_T_UINT16: uval2 >>= 8; \
185 case PSI_T_UINT32: uval2 >>= 8; \
186 case PSI_T_UINT64: \
187 res->i64 = PSI_CALC(sval1, uval2); \
188 return PSI_T_INT64; \
189 } \
190 break; \
191 case PSI_T_UINT8: uval1 >>= 8; \
192 case PSI_T_UINT16: uval1 >>= 8; \
193 case PSI_T_UINT32: uval1 >>= 8; \
194 case PSI_T_UINT64: \
195 switch (t2) { \
196 case PSI_T_INT8: sval2 >>= 8; \
197 case PSI_T_INT16: sval2 >>= 8; \
198 case PSI_T_INT32: sval2 >>= 8; \
199 case PSI_T_INT64: \
200 res->i64 = PSI_CALC(uval1, sval2); \
201 return PSI_T_INT64; \
202 case PSI_T_UINT8: uval2 >>= 8; \
203 case PSI_T_UINT16: uval2 >>= 8; \
204 case PSI_T_UINT32: uval2 >>= 8; \
205 case PSI_T_UINT64: \
206 res->u64 = PSI_CALC(uval1, uval2); \
207 return PSI_T_UINT64; \
208 } \
209 break; \
210 } \
211 } \
212 ZEND_ASSERT(0); \
213 return 0; \
214 }
215
216 #undef PSI_CALC
217 #define PSI_CALC(var1, var2) (var1) + (var2)
218 PSI_CALC_FN(add)
219 #undef PSI_CALC
220 #define PSI_CALC(var1, var2) (var1) * (var2)
221 PSI_CALC_FN(mul)
222 #undef PSI_CALC
223 #define PSI_CALC(var1, var2) (var1) - (var2)
224 PSI_CALC_FN(sub)
225 #undef PSI_CALC
226 #define PSI_CALC(var1, var2) (var1) / (var2)
227 PSI_CALC_FN(div)