xref: /openbmc/linux/tools/perf/util/expr.y (revision 3f965a7df09d7eebde0020cefe427219afe7df4a)
107516736SAndi Kleen /* Simple expression parser */
207516736SAndi Kleen %{
326226a97SJiri Olsa #define YYDEBUG 1
4*3f965a7dSIan Rogers #include <assert.h>
5edfe7f55SIan Rogers #include <math.h>
607516736SAndi Kleen #include "util/debug.h"
77f8fdcbbSIan Rogers #include "smt.h"
807516736SAndi Kleen #define IN_EXPR_Y 1
907516736SAndi Kleen #include "expr.h"
1007516736SAndi Kleen %}
1107516736SAndi Kleen 
12fc8c0a99SJiri Olsa %define api.pure full
13fc8c0a99SJiri Olsa 
1407516736SAndi Kleen %parse-param { double *final_val }
15aecce63eSJiri Olsa %parse-param { struct expr_parse_ctx *ctx }
16*3f965a7dSIan Rogers %parse-param { bool compute_ids }
1726226a97SJiri Olsa %parse-param {void *scanner}
1826226a97SJiri Olsa %lex-param {void* scanner}
1907516736SAndi Kleen 
2007516736SAndi Kleen %union {
2107516736SAndi Kleen 	double	 num;
2226226a97SJiri Olsa 	char	*str;
23*3f965a7dSIan Rogers 	struct ids {
24*3f965a7dSIan Rogers 		/*
25*3f965a7dSIan Rogers 		 * When creating ids, holds the working set of event ids. NULL
26*3f965a7dSIan Rogers 		 * implies the set is empty.
27*3f965a7dSIan Rogers 		 */
28*3f965a7dSIan Rogers 		struct hashmap *ids;
29*3f965a7dSIan Rogers 		/*
30*3f965a7dSIan Rogers 		 * The metric value. When not creating ids this is the value
31*3f965a7dSIan Rogers 		 * read from a counter, a constant or some computed value. When
32*3f965a7dSIan Rogers 		 * creating ids the value is either a constant or BOTTOM. NAN is
33*3f965a7dSIan Rogers 		 * used as the special BOTTOM value, representing a "set of all
34*3f965a7dSIan Rogers 		 * values" case.
35*3f965a7dSIan Rogers 		 */
36*3f965a7dSIan Rogers 		double val;
37*3f965a7dSIan Rogers 	} ids;
3807516736SAndi Kleen }
3907516736SAndi Kleen 
40*3f965a7dSIan Rogers %token ID NUMBER MIN MAX IF ELSE SMT_ON D_RATIO EXPR_ERROR
41d73bad06SAndi Kleen %left MIN MAX IF
4207516736SAndi Kleen %left '|'
4307516736SAndi Kleen %left '^'
4407516736SAndi Kleen %left '&'
45ff1a12f9SIan Rogers %left '<' '>'
4607516736SAndi Kleen %left '-' '+'
4707516736SAndi Kleen %left '*' '/' '%'
4807516736SAndi Kleen %left NEG NOT
49aed0d6f8SIan Rogers %type <num> NUMBER
50aed0d6f8SIan Rogers %type <str> ID
51aed0d6f8SIan Rogers %destructor { free ($$); } <str>
52*3f965a7dSIan Rogers %type <ids> expr if_expr
53*3f965a7dSIan Rogers %destructor { ids__free($$.ids); } <ids>
5407516736SAndi Kleen 
5507516736SAndi Kleen %{
5626226a97SJiri Olsa static void expr_error(double *final_val __maybe_unused,
57aecce63eSJiri Olsa 		       struct expr_parse_ctx *ctx __maybe_unused,
58*3f965a7dSIan Rogers 		       bool compute_ids __maybe_unused,
5926226a97SJiri Olsa 		       void *scanner,
6007516736SAndi Kleen 		       const char *s)
6107516736SAndi Kleen {
6207516736SAndi Kleen 	pr_debug("%s\n", s);
6307516736SAndi Kleen }
6407516736SAndi Kleen 
65*3f965a7dSIan Rogers /*
66*3f965a7dSIan Rogers  * During compute ids, the special "bottom" value uses NAN to represent the set
67*3f965a7dSIan Rogers  * of all values. NAN is selected as it isn't a useful constant value.
68*3f965a7dSIan Rogers  */
69*3f965a7dSIan Rogers #define BOTTOM NAN
70*3f965a7dSIan Rogers 
71*3f965a7dSIan Rogers static struct ids union_expr(struct ids ids1, struct ids ids2)
72*3f965a7dSIan Rogers {
73*3f965a7dSIan Rogers 	struct ids result = {
74*3f965a7dSIan Rogers 		.val = BOTTOM,
75*3f965a7dSIan Rogers 		.ids = ids__union(ids1.ids, ids2.ids),
76*3f965a7dSIan Rogers 	};
77*3f965a7dSIan Rogers 	return result;
78*3f965a7dSIan Rogers }
79*3f965a7dSIan Rogers 
80e87576c5SIan Rogers #define BINARY_LONG_OP(RESULT, OP, LHS, RHS)				\
81*3f965a7dSIan Rogers 	if (!compute_ids) {						\
82*3f965a7dSIan Rogers 		RESULT.val = (long)LHS.val OP (long)RHS.val;		\
83*3f965a7dSIan Rogers 		RESULT.ids = NULL;					\
84*3f965a7dSIan Rogers 	} else {							\
85*3f965a7dSIan Rogers 	        RESULT = union_expr(LHS, RHS);				\
86*3f965a7dSIan Rogers 	}
87e87576c5SIan Rogers 
88e87576c5SIan Rogers #define BINARY_OP(RESULT, OP, LHS, RHS)					\
89*3f965a7dSIan Rogers 	if (!compute_ids) {						\
90*3f965a7dSIan Rogers 		RESULT.val = LHS.val OP RHS.val;			\
91*3f965a7dSIan Rogers 		RESULT.ids = NULL;					\
92*3f965a7dSIan Rogers 	} else {							\
93*3f965a7dSIan Rogers 	        RESULT = union_expr(LHS, RHS);				\
94*3f965a7dSIan Rogers 	}
95e87576c5SIan Rogers 
9607516736SAndi Kleen %}
9707516736SAndi Kleen %%
9807516736SAndi Kleen 
99*3f965a7dSIan Rogers start: if_expr
10026226a97SJiri Olsa {
101*3f965a7dSIan Rogers 	if (compute_ids)
102*3f965a7dSIan Rogers 		ctx->ids = ids__union($1.ids, ctx->ids);
10326226a97SJiri Olsa 
104*3f965a7dSIan Rogers 	if (final_val)
105*3f965a7dSIan Rogers 		*final_val = $1.val;
106*3f965a7dSIan Rogers }
107*3f965a7dSIan Rogers ;
108d73bad06SAndi Kleen 
109c924e0ccSIan Rogers if_expr: expr IF expr ELSE expr
110c924e0ccSIan Rogers {
111*3f965a7dSIan Rogers 	if (!compute_ids) {
112*3f965a7dSIan Rogers 		$$.ids = NULL;
113*3f965a7dSIan Rogers 		if (fpclassify($3.val) == FP_ZERO) {
114*3f965a7dSIan Rogers 			$$.val = $5.val;
115*3f965a7dSIan Rogers 		} else {
116*3f965a7dSIan Rogers 			$$.val = $1.val;
117*3f965a7dSIan Rogers 		}
118*3f965a7dSIan Rogers 	} else {
119*3f965a7dSIan Rogers 		$$ = union_expr($1, union_expr($3, $5));
120*3f965a7dSIan Rogers 	}
121c924e0ccSIan Rogers }
122d73bad06SAndi Kleen | expr
12307516736SAndi Kleen ;
12407516736SAndi Kleen 
12507516736SAndi Kleen expr: NUMBER
126c924e0ccSIan Rogers {
127*3f965a7dSIan Rogers 	$$.val = $1;
128*3f965a7dSIan Rogers 	$$.ids = NULL;
129c924e0ccSIan Rogers }
130c924e0ccSIan Rogers | ID
131c924e0ccSIan Rogers {
132*3f965a7dSIan Rogers 	if (!compute_ids) {
133*3f965a7dSIan Rogers 		/*
134*3f965a7dSIan Rogers 		 * Compute the event's value from ID. If the ID isn't known then
135*3f965a7dSIan Rogers 		 * it isn't used to compute the formula so set to NAN.
136*3f965a7dSIan Rogers 		 */
1375c5f5e83SJiri Olsa 		struct expr_id_data *data;
1385c5f5e83SJiri Olsa 
139*3f965a7dSIan Rogers 		$$.val = NAN;
140edfe7f55SIan Rogers 		if (expr__resolve_id(ctx, $1, &data) == 0)
141*3f965a7dSIan Rogers 			$$.val = expr_id_data__value(data);
142edfe7f55SIan Rogers 
143*3f965a7dSIan Rogers 		$$.ids = NULL;
14463657578SIan Rogers 		free($1);
145*3f965a7dSIan Rogers 	} else {
146*3f965a7dSIan Rogers 		/*
147*3f965a7dSIan Rogers 		 * Set the value to BOTTOM to show that any value is possible
148*3f965a7dSIan Rogers 		 * when the event is computed. Create a set of just the ID.
149*3f965a7dSIan Rogers 		 */
150*3f965a7dSIan Rogers 		$$.val = BOTTOM;
151*3f965a7dSIan Rogers 		$$.ids = ids__new();
152*3f965a7dSIan Rogers 		if (!$$.ids || ids__insert($$.ids, $1, ctx->parent))
153*3f965a7dSIan Rogers 			YYABORT;
154*3f965a7dSIan Rogers 	}
15507516736SAndi Kleen }
156e87576c5SIan Rogers | expr '|' expr { BINARY_LONG_OP($$, |, $1, $3); }
157e87576c5SIan Rogers | expr '&' expr { BINARY_LONG_OP($$, &, $1, $3); }
158e87576c5SIan Rogers | expr '^' expr { BINARY_LONG_OP($$, ^, $1, $3); }
159e87576c5SIan Rogers | expr '<' expr { BINARY_OP($$, <, $1, $3); }
160e87576c5SIan Rogers | expr '>' expr { BINARY_OP($$, >, $1, $3); }
161e87576c5SIan Rogers | expr '+' expr { BINARY_OP($$, +, $1, $3); }
162e87576c5SIan Rogers | expr '-' expr { BINARY_OP($$, -, $1, $3); }
163e87576c5SIan Rogers | expr '*' expr { BINARY_OP($$, *, $1, $3); }
164c924e0ccSIan Rogers | expr '/' expr
165c924e0ccSIan Rogers {
166*3f965a7dSIan Rogers 	if (!compute_ids) {
167*3f965a7dSIan Rogers 		if (fpclassify($3.val) == FP_ZERO) {
1689be27a5dSIan Rogers 			pr_debug("division by zero\n");
1699be27a5dSIan Rogers 			YYABORT;
1709be27a5dSIan Rogers 		}
171*3f965a7dSIan Rogers 		$$.val = $1.val / $3.val;
172*3f965a7dSIan Rogers 		$$.ids = NULL;
173*3f965a7dSIan Rogers 	} else {
174*3f965a7dSIan Rogers 		$$ = union_expr($1, $3);
175*3f965a7dSIan Rogers 	}
1769be27a5dSIan Rogers }
177c924e0ccSIan Rogers | expr '%' expr
178c924e0ccSIan Rogers {
179*3f965a7dSIan Rogers 	if (!compute_ids) {
180*3f965a7dSIan Rogers 		if (fpclassify($3.val) == FP_ZERO) {
1819be27a5dSIan Rogers 			pr_debug("division by zero\n");
1829be27a5dSIan Rogers 			YYABORT;
1839be27a5dSIan Rogers 		}
184*3f965a7dSIan Rogers 		$$.val = (long)$1.val % (long)$3.val;
185*3f965a7dSIan Rogers 		$$.ids = NULL;
186*3f965a7dSIan Rogers 	} else {
187*3f965a7dSIan Rogers 		$$ = union_expr($1, $3);
188*3f965a7dSIan Rogers 	}
1899be27a5dSIan Rogers }
190c924e0ccSIan Rogers | D_RATIO '(' expr ',' expr ')'
191c924e0ccSIan Rogers {
192*3f965a7dSIan Rogers 	if (!compute_ids) {
193*3f965a7dSIan Rogers 		$$.ids = NULL;
194*3f965a7dSIan Rogers 		if (fpclassify($5.val) == FP_ZERO) {
195*3f965a7dSIan Rogers 			$$.val = 0.0;
1967f8fdcbbSIan Rogers 		} else {
197*3f965a7dSIan Rogers 			$$.val = $3.val / $5.val;
198*3f965a7dSIan Rogers 		}
199*3f965a7dSIan Rogers 	} else {
200*3f965a7dSIan Rogers 		$$ = union_expr($3, $5);
2017f8fdcbbSIan Rogers 	}
2027f8fdcbbSIan Rogers }
203c924e0ccSIan Rogers | '-' expr %prec NEG
204c924e0ccSIan Rogers {
205*3f965a7dSIan Rogers 	$$.val = -$2.val;
206*3f965a7dSIan Rogers 	$$.ids = $2.ids;
207c924e0ccSIan Rogers }
208c924e0ccSIan Rogers | '(' if_expr ')'
209c924e0ccSIan Rogers {
210c924e0ccSIan Rogers 	$$ = $2;
211c924e0ccSIan Rogers }
212c924e0ccSIan Rogers | MIN '(' expr ',' expr ')'
213c924e0ccSIan Rogers {
214*3f965a7dSIan Rogers 	if (!compute_ids) {
215*3f965a7dSIan Rogers 		$$.val = $3.val < $5.val ? $3.val : $5.val;
216*3f965a7dSIan Rogers 		$$.ids = NULL;
217*3f965a7dSIan Rogers 	} else {
218*3f965a7dSIan Rogers 		$$ = union_expr($3, $5);
219*3f965a7dSIan Rogers 	}
220c924e0ccSIan Rogers }
221c924e0ccSIan Rogers | MAX '(' expr ',' expr ')'
222c924e0ccSIan Rogers {
223*3f965a7dSIan Rogers 	if (!compute_ids) {
224*3f965a7dSIan Rogers 		$$.val = $3.val > $5.val ? $3.val : $5.val;
225*3f965a7dSIan Rogers 		$$.ids = NULL;
226*3f965a7dSIan Rogers 	} else {
227*3f965a7dSIan Rogers 		$$ = union_expr($3, $5);
228*3f965a7dSIan Rogers 	}
229c924e0ccSIan Rogers }
230c924e0ccSIan Rogers | SMT_ON
231c924e0ccSIan Rogers {
232*3f965a7dSIan Rogers 	$$.val = smt_on() > 0 ? 1.0 : 0.0;
233*3f965a7dSIan Rogers 	$$.ids = NULL;
234c924e0ccSIan Rogers }
23507516736SAndi Kleen ;
23607516736SAndi Kleen 
23707516736SAndi Kleen %%
238