1 /*******************************************************************************
2 Copyright (c) 2016, Michael Wallner <mike@php.net>.
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
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.
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 *******************************************************************************/
26 #include "php_psi_stdinc.h"
32 #define PSI_CALC_CAST_SET(in_type, in_val, op, out_val, out_var) \
34 case PSI_T_INT8: (out_val)->out_var op (in_val)->i8; break; \
35 case PSI_T_UINT8: (out_val)->out_var op (in_val)->u8; break; \
36 case PSI_T_INT16: (out_val)->out_var op (in_val)->i16; break; \
37 case PSI_T_UINT16: (out_val)->out_var op (in_val)->u16; break; \
38 case PSI_T_INT32: (out_val)->out_var op (in_val)->i32; break; \
39 case PSI_T_UINT32: (out_val)->out_var op (in_val)->u32; break; \
40 case PSI_T_INT64: (out_val)->out_var op (in_val)->i64; break; \
41 case PSI_T_UINT64: (out_val)->out_var op (in_val)->u64; break; \
42 case PSI_T_FLOAT: (out_val)->out_var op (in_val)->fval; break; \
43 case PSI_T_DOUBLE: (out_val)->out_var op (in_val)->dval; break; \
44 case PSI_T_LONG_DOUBLE: (out_val)->out_var op (in_val)->ldval; break; \
49 #define PSI_CALC_CAST(in_type, in_val, op, out_type, out_val) \
51 case PSI_T_INT8: PSI_CALC_CAST_SET(in_type, in_val, op, out_val, i8) break; \
52 case PSI_T_UINT8: PSI_CALC_CAST_SET(in_type, in_val, op, out_val, u8) break; \
53 case PSI_T_INT16: PSI_CALC_CAST_SET(in_type, in_val, op, out_val, i16) break; \
54 case PSI_T_UINT16: PSI_CALC_CAST_SET(in_type, in_val, op, out_val, u16) break; \
55 case PSI_T_INT32: PSI_CALC_CAST_SET(in_type, in_val, op, out_val, i32) break; \
56 case PSI_T_UINT32: PSI_CALC_CAST_SET(in_type, in_val, op, out_val, u32) break; \
57 case PSI_T_INT64: PSI_CALC_CAST_SET(in_type, in_val, op, out_val, i64) break; \
58 case PSI_T_UINT64: PSI_CALC_CAST_SET(in_type, in_val, op, out_val, u64) break; \
59 case PSI_T_FLOAT: PSI_CALC_CAST_SET(in_type, in_val, op, out_val, fval) break; \
60 case PSI_T_DOUBLE: PSI_CALC_CAST_SET(in_type, in_val, op, out_val, dval) break; \
61 case PSI_T_LONG_DOUBLE: PSI_CALC_CAST_SET(in_type, in_val, op, out_val, ldval) break; \
66 #define PSI_CALC_CAST_SET_INT(in_type, in_val, op, out_val, out_var) \
68 case PSI_T_INT8: (out_val)->out_var op (in_val)->i8; break; \
69 case PSI_T_UINT8: (out_val)->out_var op (in_val)->u8; break; \
70 case PSI_T_INT16: (out_val)->out_var op (in_val)->i16; break; \
71 case PSI_T_UINT16: (out_val)->out_var op (in_val)->u16; break; \
72 case PSI_T_INT32: (out_val)->out_var op (in_val)->i32; break; \
73 case PSI_T_UINT32: (out_val)->out_var op (in_val)->u32; break; \
74 case PSI_T_INT64: (out_val)->out_var op (in_val)->i64; break; \
75 case PSI_T_UINT64: (out_val)->out_var op (in_val)->u64; break; \
79 #define PSI_CALC_CAST_INT(in_type, in_val, op, out_type, out_val) \
81 case PSI_T_INT8: PSI_CALC_CAST_SET_INT(in_type, in_val, op, out_val, i8) break; \
82 case PSI_T_UINT8: PSI_CALC_CAST_SET_INT(in_type, in_val, op, out_val, u8) break; \
83 case PSI_T_INT16: PSI_CALC_CAST_SET_INT(in_type, in_val, op, out_val, i16) break; \
84 case PSI_T_UINT16: PSI_CALC_CAST_SET_INT(in_type, in_val, op, out_val, u16) break; \
85 case PSI_T_INT32: PSI_CALC_CAST_SET_INT(in_type, in_val, op, out_val, i32) break; \
86 case PSI_T_UINT32: PSI_CALC_CAST_SET_INT(in_type, in_val, op, out_val, u32) break; \
87 case PSI_T_INT64: PSI_CALC_CAST_SET_INT(in_type, in_val, op, out_val, i64) break; \
88 case PSI_T_UINT64: PSI_CALC_CAST_SET_INT(in_type, in_val, op, out_val, u64) break; \
93 void psi_calc_cast(token_t in_type
, impl_val
*in_val
, token_t out_type
, impl_val
*out_val
)
95 PSI_CALC_CAST(in_type
, in_val
, =, out_type
, out_val
)
99 #define PSI_CALC_OP(var) do { \
100 const char *fmt = "calc %" PRI##var ", %" PRI##var ": %" PRI##var "\n"; \
101 res->var = PSI_CALC(v1->var, v2->var); \
102 if (!res->var && (v1->var || v2->var)) fprintf(stderr, fmt, v1->var, v2->var, res->var); \
104 #define PSI_CALC_OP2(vres, var1, var2) do { \
105 const char *fmt = "calc %" PRI##var1 ", %" PRI##var2 ": %" PRI##vres "\n"; \
106 res->vres = PSI_CALC(v1->var1, v2->var2); \
107 if (!res->vres && (v1->var1 || v2->var2)) fprintf(stderr, fmt, v1->var1, v2->var2, res->vres); \
110 #define PSI_CALC_OP(var) res->var = PSI_CALC(v1->var, v2->var)
111 #define PSI_CALC_OP2(vres, var1, var2) res->vres = PSI_CALC(v1->var1, v2->var2)
114 #ifdef HAVE_LONG_DOUBLE
115 # define PSI_CALC_NO_LD
116 # define PSI_CALC_OP_LD PSI_CALC_OP(ldval)
117 # define PSI_CALC_OP2_LD2(var1) PSI_CALC_OP2(ldval, var1, ldval)
118 # define PSI_CALC_OP2_LD1(var2) PSI_CALC_OP2(ldval, ldval, var2)
120 # define PSI_CALC_NO_LD abort()
121 # define PSI_CALC_OP_LD PSI_CALC_NO_LD
122 # define PSI_CALC_OP2_LD2(var) PSI_CALC_NO_LD
123 # define PSI_CALC_OP2_LD1(var) PSI_CALC_NO_LD
126 #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) \
130 case PSI_T_FLOAT: PSI_CALC_OP(fval); break; \
131 case PSI_T_DOUBLE: PSI_CALC_OP(dval); break; \
132 case PSI_T_LONG_DOUBLE: PSI_CALC_OP_LD; break; \
133 case PSI_T_INT8: PSI_CALC_OP(i8); break; \
134 case PSI_T_UINT8: PSI_CALC_OP(u8); break; \
135 case PSI_T_INT16: PSI_CALC_OP(i16); break; \
136 case PSI_T_UINT16: PSI_CALC_OP(u16); break; \
137 case PSI_T_INT32: PSI_CALC_OP(i32); break; \
138 case PSI_T_UINT32: PSI_CALC_OP(u32); break; \
139 case PSI_T_INT64: PSI_CALC_OP(i64); break; \
140 case PSI_T_UINT64: PSI_CALC_OP(u64); break; \
141 EMPTY_SWITCH_DEFAULT_CASE(); \
144 } else if (t1 == PSI_T_DOUBLE) { \
146 case PSI_T_LONG_DOUBLE: PSI_CALC_OP2_LD2(dval); return t2; \
147 case PSI_T_FLOAT: PSI_CALC_OP2(dval, dval, fval); break; \
148 case PSI_T_INT8: PSI_CALC_OP2(dval, dval, i8); break; \
149 case PSI_T_UINT8: PSI_CALC_OP2(dval, dval, u8); break; \
150 case PSI_T_INT16: PSI_CALC_OP2(dval, dval, i16); break; \
151 case PSI_T_UINT16: PSI_CALC_OP2(dval, dval, u16); break; \
152 case PSI_T_INT32: PSI_CALC_OP2(dval, dval, i32); break; \
153 case PSI_T_UINT32: PSI_CALC_OP2(dval, dval, u32); break; \
154 case PSI_T_INT64: PSI_CALC_OP2(dval, dval, i64); break; \
155 case PSI_T_UINT64: PSI_CALC_OP2(dval, dval, u64); break; \
156 EMPTY_SWITCH_DEFAULT_CASE(); \
159 } else if (t2 == PSI_T_DOUBLE) { \
161 case PSI_T_LONG_DOUBLE: PSI_CALC_OP2_LD1(dval); return t1; \
162 case PSI_T_FLOAT: PSI_CALC_OP2(dval, fval, dval); break; \
163 case PSI_T_INT8: PSI_CALC_OP2(dval, i8, dval); break; \
164 case PSI_T_UINT8: PSI_CALC_OP2(dval, u8, dval); break; \
165 case PSI_T_INT16: PSI_CALC_OP2(dval, i16, dval); break; \
166 case PSI_T_UINT16: PSI_CALC_OP2(dval, u16, dval); break; \
167 case PSI_T_INT32: PSI_CALC_OP2(dval, i32, dval); break; \
168 case PSI_T_UINT32: PSI_CALC_OP2(dval, u32, dval); break; \
169 case PSI_T_INT64: PSI_CALC_OP2(dval, i64, dval); break; \
170 case PSI_T_UINT64: PSI_CALC_OP2(dval, u64, dval); break; \
171 EMPTY_SWITCH_DEFAULT_CASE(); \
174 } else if (t1 == PSI_T_LONG_DOUBLE) { \
177 case PSI_T_DOUBLE: PSI_CALC_OP2_LD1(dval); break; \
178 case PSI_T_FLOAT: PSI_CALC_OP2_LD1(fval); break; \
179 case PSI_T_INT8: PSI_CALC_OP2_LD1(i8); break; \
180 case PSI_T_UINT8: PSI_CALC_OP2_LD1(u8); break; \
181 case PSI_T_INT16: PSI_CALC_OP2_LD1(i16); break; \
182 case PSI_T_UINT16: PSI_CALC_OP2_LD1(u16); break; \
183 case PSI_T_INT32: PSI_CALC_OP2_LD1(i32); break; \
184 case PSI_T_UINT32: PSI_CALC_OP2_LD1(u32); break; \
185 case PSI_T_INT64: PSI_CALC_OP2_LD1(i64); break; \
186 case PSI_T_UINT64: PSI_CALC_OP2_LD1(u64); break; \
187 EMPTY_SWITCH_DEFAULT_CASE(); \
190 } else if (t2 == PSI_T_LONG_DOUBLE) { \
193 case PSI_T_DOUBLE: PSI_CALC_OP2_LD2(dval); break; \
194 case PSI_T_FLOAT: PSI_CALC_OP2_LD2(fval); break; \
195 case PSI_T_INT8: PSI_CALC_OP2_LD2(i8); break; \
196 case PSI_T_UINT8: PSI_CALC_OP2_LD2(u8); break; \
197 case PSI_T_INT16: PSI_CALC_OP2_LD2(i16); break; \
198 case PSI_T_UINT16: PSI_CALC_OP2_LD2(u16); break; \
199 case PSI_T_INT32: PSI_CALC_OP2_LD2(i32); break; \
200 case PSI_T_UINT32: PSI_CALC_OP2_LD2(u32); break; \
201 case PSI_T_INT64: PSI_CALC_OP2_LD2(i64); break; \
202 case PSI_T_UINT64: PSI_CALC_OP2_LD2(u64); break; \
203 EMPTY_SWITCH_DEFAULT_CASE(); \
206 } else if (t1 == PSI_T_FLOAT) { \
208 case PSI_T_LONG_DOUBLE: PSI_CALC_OP2_LD2(fval); return t2; \
209 case PSI_T_DOUBLE: PSI_CALC_OP2(dval, fval, dval); return t2; \
210 case PSI_T_INT8: PSI_CALC_OP2(fval, fval, i8); break; \
211 case PSI_T_UINT8: PSI_CALC_OP2(fval, fval, u8); break; \
212 case PSI_T_INT16: PSI_CALC_OP2(fval, fval, i16); break; \
213 case PSI_T_UINT16: PSI_CALC_OP2(fval, fval, u16); break; \
214 case PSI_T_INT32: PSI_CALC_OP2(fval, fval, i32); break; \
215 case PSI_T_UINT32: PSI_CALC_OP2(fval, fval, u32); break; \
216 case PSI_T_INT64: PSI_CALC_OP2(fval, fval, i64); break; \
217 case PSI_T_UINT64: PSI_CALC_OP2(fval, fval, u64); break; \
218 EMPTY_SWITCH_DEFAULT_CASE(); \
221 } else if (t2 == PSI_T_FLOAT) { \
223 case PSI_T_LONG_DOUBLE: PSI_CALC_OP2_LD1(fval); return t1; \
224 case PSI_T_DOUBLE: PSI_CALC_OP2(dval, dval, fval); return t1; \
225 case PSI_T_INT8: PSI_CALC_OP2(fval, i8, fval); break; \
226 case PSI_T_UINT8: PSI_CALC_OP2(fval, u8, fval); break; \
227 case PSI_T_INT16: PSI_CALC_OP2(fval, i16, fval); break; \
228 case PSI_T_UINT16: PSI_CALC_OP2(fval, u16, fval); break; \
229 case PSI_T_INT32: PSI_CALC_OP2(fval, i32, fval); break; \
230 case PSI_T_UINT32: PSI_CALC_OP2(fval, u32, fval); break; \
231 case PSI_T_INT64: PSI_CALC_OP2(fval, i64, fval); break; \
232 case PSI_T_UINT64: PSI_CALC_OP2(fval, u64, fval); break; \
233 EMPTY_SWITCH_DEFAULT_CASE(); \
237 int64_t sval1 = v1->i64, sval2 = v2->i64; \
238 uint64_t uval1 = v1->u64, uval2 = v2->u64; \
240 case PSI_T_INT8: sval1 >>= 8; \
241 case PSI_T_INT16: sval1 >>= 8; \
242 case PSI_T_INT32: sval1 >>= 8; \
245 case PSI_T_INT8: sval2 >>= 8; \
246 case PSI_T_INT16: sval2 >>= 8; \
247 case PSI_T_INT32: sval2 >>= 8; \
249 res->i64 = PSI_CALC(sval1 , sval2); \
250 return PSI_T_INT64; \
251 case PSI_T_UINT8: uval2 >>= 8; \
252 case PSI_T_UINT16: uval2 >>= 8; \
253 case PSI_T_UINT32: uval2 >>= 8; \
255 res->i64 = PSI_CALC(sval1, uval2); \
256 return PSI_T_INT64; \
259 case PSI_T_UINT8: uval1 >>= 8; \
260 case PSI_T_UINT16: uval1 >>= 8; \
261 case PSI_T_UINT32: uval1 >>= 8; \
264 case PSI_T_INT8: sval2 >>= 8; \
265 case PSI_T_INT16: sval2 >>= 8; \
266 case PSI_T_INT32: sval2 >>= 8; \
268 res->i64 = PSI_CALC(uval1, sval2); \
269 return PSI_T_INT64; \
270 case PSI_T_UINT8: uval2 >>= 8; \
271 case PSI_T_UINT16: uval2 >>= 8; \
272 case PSI_T_UINT32: uval2 >>= 8; \
274 res->u64 = PSI_CALC(uval1, uval2); \
275 return PSI_T_UINT64; \
285 #define PSI_CALC(var1, var2) (var1) + (var2)
288 #define PSI_CALC(var1, var2) (var1) * (var2)
291 #define PSI_CALC(var1, var2) (var1) - (var2)
294 #define PSI_CALC(var1, var2) (var1) / (var2)
298 token_t
psi_calc_mod(token_t t1
, impl_val
*v1
, token_t t2
, impl_val
*v2
, impl_val
*res
)
302 PSI_CALC_CAST(t1
, v1
, =, PSI_T_INT64
, &i1
);
303 PSI_CALC_CAST(t2
, v2
, =, PSI_T_INT64
, &i2
);
305 res
->i64
= i1
.i64
% i2
.i64
;
310 #define PSI_CALC_BIT_FN(op) token_t psi_calc_##op(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res) \
313 PSI_CALC_CAST(t1, v1, =, PSI_T_UINT64, &i1); \
314 PSI_CALC_CAST(t2, v2, =, PSI_T_UINT64, &i2); \
315 res->u64 = PSI_CALC(i1.u64, i2.u64); \
316 return PSI_T_UINT64; \
319 #define PSI_CALC(var1, var2) (var1) << (var2)
320 PSI_CALC_BIT_FN(bin_lshift
)
322 #define PSI_CALC(var1, var2) (var1) >> (var2)
323 PSI_CALC_BIT_FN(bin_rshift
)
325 #define PSI_CALC(var1, var2) (var1) & (var2)
326 PSI_CALC_BIT_FN(bin_and
)
328 #define PSI_CALC(var1, var2) (var1) ^ (var2)
329 PSI_CALC_BIT_FN(bin_xor
)
331 #define PSI_CALC(var1, var2) (var1) | (var2)
332 PSI_CALC_BIT_FN(bin_or
)
335 token_t
psi_calc_not(token_t t1
, impl_val
*v1
, token_t t2
, impl_val
*v2
, impl_val
*res
)
340 PSI_CALC_CAST(t1
, v1
, =!, t1
, res
);
344 token_t
psi_calc_bin_not(token_t t1
, impl_val
*v1
, token_t t2
, impl_val
*v2
, impl_val
*res
)
351 PSI_CALC_CAST(t1
, v1
, =, PSI_T_UINT64
, &i1
);
352 PSI_CALC_CAST_INT(t1
, &i1
, =~, t1
, res
);