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, out_val, out_var) \
34 case PSI_T_INT8: (out_val)->out_var = (in_val)->i8; break; \
35 case PSI_T_UINT8: (out_val)->out_var = (in_val)->u8; break; \
36 case PSI_T_INT16: (out_val)->out_var = (in_val)->i16; break; \
37 case PSI_T_UINT16: (out_val)->out_var = (in_val)->u16; break; \
38 case PSI_T_INT32: (out_val)->out_var = (in_val)->i32; break; \
39 case PSI_T_UINT32: (out_val)->out_var = (in_val)->u32; break; \
40 case PSI_T_INT64: (out_val)->out_var = (in_val)->i64; break; \
41 case PSI_T_UINT64: (out_val)->out_var = (in_val)->u64; break; \
42 case PSI_T_FLOAT: (out_val)->out_var = (in_val)->fval; break; \
43 case PSI_T_DOUBLE: (out_val)->out_var = (in_val)->dval; break; \
44 case PSI_T_LONG_DOUBLE: (out_val)->out_var = (in_val)->ldval; break; \
49 #define PSI_CALC_CAST(in_type, in_val, out_type, out_val) \
51 case PSI_T_INT8: PSI_CALC_CAST_SET(in_type, in_val, out_val, i8) break; \
52 case PSI_T_UINT8: PSI_CALC_CAST_SET(in_type, in_val, out_val, u8) break; \
53 case PSI_T_INT16: PSI_CALC_CAST_SET(in_type, in_val, out_val, i16) break; \
54 case PSI_T_UINT16: PSI_CALC_CAST_SET(in_type, in_val, out_val, u16) break; \
55 case PSI_T_INT32: PSI_CALC_CAST_SET(in_type, in_val, out_val, i32) break; \
56 case PSI_T_UINT32: PSI_CALC_CAST_SET(in_type, in_val, out_val, u32) break; \
57 case PSI_T_INT64: PSI_CALC_CAST_SET(in_type, in_val, out_val, i64) break; \
58 case PSI_T_UINT64: PSI_CALC_CAST_SET(in_type, in_val, out_val, u64) break; \
59 case PSI_T_FLOAT: PSI_CALC_CAST_SET(in_type, in_val, out_val, fval) break; \
60 case PSI_T_DOUBLE: PSI_CALC_CAST_SET(in_type, in_val, out_val, dval) break; \
61 case PSI_T_LONG_DOUBLE: PSI_CALC_CAST_SET(in_type, in_val, out_val, ldval) break; \
66 void psi_calc_cast(token_t in_type
, impl_val
*in_val
, token_t out_type
, impl_val
*out_val
)
68 PSI_CALC_CAST(in_type
, in_val
, out_type
, out_val
)
72 #define PSI_CALC_OP(var) do { \
73 const char *fmt = "calc %" PRI##var ", %" PRI##var ": %" PRI##var "\n"; \
74 res->var = PSI_CALC(v1->var, v2->var); \
75 if (!res->var && (v1->var || v2->var)) fprintf(stderr, fmt, v1->var, v2->var, res->var); \
77 #define PSI_CALC_OP2(vres, var1, var2) do { \
78 const char *fmt = "calc %" PRI##var1 ", %" PRI##var2 ": %" PRI##vres "\n"; \
79 res->vres = PSI_CALC(v1->var1, v2->var2); \
80 if (!res->vres && (v1->var1 || v2->var2)) fprintf(stderr, fmt, v1->var1, v2->var2, res->vres); \
83 #define PSI_CALC_OP(var) res->var = PSI_CALC(v1->var, v2->var)
84 #define PSI_CALC_OP2(vres, var1, var2) res->vres = PSI_CALC(v1->var1, v2->var2)
87 #ifdef HAVE_LONG_DOUBLE
88 # define PSI_CALC_NO_LD
89 # define PSI_CALC_OP_LD PSI_CALC_OP(ldval)
90 # define PSI_CALC_OP2_LD2(var1) PSI_CALC_OP2(ldval, var1, ldval)
91 # define PSI_CALC_OP2_LD1(var2) PSI_CALC_OP2(ldval, ldval, var2)
93 # define PSI_CALC_NO_LD abort()
94 # define PSI_CALC_OP_LD PSI_CALC_NO_LD
95 # define PSI_CALC_OP2_LD2(var) PSI_CALC_NO_LD
96 # define PSI_CALC_OP2_LD1(var) PSI_CALC_NO_LD
99 #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) \
103 case PSI_T_FLOAT: PSI_CALC_OP(fval); break; \
104 case PSI_T_DOUBLE: PSI_CALC_OP(dval); break; \
105 case PSI_T_LONG_DOUBLE: PSI_CALC_OP_LD; break; \
106 case PSI_T_INT8: PSI_CALC_OP(i8); break; \
107 case PSI_T_UINT8: PSI_CALC_OP(u8); break; \
108 case PSI_T_INT16: PSI_CALC_OP(i16); break; \
109 case PSI_T_UINT16: PSI_CALC_OP(u16); break; \
110 case PSI_T_INT32: PSI_CALC_OP(i32); break; \
111 case PSI_T_UINT32: PSI_CALC_OP(u32); break; \
112 case PSI_T_INT64: PSI_CALC_OP(i64); break; \
113 case PSI_T_UINT64: PSI_CALC_OP(u64); break; \
114 EMPTY_SWITCH_DEFAULT_CASE(); \
117 } else if (t1 == PSI_T_DOUBLE) { \
119 case PSI_T_LONG_DOUBLE: PSI_CALC_OP2_LD2(dval); return t2; \
120 case PSI_T_FLOAT: PSI_CALC_OP2(dval, dval, fval); break; \
121 case PSI_T_INT8: PSI_CALC_OP2(dval, dval, i8); break; \
122 case PSI_T_UINT8: PSI_CALC_OP2(dval, dval, u8); break; \
123 case PSI_T_INT16: PSI_CALC_OP2(dval, dval, i16); break; \
124 case PSI_T_UINT16: PSI_CALC_OP2(dval, dval, u16); break; \
125 case PSI_T_INT32: PSI_CALC_OP2(dval, dval, i32); break; \
126 case PSI_T_UINT32: PSI_CALC_OP2(dval, dval, u32); break; \
127 case PSI_T_INT64: PSI_CALC_OP2(dval, dval, i64); break; \
128 case PSI_T_UINT64: PSI_CALC_OP2(dval, dval, u64); break; \
129 EMPTY_SWITCH_DEFAULT_CASE(); \
132 } else if (t2 == PSI_T_DOUBLE) { \
134 case PSI_T_LONG_DOUBLE: PSI_CALC_OP2_LD1(dval); return t1; \
135 case PSI_T_FLOAT: PSI_CALC_OP2(dval, fval, dval); break; \
136 case PSI_T_INT8: PSI_CALC_OP2(dval, i8, dval); break; \
137 case PSI_T_UINT8: PSI_CALC_OP2(dval, u8, dval); break; \
138 case PSI_T_INT16: PSI_CALC_OP2(dval, i16, dval); break; \
139 case PSI_T_UINT16: PSI_CALC_OP2(dval, u16, dval); break; \
140 case PSI_T_INT32: PSI_CALC_OP2(dval, i32, dval); break; \
141 case PSI_T_UINT32: PSI_CALC_OP2(dval, u32, dval); break; \
142 case PSI_T_INT64: PSI_CALC_OP2(dval, i64, dval); break; \
143 case PSI_T_UINT64: PSI_CALC_OP2(dval, u64, dval); break; \
144 EMPTY_SWITCH_DEFAULT_CASE(); \
147 } else if (t1 == PSI_T_LONG_DOUBLE) { \
150 case PSI_T_DOUBLE: PSI_CALC_OP2_LD1(dval); break; \
151 case PSI_T_FLOAT: PSI_CALC_OP2_LD1(fval); break; \
152 case PSI_T_INT8: PSI_CALC_OP2_LD1(i8); break; \
153 case PSI_T_UINT8: PSI_CALC_OP2_LD1(u8); break; \
154 case PSI_T_INT16: PSI_CALC_OP2_LD1(i16); break; \
155 case PSI_T_UINT16: PSI_CALC_OP2_LD1(u16); break; \
156 case PSI_T_INT32: PSI_CALC_OP2_LD1(i32); break; \
157 case PSI_T_UINT32: PSI_CALC_OP2_LD1(u32); break; \
158 case PSI_T_INT64: PSI_CALC_OP2_LD1(i64); break; \
159 case PSI_T_UINT64: PSI_CALC_OP2_LD1(u64); break; \
160 EMPTY_SWITCH_DEFAULT_CASE(); \
163 } else if (t2 == PSI_T_LONG_DOUBLE) { \
166 case PSI_T_DOUBLE: PSI_CALC_OP2_LD2(dval); break; \
167 case PSI_T_FLOAT: PSI_CALC_OP2_LD2(fval); break; \
168 case PSI_T_INT8: PSI_CALC_OP2_LD2(i8); break; \
169 case PSI_T_UINT8: PSI_CALC_OP2_LD2(u8); break; \
170 case PSI_T_INT16: PSI_CALC_OP2_LD2(i16); break; \
171 case PSI_T_UINT16: PSI_CALC_OP2_LD2(u16); break; \
172 case PSI_T_INT32: PSI_CALC_OP2_LD2(i32); break; \
173 case PSI_T_UINT32: PSI_CALC_OP2_LD2(u32); break; \
174 case PSI_T_INT64: PSI_CALC_OP2_LD2(i64); break; \
175 case PSI_T_UINT64: PSI_CALC_OP2_LD2(u64); break; \
176 EMPTY_SWITCH_DEFAULT_CASE(); \
179 } else if (t1 == PSI_T_FLOAT) { \
181 case PSI_T_LONG_DOUBLE: PSI_CALC_OP2_LD2(fval); return t2; \
182 case PSI_T_DOUBLE: PSI_CALC_OP2(dval, fval, dval); return t2; \
183 case PSI_T_INT8: PSI_CALC_OP2(fval, fval, i8); break; \
184 case PSI_T_UINT8: PSI_CALC_OP2(fval, fval, u8); break; \
185 case PSI_T_INT16: PSI_CALC_OP2(fval, fval, i16); break; \
186 case PSI_T_UINT16: PSI_CALC_OP2(fval, fval, u16); break; \
187 case PSI_T_INT32: PSI_CALC_OP2(fval, fval, i32); break; \
188 case PSI_T_UINT32: PSI_CALC_OP2(fval, fval, u32); break; \
189 case PSI_T_INT64: PSI_CALC_OP2(fval, fval, i64); break; \
190 case PSI_T_UINT64: PSI_CALC_OP2(fval, fval, u64); break; \
191 EMPTY_SWITCH_DEFAULT_CASE(); \
194 } else if (t2 == PSI_T_FLOAT) { \
196 case PSI_T_LONG_DOUBLE: PSI_CALC_OP2_LD1(fval); return t1; \
197 case PSI_T_DOUBLE: PSI_CALC_OP2(dval, dval, fval); return t1; \
198 case PSI_T_INT8: PSI_CALC_OP2(fval, i8, fval); break; \
199 case PSI_T_UINT8: PSI_CALC_OP2(fval, u8, fval); break; \
200 case PSI_T_INT16: PSI_CALC_OP2(fval, i16, fval); break; \
201 case PSI_T_UINT16: PSI_CALC_OP2(fval, u16, fval); break; \
202 case PSI_T_INT32: PSI_CALC_OP2(fval, i32, fval); break; \
203 case PSI_T_UINT32: PSI_CALC_OP2(fval, u32, fval); break; \
204 case PSI_T_INT64: PSI_CALC_OP2(fval, i64, fval); break; \
205 case PSI_T_UINT64: PSI_CALC_OP2(fval, u64, fval); break; \
206 EMPTY_SWITCH_DEFAULT_CASE(); \
210 int64_t sval1 = v1->i64, sval2 = v2->i64; \
211 uint64_t uval1 = v1->u64, uval2 = v2->u64; \
213 case PSI_T_INT8: sval1 >>= 8; \
214 case PSI_T_INT16: sval1 >>= 8; \
215 case PSI_T_INT32: sval1 >>= 8; \
218 case PSI_T_INT8: sval2 >>= 8; \
219 case PSI_T_INT16: sval2 >>= 8; \
220 case PSI_T_INT32: sval2 >>= 8; \
222 res->i64 = PSI_CALC(sval1 , sval2); \
223 return PSI_T_INT64; \
224 case PSI_T_UINT8: uval2 >>= 8; \
225 case PSI_T_UINT16: uval2 >>= 8; \
226 case PSI_T_UINT32: uval2 >>= 8; \
228 res->i64 = PSI_CALC(sval1, uval2); \
229 return PSI_T_INT64; \
232 case PSI_T_UINT8: uval1 >>= 8; \
233 case PSI_T_UINT16: uval1 >>= 8; \
234 case PSI_T_UINT32: uval1 >>= 8; \
237 case PSI_T_INT8: sval2 >>= 8; \
238 case PSI_T_INT16: sval2 >>= 8; \
239 case PSI_T_INT32: sval2 >>= 8; \
241 res->i64 = PSI_CALC(uval1, sval2); \
242 return PSI_T_INT64; \
243 case PSI_T_UINT8: uval2 >>= 8; \
244 case PSI_T_UINT16: uval2 >>= 8; \
245 case PSI_T_UINT32: uval2 >>= 8; \
247 res->u64 = PSI_CALC(uval1, uval2); \
248 return PSI_T_UINT64; \
258 #define PSI_CALC(var1, var2) (var1) + (var2)
261 #define PSI_CALC(var1, var2) (var1) * (var2)
264 #define PSI_CALC(var1, var2) (var1) - (var2)
267 #define PSI_CALC(var1, var2) (var1) / (var2)
271 #define PSI_CALC_BIN_FN(op) token_t psi_calc_##op(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res) \
274 PSI_CALC_CAST(t1, v1, PSI_T_UINT64, &i1); \
275 PSI_CALC_CAST(t2, v2, PSI_T_UINT64, &i2); \
276 res->u64 = PSI_CALC(i1.u64, i2.u64); \
277 return PSI_T_UINT64; \
280 #define PSI_CALC(var1, var2) (var1) << (var2)
281 PSI_CALC_BIN_FN(bin_lshift
)
283 #define PSI_CALC(var1, var2) (var1) >> (var2)
284 PSI_CALC_BIN_FN(bin_rshift
)
286 #define PSI_CALC(var1, var2) (var1) & (var2)
287 PSI_CALC_BIN_FN(bin_and
)
289 #define PSI_CALC(var1, var2) (var1) ^ (var2)
290 PSI_CALC_BIN_FN(bin_xor
)
292 #define PSI_CALC(var1, var2) (var1) | (var2)
293 PSI_CALC_BIN_FN(bin_or
)