Line data Source code
1 : #ifndef AMREX_PARSER_Y_H_
2 : #define AMREX_PARSER_Y_H_
3 : #include <AMReX_Config.H>
4 :
5 : #include <AMReX_GpuQualifiers.H>
6 : #include <AMReX_GpuPrint.H>
7 : #include <AMReX_Math.H>
8 : #include <AMReX_Print.H>
9 : #include <AMReX_REAL.H>
10 :
11 : #include <cstddef>
12 : #include <cstdio>
13 : #include <cstdlib>
14 : #include <cstring>
15 : #include <set>
16 : #include <string>
17 : #include <string_view>
18 : #include <type_traits>
19 :
20 : void amrex_parsererror (char const *s, ...);
21 :
22 : namespace amrex {
23 :
24 : enum parser_f1_t { // Built-in functions with one argument
25 : PARSER_SQRT,
26 : PARSER_EXP,
27 : PARSER_LOG,
28 : PARSER_LOG10,
29 : PARSER_SIN,
30 : PARSER_COS,
31 : PARSER_TAN,
32 : PARSER_ASIN,
33 : PARSER_ACOS,
34 : PARSER_ATAN,
35 : PARSER_SINH,
36 : PARSER_COSH,
37 : PARSER_TANH,
38 : PARSER_ASINH,
39 : PARSER_ACOSH,
40 : PARSER_ATANH,
41 : PARSER_ABS,
42 : PARSER_FLOOR,
43 : PARSER_CEIL,
44 : PARSER_COMP_ELLINT_1,
45 : PARSER_COMP_ELLINT_2,
46 : PARSER_ERF
47 : };
48 :
49 : static
50 : #if defined(__INTEL_COMPILER) && defined(__EDG__)
51 : const
52 : #else
53 : constexpr
54 : #endif
55 : std::string_view parser_f1_s[] =
56 : {
57 : "sqrt",
58 : "exp",
59 : "log",
60 : "log10",
61 : "sin",
62 : "cos",
63 : "tan",
64 : "asin",
65 : "acos",
66 : "atan",
67 : "sinh",
68 : "cosh",
69 : "tanh",
70 : "asinh",
71 : "acosh",
72 : "atanh",
73 : "abs",
74 : "floor",
75 : "ceil",
76 : "comp_ellint_1",
77 : "comp_ellint_2",
78 : "erf"
79 : };
80 :
81 : enum parser_f2_t { // Built-in functions with two arguments
82 : PARSER_POW,
83 : PARSER_ATAN2,
84 : PARSER_GT,
85 : PARSER_LT,
86 : PARSER_GEQ,
87 : PARSER_LEQ,
88 : PARSER_EQ,
89 : PARSER_NEQ,
90 : PARSER_AND,
91 : PARSER_OR,
92 : PARSER_HEAVISIDE,
93 : PARSER_JN,
94 : PARSER_MIN,
95 : PARSER_MAX,
96 : PARSER_FMOD
97 : };
98 :
99 : static
100 : #if defined(__INTEL_COMPILER) && defined(__EDG__)
101 : const
102 : #else
103 : constexpr
104 : #endif
105 : std::string_view parser_f2_s[] =
106 : {
107 : "pow",
108 : "atan2",
109 : "gt",
110 : "lt",
111 : "geq",
112 : "leq",
113 : "eq",
114 : "neq",
115 : "and",
116 : "or",
117 : "heaviside",
118 : "jn",
119 : "min",
120 : "max",
121 : "fmod"
122 : };
123 :
124 : enum parser_f3_t { // functions with three arguments
125 : PARSER_IF
126 : };
127 :
128 : static
129 : #if defined(__INTEL_COMPILER) && defined(__EDG__)
130 : const
131 : #else
132 : constexpr
133 : #endif
134 : std::string_view parser_f3_s[] =
135 : {
136 : "if"
137 : };
138 :
139 : enum parser_node_t {
140 : PARSER_NUMBER,
141 : PARSER_SYMBOL,
142 : PARSER_ADD,
143 : PARSER_SUB,
144 : PARSER_MUL,
145 : PARSER_DIV,
146 : PARSER_F1,
147 : PARSER_F2,
148 : PARSER_F3,
149 : PARSER_ASSIGN,
150 : PARSER_LIST
151 : };
152 :
153 : static
154 : #if defined(__INTEL_COMPILER) && defined(__EDG__)
155 : const
156 : #else
157 : constexpr
158 : #endif
159 : std::string_view parser_node_s[] =
160 : {
161 : "number",
162 : "symbol",
163 : "add",
164 : "sub",
165 : "mul",
166 : "div",
167 : "f1",
168 : "f2",
169 : "f3",
170 : "assign",
171 : "list"
172 : };
173 :
174 : /* In C, the address of the first member of a struct is the same as
175 : * the address of the struct itself. Because of this, all struct parser_*
176 : * pointers can be passed around as struct parser_node pointer and enum
177 : * parser_node_t type can be safely checked to determine their real type.
178 : */
179 :
180 : struct parser_node {
181 : enum parser_node_t type;
182 : enum parser_node_t padding;
183 : struct parser_node* l; // NOLINT(misc-confusable-identifiers)
184 : struct parser_node* r;
185 : struct parser_node* padding2;
186 : };
187 :
188 : struct alignas(parser_node) parser_number {
189 : enum parser_node_t type;
190 : double value;
191 : };
192 :
193 : struct alignas(parser_node) parser_symbol {
194 : enum parser_node_t type;
195 : char* name;
196 : int ip;
197 : };
198 :
199 : struct alignas(parser_node) parser_f1 { /* Builtin functions with one argument */
200 : enum parser_node_t type;
201 : enum parser_f1_t ftype;
202 : struct parser_node* l; // NOLINT(misc-confusable-identifiers)
203 : struct parser_node* padding1;
204 : struct parser_node* padding2;
205 : };
206 :
207 : struct alignas(parser_node) parser_f2 { /* Builtin functions with two arguments */
208 : enum parser_node_t type;
209 : enum parser_f2_t ftype;
210 : struct parser_node* l; // NOLINT(misc-confusable-identifiers)
211 : struct parser_node* r;
212 : struct parser_node* padding;
213 : };
214 :
215 : struct alignas(parser_node) parser_f3 { /* Builtin functions with three arguments */
216 : enum parser_node_t type;
217 : enum parser_f3_t ftype;
218 : struct parser_node* n1;
219 : struct parser_node* n2;
220 : struct parser_node* n3;
221 : };
222 :
223 : struct alignas(parser_node) parser_assign {
224 : enum parser_node_t type;
225 : struct parser_symbol* s;
226 : struct parser_node* v;
227 : };
228 :
229 : static_assert(sizeof(parser_f3) <= sizeof(parser_node), "amrex parser: sizeof parser_node too small");
230 :
231 : /*******************************************************************/
232 :
233 : /* These functions are used in bison rules to generate the original AST. */
234 : void parser_defexpr (struct parser_node* body);
235 : struct parser_symbol* parser_makesymbol (char* name);
236 : struct parser_node* parser_newnode (enum parser_node_t type, struct parser_node* l,
237 : struct parser_node* r);
238 : struct parser_node* parser_newneg (struct parser_node* n);
239 : struct parser_node* parser_newnumber (double d);
240 : struct parser_node* parser_newsymbol (struct parser_symbol* sym);
241 : struct parser_node* parser_newf1 (enum parser_f1_t ftype, struct parser_node* l);
242 : struct parser_node* parser_newf2 (enum parser_f2_t ftype, struct parser_node* l,
243 : struct parser_node* r);
244 : struct parser_node* parser_newf3 (enum parser_f3_t ftype, struct parser_node* n1,
245 : struct parser_node* n2, struct parser_node* n3);
246 : struct parser_node* parser_newassign (struct parser_symbol* s, struct parser_node* v);
247 : struct parser_node* parser_newlist (struct parser_node* nl, struct parser_node* nr);
248 :
249 : /*******************************************************************/
250 :
251 : /* This is our struct for storing AST in a more packed way. The whole
252 : * tree is stored in a contiguous chunk of memory starting from void*
253 : * p_root with a size of sz_mempool.
254 : */
255 : struct amrex_parser {
256 : void* p_root;
257 : void* p_free;
258 : struct parser_node* ast;
259 : std::size_t sz_mempool;
260 : };
261 :
262 : struct amrex_parser* amrex_parser_new ();
263 : void amrex_parser_delete (struct amrex_parser* parser);
264 :
265 : struct amrex_parser* parser_dup (struct amrex_parser* source);
266 : struct parser_node* parser_ast_dup (struct amrex_parser* parser, struct parser_node* node, int move);
267 :
268 : void parser_regvar (struct amrex_parser* parser, char const* name, int i);
269 : void parser_setconst (struct amrex_parser* parser, char const* name, double c);
270 : void parser_print (struct amrex_parser* parser);
271 : std::set<std::string> parser_get_symbols (struct amrex_parser* parser);
272 : int parser_depth (struct amrex_parser* parser);
273 :
274 : /* We need to walk the tree in these functions */
275 : void parser_ast_optimize (struct parser_node* node);
276 : std::size_t parser_ast_size (struct parser_node* node);
277 : void parser_ast_print (struct parser_node* node, std::string const& space, std::ostream& printer);
278 : void parser_ast_regvar (struct parser_node* node, char const* name, int i);
279 : void parser_ast_setconst (struct parser_node* node, char const* name, double c);
280 : void parser_ast_get_symbols (struct parser_node* node, std::set<std::string>& symbols,
281 : std::set<std::string>& local_symbols);
282 : int parser_ast_depth (struct parser_node* node);
283 : void parser_ast_sort (struct parser_node* node);
284 :
285 : /*******************************************************************/
286 : double parser_get_number (struct parser_node* node);
287 : void parser_set_number (struct parser_node* node, double v);
288 : bool parser_node_equal (struct parser_node* a, struct parser_node* b);
289 : /*******************************************************************/
290 :
291 : template <typename T>
292 : AMREX_GPU_HOST_DEVICE AMREX_NO_INLINE
293 30 : T parser_math_exp (T a) { return std::exp(a); }
294 :
295 : template <typename T>
296 : AMREX_GPU_HOST_DEVICE AMREX_NO_INLINE
297 0 : T parser_math_log (T a) { return std::log(a); }
298 :
299 : template <typename T>
300 : AMREX_GPU_HOST_DEVICE AMREX_NO_INLINE
301 0 : T parser_math_log10 (T a) { return std::log10(a); }
302 :
303 : template <typename T>
304 : AMREX_GPU_HOST_DEVICE AMREX_NO_INLINE
305 0 : T parser_math_sin (T a) { return std::sin(a); }
306 :
307 : template <typename T>
308 : AMREX_GPU_HOST_DEVICE AMREX_NO_INLINE
309 0 : T parser_math_cos (T a) { return std::cos(a); }
310 :
311 : template <typename T>
312 : AMREX_GPU_HOST_DEVICE AMREX_NO_INLINE
313 0 : T parser_math_tan (T a) { return std::tan(a); }
314 :
315 : template <typename T>
316 : AMREX_GPU_HOST_DEVICE AMREX_NO_INLINE
317 0 : T parser_math_asin (T a) { return std::asin(a); }
318 :
319 : template <typename T>
320 : AMREX_GPU_HOST_DEVICE AMREX_NO_INLINE
321 0 : T parser_math_acos (T a) { return std::acos(a); }
322 :
323 : template <typename T>
324 : AMREX_GPU_HOST_DEVICE AMREX_NO_INLINE
325 0 : T parser_math_atan (T a) { return std::atan(a); }
326 :
327 : template <typename T>
328 : AMREX_GPU_HOST_DEVICE AMREX_NO_INLINE
329 0 : T parser_math_sinh (T a) { return std::sinh(a); }
330 :
331 : template <typename T>
332 : AMREX_GPU_HOST_DEVICE AMREX_NO_INLINE
333 0 : T parser_math_cosh (T a) { return std::cosh(a); }
334 :
335 : template <typename T>
336 : AMREX_GPU_HOST_DEVICE AMREX_NO_INLINE
337 7056 : T parser_math_tanh (T a) { return std::tanh(a); }
338 :
339 : template <typename T>
340 : AMREX_GPU_HOST_DEVICE AMREX_NO_INLINE
341 0 : T parser_math_asinh (T a) { return std::asinh(a); }
342 :
343 : template <typename T>
344 : AMREX_GPU_HOST_DEVICE AMREX_NO_INLINE
345 0 : T parser_math_acosh (T a) { return std::acosh(a); }
346 :
347 : template <typename T>
348 : AMREX_GPU_HOST_DEVICE AMREX_NO_INLINE
349 0 : T parser_math_atanh (T a) { return std::atanh(a); }
350 :
351 : template <typename T>
352 : AMREX_GPU_HOST_DEVICE AMREX_NO_INLINE
353 0 : T parser_math_comp_ellint_1 (T a)
354 : {
355 : #if defined(__GNUC__) && !defined(__clang__) && !defined(__CUDA_ARCH__) && !defined(__NVCOMPILER)
356 0 : return std::comp_ellint_1(a);
357 : #else
358 : amrex::ignore_unused(a);
359 : AMREX_ALWAYS_ASSERT_WITH_MESSAGE(false, "parser: comp_ellint_1 only supported with gcc and cpu");
360 : return 0.0;
361 : #endif
362 : }
363 :
364 : template <typename T>
365 : AMREX_GPU_HOST_DEVICE AMREX_NO_INLINE
366 0 : T parser_math_comp_ellint_2 (T a)
367 : {
368 : #if defined(__GNUC__) && !defined(__clang__) && !defined(__CUDA_ARCH__) && !defined(__NVCOMPILER)
369 0 : return std::comp_ellint_2(a);
370 : #else
371 : amrex::ignore_unused(a);
372 : AMREX_ALWAYS_ASSERT_WITH_MESSAGE(false, "parser: comp_ellint_2 only supported with gcc and cpu");
373 : return 0.0;
374 : #endif
375 : }
376 :
377 : template <typename T>
378 : AMREX_GPU_HOST_DEVICE AMREX_NO_INLINE
379 0 : T parser_math_erf(T a)
380 : {
381 0 : return std::erf(a);
382 : }
383 :
384 : template <typename T>
385 : AMREX_GPU_HOST_DEVICE AMREX_NO_INLINE
386 0 : T parser_math_pow (T a, T b) { return std::pow(a,b); }
387 :
388 : template <typename T>
389 : AMREX_GPU_HOST_DEVICE AMREX_NO_INLINE
390 0 : T parser_math_atan2 (T a, T b) { return std::atan2(a,b); }
391 :
392 : template <typename T>
393 : AMREX_GPU_HOST_DEVICE AMREX_NO_INLINE
394 0 : T parser_math_jn (int a, T b)
395 : {
396 : #if defined AMREX_USE_SYCL || defined __MINGW32__
397 : amrex::ignore_unused(a,b);
398 : // neither jn(f) nor std::cyl_bessel_j work yet
399 : // https://github.com/oneapi-src/oneAPI-spec/issues/308
400 : AMREX_ALWAYS_ASSERT_WITH_MESSAGE(false, "parser: jn in SYCL not supported yet");
401 : return 0.0;
402 : #else
403 0 : return jn(a, b);
404 : #endif
405 : }
406 :
407 : AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE double
408 : parser_call_f1 (enum parser_f1_t type, double a)
409 : {
410 7086 : switch (type) {
411 0 : case PARSER_SQRT: return std::sqrt(a);
412 30 : case PARSER_EXP: return parser_math_exp<double>(a);
413 0 : case PARSER_LOG: return parser_math_log<double>(a);
414 0 : case PARSER_LOG10: return parser_math_log10<double>(a);
415 0 : case PARSER_SIN: return parser_math_sin<double>(a);
416 0 : case PARSER_COS: return parser_math_cos<double>(a);
417 0 : case PARSER_TAN: return parser_math_tan<double>(a);
418 0 : case PARSER_ASIN: return parser_math_asin<double>(a);
419 0 : case PARSER_ACOS: return parser_math_acos<double>(a);
420 0 : case PARSER_ATAN: return parser_math_atan<double>(a);
421 0 : case PARSER_SINH: return parser_math_sinh<double>(a);
422 0 : case PARSER_COSH: return parser_math_cosh<double>(a);
423 7056 : case PARSER_TANH: return parser_math_tanh<double>(a);
424 0 : case PARSER_ASINH: return parser_math_asinh<double>(a);
425 0 : case PARSER_ACOSH: return parser_math_acosh<double>(a);
426 0 : case PARSER_ATANH: return parser_math_atanh<double>(a);
427 0 : case PARSER_ABS: return std::abs(a);
428 0 : case PARSER_FLOOR: return std::floor(a);
429 0 : case PARSER_CEIL: return std::ceil(a);
430 0 : case PARSER_COMP_ELLINT_1: return parser_math_comp_ellint_1<double>(a);
431 0 : case PARSER_COMP_ELLINT_2: return parser_math_comp_ellint_2<double>(a);
432 0 : case PARSER_ERF: return parser_math_erf<double>(a);
433 0 : default:
434 : amrex::Abort("parser_call_f1: Unknown function ");
435 0 : return 0.0;
436 : }
437 : }
438 :
439 : AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE double
440 : parser_call_f2 (enum parser_f2_t type, double a, double b)
441 : {
442 22064 : switch (type) {
443 0 : case PARSER_POW:
444 0 : return parser_math_pow<double>(a,b);
445 0 : case PARSER_ATAN2:
446 0 : return parser_math_atan2<double>(a,b);
447 11032 : case PARSER_GT:
448 11032 : return (a > b) ? 1.0 : 0.0;
449 11032 : case PARSER_LT:
450 11032 : return (a < b) ? 1.0 : 0.0;
451 0 : case PARSER_GEQ:
452 0 : return (a >= b) ? 1.0 : 0.0;
453 0 : case PARSER_LEQ:
454 0 : return (a <= b) ? 1.0 : 0.0;
455 0 : case PARSER_EQ:
456 0 : return (a == b) ? 1.0 : 0.0;
457 0 : case PARSER_NEQ:
458 0 : return (a != b) ? 1.0 : 0.0;
459 0 : case PARSER_AND:
460 0 : return ((a != 0.0) && (b != 0.0)) ? 1.0 : 0.0;
461 0 : case PARSER_OR:
462 0 : return ((a != 0.0) || (b != 0.0)) ? 1.0 : 0.0;
463 0 : case PARSER_HEAVISIDE:
464 0 : return (a < 0.0) ? 0.0 : ((a > 0.0) ? 1.0 : b);
465 0 : case PARSER_JN:
466 0 : return parser_math_jn<double>(int(a),b);
467 0 : case PARSER_MIN:
468 0 : return (a < b) ? a : b;
469 0 : case PARSER_MAX:
470 0 : return (a > b) ? a : b;
471 0 : case PARSER_FMOD:
472 0 : return std::fmod(a,b);
473 0 : default:
474 : amrex::Abort("parser_call_f2: Unknown function");
475 0 : return 0.0;
476 : }
477 : }
478 :
479 : AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE double
480 : parser_call_f3 (enum parser_f3_t /*type*/, double a, double b, double c)
481 : {
482 : // There is only one type currently
483 : return (a != 0.0) ? b : c;
484 : }
485 :
486 : }
487 :
488 : #endif
|