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