1*93f3d2b8Schs /*
2*93f3d2b8Schs * CDDL HEADER START
3*93f3d2b8Schs *
4*93f3d2b8Schs * This file and its contents are supplied under the terms of the
5*93f3d2b8Schs * Common Development and Distribution License ("CDDL"), version 1.0.
6*93f3d2b8Schs * You may only use this file in accordance with the terms of version
7*93f3d2b8Schs * 1.0 of the CDDL.
8*93f3d2b8Schs *
9*93f3d2b8Schs * A full copy of the text of the CDDL should have accompanied this
10*93f3d2b8Schs * source. A copy of the CDDL is also available via the Internet at
11*93f3d2b8Schs * http://www.illumos.org/license/CDDL.
12*93f3d2b8Schs *
13*93f3d2b8Schs * CDDL HEADER END
14*93f3d2b8Schs */
15*93f3d2b8Schs
16*93f3d2b8Schs /*
17*93f3d2b8Schs * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
18*93f3d2b8Schs */
19*93f3d2b8Schs
20*93f3d2b8Schs /*
21*93f3d2b8Schs * Syntactic sugar features are implemented by transforming the D parse tree
22*93f3d2b8Schs * such that it only uses the subset of D that is supported by the rest of the
23*93f3d2b8Schs * compiler / the kernel. A clause containing these language features is
24*93f3d2b8Schs * referred to as a "super-clause", and its transformation typically entails
25*93f3d2b8Schs * creating several "sub-clauses" to implement it. For diagnosability, the
26*93f3d2b8Schs * sub-clauses will be printed if the "-xtree=8" flag is specified.
27*93f3d2b8Schs *
28*93f3d2b8Schs * Currently, the only syntactic sugar feature is "if/else" statements. Each
29*93f3d2b8Schs * basic block (e.g. the body of the "if" and "else" statements, and the
30*93f3d2b8Schs * statements before and after) is turned into its own sub-clause, with a
31*93f3d2b8Schs * predicate that causes it to be executed only if the code flows to this point.
32*93f3d2b8Schs * Nested if/else statements are supported.
33*93f3d2b8Schs *
34*93f3d2b8Schs * This infrastructure is designed to accommodate other syntactic sugar features
35*93f3d2b8Schs * in the future.
36*93f3d2b8Schs */
37*93f3d2b8Schs
38*93f3d2b8Schs #include <sys/types.h>
39*93f3d2b8Schs #include <sys/wait.h>
40*93f3d2b8Schs #include <sys/sysmacros.h>
41*93f3d2b8Schs
42*93f3d2b8Schs #include <assert.h>
43*93f3d2b8Schs #include <strings.h>
44*93f3d2b8Schs #include <stdlib.h>
45*93f3d2b8Schs #include <stdio.h>
46*93f3d2b8Schs #include <ctype.h>
47*93f3d2b8Schs #include <dt_module.h>
48*93f3d2b8Schs #include <dt_program.h>
49*93f3d2b8Schs #include <dt_provider.h>
50*93f3d2b8Schs #include <dt_printf.h>
51*93f3d2b8Schs #include <dt_pid.h>
52*93f3d2b8Schs #include <dt_grammar.h>
53*93f3d2b8Schs #include <dt_ident.h>
54*93f3d2b8Schs #include <dt_string.h>
55*93f3d2b8Schs #include <dt_impl.h>
56*93f3d2b8Schs
57*93f3d2b8Schs typedef struct dt_sugar_parse {
58*93f3d2b8Schs dtrace_hdl_t *dtsp_dtp; /* dtrace handle */
59*93f3d2b8Schs dt_node_t *dtsp_pdescs; /* probe descriptions */
60*93f3d2b8Schs int dtsp_num_conditions; /* number of condition variables */
61*93f3d2b8Schs int dtsp_num_ifs; /* number of "if" statements */
62*93f3d2b8Schs dt_node_t *dtsp_clause_list; /* list of clauses */
63*93f3d2b8Schs } dt_sugar_parse_t;
64*93f3d2b8Schs
65*93f3d2b8Schs static void dt_sugar_visit_stmts(dt_sugar_parse_t *, dt_node_t *, int);
66*93f3d2b8Schs
67*93f3d2b8Schs /*
68*93f3d2b8Schs * Return a node for "self->%error".
69*93f3d2b8Schs *
70*93f3d2b8Schs * Note that the "%" is part of the variable name, and is included so that
71*93f3d2b8Schs * this variable name can not collide with any user-specified variable.
72*93f3d2b8Schs *
73*93f3d2b8Schs * This error variable is used to keep track of if there has been an error
74*93f3d2b8Schs * in any of the sub-clauses, and is used to prevent execution of subsequent
75*93f3d2b8Schs * sub-clauses following an error.
76*93f3d2b8Schs */
77*93f3d2b8Schs static dt_node_t *
dt_sugar_new_error_var(void)78*93f3d2b8Schs dt_sugar_new_error_var(void)
79*93f3d2b8Schs {
80*93f3d2b8Schs return (dt_node_op2(DT_TOK_PTR, dt_node_ident(strdup("self")),
81*93f3d2b8Schs dt_node_ident(strdup("%error"))));
82*93f3d2b8Schs }
83*93f3d2b8Schs
84*93f3d2b8Schs /*
85*93f3d2b8Schs * Append this clause to the clause list.
86*93f3d2b8Schs */
87*93f3d2b8Schs static void
dt_sugar_append_clause(dt_sugar_parse_t * dp,dt_node_t * clause)88*93f3d2b8Schs dt_sugar_append_clause(dt_sugar_parse_t *dp, dt_node_t *clause)
89*93f3d2b8Schs {
90*93f3d2b8Schs dp->dtsp_clause_list = dt_node_link(dp->dtsp_clause_list, clause);
91*93f3d2b8Schs }
92*93f3d2b8Schs
93*93f3d2b8Schs /*
94*93f3d2b8Schs * Prepend this clause to the clause list.
95*93f3d2b8Schs */
96*93f3d2b8Schs static void
dt_sugar_prepend_clause(dt_sugar_parse_t * dp,dt_node_t * clause)97*93f3d2b8Schs dt_sugar_prepend_clause(dt_sugar_parse_t *dp, dt_node_t *clause)
98*93f3d2b8Schs {
99*93f3d2b8Schs dp->dtsp_clause_list = dt_node_link(clause, dp->dtsp_clause_list);
100*93f3d2b8Schs }
101*93f3d2b8Schs
102*93f3d2b8Schs /*
103*93f3d2b8Schs * Return a node for "this->%condition_<condid>", or NULL if condid==0.
104*93f3d2b8Schs *
105*93f3d2b8Schs * Note that the "%" is part of the variable name, and is included so that
106*93f3d2b8Schs * this variable name can not collide with any user-specified variable.
107*93f3d2b8Schs */
108*93f3d2b8Schs static dt_node_t *
dt_sugar_new_condition_var(int condid)109*93f3d2b8Schs dt_sugar_new_condition_var(int condid)
110*93f3d2b8Schs {
111*93f3d2b8Schs char *str;
112*93f3d2b8Schs
113*93f3d2b8Schs if (condid == 0)
114*93f3d2b8Schs return (NULL);
115*93f3d2b8Schs assert(condid > 0);
116*93f3d2b8Schs
117*93f3d2b8Schs (void) asprintf(&str, "%%condition_%d", ABS(condid));
118*93f3d2b8Schs return (dt_node_op2(DT_TOK_PTR, dt_node_ident(strdup("this")),
119*93f3d2b8Schs dt_node_ident(str)));
120*93f3d2b8Schs }
121*93f3d2b8Schs
122*93f3d2b8Schs /*
123*93f3d2b8Schs * Return new clause to evaluate predicate and set newcond. condid is
124*93f3d2b8Schs * the condition that we are already under, or 0 if none.
125*93f3d2b8Schs * The new clause will be of the form:
126*93f3d2b8Schs *
127*93f3d2b8Schs * dp_pdescs
128*93f3d2b8Schs * /!self->%error/
129*93f3d2b8Schs * {
130*93f3d2b8Schs * this->%condition_<newcond> =
131*93f3d2b8Schs * (this->%condition_<condid> && pred);
132*93f3d2b8Schs * }
133*93f3d2b8Schs *
134*93f3d2b8Schs * Note: if condid==0, we will instead do "... = (1 && pred)", to effectively
135*93f3d2b8Schs * convert the pred to a boolean.
136*93f3d2b8Schs *
137*93f3d2b8Schs * Note: Unless an error has been encountered, we always set the condition
138*93f3d2b8Schs * variable (either to 0 or 1). This lets us avoid resetting the condition
139*93f3d2b8Schs * variables back to 0 when the super-clause completes.
140*93f3d2b8Schs */
141*93f3d2b8Schs static dt_node_t *
dt_sugar_new_condition_impl(dt_sugar_parse_t * dp,dt_node_t * pred,int condid,int newcond)142*93f3d2b8Schs dt_sugar_new_condition_impl(dt_sugar_parse_t *dp,
143*93f3d2b8Schs dt_node_t *pred, int condid, int newcond)
144*93f3d2b8Schs {
145*93f3d2b8Schs dt_node_t *value, *body, *newpred;
146*93f3d2b8Schs
147*93f3d2b8Schs /* predicate is !self->%error */
148*93f3d2b8Schs newpred = dt_node_op1(DT_TOK_LNEG, dt_sugar_new_error_var());
149*93f3d2b8Schs
150*93f3d2b8Schs if (condid == 0) {
151*93f3d2b8Schs /*
152*93f3d2b8Schs * value is (1 && pred)
153*93f3d2b8Schs *
154*93f3d2b8Schs * Note, D doesn't allow a probe-local "this" variable to
155*93f3d2b8Schs * be reused as a different type, even from a different probe.
156*93f3d2b8Schs * Therefore, value can't simply be <pred>, because then
157*93f3d2b8Schs * its type could be different when we reuse this condid
158*93f3d2b8Schs * in a different meta-clause.
159*93f3d2b8Schs */
160*93f3d2b8Schs value = dt_node_op2(DT_TOK_LAND, dt_node_int(1), pred);
161*93f3d2b8Schs } else {
162*93f3d2b8Schs /* value is (this->%condition_<condid> && pred) */
163*93f3d2b8Schs value = dt_node_op2(DT_TOK_LAND,
164*93f3d2b8Schs dt_sugar_new_condition_var(condid), pred);
165*93f3d2b8Schs }
166*93f3d2b8Schs
167*93f3d2b8Schs /* body is "this->%condition_<retval> = <value>;" */
168*93f3d2b8Schs body = dt_node_statement(dt_node_op2(DT_TOK_ASGN,
169*93f3d2b8Schs dt_sugar_new_condition_var(newcond), value));
170*93f3d2b8Schs
171*93f3d2b8Schs return (dt_node_clause(dp->dtsp_pdescs, newpred, body));
172*93f3d2b8Schs }
173*93f3d2b8Schs
174*93f3d2b8Schs /*
175*93f3d2b8Schs * Generate a new clause to evaluate predicate and set a new condition variable,
176*93f3d2b8Schs * whose ID will be returned. The new clause will be appended to
177*93f3d2b8Schs * dp_first_new_clause.
178*93f3d2b8Schs */
179*93f3d2b8Schs static int
dt_sugar_new_condition(dt_sugar_parse_t * dp,dt_node_t * pred,int condid)180*93f3d2b8Schs dt_sugar_new_condition(dt_sugar_parse_t *dp, dt_node_t *pred, int condid)
181*93f3d2b8Schs {
182*93f3d2b8Schs dp->dtsp_num_conditions++;
183*93f3d2b8Schs dt_sugar_append_clause(dp, dt_sugar_new_condition_impl(dp,
184*93f3d2b8Schs pred, condid, dp->dtsp_num_conditions));
185*93f3d2b8Schs return (dp->dtsp_num_conditions);
186*93f3d2b8Schs }
187*93f3d2b8Schs
188*93f3d2b8Schs /*
189*93f3d2b8Schs * Visit the specified node and all of its descendants. Currently this is only
190*93f3d2b8Schs * used to count the number of "if" statements (dtsp_num_ifs).
191*93f3d2b8Schs */
192*93f3d2b8Schs static void
dt_sugar_visit_all(dt_sugar_parse_t * dp,dt_node_t * dnp)193*93f3d2b8Schs dt_sugar_visit_all(dt_sugar_parse_t *dp, dt_node_t *dnp)
194*93f3d2b8Schs {
195*93f3d2b8Schs dt_node_t *arg;
196*93f3d2b8Schs
197*93f3d2b8Schs switch (dnp->dn_kind) {
198*93f3d2b8Schs case DT_NODE_FREE:
199*93f3d2b8Schs case DT_NODE_INT:
200*93f3d2b8Schs case DT_NODE_STRING:
201*93f3d2b8Schs case DT_NODE_SYM:
202*93f3d2b8Schs case DT_NODE_TYPE:
203*93f3d2b8Schs case DT_NODE_PROBE:
204*93f3d2b8Schs case DT_NODE_PDESC:
205*93f3d2b8Schs case DT_NODE_IDENT:
206*93f3d2b8Schs break;
207*93f3d2b8Schs
208*93f3d2b8Schs case DT_NODE_FUNC:
209*93f3d2b8Schs for (arg = dnp->dn_args; arg != NULL; arg = arg->dn_list)
210*93f3d2b8Schs dt_sugar_visit_all(dp, arg);
211*93f3d2b8Schs break;
212*93f3d2b8Schs
213*93f3d2b8Schs case DT_NODE_OP1:
214*93f3d2b8Schs dt_sugar_visit_all(dp, dnp->dn_child);
215*93f3d2b8Schs break;
216*93f3d2b8Schs
217*93f3d2b8Schs case DT_NODE_OP2:
218*93f3d2b8Schs dt_sugar_visit_all(dp, dnp->dn_left);
219*93f3d2b8Schs dt_sugar_visit_all(dp, dnp->dn_right);
220*93f3d2b8Schs if (dnp->dn_op == DT_TOK_LBRAC) {
221*93f3d2b8Schs dt_node_t *ln = dnp->dn_right;
222*93f3d2b8Schs while (ln->dn_list != NULL) {
223*93f3d2b8Schs dt_sugar_visit_all(dp, ln->dn_list);
224*93f3d2b8Schs ln = ln->dn_list;
225*93f3d2b8Schs }
226*93f3d2b8Schs }
227*93f3d2b8Schs break;
228*93f3d2b8Schs
229*93f3d2b8Schs case DT_NODE_OP3:
230*93f3d2b8Schs dt_sugar_visit_all(dp, dnp->dn_expr);
231*93f3d2b8Schs dt_sugar_visit_all(dp, dnp->dn_left);
232*93f3d2b8Schs dt_sugar_visit_all(dp, dnp->dn_right);
233*93f3d2b8Schs break;
234*93f3d2b8Schs
235*93f3d2b8Schs case DT_NODE_DEXPR:
236*93f3d2b8Schs case DT_NODE_DFUNC:
237*93f3d2b8Schs dt_sugar_visit_all(dp, dnp->dn_expr);
238*93f3d2b8Schs break;
239*93f3d2b8Schs
240*93f3d2b8Schs case DT_NODE_AGG:
241*93f3d2b8Schs for (arg = dnp->dn_aggtup; arg != NULL; arg = arg->dn_list)
242*93f3d2b8Schs dt_sugar_visit_all(dp, arg);
243*93f3d2b8Schs
244*93f3d2b8Schs if (dnp->dn_aggfun)
245*93f3d2b8Schs dt_sugar_visit_all(dp, dnp->dn_aggfun);
246*93f3d2b8Schs break;
247*93f3d2b8Schs
248*93f3d2b8Schs case DT_NODE_CLAUSE:
249*93f3d2b8Schs for (arg = dnp->dn_pdescs; arg != NULL; arg = arg->dn_list)
250*93f3d2b8Schs dt_sugar_visit_all(dp, arg);
251*93f3d2b8Schs
252*93f3d2b8Schs if (dnp->dn_pred != NULL)
253*93f3d2b8Schs dt_sugar_visit_all(dp, dnp->dn_pred);
254*93f3d2b8Schs
255*93f3d2b8Schs for (arg = dnp->dn_acts; arg != NULL; arg = arg->dn_list)
256*93f3d2b8Schs dt_sugar_visit_all(dp, arg);
257*93f3d2b8Schs break;
258*93f3d2b8Schs
259*93f3d2b8Schs case DT_NODE_INLINE: {
260*93f3d2b8Schs const dt_idnode_t *inp = dnp->dn_ident->di_iarg;
261*93f3d2b8Schs
262*93f3d2b8Schs dt_sugar_visit_all(dp, inp->din_root);
263*93f3d2b8Schs break;
264*93f3d2b8Schs }
265*93f3d2b8Schs case DT_NODE_MEMBER:
266*93f3d2b8Schs if (dnp->dn_membexpr)
267*93f3d2b8Schs dt_sugar_visit_all(dp, dnp->dn_membexpr);
268*93f3d2b8Schs break;
269*93f3d2b8Schs
270*93f3d2b8Schs case DT_NODE_XLATOR:
271*93f3d2b8Schs for (arg = dnp->dn_members; arg != NULL; arg = arg->dn_list)
272*93f3d2b8Schs dt_sugar_visit_all(dp, arg);
273*93f3d2b8Schs break;
274*93f3d2b8Schs
275*93f3d2b8Schs case DT_NODE_PROVIDER:
276*93f3d2b8Schs for (arg = dnp->dn_probes; arg != NULL; arg = arg->dn_list)
277*93f3d2b8Schs dt_sugar_visit_all(dp, arg);
278*93f3d2b8Schs break;
279*93f3d2b8Schs
280*93f3d2b8Schs case DT_NODE_PROG:
281*93f3d2b8Schs for (arg = dnp->dn_list; arg != NULL; arg = arg->dn_list)
282*93f3d2b8Schs dt_sugar_visit_all(dp, arg);
283*93f3d2b8Schs break;
284*93f3d2b8Schs
285*93f3d2b8Schs case DT_NODE_IF:
286*93f3d2b8Schs dp->dtsp_num_ifs++;
287*93f3d2b8Schs dt_sugar_visit_all(dp, dnp->dn_conditional);
288*93f3d2b8Schs
289*93f3d2b8Schs for (arg = dnp->dn_body; arg != NULL; arg = arg->dn_list)
290*93f3d2b8Schs dt_sugar_visit_all(dp, arg);
291*93f3d2b8Schs for (arg = dnp->dn_alternate_body; arg != NULL;
292*93f3d2b8Schs arg = arg->dn_list)
293*93f3d2b8Schs dt_sugar_visit_all(dp, arg);
294*93f3d2b8Schs
295*93f3d2b8Schs break;
296*93f3d2b8Schs
297*93f3d2b8Schs default:
298*93f3d2b8Schs (void) dnerror(dnp, D_UNKNOWN, "bad node %p, kind %d\n",
299*93f3d2b8Schs (void *)dnp, dnp->dn_kind);
300*93f3d2b8Schs }
301*93f3d2b8Schs }
302*93f3d2b8Schs
303*93f3d2b8Schs /*
304*93f3d2b8Schs * Return a new clause which resets the error variable to zero:
305*93f3d2b8Schs *
306*93f3d2b8Schs * dp_pdescs{ self->%error = 0; }
307*93f3d2b8Schs *
308*93f3d2b8Schs * This clause will be executed at the beginning of each meta-clause, to
309*93f3d2b8Schs * ensure the error variable is unset (in case the previous meta-clause
310*93f3d2b8Schs * failed).
311*93f3d2b8Schs */
312*93f3d2b8Schs static dt_node_t *
dt_sugar_new_clearerror_clause(dt_sugar_parse_t * dp)313*93f3d2b8Schs dt_sugar_new_clearerror_clause(dt_sugar_parse_t *dp)
314*93f3d2b8Schs {
315*93f3d2b8Schs dt_node_t *stmt = dt_node_statement(dt_node_op2(DT_TOK_ASGN,
316*93f3d2b8Schs dt_sugar_new_error_var(), dt_node_int(0)));
317*93f3d2b8Schs return (dt_node_clause(dp->dtsp_pdescs, NULL, stmt));
318*93f3d2b8Schs }
319*93f3d2b8Schs
320*93f3d2b8Schs /*
321*93f3d2b8Schs * Evaluate the conditional, and recursively visit the body of the "if"
322*93f3d2b8Schs * statement (and the "else", if present).
323*93f3d2b8Schs */
324*93f3d2b8Schs static void
dt_sugar_do_if(dt_sugar_parse_t * dp,dt_node_t * if_stmt,int precondition)325*93f3d2b8Schs dt_sugar_do_if(dt_sugar_parse_t *dp, dt_node_t *if_stmt, int precondition)
326*93f3d2b8Schs {
327*93f3d2b8Schs int newid;
328*93f3d2b8Schs
329*93f3d2b8Schs assert(if_stmt->dn_kind == DT_NODE_IF);
330*93f3d2b8Schs
331*93f3d2b8Schs /* condition */
332*93f3d2b8Schs newid = dt_sugar_new_condition(dp,
333*93f3d2b8Schs if_stmt->dn_conditional, precondition);
334*93f3d2b8Schs
335*93f3d2b8Schs /* body of if */
336*93f3d2b8Schs dt_sugar_visit_stmts(dp, if_stmt->dn_body, newid);
337*93f3d2b8Schs
338*93f3d2b8Schs /*
339*93f3d2b8Schs * Visit the body of the "else" statement, if present. Note that we
340*93f3d2b8Schs * generate a new condition which is the inverse of the previous
341*93f3d2b8Schs * condition.
342*93f3d2b8Schs */
343*93f3d2b8Schs if (if_stmt->dn_alternate_body != NULL) {
344*93f3d2b8Schs dt_node_t *pred =
345*93f3d2b8Schs dt_node_op1(DT_TOK_LNEG, dt_sugar_new_condition_var(newid));
346*93f3d2b8Schs dt_sugar_visit_stmts(dp, if_stmt->dn_alternate_body,
347*93f3d2b8Schs dt_sugar_new_condition(dp, pred, precondition));
348*93f3d2b8Schs }
349*93f3d2b8Schs }
350*93f3d2b8Schs
351*93f3d2b8Schs /*
352*93f3d2b8Schs * Generate a new clause to evaluate the statements based on the condition.
353*93f3d2b8Schs * The new clause will be appended to dp_first_new_clause.
354*93f3d2b8Schs *
355*93f3d2b8Schs * dp_pdescs
356*93f3d2b8Schs * /!self->%error && this->%condition_<condid>/
357*93f3d2b8Schs * {
358*93f3d2b8Schs * stmts
359*93f3d2b8Schs * }
360*93f3d2b8Schs */
361*93f3d2b8Schs static void
dt_sugar_new_basic_block(dt_sugar_parse_t * dp,int condid,dt_node_t * stmts)362*93f3d2b8Schs dt_sugar_new_basic_block(dt_sugar_parse_t *dp, int condid, dt_node_t *stmts)
363*93f3d2b8Schs {
364*93f3d2b8Schs dt_node_t *pred = NULL;
365*93f3d2b8Schs
366*93f3d2b8Schs if (condid == 0) {
367*93f3d2b8Schs /*
368*93f3d2b8Schs * Don't bother with !error on the first clause, because if
369*93f3d2b8Schs * there is only one clause, we don't add the prelude to
370*93f3d2b8Schs * zero out %error.
371*93f3d2b8Schs */
372*93f3d2b8Schs if (dp->dtsp_num_conditions != 0) {
373*93f3d2b8Schs pred = dt_node_op1(DT_TOK_LNEG,
374*93f3d2b8Schs dt_sugar_new_error_var());
375*93f3d2b8Schs }
376*93f3d2b8Schs } else {
377*93f3d2b8Schs pred = dt_node_op2(DT_TOK_LAND,
378*93f3d2b8Schs dt_node_op1(DT_TOK_LNEG, dt_sugar_new_error_var()),
379*93f3d2b8Schs dt_sugar_new_condition_var(condid));
380*93f3d2b8Schs }
381*93f3d2b8Schs dt_sugar_append_clause(dp,
382*93f3d2b8Schs dt_node_clause(dp->dtsp_pdescs, pred, stmts));
383*93f3d2b8Schs }
384*93f3d2b8Schs
385*93f3d2b8Schs /*
386*93f3d2b8Schs * Visit all the statements in this list, and break them into basic blocks,
387*93f3d2b8Schs * generating new clauses for "if" and "else" statements.
388*93f3d2b8Schs */
389*93f3d2b8Schs static void
dt_sugar_visit_stmts(dt_sugar_parse_t * dp,dt_node_t * stmts,int precondition)390*93f3d2b8Schs dt_sugar_visit_stmts(dt_sugar_parse_t *dp, dt_node_t *stmts, int precondition)
391*93f3d2b8Schs {
392*93f3d2b8Schs dt_node_t *stmt;
393*93f3d2b8Schs dt_node_t *prev_stmt = NULL;
394*93f3d2b8Schs dt_node_t *next_stmt;
395*93f3d2b8Schs dt_node_t *first_stmt_in_basic_block = NULL;
396*93f3d2b8Schs
397*93f3d2b8Schs for (stmt = stmts; stmt != NULL; stmt = next_stmt) {
398*93f3d2b8Schs next_stmt = stmt->dn_list;
399*93f3d2b8Schs
400*93f3d2b8Schs if (stmt->dn_kind != DT_NODE_IF) {
401*93f3d2b8Schs if (first_stmt_in_basic_block == NULL)
402*93f3d2b8Schs first_stmt_in_basic_block = stmt;
403*93f3d2b8Schs prev_stmt = stmt;
404*93f3d2b8Schs continue;
405*93f3d2b8Schs }
406*93f3d2b8Schs
407*93f3d2b8Schs /*
408*93f3d2b8Schs * Remove this and following statements from the previous
409*93f3d2b8Schs * clause.
410*93f3d2b8Schs */
411*93f3d2b8Schs if (prev_stmt != NULL)
412*93f3d2b8Schs prev_stmt->dn_list = NULL;
413*93f3d2b8Schs
414*93f3d2b8Schs /*
415*93f3d2b8Schs * Generate clause for statements preceding the "if"
416*93f3d2b8Schs */
417*93f3d2b8Schs if (first_stmt_in_basic_block != NULL) {
418*93f3d2b8Schs dt_sugar_new_basic_block(dp, precondition,
419*93f3d2b8Schs first_stmt_in_basic_block);
420*93f3d2b8Schs }
421*93f3d2b8Schs
422*93f3d2b8Schs dt_sugar_do_if(dp, stmt, precondition);
423*93f3d2b8Schs
424*93f3d2b8Schs first_stmt_in_basic_block = NULL;
425*93f3d2b8Schs
426*93f3d2b8Schs prev_stmt = stmt;
427*93f3d2b8Schs }
428*93f3d2b8Schs
429*93f3d2b8Schs /* generate clause for statements after last "if". */
430*93f3d2b8Schs if (first_stmt_in_basic_block != NULL) {
431*93f3d2b8Schs dt_sugar_new_basic_block(dp, precondition,
432*93f3d2b8Schs first_stmt_in_basic_block);
433*93f3d2b8Schs }
434*93f3d2b8Schs }
435*93f3d2b8Schs
436*93f3d2b8Schs /*
437*93f3d2b8Schs * Generate a new clause which will set the error variable when an error occurs.
438*93f3d2b8Schs * Only one of these clauses is created per program (e.g. script file).
439*93f3d2b8Schs * The clause is:
440*93f3d2b8Schs *
441*93f3d2b8Schs * dtrace:::ERROR{ self->%error = 1; }
442*93f3d2b8Schs */
443*93f3d2b8Schs static dt_node_t *
dt_sugar_makeerrorclause(void)444*93f3d2b8Schs dt_sugar_makeerrorclause(void)
445*93f3d2b8Schs {
446*93f3d2b8Schs dt_node_t *acts, *pdesc;
447*93f3d2b8Schs
448*93f3d2b8Schs pdesc = dt_node_pdesc_by_name(strdup("dtrace:::ERROR"));
449*93f3d2b8Schs
450*93f3d2b8Schs acts = dt_node_statement(dt_node_op2(DT_TOK_ASGN,
451*93f3d2b8Schs dt_sugar_new_error_var(), dt_node_int(1)));
452*93f3d2b8Schs
453*93f3d2b8Schs return (dt_node_clause(pdesc, NULL, acts));
454*93f3d2b8Schs }
455*93f3d2b8Schs
456*93f3d2b8Schs /*
457*93f3d2b8Schs * Transform the super-clause into straight-D, returning the new list of
458*93f3d2b8Schs * sub-clauses.
459*93f3d2b8Schs */
460*93f3d2b8Schs dt_node_t *
dt_compile_sugar(dtrace_hdl_t * dtp,dt_node_t * clause)461*93f3d2b8Schs dt_compile_sugar(dtrace_hdl_t *dtp, dt_node_t *clause)
462*93f3d2b8Schs {
463*93f3d2b8Schs dt_sugar_parse_t dp = { 0 };
464*93f3d2b8Schs int condid = 0;
465*93f3d2b8Schs
466*93f3d2b8Schs dp.dtsp_dtp = dtp;
467*93f3d2b8Schs dp.dtsp_pdescs = clause->dn_pdescs;
468*93f3d2b8Schs
469*93f3d2b8Schs /* make dt_node_int() generate an "int"-typed integer */
470*93f3d2b8Schs yyintdecimal = B_TRUE;
471*93f3d2b8Schs yyintsuffix[0] = '\0';
472*93f3d2b8Schs yyintprefix = 0;
473*93f3d2b8Schs
474*93f3d2b8Schs dt_sugar_visit_all(&dp, clause);
475*93f3d2b8Schs
476*93f3d2b8Schs if (dp.dtsp_num_ifs == 0 && dp.dtsp_num_conditions == 0) {
477*93f3d2b8Schs /*
478*93f3d2b8Schs * There is nothing that modifies the number of clauses. Use
479*93f3d2b8Schs * the existing clause as-is, with its predicate intact. This
480*93f3d2b8Schs * ensures that in the absence of D sugar, the body of the
481*93f3d2b8Schs * clause can create a variable that is referenced in the
482*93f3d2b8Schs * predicate.
483*93f3d2b8Schs */
484*93f3d2b8Schs dt_sugar_append_clause(&dp, dt_node_clause(clause->dn_pdescs,
485*93f3d2b8Schs clause->dn_pred, clause->dn_acts));
486*93f3d2b8Schs } else {
487*93f3d2b8Schs if (clause->dn_pred != NULL) {
488*93f3d2b8Schs condid = dt_sugar_new_condition(&dp,
489*93f3d2b8Schs clause->dn_pred, condid);
490*93f3d2b8Schs }
491*93f3d2b8Schs
492*93f3d2b8Schs if (clause->dn_acts == NULL) {
493*93f3d2b8Schs /*
494*93f3d2b8Schs * dt_sugar_visit_stmts() does not emit a clause with
495*93f3d2b8Schs * an empty body (e.g. if there's an empty "if" body),
496*93f3d2b8Schs * but we need the empty body here so that we
497*93f3d2b8Schs * continue to get the default tracing action.
498*93f3d2b8Schs */
499*93f3d2b8Schs dt_sugar_new_basic_block(&dp, condid, NULL);
500*93f3d2b8Schs } else {
501*93f3d2b8Schs dt_sugar_visit_stmts(&dp, clause->dn_acts, condid);
502*93f3d2b8Schs }
503*93f3d2b8Schs }
504*93f3d2b8Schs
505*93f3d2b8Schs if (dp.dtsp_num_conditions != 0) {
506*93f3d2b8Schs dt_sugar_prepend_clause(&dp,
507*93f3d2b8Schs dt_sugar_new_clearerror_clause(&dp));
508*93f3d2b8Schs }
509*93f3d2b8Schs
510*93f3d2b8Schs if (dp.dtsp_clause_list != NULL &&
511*93f3d2b8Schs dp.dtsp_clause_list->dn_list != NULL && !dtp->dt_has_sugar) {
512*93f3d2b8Schs dtp->dt_has_sugar = B_TRUE;
513*93f3d2b8Schs dt_sugar_prepend_clause(&dp, dt_sugar_makeerrorclause());
514*93f3d2b8Schs }
515*93f3d2b8Schs return (dp.dtsp_clause_list);
516*93f3d2b8Schs }
517