1 /* SPDX-License-Identifier: BSD-3-Clause
2  *
3  * Copyright(c) 2016 Intel Corporation. All rights reserved.
4  *
5  * Author: Michal Jerzy Wierzbicki <michalx.wierzbicki@intel.com>
6  */
7 
8 #ifndef __SOF_TRACE_PREPROC_H__
9 #define __SOF_TRACE_PREPROC_H__
10 
11 /* Macros in this file are to be invoked directly from code.
12  * In order to work, they require a number of other macros that are
13  * defined in the header file specified below.
14  * Macros from the file specified below are not to meant to be used
15  * directly / independently.
16  * For more detailed commentary of innards of macros in this file,
17  * see file specified below.
18  */
19 #include <sof/trace/preproc-private.h>
20 #include <stdint.h>
21 
22 /* count number of var args - during preprocesing
23  * works for predefined number of args
24  * META_COUNT_VARAGS_BEFORE_COMPILE(A,B,C,D) evaluates to 4
25  */
26 #define META_COUNT_VARAGS_BEFORE_COMPILE(...)\
27 	META_DEC(\
28 		_META_PP_NARG_BEFORE_COMPILE_(\
29 			_, ##__VA_ARGS__, _META_PP_RSEQ_N()\
30 		)\
31 	)
32 
33 /* treat x as string while forcing x expansion beforehand */
34 #define META_QUOTE(x) _META_QUOTE(x)
35 
36 /* concat x and y while forcing x and y expansion beforehand */
37 #define META_CONCAT(x, y) _META_CONCAT_BASE(x, y)
38 
39 /* discard first x-1 args in vararg and return the xth arg */
40 
41 #define META_GET_ARG_N(n, ...) META_CONCAT(_META_GET_ARG_, n)(__VA_ARGS__)
42 
43 #define META_HAS_ARGS(...) META_BOOL(\
44 	_META_GET_ARG_1(_META_NO_ARGS __VA_ARGS__)()\
45 )
46 
47 /* Only META_NOT(0)   evaulates to 1
48  * notice, that any x!=0 would also result in 0
49  * e.x. META_NOT(123) evaluates to 0
50  */
51 #define META_NOT(x) _META_IS_PROBE(META_CONCAT(_META_NOT_, x))
52 /* hacky way to convert tokens into 0 1*/
53 #define META_BOOL(x) META_NOT(META_NOT(x))
54 
55 /* META_IF_ELSE(X)(a)(b) expands to
56  * b for X == 0
57  * a for X != 0
58  */
59 #define META_IF_ELSE(condition) _META_IF_ELSE(META_BOOL(condition))
60 
61 /* same story with indirection as META_IF_ELSE */
62 #define META_IF(condition) _META_IIF(META_BOOL(condition))
63 
64 /* primitive recursion
65  * default depth is 8
66  */
67 #define META_RECURSE(...) _META_REQRS_8(__VA_ARGS__)
68 /* choose explicitly depth of recursion
69  */
70 #define META_RECURSE_N(depth, ...)\
71 	META_CONCAT(_META_REQRS_, depth)(__VA_ARGS__)
72 
73 /* The only sane way I found to increment values in cpreproc */
74 #define META_INC(x) META_CONCAT(_META_INC_, x)
75 
76 /* The only sane way I found to decrement values in cpreproc */
77 #define META_DEC(x) META_CONCAT(_META_DEC_, x)
78 
79 /* Delay macro m expansion depth times
80  * by writing META_DEFER(0, m)(args) we expand it in 1st scan
81  * by writing META_DEFER(1, m)(args) we expand it in 2nd scan
82  * ...
83  * by writing META_DEFER(n, m)(args) we expand it in n+1nth scan
84  */
85 #define META_DEFER(depth, m) m _META_DEFER_N(depth)
86 
87 /* while(count--!=0) do
88  * uses DEC so count == N can only work if all following exist
89  * DEC_0, DEC_1, ..., DEC_N-1, DEC_N
90  */
91 #define META_REPEAT(count, macro, ...)\
92 	_META_WHEN(count)\
93 	(\
94 		_META_DEFER_2(_META_REPEAT_INDIRECT) ()  \
95 			(META_DEC(count), macro, __VA_ARGS__)\
96 		_META_DEFER_2(macro)\
97 			(META_DEC(count),        __VA_ARGS__)\
98 	)
99 
100 /* map every group of arg_count arguments onto function m
101  * i.e. arg_count=2;m=ADD;args=1,2,3,4,5,6,7...
102  * results in ADD(1,2) ADD(3,4) ADD(5,6) and so on
103  * MAP##N must exist for arg_count == N to work
104  */
105 #define META_MAP(arg_count, m, ...) META_RECURSE(\
106 	_META_MAP_BODY(arg_count, m, __VA_ARGS__))
107 
108 /* map aggregator and every group of arg_count arguments onto function m
109  * i.e. aggr=x;arg_count=1;m=ADD;args=1,2,3,4,5,6,7...
110  * results in x = ... ADD(7,ADD(6,ADD(5,ADD(4,ADD(3,ADD(2,ADD(1,x))))))) ...
111  * MAP##N must exist for arg_count == N to work
112  */
113 #define META_MAP_AGGREGATE(arg_count, m, aggr, ...)\
114 	META_CONCAT(_META_MAP_AGGREGATE_, arg_count)(m, aggr, __VA_ARGS__)
115 
116 /* META_CONCAT_SEQ is basicaly variadic version of macro META_CONCAT
117  * META_CONCAT_SEQ(A,B,C,D) tokenizes to ABCD
118  */
119 #define META_CONCAT_SEQ(aggr, ...) META_RECURSE(\
120 	META_MAP_AGGREGATE(1, META_CONCAT, aggr, __VA_ARGS__))
121 
122 /* META_CONCAT with parametrised delimeter between concatenised tokens
123  * META_CONCAT_SEQ_DELIM_(A,B,C,D) tokenizes as A_B_C_D
124  */
125 #define META_CONCAT_SEQ_DELIM_(aggr, ...) META_RECURSE(\
126 	META_MAP_AGGREGATE(1, _META_CONCAT_DELIM_, aggr, __VA_ARGS__))
127 
128 /* META_SEQ_FROM_0_TO(3, META_SEQ_STEP_param)
129  * produces , param0 , param1 , param2
130  */
131 #define META_SEQ_FROM_0_TO(arg_count, func)\
132 	META_RECURSE(META_REPEAT(arg_count, func, ~))
133 
134 /* Macros to be used as 2nd argument of macro META_SEQ_FROM_0_TO
135  * for instance
136  * META_SEQ_FROM_0_TO(arg_count, META_SEQ_STEP)
137  * produces
138  * 0 1 2 3 4
139  */
140 #define META_SEQ_STEP(i, _) i
141 #define META_SEQ_STEP_param(i, _) , META_CONCAT(param, i)
142 #define META_SEQ_STEP_param_uint32_t(i, _) , uint32_t META_CONCAT(param, i)
143 #define META_SEQ_STEP_param_uint64_t(i, _) , uint64_t META_CONCAT(param, i)
144 #define META_SEQ_STEP_param_int32_t( i, _) ,  int32_t META_CONCAT(param, i)
145 #define META_SEQ_STEP_param_int64_t( i, _) ,  int64_t META_CONCAT(param, i)
146 
147 #define META_SEQ_STEP_id(i, _) , META_CONCAT(id_, i)
148 #define META_SEQ_STEP_id_uint32_t(i, _) , uint32_t META_CONCAT(id_, i)
149 
150 /* generates function signature
151  * for instance with:
152  *   prefix=foo ; postfix=__bar ; return_t=void
153  *   args=(int x, int y)
154  * will produce:
155  *  void foo_bar(int x, int y)
156  */
157 #define META_FUNC_WITH_VARARGS(prefix, postfix, return_t, args)\
158 		return_t META_CONCAT(prefix, postfix) (args)
159 
160 /* counteract compiler warning about unused variables */
161 #define UNUSED(arg1, ...) do { META_RECURSE( \
162 	META_MAP_AGGREGATE(1, _META_VOID2, _META_VOID(arg1), __VA_ARGS__)); \
163 	} while (0)
164 
165 #endif /* __SOF_TRACE_PREPROC_H__ */
166