]> sourceware.org Git - systemtap.git/blame - elaborate.cxx
Simplify dead_assignment_remover
[systemtap.git] / elaborate.cxx
CommitLineData
2b066ec1 1// elaboration functions
0f16be72 2// Copyright (C) 2005-2008 Red Hat Inc.
1773fd03 3// Copyright (C) 2008 Intel Corporation
69c68955
FCE
4//
5// This file is part of systemtap, and is free software. You can
6// redistribute it and/or modify it under the terms of the GNU General
7// Public License (GPL); either version 2, or (at your option) any
8// later version.
2b066ec1
FCE
9
10#include "config.h"
11#include "elaborate.h"
12#include "parse.h"
20c6c071 13#include "tapsets.h"
dc38c0ae 14#include "session.h"
72dbc915 15#include "util.h"
2b066ec1
FCE
16
17extern "C" {
18#include <sys/utsname.h>
a477f3f1 19#include <fnmatch.h>
2b066ec1
FCE
20}
21
2b066ec1 22#include <algorithm>
67c0a579
GH
23#include <fstream>
24#include <map>
29e64872 25#include <cassert>
67c0a579
GH
26#include <set>
27#include <vector>
1b07c728
FCE
28#include <algorithm>
29#include <iterator>
30
2b066ec1 31
2b066ec1
FCE
32using namespace std;
33
34
35// ------------------------------------------------------------------------
36
5d23847d
FCE
37// Used in probe_point condition construction. Either argument may be
38// NULL; if both, return NULL too. Resulting expression is a deep
39// copy for symbol resolution purposes.
40expression* add_condition (expression* a, expression* b)
41{
42 if (!a && !b) return 0;
43 if (! a) return deep_copy_visitor::deep_copy(b);
44 if (! b) return deep_copy_visitor::deep_copy(a);
45 logical_and_expr la;
46 la.op = "&&";
47 la.left = a;
48 la.right = b;
49 la.tok = a->tok; // or could be b->tok
50 return deep_copy_visitor::deep_copy(& la);
51}
52
53// ------------------------------------------------------------------------
54
55
2b066ec1
FCE
56
57derived_probe::derived_probe (probe *p):
58 base (p)
59{
5d23847d
FCE
60 assert (p);
61 this->locations = p->locations;
62 this->tok = p->tok;
63 this->privileged = p->privileged;
64 this->body = deep_copy_visitor::deep_copy(p->body);
2b066ec1
FCE
65}
66
67
68derived_probe::derived_probe (probe *p, probe_point *l):
69 base (p)
70{
5d23847d
FCE
71 assert (p);
72 this->tok = p->tok;
73 this->privileged = p->privileged;
74 this->body = deep_copy_visitor::deep_copy(p->body);
cbbe8080 75
5d23847d
FCE
76 assert (l);
77 this->locations.push_back (l);
2b066ec1
FCE
78}
79
98afd80e 80
b8da0ad1
FCE
81void
82derived_probe::printsig (ostream& o) const
83{
84 probe::printsig (o);
85 printsig_nested (o);
86}
87
88void
89derived_probe::printsig_nested (ostream& o) const
90{
91 // We'd like to enclose the probe derivation chain in a /* */
92 // comment delimiter. But just printing /* base->printsig() */ is
93 // not enough, since base might itself be a derived_probe. So we,
94 // er, "cleverly" encode our nesting state as a formatting flag for
95 // the ostream.
96 ios::fmtflags f = o.flags (ios::internal);
97 if (f & ios::internal)
98 {
99 // already nested
100 o << " <- ";
101 base->printsig (o);
102 }
103 else
104 {
105 // outermost nesting
106 o << " /* <- ";
107 base->printsig (o);
108 o << " */";
109 }
110 // restore flags
111 (void) o.flags (f);
112}
113
114
c3a3c0c9 115void
2c5a19c6 116derived_probe::collect_derivation_chain (std::vector<probe*> &probes_list)
c3a3c0c9
WC
117{
118 probes_list.push_back(this);
119 base->collect_derivation_chain(probes_list);
120}
121
122
b20febf3 123probe_point*
b8da0ad1 124derived_probe::sole_location () const
dc38c0ae 125{
b20febf3
FCE
126 if (locations.size() == 0)
127 throw semantic_error ("derived_probe with no locations", this->tok);
128 else if (locations.size() > 1)
129 throw semantic_error ("derived_probe with too many locations", this->tok);
57148ee7 130 else
b20febf3 131 return locations[0];
dc38c0ae
DS
132}
133
134
47dd066d 135
20c6c071 136// ------------------------------------------------------------------------
98afd80e
FCE
137// Members of derived_probe_builder
138
139bool
140derived_probe_builder::get_param (std::map<std::string, literal*> const & params,
141 const std::string& key,
142 std::string& value)
143{
144 map<string, literal *>::const_iterator i = params.find (key);
145 if (i == params.end())
146 return false;
147 literal_string * ls = dynamic_cast<literal_string *>(i->second);
148 if (!ls)
149 return false;
150 value = ls->value;
151 return true;
152}
153
20c6c071 154
98afd80e
FCE
155bool
156derived_probe_builder::get_param (std::map<std::string, literal*> const & params,
157 const std::string& key,
158 int64_t& value)
159{
160 map<string, literal *>::const_iterator i = params.find (key);
161 if (i == params.end())
162 return false;
163 if (i->second == NULL)
164 return false;
165 literal_number * ln = dynamic_cast<literal_number *>(i->second);
166 if (!ln)
167 return false;
168 value = ln->value;
169 return true;
170}
171
172
888af770
FCE
173bool
174derived_probe_builder::has_null_param (std::map<std::string, literal*> const & params,
175 const std::string& key)
176{
177 map<string, literal *>::const_iterator i = params.find(key);
178 return (i != params.end() && i->second == NULL);
179}
180
181
98afd80e
FCE
182
183// ------------------------------------------------------------------------
20c6c071
GH
184// Members of match_key.
185
57148ee7
FCE
186match_key::match_key(string const & n)
187 : name(n),
188 have_parameter(false),
5d23847d 189 parameter_type(pe_unknown)
20c6c071
GH
190{
191}
192
193match_key::match_key(probe_point::component const & c)
194 : name(c.functor),
195 have_parameter(c.arg != NULL),
5d23847d 196 parameter_type(c.arg ? c.arg->type : pe_unknown)
20c6c071
GH
197{
198}
199
200match_key &
57148ee7 201match_key::with_number()
20c6c071
GH
202{
203 have_parameter = true;
5d23847d 204 parameter_type = pe_long;
20c6c071
GH
205 return *this;
206}
207
208match_key &
57148ee7 209match_key::with_string()
20c6c071
GH
210{
211 have_parameter = true;
5d23847d 212 parameter_type = pe_string;
20c6c071
GH
213 return *this;
214}
215
57148ee7 216string
20c6c071
GH
217match_key::str() const
218{
219 if (have_parameter)
220 switch (parameter_type)
221 {
5d23847d
FCE
222 case pe_string: return name + "(string)";
223 case pe_long: return name + "(number)";
20c6c071
GH
224 default: return name + "(...)";
225 }
226 return name;
227}
228
57148ee7 229bool
20c6c071
GH
230match_key::operator<(match_key const & other) const
231{
232 return ((name < other.name)
57148ee7
FCE
233
234 || (name == other.name
20c6c071 235 && have_parameter < other.have_parameter)
57148ee7
FCE
236
237 || (name == other.name
238 && have_parameter == other.have_parameter
20c6c071
GH
239 && parameter_type < other.parameter_type));
240}
2b066ec1 241
a477f3f1
DS
242static bool
243isglob(string const & str)
244{
245 return(str.find('*') != str.npos);
246}
247
248bool
249match_key::globmatch(match_key const & other) const
250{
251 const char *other_str = other.name.c_str();
252 const char *name_str = name.c_str();
253
254 return ((fnmatch(name_str, other_str, FNM_NOESCAPE) == 0)
57148ee7 255 && have_parameter == other.have_parameter
a477f3f1
DS
256 && parameter_type == other.parameter_type);
257}
258
2b066ec1 259// ------------------------------------------------------------------------
20c6c071
GH
260// Members of match_node
261// ------------------------------------------------------------------------
262
263match_node::match_node()
264 : end(NULL)
265{}
266
267match_node *
57148ee7 268match_node::bind(match_key const & k)
20c6c071 269{
b4ceace2
FCE
270 if (k.name == "*")
271 throw semantic_error("invalid use of wildcard probe point component");
272
20c6c071
GH
273 map<match_key, match_node *>::const_iterator i = sub.find(k);
274 if (i != sub.end())
275 return i->second;
276 match_node * n = new match_node();
277 sub.insert(make_pair(k, n));
278 return n;
279}
280
57148ee7 281void
20c6c071
GH
282match_node::bind(derived_probe_builder * e)
283{
284 if (end)
59bafbe8 285 throw semantic_error("duplicate probe point pattern");
20c6c071
GH
286 end = e;
287}
288
57148ee7 289match_node *
20c6c071
GH
290match_node::bind(string const & k)
291{
292 return bind(match_key(k));
293}
294
295match_node *
296match_node::bind_str(string const & k)
297{
298 return bind(match_key(k).with_string());
299}
300
57148ee7 301match_node *
20c6c071
GH
302match_node::bind_num(string const & k)
303{
304 return bind(match_key(k).with_number());
305}
306
b4ceace2
FCE
307
308void
309match_node::find_and_build (systemtap_session& s,
310 probe* p, probe_point *loc, unsigned pos,
311 vector<derived_probe *>& results)
20c6c071 312{
b4ceace2 313 assert (pos <= loc->components.size());
57148ee7 314 if (pos == loc->components.size()) // matched all probe point components so far
20c6c071 315 {
b4ceace2
FCE
316 derived_probe_builder *b = end; // may be 0 if only nested names are bound
317
318 if (! b)
319 {
320 string alternatives;
321 for (sub_map_iterator_t i = sub.begin(); i != sub.end(); i++)
322 alternatives += string(" ") + i->first.str();
323
57148ee7 324 throw semantic_error (string("probe point truncated at position ") +
b4ceace2 325 lex_cast<string> (pos) +
cfd621bc 326 " (follow:" + alternatives + ")", loc->tok);
b4ceace2
FCE
327 }
328
329 map<string, literal *> param_map;
330 for (unsigned i=0; i<pos; i++)
331 param_map[loc->components[i]->functor] = loc->components[i]->arg;
332 // maybe 0
333
334 b->build (s, p, loc, param_map, results);
20c6c071 335 }
a477f3f1 336 else if (isglob(loc->components[pos]->functor)) // wildcard?
20c6c071 337 {
a477f3f1
DS
338 match_key match (* loc->components[pos]);
339
828c3ed5
DS
340 // Call find_and_build for each possible match. Ignore errors -
341 // unless we don't find any match.
342 unsigned int num_results = results.size();
b4ceace2
FCE
343 for (sub_map_iterator_t i = sub.begin(); i != sub.end(); i++)
344 {
a477f3f1 345 const match_key& subkey = i->first;
828c3ed5 346 match_node* subnode = i->second;
a477f3f1 347
49abf162
FCE
348 if (pending_interrupts) break;
349
a477f3f1 350 if (match.globmatch(subkey))
828c3ed5 351 {
ddfc759e
DS
352 if (s.verbose > 2)
353 clog << "wildcard '" << loc->components[pos]->functor
354 << "' matched '" << subkey.name << "'" << endl;
355
356 // When we have a wildcard, we need to create a copy of
357 // the probe point. Then we'll create a copy of the
358 // wildcard component, and substitute the non-wildcard
359 // functor.
360 probe_point *non_wildcard_pp = new probe_point(*loc);
361 probe_point::component *non_wildcard_component
362 = new probe_point::component(*loc->components[pos]);
363 non_wildcard_component->functor = subkey.name;
364 non_wildcard_pp->components[pos] = non_wildcard_component;
365
5d23847d
FCE
366 // NB: probe conditions are not attached at the wildcard
367 // (component/functor) level, but at the overall
368 // probe_point level.
369
ddfc759e 370 // recurse (with the non-wildcard probe point)
a477f3f1
DS
371 try
372 {
ddfc759e
DS
373 subnode->find_and_build (s, p, non_wildcard_pp, pos+1,
374 results);
a477f3f1
DS
375 }
376 catch (const semantic_error& e)
377 {
378 // Ignore semantic_errors while expanding wildcards.
379 // If we get done and nothing was expanded, the code
380 // following the loop will complain.
ddfc759e
DS
381
382 // If this wildcard didn't match, cleanup.
383 delete non_wildcard_pp;
384 delete non_wildcard_component;
a477f3f1 385 }
828c3ed5 386 }
a477f3f1 387 }
cedd10f4 388 if (! loc->optional && num_results == results.size())
828c3ed5
DS
389 {
390 // We didn't find any wildcard matches (since the size of
391 // the result vector didn't change). Throw an error.
392 string alternatives;
393 for (sub_map_iterator_t i = sub.begin(); i != sub.end(); i++)
394 alternatives += string(" ") + i->first.str();
57148ee7 395
828c3ed5
DS
396 throw semantic_error(string("probe point mismatch at position ") +
397 lex_cast<string> (pos) +
a8cf6a45
MW
398 " (alternatives:" + alternatives + ")" +
399 " didn't find any wildcard matches",
cfd621bc 400 loc->tok);
828c3ed5 401 }
b4ceace2 402 }
57148ee7 403 else
20c6c071 404 {
b4ceace2
FCE
405 match_key match (* loc->components[pos]);
406 sub_map_iterator_t i = sub.find (match);
407 if (i == sub.end()) // no match
408 {
409 string alternatives;
410 for (sub_map_iterator_t i = sub.begin(); i != sub.end(); i++)
411 alternatives += string(" ") + i->first.str();
57148ee7
FCE
412
413 throw semantic_error (string("probe point mismatch at position ") +
b4ceace2 414 lex_cast<string> (pos) +
cfd621bc
FCE
415 " (alternatives:" + alternatives + ")",
416 loc->tok);
b4ceace2
FCE
417 }
418
419 match_node* subnode = i->second;
420 // recurse
421 subnode->find_and_build (s, p, loc, pos+1, results);
20c6c071
GH
422 }
423}
424
b4ceace2 425
aa30ccd3
FCE
426void
427match_node::build_no_more (systemtap_session& s)
428{
429 for (sub_map_iterator_t i = sub.begin(); i != sub.end(); i++)
430 i->second->build_no_more (s);
431 if (end) end->build_no_more (s);
432}
433
434
20c6c071
GH
435// ------------------------------------------------------------------------
436// Alias probes
437// ------------------------------------------------------------------------
438
c1d5f3f6
FCE
439struct alias_derived_probe: public derived_probe
440{
2c5a19c6
DB
441 alias_derived_probe (probe* base, probe_point *l, const probe_alias *a):
442 derived_probe (base, l), alias(a) {}
c1d5f3f6 443
b20febf3
FCE
444 void upchuck () { throw semantic_error ("inappropriate", this->tok); }
445
446 // Alias probes are immediately expanded to other derived_probe
447 // types, and are not themselves emitted or listed in
448 // systemtap_session.probes
dc38c0ae 449
78f6bba6 450 void join_group (systemtap_session&) { upchuck (); }
2c5a19c6
DB
451
452 virtual const probe_alias *get_alias () const { return alias; }
453
454private:
455 const probe_alias *alias; // Used to check for recursion
c1d5f3f6
FCE
456};
457
458
20c6c071 459struct
57148ee7 460alias_expansion_builder
20c6c071
GH
461 : public derived_probe_builder
462{
463 probe_alias * alias;
464
57148ee7 465 alias_expansion_builder(probe_alias * a)
20c6c071
GH
466 : alias(a)
467 {}
468
5227f1ea 469 virtual void build(systemtap_session & sess,
57148ee7 470 probe * use,
20c6c071 471 probe_point * location,
78f6bba6 472 std::map<std::string, literal *> const &,
20c6c071
GH
473 vector<derived_probe *> & finished_results)
474 {
2c5a19c6
DB
475 // Don't build the alias expansion if infinite recursion is detected.
476 if (checkForRecursiveExpansion (use)) {
477 stringstream msg;
478 msg << "Recursive loop in alias expansion of " << *location << " at " << location->tok->location;
479 // semantic_errors thrown here are ignored.
480 sess.print_error (semantic_error (msg.str()));
481 return;
482 }
483
20c6c071 484 // We're going to build a new probe and wrap it up in an
c8959a29 485 // alias_expansion_probe so that the expansion loop recognizes it as
20c6c071 486 // such and re-expands its expansion.
57148ee7 487
2c5a19c6 488 alias_derived_probe * n = new alias_derived_probe (use, location /* soon overwritten */, this->alias);
20c6c071
GH
489 n->body = new block();
490
5d23847d 491 // The new probe gets the location list of the alias (with incoming condition joined)
20c6c071 492 n->locations = alias->locations;
5d23847d
FCE
493 for (unsigned i=0; i<n->locations.size(); i++)
494 n->locations[i]->condition = add_condition (n->locations[i]->condition,
495 location->condition);
496
c3a3c0c9
WC
497 // the token location of the alias,
498 n->tok = location->tok;
20c6c071 499
5227f1ea 500 // and statements representing the concatenation of the alias'
57148ee7 501 // body with the use's.
5227f1ea
GH
502 //
503 // NB: locals are *not* copied forward, from either alias or
504 // use. The expansion should have its locals re-inferred since
505 // there's concatenated code here and we only want one vardecl per
506 // resulting variable.
507
cedd10f4 508 if (alias->epilogue_style)
ba6f838d 509 n->body = new block (use->body, alias->body);
cedd10f4 510 else
ba6f838d 511 n->body = new block (alias->body, use->body);
57148ee7 512
cedd10f4 513 derive_probes (sess, n, finished_results, location->optional);
20c6c071 514 }
2c5a19c6
DB
515
516 bool checkForRecursiveExpansion (probe *use)
517 {
518 // Collect the derivation chain of this probe.
519 vector<probe*>derivations;
520 use->collect_derivation_chain (derivations);
521
522 // Check all probe points in the alias expansion against the currently-being-expanded probe point
523 // of each of the probes in the derivation chain, looking for a match. This
524 // indicates infinite recursion.
525 // The first element of the derivation chain will be the derived_probe representing 'use', so
526 // start the search with the second element.
527 assert (derivations.size() > 0);
528 assert (derivations[0] == use);
529 for (unsigned d = 1; d < derivations.size(); ++d) {
530 if (use->get_alias() == derivations[d]->get_alias())
531 return true; // recursion detected
532 }
533 return false;
534 }
20c6c071
GH
535};
536
537
538// ------------------------------------------------------------------------
539// Pattern matching
540// ------------------------------------------------------------------------
541
542
543// Register all the aliases we've seen in library files, and the user
544// file, as patterns.
545
546void
547systemtap_session::register_library_aliases()
548{
549 vector<stapfile*> files(library_files);
550 files.push_back(user_file);
551
552 for (unsigned f = 0; f < files.size(); ++f)
553 {
554 stapfile * file = files[f];
555 for (unsigned a = 0; a < file->aliases.size(); ++a)
556 {
557 probe_alias * alias = file->aliases[a];
57148ee7 558 try
59bafbe8
FCE
559 {
560 for (unsigned n = 0; n < alias->alias_names.size(); ++n)
561 {
562 probe_point * name = alias->alias_names[n];
563 match_node * n = pattern_root;
564 for (unsigned c = 0; c < name->components.size(); ++c)
565 {
566 probe_point::component * comp = name->components[c];
567 // XXX: alias parameters
568 if (comp->arg)
57148ee7
FCE
569 throw semantic_error("alias component "
570 + comp->functor
59bafbe8
FCE
571 + " contains illegal parameter");
572 n = n->bind(comp->functor);
573 }
574 n->bind(new alias_expansion_builder(alias));
575 }
576 }
577 catch (const semantic_error& e)
578 {
7e41d3dc
FCE
579 semantic_error* er = new semantic_error (e); // copy it
580 stringstream msg;
581 msg << e.msg2;
582 msg << " while registering probe alias ";
583 alias->printsig(msg);
584 er->msg2 = msg.str();
585 print_error (* er);
586 delete er;
59bafbe8 587 }
20c6c071
GH
588 }
589 }
590}
591
592
5227f1ea
GH
593static unsigned max_recursion = 100;
594
57148ee7 595struct
5227f1ea
GH
596recursion_guard
597{
598 unsigned & i;
599 recursion_guard(unsigned & i) : i(i)
600 {
601 if (i > max_recursion)
602 throw semantic_error("recursion limit reached");
603 ++i;
604 }
57148ee7 605 ~recursion_guard()
5227f1ea
GH
606 {
607 --i;
608 }
609};
610
20c6c071
GH
611// The match-and-expand loop.
612void
b4ceace2
FCE
613derive_probes (systemtap_session& s,
614 probe *p, vector<derived_probe*>& dps,
cedd10f4 615 bool optional)
20c6c071
GH
616{
617 for (unsigned i = 0; i < p->locations.size(); ++i)
618 {
49abf162
FCE
619 if (pending_interrupts) break;
620
20c6c071 621 probe_point *loc = p->locations[i];
a971b891 622
fe3d01fa
FCE
623 try
624 {
fe3d01fa 625 unsigned num_atbegin = dps.size();
d898100a
FCE
626
627 // Pass down optional flag from e.g. alias reference to each
628 // probe_point instance. We do this by temporarily overriding
629 // the probe_point optional flag. We could instead deep-copy
630 // and set a flag on the copy permanently.
631 bool old_loc_opt = loc->optional;
632 loc->optional = loc->optional || optional;
633 s.pattern_root->find_and_build (s, p, loc, 0, dps); // <-- actual derivation!
634 loc->optional = old_loc_opt;
fe3d01fa 635 unsigned num_atend = dps.size();
d898100a
FCE
636
637 if (! (loc->optional||optional) && // something required, but
cedd10f4 638 num_atbegin == num_atend) // nothing new derived!
d898100a
FCE
639 throw semantic_error ("no match");
640
641 if (loc->sufficient && (num_atend > num_atbegin))
642 {
643 if (s.verbose > 1)
644 {
645 clog << "Probe point ";
646 p->locations[i]->print(clog);
647 clog << " sufficient, skipped";
648 for (unsigned j = i+1; j < p->locations.size(); ++j)
649 {
650 clog << " ";
651 p->locations[j]->print(clog);
652 }
653 clog << endl;
654 }
655 break; // we need not try to derive for any other locations
656 }
fe3d01fa
FCE
657 }
658 catch (const semantic_error& e)
659 {
b4ceace2 660 // XXX: prefer not to print_error at every nest/unroll level
7e41d3dc
FCE
661
662 semantic_error* er = new semantic_error (e); // copy it
663 stringstream msg;
664 msg << e.msg2;
665 msg << " while resolving probe point " << *loc;
666 er->msg2 = msg.str();
667 s.print_error (* er);
668 delete er;
fe3d01fa 669 }
a971b891 670
20c6c071
GH
671 }
672}
673
b4ceace2
FCE
674
675
20c6c071 676// ------------------------------------------------------------------------
67c0a579 677//
d02548c0 678// Indexable usage checks
67c0a579
GH
679//
680
d02548c0 681struct symbol_fetcher
07c17d67 682 : public throwing_visitor
67c0a579 683{
d02548c0 684 symbol *&sym;
67c0a579 685
57148ee7 686 symbol_fetcher (symbol *&sym): sym(sym)
67c0a579
GH
687 {}
688
d02548c0
GH
689 void visit_symbol (symbol* e)
690 {
691 sym = e;
692 }
693
b0be9bdb
FCE
694 void visit_target_symbol (target_symbol* e)
695 {
696 sym = e;
697 }
698
d02548c0
GH
699 void visit_arrayindex (arrayindex* e)
700 {
701 e->base->visit_indexable (this);
702 }
703
704 void throwone (const token* t)
705 {
706 throw semantic_error ("Expecting symbol or array index expression", t);
707 }
708};
709
07c17d67 710symbol *
d02548c0
GH
711get_symbol_within_expression (expression *e)
712{
713 symbol *sym = NULL;
714 symbol_fetcher fetcher(sym);
715 e->visit (&fetcher);
b0be9bdb 716 return sym; // NB: may be null!
d02548c0
GH
717}
718
719static symbol *
720get_symbol_within_indexable (indexable *ix)
721{
722 symbol *array = NULL;
723 hist_op *hist = NULL;
724 classify_indexable(ix, array, hist);
725 if (array)
726 return array;
727 else
728 return get_symbol_within_expression (hist->stat);
729}
730
731struct mutated_var_collector
07c17d67 732 : public traversing_visitor
d02548c0
GH
733{
734 set<vardecl *> * mutated_vars;
735
57148ee7 736 mutated_var_collector (set<vardecl *> * mm)
d02548c0
GH
737 : mutated_vars (mm)
738 {}
739
740 void visit_assignment(assignment* e)
741 {
742 if (e->type == pe_stats && e->op == "<<<")
743 {
744 vardecl *vd = get_symbol_within_expression (e->left)->referent;
745 if (vd)
746 mutated_vars->insert (vd);
747 }
1bbeef03 748 traversing_visitor::visit_assignment(e);
d02548c0
GH
749 }
750
67c0a579
GH
751 void visit_arrayindex (arrayindex *e)
752 {
d02548c0
GH
753 if (is_active_lvalue (e))
754 {
755 symbol *sym;
756 if (e->base->is_symbol (sym))
757 mutated_vars->insert (sym->referent);
758 else
759 throw semantic_error("Assignment to read-only histogram bucket", e->tok);
760 }
1bbeef03 761 traversing_visitor::visit_arrayindex (e);
67c0a579
GH
762 }
763};
764
765
d02548c0 766struct no_var_mutation_during_iteration_check
07c17d67 767 : public traversing_visitor
67c0a579
GH
768{
769 systemtap_session & session;
d02548c0
GH
770 map<functiondecl *,set<vardecl *> *> & function_mutates_vars;
771 vector<vardecl *> vars_being_iterated;
57148ee7
FCE
772
773 no_var_mutation_during_iteration_check
67c0a579 774 (systemtap_session & sess,
d02548c0
GH
775 map<functiondecl *,set<vardecl *> *> & fmv)
776 : session(sess), function_mutates_vars (fmv)
67c0a579
GH
777 {}
778
779 void visit_arrayindex (arrayindex *e)
780 {
d7f3e0c5 781 if (is_active_lvalue(e))
67c0a579 782 {
d02548c0
GH
783 vardecl *vd = get_symbol_within_indexable (e->base)->referent;
784 if (vd)
67c0a579 785 {
d02548c0 786 for (unsigned i = 0; i < vars_being_iterated.size(); ++i)
67c0a579 787 {
d02548c0
GH
788 vardecl *v = vars_being_iterated[i];
789 if (v == vd)
790 {
791 string err = ("variable '" + v->name +
792 "' modified during 'foreach' iteration");
793 session.print_error (semantic_error (err, e->tok));
794 }
67c0a579
GH
795 }
796 }
797 }
1bbeef03 798 traversing_visitor::visit_arrayindex (e);
67c0a579
GH
799 }
800
801 void visit_functioncall (functioncall* e)
802 {
57148ee7 803 map<functiondecl *,set<vardecl *> *>::const_iterator i
d02548c0 804 = function_mutates_vars.find (e->referent);
67c0a579 805
d02548c0 806 if (i != function_mutates_vars.end())
67c0a579 807 {
d02548c0 808 for (unsigned j = 0; j < vars_being_iterated.size(); ++j)
67c0a579 809 {
d02548c0 810 vardecl *m = vars_being_iterated[j];
67c0a579
GH
811 if (i->second->find (m) != i->second->end())
812 {
d02548c0 813 string err = ("function call modifies var '" + m->name +
67c0a579
GH
814 "' during 'foreach' iteration");
815 session.print_error (semantic_error (err, e->tok));
816 }
817 }
818 }
819
1bbeef03 820 traversing_visitor::visit_functioncall (e);
67c0a579
GH
821 }
822
823 void visit_foreach_loop(foreach_loop* s)
824 {
d02548c0
GH
825 vardecl *vd = get_symbol_within_indexable (s->base)->referent;
826
827 if (vd)
828 vars_being_iterated.push_back (vd);
57148ee7 829
1bbeef03 830 traversing_visitor::visit_foreach_loop (s);
d02548c0
GH
831
832 if (vd)
833 vars_being_iterated.pop_back();
67c0a579
GH
834 }
835};
20c6c071 836
2b066ec1 837
67c0a579
GH
838// ------------------------------------------------------------------------
839
07c17d67
GH
840struct stat_decl_collector
841 : public traversing_visitor
842{
843 systemtap_session & session;
57148ee7 844
07c17d67
GH
845 stat_decl_collector(systemtap_session & sess)
846 : session(sess)
847 {}
848
849 void visit_stat_op (stat_op* e)
850 {
851 symbol *sym = get_symbol_within_expression (e->stat);
852 if (session.stat_decls.find(sym->name) == session.stat_decls.end())
853 session.stat_decls[sym->name] = statistic_decl();
854 }
855
856 void visit_assignment (assignment* e)
857 {
858 if (e->op == "<<<")
859 {
860 symbol *sym = get_symbol_within_expression (e->left);
861 if (session.stat_decls.find(sym->name) == session.stat_decls.end())
862 session.stat_decls[sym->name] = statistic_decl();
863 }
864 else
865 traversing_visitor::visit_assignment(e);
866 }
867
868 void visit_hist_op (hist_op* e)
869 {
870 symbol *sym = get_symbol_within_expression (e->stat);
871 statistic_decl new_stat;
872
873 if (e->htype == hist_linear)
874 {
875 new_stat.type = statistic_decl::linear;
876 assert (e->params.size() == 3);
877 new_stat.linear_low = e->params[0];
878 new_stat.linear_high = e->params[1];
879 new_stat.linear_step = e->params[2];
880 }
881 else
882 {
883 assert (e->htype == hist_log);
884 new_stat.type = statistic_decl::logarithmic;
e38723d2 885 assert (e->params.size() == 0);
07c17d67
GH
886 }
887
888 map<string, statistic_decl>::iterator i = session.stat_decls.find(sym->name);
889 if (i == session.stat_decls.end())
890 session.stat_decls[sym->name] = new_stat;
891 else
892 {
893 statistic_decl & old_stat = i->second;
894 if (!(old_stat == new_stat))
895 {
896 if (old_stat.type == statistic_decl::none)
897 i->second = new_stat;
898 else
899 {
900 // FIXME: Support multiple co-declared histogram types
57148ee7 901 semantic_error se("multiple histogram types declared on '" + sym->name + "'",
07c17d67
GH
902 e->tok);
903 session.print_error (se);
904 }
905 }
57148ee7 906 }
07c17d67
GH
907 }
908
909};
910
911static int
912semantic_pass_stats (systemtap_session & sess)
913{
914 stat_decl_collector sdc(sess);
915
f76427a2
FCE
916 for (map<string,functiondecl*>::iterator it = sess.functions.begin(); it != sess.functions.end(); it++)
917 it->second->body->visit (&sdc);
07c17d67 918
57148ee7 919 for (unsigned i = 0; i < sess.probes.size(); ++i)
07c17d67
GH
920 sess.probes[i]->body->visit (&sdc);
921
922 for (unsigned i = 0; i < sess.globals.size(); ++i)
923 {
924 vardecl *v = sess.globals[i];
925 if (v->type == pe_stats)
926 {
57148ee7 927
07c17d67
GH
928 if (sess.stat_decls.find(v->name) == sess.stat_decls.end())
929 {
930 semantic_error se("unable to infer statistic parameters for global '" + v->name + "'");
931 sess.print_error (se);
932 }
933 }
934 }
57148ee7 935
7e41d3dc 936 return sess.num_errors();
07c17d67
GH
937}
938
5d23847d
FCE
939// ------------------------------------------------------------------------
940
941// Enforce variable-related invariants: no modification of
942// a foreach()-iterated array.
943static int
944semantic_pass_vars (systemtap_session & sess)
945{
57148ee7 946
5d23847d
FCE
947 map<functiondecl *, set<vardecl *> *> fmv;
948 no_var_mutation_during_iteration_check chk(sess, fmv);
57148ee7 949
f76427a2 950 for (map<string,functiondecl*>::iterator it = sess.functions.begin(); it != sess.functions.end(); it++)
5d23847d 951 {
f76427a2 952 functiondecl * fn = it->second;
5d23847d
FCE
953 if (fn->body)
954 {
955 set<vardecl *> * m = new set<vardecl *>();
956 mutated_var_collector mc (m);
957 fn->body->visit (&mc);
958 fmv[fn] = m;
959 }
960 }
961
f76427a2 962 for (map<string,functiondecl*>::iterator it = sess.functions.begin(); it != sess.functions.end(); it++)
5d23847d 963 {
f76427a2
FCE
964 functiondecl * fn = it->second;
965 if (fn->body) fn->body->visit (&chk);
5d23847d
FCE
966 }
967
968 for (unsigned i = 0; i < sess.probes.size(); ++i)
969 {
970 if (sess.probes[i]->body)
971 sess.probes[i]->body->visit (&chk);
57148ee7 972 }
5d23847d
FCE
973
974 return sess.num_errors();
975}
976
977
978// ------------------------------------------------------------------------
979
980// Rewrite probe condition expressions into probe bodies. Tricky and
981// exciting business, this. This:
982//
983// probe foo if (g1 || g2) { ... }
984// probe bar { ... g1 ++ ... }
985//
986// becomes:
987//
988// probe begin(MAX) { if (! (g1 || g2)) %{ disable_probe_foo %} }
989// probe foo { if (! (g1 || g2)) next; ... }
57148ee7 990// probe bar { ... g1 ++ ...;
5d23847d
FCE
991// if (g1 || g2) %{ enable_probe_foo %} else %{ disable_probe_foo %}
992// }
993//
994// XXX: As a first cut, do only the "inline probe condition" part of the
995// transform.
996
997static int
998semantic_pass_conditions (systemtap_session & sess)
999{
1000 for (unsigned i = 0; i < sess.probes.size(); ++i)
1001 {
1002 derived_probe* p = sess.probes[i];
1003 expression* e = p->sole_location()->condition;
1004 if (e)
1005 {
1006 varuse_collecting_visitor vut;
1007 e->visit (& vut);
1008
1009 if (! vut.written.empty())
1010 {
1011 string err = ("probe condition must not modify any variables");
1012 sess.print_error (semantic_error (err, e->tok));
1013 }
1014 else if (vut.embedded_seen)
1015 {
1016 sess.print_error (semantic_error ("probe condition must not include impure embedded-C", e->tok));
1017 }
1018
1019 // Add the condition expression to the front of the
1020 // derived_probe body.
1021 if_statement *ifs = new if_statement ();
1022 ifs->tok = e->tok;
1023 ifs->thenblock = new next_statement ();
1024 ifs->thenblock->tok = e->tok;
1025 ifs->elseblock = NULL;
1026 unary_expression *notex = new unary_expression ();
1027 notex->op = "!";
1028 notex->tok = e->tok;
1029 notex->operand = e;
1030 ifs->condition = notex;
ba6f838d 1031 p->body = new block (ifs, p->body);
5d23847d 1032 }
57148ee7 1033 }
5d23847d
FCE
1034
1035 return sess.num_errors();
1036}
1037
1038
07c17d67
GH
1039// ------------------------------------------------------------------------
1040
2b066ec1
FCE
1041
1042static int semantic_pass_symbols (systemtap_session&);
c214bd6a
DS
1043static int semantic_pass_optimize1 (systemtap_session&);
1044static int semantic_pass_optimize2 (systemtap_session&);
2b066ec1 1045static int semantic_pass_types (systemtap_session&);
d02548c0 1046static int semantic_pass_vars (systemtap_session&);
07c17d67 1047static int semantic_pass_stats (systemtap_session&);
5d23847d 1048static int semantic_pass_conditions (systemtap_session&);
2b066ec1
FCE
1049
1050
1051// Link up symbols to their declarations. Set the session's
1052// files/probes/functions/globals vectors from the transitively
1053// reached set of stapfiles in s.library_files, starting from
20c6c071 1054// s.user_file. Perform automatic tapset inclusion and probe
2b066ec1
FCE
1055// alias expansion.
1056static int
1057semantic_pass_symbols (systemtap_session& s)
1058{
1059 symresolution_info sym (s);
1060
1061 // NB: s.files can grow during this iteration, so size() can
1062 // return gradually increasing numbers.
1063 s.files.push_back (s.user_file);
1064 for (unsigned i = 0; i < s.files.size(); i++)
1065 {
49abf162 1066 if (pending_interrupts) break;
2b066ec1
FCE
1067 stapfile* dome = s.files[i];
1068
1069 // Pass 1: add globals and functions to systemtap-session master list,
1070 // so the find_* functions find them
1071
1072 for (unsigned i=0; i<dome->globals.size(); i++)
1073 s.globals.push_back (dome->globals[i]);
1074
1075 for (unsigned i=0; i<dome->functions.size(); i++)
f76427a2 1076 s.functions[dome->functions[i]->name] = dome->functions[i];
2b066ec1 1077
54dfabe9
FCE
1078 for (unsigned i=0; i<dome->embeds.size(); i++)
1079 s.embeds.push_back (dome->embeds[i]);
1080
2b066ec1
FCE
1081 // Pass 2: process functions
1082
1083 for (unsigned i=0; i<dome->functions.size(); i++)
1084 {
49abf162 1085 if (pending_interrupts) break;
2b066ec1
FCE
1086 functiondecl* fd = dome->functions[i];
1087
57148ee7 1088 try
2b066ec1 1089 {
8a43522c
GH
1090 sym.current_function = fd;
1091 sym.current_probe = 0;
1092 fd->body->visit (& sym);
2b066ec1
FCE
1093 }
1094 catch (const semantic_error& e)
1095 {
1096 s.print_error (e);
1097 }
1098 }
1099
5227f1ea 1100 // Pass 3: derive probes and resolve any further symbols in the
57148ee7 1101 // derived results.
2b066ec1
FCE
1102
1103 for (unsigned i=0; i<dome->probes.size(); i++)
1104 {
49abf162 1105 if (pending_interrupts) break;
2b066ec1
FCE
1106 probe* p = dome->probes [i];
1107 vector<derived_probe*> dps;
1108
a971b891
FCE
1109 // much magic happens here: probe alias expansion, wildcard
1110 // matching, low-level derived_probe construction.
b4ceace2 1111 derive_probes (s, p, dps);
2b066ec1
FCE
1112
1113 for (unsigned j=0; j<dps.size(); j++)
1114 {
49abf162 1115 if (pending_interrupts) break;
2b066ec1 1116 derived_probe* dp = dps[j];
b20febf3
FCE
1117 s.probes.push_back (dp);
1118 dp->join_group (s);
2b066ec1 1119
57148ee7 1120 try
2b066ec1
FCE
1121 {
1122 sym.current_function = 0;
5227f1ea 1123 sym.current_probe = dp;
2b066ec1 1124 dp->body->visit (& sym);
5d23847d
FCE
1125
1126 // Process the probe-point condition expression.
1127 sym.current_function = 0;
1128 sym.current_probe = 0;
1129 if (dp->sole_location()->condition)
1130 dp->sole_location()->condition->visit (& sym);
2b066ec1
FCE
1131 }
1132 catch (const semantic_error& e)
1133 {
1134 s.print_error (e);
1135 }
1136 }
1137 }
1138 }
aa30ccd3
FCE
1139
1140 // Inform all derived_probe builders that we're done with
1141 // all resolution, so it's time to release caches.
1142 s.pattern_root->build_no_more (s);
57148ee7 1143
7e41d3dc 1144 return s.num_errors(); // all those print_error calls
2b066ec1
FCE
1145}
1146
1147
0a102c82
SC
1148// Keep unread global variables for probe end value display.
1149void add_global_var_display (systemtap_session& s)
1150{
5ae31731
FCE
1151 // Don't generate synthetic end probes when in listings mode;
1152 // it would clutter up the list of probe points with "end ...".
1153 if (s.listing_mode) return;
3438f38f 1154
0a102c82
SC
1155 varuse_collecting_visitor vut;
1156 for (unsigned i=0; i<s.probes.size(); i++)
1157 {
1158 s.probes[i]->body->visit (& vut);
1159
1160 if (s.probes[i]->sole_location()->condition)
1161 s.probes[i]->sole_location()->condition->visit (& vut);
1162 }
1163
1164 for (unsigned g=0; g < s.globals.size(); g++)
1165 {
1166 vardecl* l = s.globals[g];
1167 if (vut.read.find (l) != vut.read.end()
e491a713 1168 || vut.written.find (l) == vut.written.end())
0a102c82
SC
1169 continue;
1170
b5852334 1171 // Don't generate synthetic end probes for unread globals
5ae31731
FCE
1172 // declared only within tapsets. (RHBZ 468139), but rather
1173 // only within the end-user script.
1174
7584f162
RA
1175 bool tapset_global = false;
1176 for (size_t m=0; m < s.library_files.size(); m++)
1177 {
1178 for (size_t n=0; n < s.library_files[m]->globals.size(); n++)
1179 {
1180 if (l->name == s.library_files[m]->globals[n]->name)
1181 {tapset_global = true; break;}
1182 }
1183 }
1184 if (tapset_global)
1185 continue;
5ae31731 1186
0a102c82
SC
1187 print_format* pf = new print_format;
1188 probe* p = new probe;
1189 probe_point* pl = new probe_point;
1190 probe_point::component* c = new probe_point::component("end");
1191 token* print_tok = new token;
1192 vector<derived_probe*> dps;
6d2685fe 1193 block *b = new block;
0a102c82
SC
1194
1195 pl->components.push_back (c);
db48cbe9 1196 p->tok = l->tok;
0a102c82
SC
1197 p->locations.push_back (pl);
1198 print_tok->type = tok_identifier;
1199 print_tok->content = "printf";
1200
1201 // Create a symbol
1202 symbol* g_sym = new symbol;
1203 g_sym->name = l->name;
1204 g_sym->tok = l->tok;
1205 g_sym->type = l->type;
57148ee7 1206 g_sym->referent = l;
0a102c82
SC
1207
1208 pf->print_to_stream = true;
1209 pf->print_with_format = true;
1210 pf->print_with_delim = false;
1211 pf->print_with_newline = false;
1212 pf->print_char = false;
1213 pf->raw_components += l->name;
1214 pf->tok = print_tok;
1215
1216 if (l->index_types.size() == 0) // Scalar
1217 {
e071e49b
SC
1218 if (l->type == pe_stats)
1219 pf->raw_components += " @count=%#x @min=%#x @max=%#x @sum=%#x @avg=%#x\\n";
1220 else if (l->type == pe_string)
0a102c82
SC
1221 pf->raw_components += "=\"%#s\"\\n";
1222 else
1223 pf->raw_components += "=%#x\\n";
0a102c82
SC
1224 pf->components = print_format::string_to_components(pf->raw_components);
1225 expr_statement* feb = new expr_statement;
1226 feb->value = pf;
1227 feb->tok = print_tok;
e071e49b
SC
1228 if (l->type == pe_stats)
1229 {
1230 struct stat_op* so [5];
1231 const stat_component_type stypes[] = {sc_count, sc_min, sc_max, sc_sum, sc_average};
1232
1233 for (unsigned si = 0;
1234 si < (sizeof(so)/sizeof(struct stat_op*));
1235 si++)
1236 {
1237 so[si]= new stat_op;
1238 so[si]->ctype = stypes[si];
1239 so[si]->type = pe_long;
1240 so[si]->stat = g_sym;
1241 so[si]->tok = l->tok;
1242 pf->args.push_back(so[si]);
1243 }
1244 }
1245 else
1246 pf->args.push_back(g_sym);
271d408e
WH
1247
1248 /* PR7053: Checking empty aggregate for global variable */
1249 if (l->type == pe_stats) {
1250 stat_op *so= new stat_op;
1251 so->ctype = sc_count;
1252 so->type = pe_long;
1253 so->stat = g_sym;
1254 so->tok = l->tok;
1255 comparison *be = new comparison;
1256 be->op = ">";
1257 be->tok = l->tok;
1258 be->left = so;
1259 be->right = new literal_number(0);
1260
1261 /* Create printf @count=0x0 in else block */
1262 print_format* pf_0 = new print_format;
1263 pf_0->print_to_stream = true;
1264 pf_0->print_with_format = true;
1265 pf_0->print_with_delim = false;
1266 pf_0->print_with_newline = false;
1267 pf_0->print_char = false;
1268 pf_0->raw_components += l->name;
1269 pf_0->raw_components += " @count=0x0\\n";
1270 pf_0->tok = print_tok;
1271 pf_0->components = print_format::string_to_components(pf_0->raw_components);
1272 expr_statement* feb_else = new expr_statement;
1273 feb_else->value = pf_0;
1274 feb_else->tok = print_tok;
1275 if_statement *ifs = new if_statement;
1276 ifs->tok = l->tok;
1277 ifs->condition = be;
1278 ifs->thenblock = feb ;
1279 ifs->elseblock = feb_else;
1280 b->statements.push_back(ifs);
1281 }
1282 else /* other non-stat cases */
1283 b->statements.push_back(feb);
0a102c82
SC
1284 }
1285 else // Array
1286 {
1287 int idx_count = l->index_types.size();
0a102c82
SC
1288 symbol* idx_sym[idx_count];
1289 vardecl* idx_v[idx_count];
1290 // Create a foreach loop
0a102c82 1291 foreach_loop* fe = new foreach_loop;
e91b23bc
FCE
1292 fe->sort_direction = -1; // imply decreasing sort on value
1293 fe->sort_column = 0; // as in foreach ([a,b,c] in array-) { }
0a102c82
SC
1294 fe->limit = NULL;
1295
1296 // Create indices for the foreach loop
1297 for (int i=0; i < idx_count; i++)
1298 {
0a102c82
SC
1299 char *idx_name;
1300 if (asprintf (&idx_name, "idx%d", i) < 0)
1301 return;
0a102c82 1302 idx_sym[i] = new symbol;
0a102c82 1303 idx_sym[i]->name = idx_name;
db48cbe9 1304 idx_sym[i]->tok = l->tok;
0a102c82
SC
1305 idx_v[i] = new vardecl;
1306 idx_v[i]->name = idx_name;
0a102c82 1307 idx_v[i]->type = l->index_types[i];
db48cbe9 1308 idx_v[i]->tok = l->tok;
0a102c82
SC
1309 idx_sym[i]->referent = idx_v[i];
1310 fe->indexes.push_back (idx_sym[i]);
1311 }
1312
1313 // Create a printf for the foreach loop
57148ee7 1314 pf->raw_components += "[";
0a102c82 1315 for (int i=0; i < idx_count; i++)
57148ee7
FCE
1316 {
1317 if (i > 0)
1318 pf->raw_components += ",";
1319 if (l->index_types[i] == pe_string)
1320 pf->raw_components += "\"%#s\"";
1321 else
1322 pf->raw_components += "%#d";
1323 }
1324 pf->raw_components += "]";
e491a713
SC
1325 if (l->type == pe_stats)
1326 pf->raw_components += " @count=%#x @min=%#x @max=%#x @sum=%#x @avg=%#x\\n";
1327 else if (l->type == pe_string)
0a102c82
SC
1328 pf->raw_components += "=\"%#s\"\\n";
1329 else
1330 pf->raw_components += "=%#x\\n";
1331
1332 // Create an index for the array
1333 struct arrayindex* ai = new arrayindex;
1334 ai->tok = l->tok;
1335 ai->base = g_sym;
e491a713 1336
0a102c82
SC
1337 for (int i=0; i < idx_count; i++)
1338 {
1339 ai->indexes.push_back (idx_sym[i]);
1340 pf->args.push_back(idx_sym[i]);
1341 }
e491a713
SC
1342 if (l->type == pe_stats)
1343 {
1344 struct stat_op* so [5];
e491a713 1345 const stat_component_type stypes[] = {sc_count, sc_min, sc_max, sc_sum, sc_average};
e071e49b
SC
1346
1347 ai->type = pe_stats;
db48cbe9
SC
1348 for (unsigned si = 0;
1349 si < (sizeof(so)/sizeof(struct stat_op*));
1350 si++)
e491a713
SC
1351 {
1352 so[si]= new stat_op;
1353 so[si]->ctype = stypes[si];
1354 so[si]->type = pe_long;
1355 so[si]->stat = ai;
db48cbe9 1356 so[si]->tok = l->tok;
e071e49b 1357 pf->args.push_back(so[si]);
e491a713 1358 }
e491a713
SC
1359 }
1360 else
1361 pf->args.push_back(ai);
57148ee7 1362
0a102c82
SC
1363 pf->components = print_format::string_to_components(pf->raw_components);
1364 expr_statement* feb = new expr_statement;
1365 feb->value = pf;
0a102c82
SC
1366 fe->base = g_sym;
1367 fe->block = (statement*)feb;
1368 b->statements.push_back(fe);
0a102c82
SC
1369 }
1370
0a102c82 1371 // Add created probe
6d2685fe
SC
1372 p->body = b;
1373 derive_probes (s, p, dps);
0a102c82
SC
1374 for (unsigned i = 0; i < dps.size(); i++)
1375 {
1376 derived_probe* dp = dps[i];
1377 s.probes.push_back (dp);
1378 dp->join_group (s);
1379 }
6d2685fe
SC
1380 // Repopulate symbol and type info
1381 symresolution_info sym (s);
1382 sym.current_function = 0;
1383 sym.current_probe = dps[0];
1384 dps[0]->body->visit (& sym);
0a102c82 1385
6d2685fe
SC
1386 semantic_pass_types(s);
1387 // Mark that variable is read
0a102c82
SC
1388 vut.read.insert (l);
1389 }
1390}
2b066ec1
FCE
1391
1392int
1393semantic_pass (systemtap_session& s)
1394{
59bafbe8 1395 int rc = 0;
20c6c071 1396
57148ee7 1397 try
59bafbe8
FCE
1398 {
1399 s.register_library_aliases();
1400 register_standard_tapsets(s);
57148ee7 1401
5d23847d
FCE
1402 if (rc == 0) rc = semantic_pass_symbols (s);
1403 if (rc == 0) rc = semantic_pass_conditions (s);
c214bd6a 1404 if (rc == 0 && ! s.unoptimized) rc = semantic_pass_optimize1 (s);
59bafbe8 1405 if (rc == 0) rc = semantic_pass_types (s);
0a102c82 1406 if (rc == 0) add_global_var_display (s);
c214bd6a 1407 if (rc == 0 && ! s.unoptimized) rc = semantic_pass_optimize2 (s);
d02548c0 1408 if (rc == 0) rc = semantic_pass_vars (s);
07c17d67 1409 if (rc == 0) rc = semantic_pass_stats (s);
57148ee7 1410
277f2b79
FCE
1411 if (s.probes.size() == 0 && !s.listing_mode)
1412 throw semantic_error ("no probes found");
59bafbe8
FCE
1413 }
1414 catch (const semantic_error& e)
1415 {
1416 s.print_error (e);
21beacc9 1417 rc ++;
59bafbe8 1418 }
57148ee7 1419
2b066ec1
FCE
1420 return rc;
1421}
1422
1423
1424// ------------------------------------------------------------------------
1425
1426
1427systemtap_session::systemtap_session ():
b20febf3 1428 // NB: pointer members must be manually initialized!
20c6c071 1429 pattern_root(new match_node),
b20febf3 1430 user_file (0),
57148ee7
FCE
1431 be_derived_probes(0),
1432 dwarf_derived_probes(0),
1433 uprobe_derived_probes(0),
1434 utrace_derived_probes(0),
1435 itrace_derived_probes(0),
1436 task_finder_derived_probes(0),
1437 timer_derived_probes(0),
1438 profile_derived_probes(0),
1439 mark_derived_probes(0),
1440 hrtimer_derived_probes(0),
1441 perfmon_derived_probes(0),
1442 procfs_derived_probes(0),
6561773f
FCE
1443 op (0), up (0),
1444 sym_kprobes_text_start (0),
1445 sym_kprobes_text_end (0),
cfd621bc 1446 sym_stext (0),
405b71b8 1447 module_cache (0),
cfd621bc 1448 last_token (0)
2b066ec1
FCE
1449{
1450}
1451
1452
cfd621bc
FCE
1453// Print this given token, but abbreviate it if the last one had the
1454// same file name.
1455void
1456systemtap_session::print_token (ostream& o, const token* tok)
1457{
1458 assert (tok);
1459
1460 if (last_token && last_token->location.file == tok->location.file)
1461 {
1462 stringstream tmpo;
1463 tmpo << *tok;
1464 string ts = tmpo.str();
1465 // search & replace the file name with nothing
1466 size_t idx = ts.find (tok->location.file);
1467 if (idx != string::npos)
1468 ts.replace (idx, tok->location.file.size(), "");
57148ee7 1469
cfd621bc
FCE
1470 o << ts;
1471 }
1472 else
1473 o << *tok;
1474
1475 last_token = tok;
1476}
1477
1478
1479
2b066ec1
FCE
1480void
1481systemtap_session::print_error (const semantic_error& e)
1482{
b487a14d 1483 string message_str[2];
1b1b4ceb 1484 string align_semantic_error (" ");
7e41d3dc 1485
b487a14d
FCE
1486 // We generate two messages. The second one ([1]) is printed
1487 // without token compression, for purposes of duplicate elimination.
1488 // This way, the same message that may be generated once with a
1489 // compressed and once with an uncompressed token still only gets
1490 // printed once.
1491 for (int i=0; i<2; i++)
1492 {
1493 stringstream message;
fecccf83 1494
b487a14d
FCE
1495 message << "semantic error: " << e.what ();
1496 if (e.tok1 || e.tok2)
1497 message << ": ";
fecccf83 1498 if (e.tok1)
b487a14d
FCE
1499 {
1500 if (i == 0) print_token (message, e.tok1);
1501 else message << *e.tok1;
1502 }
1503 message << e.msg2;
fecccf83 1504 if (e.tok2)
b487a14d
FCE
1505 {
1506 if (i == 0) print_token (message, e.tok2);
1507 else message << *e.tok2;
1508 }
1509 message << endl;
1510 message_str[i] = message.str();
1511 }
7e41d3dc
FCE
1512
1513 // Duplicate elimination
b487a14d 1514 if (seen_errors.find (message_str[1]) == seen_errors.end())
7e41d3dc 1515 {
b487a14d
FCE
1516 seen_errors.insert (message_str[1]);
1517 cerr << message_str[0];
1b1b4ceb
RA
1518
1519 if (e.tok1)
1520 print_error_source (cerr, align_semantic_error, e.tok1);
1521
1522 if (e.tok2)
1523 print_error_source (cerr, align_semantic_error, e.tok2);
7e41d3dc
FCE
1524 }
1525
1526 if (e.chain)
1527 print_error (* e.chain);
2b066ec1
FCE
1528}
1529
1b1b4ceb
RA
1530void
1531systemtap_session::print_error_source (std::ostream& message,
1532 std::string& align, const token* tok)
1533{
1534 unsigned i = 0;
1535 unsigned line = tok->location.line;
1536 unsigned col = tok->location.column;
1537 string file_contents;
84680f7e
FCE
1538
1539 assert (tok);
1b1b4ceb
RA
1540 if (tok->location.stap_file)
1541 file_contents = tok->location.stap_file->file_contents;
1542 else
1543 //No source to print, silently exit
1544 return;
1545 size_t start_pos = 0, end_pos = 0;
1546 //Navigate to the appropriate line
1547 while (i != line && end_pos != std::string::npos)
1548 {
1549 start_pos = end_pos;
1550 end_pos = file_contents.find ('\n', start_pos) + 1;
1551 i++;
1552 }
1553 message << align << "source: " << file_contents.substr (start_pos, end_pos-start_pos-1) << endl;
1554 message << align << " ";
1555 //Navigate to the appropriate column
1556 for (i=start_pos; i<start_pos+col-1; i++)
1557 {
1558 if(isspace(file_contents[i]))
1559 message << file_contents[i];
1560 else
1561 message << ' ';
1562 }
1563 message << "^" << endl;
1564}
1565
ab54fa85 1566void
cfd621bc 1567systemtap_session::print_warning (const string& message_str, const token* tok)
ab54fa85 1568{
ab54fa85 1569 // Duplicate elimination
1b1b4ceb 1570 string align_warning (" ");
f2782fe5 1571 if (seen_warnings.find (message_str) == seen_warnings.end())
ab54fa85 1572 {
ee448707 1573 seen_warnings.insert (message_str);
cfd621bc
FCE
1574 clog << "WARNING: " << message_str;
1575 if (tok) { clog << ": "; print_token (clog, tok); }
1576 clog << endl;
84680f7e 1577 if (tok) { print_error_source (clog, align_warning, tok); }
ab54fa85
SC
1578 }
1579}
1580
2b066ec1
FCE
1581
1582// ------------------------------------------------------------------------
1583// semantic processing: symbol resolution
1584
1585
1586symresolution_info::symresolution_info (systemtap_session& s):
5227f1ea 1587 session (s), current_function (0), current_probe (0)
2b066ec1
FCE
1588{
1589}
1590
1591
1592void
1593symresolution_info::visit_block (block* e)
1594{
1595 for (unsigned i=0; i<e->statements.size(); i++)
1596 {
57148ee7 1597 try
2b066ec1
FCE
1598 {
1599 e->statements[i]->visit (this);
1600 }
1601 catch (const semantic_error& e)
1602 {
1603 session.print_error (e);
1604 }
1605 }
1606}
1607
1608
69c68955
FCE
1609void
1610symresolution_info::visit_foreach_loop (foreach_loop* e)
1611{
1612 for (unsigned i=0; i<e->indexes.size(); i++)
1613 e->indexes[i]->visit (this);
1614
57148ee7 1615 symbol *array = NULL;
d02548c0
GH
1616 hist_op *hist = NULL;
1617 classify_indexable (e->base, array, hist);
69c68955 1618
d02548c0
GH
1619 if (array)
1620 {
1621 if (!array->referent)
57148ee7 1622 {
d02548c0
GH
1623 vardecl* d = find_var (array->name, e->indexes.size ());
1624 if (d)
1625 array->referent = d;
1626 else
2a99f48f 1627 {
7e41d3dc
FCE
1628 stringstream msg;
1629 msg << "unresolved arity-" << e->indexes.size()
1630 << " global array " << array->name;
1631 throw semantic_error (msg.str(), e->tok);
2a99f48f 1632 }
d02548c0
GH
1633 }
1634 }
57148ee7 1635 else
d02548c0
GH
1636 {
1637 assert (hist);
1638 hist->visit (this);
1639 }
69c68955 1640
27f21e8c
DS
1641 if (e->limit)
1642 e->limit->visit (this);
1643
69c68955
FCE
1644 e->block->visit (this);
1645}
1646
d02548c0 1647
57148ee7 1648struct
d98d459c
GH
1649delete_statement_symresolution_info:
1650 public traversing_visitor
1651{
1652 symresolution_info *parent;
1653
1654 delete_statement_symresolution_info (symresolution_info *p):
1655 parent(p)
1656 {}
1657
1658 void visit_arrayindex (arrayindex* e)
1659 {
1660 parent->visit_arrayindex (e);
1661 }
1662 void visit_functioncall (functioncall* e)
1663 {
1664 parent->visit_functioncall (e);
1665 }
1666
1667 void visit_symbol (symbol* e)
1668 {
1669 if (e->referent)
1670 return;
57148ee7 1671
d98d459c
GH
1672 vardecl* d = parent->find_var (e->name, -1);
1673 if (d)
1674 e->referent = d;
1675 else
1676 throw semantic_error ("unresolved array in delete statement", e->tok);
1677 }
1678};
1679
57148ee7 1680void
d98d459c
GH
1681symresolution_info::visit_delete_statement (delete_statement* s)
1682{
1683 delete_statement_symresolution_info di (this);
1684 s->value->visit (&di);
1685}
1686
69c68955 1687
2b066ec1
FCE
1688void
1689symresolution_info::visit_symbol (symbol* e)
1690{
1691 if (e->referent)
1692 return;
1693
313b2f74 1694 vardecl* d = find_var (e->name, 0);
2b066ec1
FCE
1695 if (d)
1696 e->referent = d;
1697 else
1698 {
1699 // new local
1700 vardecl* v = new vardecl;
1701 v->name = e->name;
1702 v->tok = e->tok;
1703 if (current_function)
1704 current_function->locals.push_back (v);
1705 else if (current_probe)
1706 current_probe->locals.push_back (v);
1707 else
5d23847d
FCE
1708 // must be probe-condition expression
1709 throw semantic_error ("probe condition must not reference undeclared global", e->tok);
2b066ec1
FCE
1710 e->referent = v;
1711 }
1712}
1713
1714
1715void
1716symresolution_info::visit_arrayindex (arrayindex* e)
1717{
1718 for (unsigned i=0; i<e->indexes.size(); i++)
1719 e->indexes[i]->visit (this);
1720
57148ee7 1721 symbol *array = NULL;
d02548c0
GH
1722 hist_op *hist = NULL;
1723 classify_indexable(e->base, array, hist);
2b066ec1 1724
d02548c0 1725 if (array)
313b2f74 1726 {
d02548c0
GH
1727 if (array->referent)
1728 return;
1729
1730 vardecl* d = find_var (array->name, e->indexes.size ());
1731 if (d)
1732 array->referent = d;
313b2f74 1733 else
d02548c0
GH
1734 {
1735 // new local
1736 vardecl* v = new vardecl;
1737 v->set_arity(e->indexes.size());
1738 v->name = array->name;
1739 v->tok = array->tok;
1740 if (current_function)
1741 current_function->locals.push_back (v);
1742 else if (current_probe)
1743 current_probe->locals.push_back (v);
1744 else
1745 // must not happen
1746 throw semantic_error ("no current probe/function", e->tok);
1747 array->referent = v;
57148ee7 1748 }
d02548c0
GH
1749 }
1750 else
1751 {
1752 assert (hist);
1753 hist->visit (this);
313b2f74 1754 }
2b066ec1
FCE
1755}
1756
1757
1758void
1759symresolution_info::visit_functioncall (functioncall* e)
1760{
5d23847d
FCE
1761 // XXX: we could relax this, if we're going to examine the
1762 // vartracking data recursively. See testsuite/semko/fortytwo.stp.
1763 if (! (current_function || current_probe))
1764 {
1765 // must be probe-condition expression
1766 throw semantic_error ("probe condition must not reference function", e->tok);
1767 }
1768
2b066ec1
FCE
1769 for (unsigned i=0; i<e->args.size(); i++)
1770 e->args[i]->visit (this);
1771
1772 if (e->referent)
1773 return;
1774
1775 functiondecl* d = find_function (e->function, e->args.size ());
1776 if (d)
1777 e->referent = d;
1778 else
2a99f48f 1779 {
7e41d3dc
FCE
1780 stringstream msg;
1781 msg << "unresolved arity-" << e->args.size()
1782 << " function";
1783 throw semantic_error (msg.str(), e->tok);
2a99f48f 1784 }
2b066ec1
FCE
1785}
1786
1787
57148ee7 1788vardecl*
d98d459c 1789symresolution_info::find_var (const string& name, int arity)
2b066ec1 1790{
5d23847d
FCE
1791 if (current_function || current_probe)
1792 {
1793 // search locals
57148ee7 1794 vector<vardecl*>& locals = (current_function ?
5d23847d
FCE
1795 current_function->locals :
1796 current_probe->locals);
57148ee7
FCE
1797
1798
5d23847d 1799 for (unsigned i=0; i<locals.size(); i++)
57148ee7 1800 if (locals[i]->name == name
5d23847d
FCE
1801 && locals[i]->compatible_arity(arity))
1802 {
1803 locals[i]->set_arity (arity);
1804 return locals[i];
1805 }
1806 }
2b066ec1 1807
313b2f74
GH
1808 // search function formal parameters (for scalars)
1809 if (arity == 0 && current_function)
2b066ec1
FCE
1810 for (unsigned i=0; i<current_function->formal_args.size(); i++)
1811 if (current_function->formal_args[i]->name == name)
8846477c
FCE
1812 {
1813 // NB: no need to check arity here: formal args always scalar
1814 current_function->formal_args[i]->set_arity (0);
1815 return current_function->formal_args[i];
1816 }
2b066ec1 1817
313b2f74 1818 // search processed globals
2b066ec1 1819 for (unsigned i=0; i<session.globals.size(); i++)
313b2f74 1820 if (session.globals[i]->name == name
57148ee7 1821 && session.globals[i]->compatible_arity(arity))
8846477c 1822 {
313b2f74 1823 session.globals[i]->set_arity (arity);
8846477c
FCE
1824 return session.globals[i];
1825 }
57148ee7 1826
2b066ec1
FCE
1827 // search library globals
1828 for (unsigned i=0; i<session.library_files.size(); i++)
1829 {
1830 stapfile* f = session.library_files[i];
1831 for (unsigned j=0; j<f->globals.size(); j++)
84e5ea0f
FCE
1832 {
1833 vardecl* g = f->globals[j];
1834 if (g->name == name && g->compatible_arity (arity))
1835 {
d98d459c 1836 g->set_arity (arity);
57148ee7
FCE
1837
1838 // put library into the queue if not already there
1839 if (find (session.files.begin(), session.files.end(), f)
84e5ea0f
FCE
1840 == session.files.end())
1841 session.files.push_back (f);
57148ee7 1842
84e5ea0f
FCE
1843 return g;
1844 }
1845 }
2b066ec1
FCE
1846 }
1847
2b066ec1 1848 return 0;
2b066ec1
FCE
1849}
1850
1851
57148ee7 1852functiondecl*
2b066ec1
FCE
1853symresolution_info::find_function (const string& name, unsigned arity)
1854{
f76427a2
FCE
1855 // the common path
1856 if (session.functions.find(name) != session.functions.end())
2b066ec1 1857 {
f76427a2
FCE
1858 functiondecl* fd = session.functions[name];
1859 assert (fd->name == name);
1860 if (fd->formal_args.size() == arity)
2b066ec1
FCE
1861 return fd;
1862 }
1863
1864 // search library globals
1865 for (unsigned i=0; i<session.library_files.size(); i++)
1866 {
1867 stapfile* f = session.library_files[i];
1868 for (unsigned j=0; j<f->functions.size(); j++)
1869 if (f->functions[j]->name == name &&
1870 f->functions[j]->formal_args.size() == arity)
1871 {
1872 // put library into the queue if not already there
1873 if (0) // session.verbose_resolution
1874 cerr << " function " << name << " "
1875 << "is defined from " << f->name << endl;
1876
57148ee7 1877 if (find (session.files.begin(), session.files.end(), f)
2b066ec1
FCE
1878 == session.files.end())
1879 session.files.push_back (f);
1880 // else .. print different message?
1881
1882 return f->functions[j];
1883 }
1884 }
1885
1886 return 0;
2b066ec1
FCE
1887}
1888
1889
cbfbbf69
FCE
1890
1891// ------------------------------------------------------------------------
1892// optimization
1893
1894
1895// Do away with functiondecls that are never (transitively) called
1896// from probes.
1897void semantic_pass_opt1 (systemtap_session& s, bool& relaxed_p)
1898{
1899 functioncall_traversing_visitor ftv;
1900 for (unsigned i=0; i<s.probes.size(); i++)
5d23847d
FCE
1901 {
1902 s.probes[i]->body->visit (& ftv);
1903 if (s.probes[i]->sole_location()->condition)
1904 s.probes[i]->sole_location()->condition->visit (& ftv);
1905 }
f76427a2
FCE
1906 vector<functiondecl*> new_unused_functions;
1907 for (map<string,functiondecl*>::iterator it = s.functions.begin(); it != s.functions.end(); it++)
cbfbbf69 1908 {
f76427a2
FCE
1909 functiondecl* fd = it->second;
1910 if (ftv.traversed.find(fd) == ftv.traversed.end())
cbfbbf69 1911 {
f76427a2 1912 if (fd->tok->location.file == s.user_file->name && // !tapset
a9e8f7e0 1913 ! s.suppress_warnings)
f76427a2 1914 s.print_warning ("eliding unused function '" + fd->name + "'", fd->tok);
a9e8f7e0 1915 else if (s.verbose>2)
f76427a2 1916 clog << "Eliding unused function " << fd->name
cbfbbf69 1917 << endl;
f76427a2
FCE
1918 // s.functions.erase (it); // NB: can't, since we're already iterating upon it
1919 new_unused_functions.push_back (fd);
cbfbbf69 1920 relaxed_p = false;
cbfbbf69 1921 }
f76427a2
FCE
1922 }
1923 for (unsigned i=0; i<new_unused_functions.size(); i++)
1924 {
1925 map<string,functiondecl*>::iterator where = s.functions.find (new_unused_functions[i]->name);
1926 assert (where != s.functions.end());
1927 s.functions.erase (where);
1928 if (s.tapset_compile_coverage)
1929 s.unused_functions.push_back (new_unused_functions[i]);
cbfbbf69
FCE
1930 }
1931}
1932
1933
1934// ------------------------------------------------------------------------
1935
1936// Do away with local & global variables that are never
1937// written nor read.
cfd621bc 1938void semantic_pass_opt2 (systemtap_session& s, bool& relaxed_p, unsigned iterations)
cbfbbf69
FCE
1939{
1940 varuse_collecting_visitor vut;
cfd621bc 1941
cbfbbf69 1942 for (unsigned i=0; i<s.probes.size(); i++)
5d23847d
FCE
1943 {
1944 s.probes[i]->body->visit (& vut);
1945
1946 if (s.probes[i]->sole_location()->condition)
1947 s.probes[i]->sole_location()->condition->visit (& vut);
1948 }
1949
cbfbbf69
FCE
1950 // NB: Since varuse_collecting_visitor also traverses down
1951 // actually called functions, we don't need to explicitly
1952 // iterate over them. Uncalled ones should have been pruned
1953 // in _opt1 above.
1954 //
1955 // for (unsigned i=0; i<s.functions.size(); i++)
1956 // s.functions[i]->body->visit (& vut);
57148ee7 1957
cbfbbf69 1958 // Now in vut.read/written, we have a mixture of all locals, globals
57148ee7
FCE
1959
1960 for (unsigned i=0; i<s.probes.size(); i++)
cbfbbf69
FCE
1961 for (unsigned j=0; j<s.probes[i]->locals.size(); /* see below */)
1962 {
1963 vardecl* l = s.probes[i]->locals[j];
a9e8f7e0 1964
cbfbbf69
FCE
1965 if (vut.read.find (l) == vut.read.end() &&
1966 vut.written.find (l) == vut.written.end())
1967 {
a9e8f7e0
FCE
1968 if (l->tok->location.file == s.user_file->name && // !tapset
1969 ! s.suppress_warnings)
cfd621bc 1970 s.print_warning ("eliding unused variable '" + l->name + "'", l->tok);
a9e8f7e0 1971 else if (s.verbose>2)
cbfbbf69 1972 clog << "Eliding unused local variable "
1b07c728 1973 << l->name << " in " << s.probes[i]->name << endl;
c3a3c0c9
WC
1974 if (s.tapset_compile_coverage) {
1975 s.probes[i]->unused_locals.push_back
1976 (s.probes[i]->locals[j]);
1977 }
cbfbbf69
FCE
1978 s.probes[i]->locals.erase(s.probes[i]->locals.begin() + j);
1979 relaxed_p = false;
1980 // don't increment j
1981 }
1982 else
27d24ae2
FCE
1983 {
1984 if (vut.written.find (l) == vut.written.end())
cfd621bc 1985 if (iterations == 0 && ! s.suppress_warnings)
6643650d
SC
1986 {
1987 stringstream o;
1988 vector<vardecl*>::iterator it;
cfd621bc
FCE
1989 for (it = s.probes[i]->locals.begin(); it != s.probes[i]->locals.end(); it++)
1990 if (l->name != (*it)->name)
1991 o << " " << (*it)->name;
1992 for (it = s.globals.begin(); it != s.globals.end(); it++)
1993 if (l->name != (*it)->name)
1994 o << " " << (*it)->name;
1995
1996 s.print_warning ("read-only local variable '" + l->name + "' " +
1997 (o.str() == "" ? "" : ("(alternatives:" + o.str() + ")")), l->tok);
6643650d 1998 }
27d24ae2
FCE
1999 j++;
2000 }
cbfbbf69 2001 }
57148ee7 2002
f76427a2
FCE
2003 for (map<string,functiondecl*>::iterator it = s.functions.begin(); it != s.functions.end(); it++)
2004 {
2005 functiondecl *fd = it->second;
2006 for (unsigned j=0; j<fd->locals.size(); /* see below */)
2007 {
2008 vardecl* l = fd->locals[j];
2009 if (vut.read.find (l) == vut.read.end() &&
2010 vut.written.find (l) == vut.written.end())
2011 {
2012 if (l->tok->location.file == s.user_file->name && // !tapset
2013 ! s.suppress_warnings)
2014 s.print_warning ("eliding unused variable '" + l->name + "'", l->tok);
2015 else if (s.verbose>2)
2016 clog << "Eliding unused local variable "
2017 << l->name << " in function " << fd->name
2018 << endl;
2019 if (s.tapset_compile_coverage) {
2020 fd->unused_locals.push_back (fd->locals[j]);
2021 }
2022 fd->locals.erase(fd->locals.begin() + j);
2023 relaxed_p = false;
2024 // don't increment j
2025 }
2026 else
2027 {
2028 if (vut.written.find (l) == vut.written.end())
2029 if (iterations == 0 && ! s.suppress_warnings)
2030 {
2031 stringstream o;
2032 vector<vardecl*>::iterator it;
2033 for (it = fd->formal_args.begin() ;
2034 it != fd->formal_args.end(); it++)
2035 if (l->name != (*it)->name)
2036 o << " " << (*it)->name;
2037 for (it = fd->locals.begin(); it != fd->locals.end(); it++)
2038 if (l->name != (*it)->name)
2039 o << " " << (*it)->name;
2040 for (it = s.globals.begin(); it != s.globals.end(); it++)
2041 if (l->name != (*it)->name)
2042 o << " " << (*it)->name;
2043
2044 s.print_warning ("read-only local variable '" + l->name + "' " +
2045 (o.str() == "" ? "" : ("(alternatives:" + o.str() + ")")), l->tok);
2046 }
cfd621bc 2047
f76427a2
FCE
2048 j++;
2049 }
2050 }
2051 }
cbfbbf69
FCE
2052 for (unsigned i=0; i<s.globals.size(); /* see below */)
2053 {
2054 vardecl* l = s.globals[i];
2055 if (vut.read.find (l) == vut.read.end() &&
2056 vut.written.find (l) == vut.written.end())
2057 {
a9e8f7e0
FCE
2058 if (l->tok->location.file == s.user_file->name && // !tapset
2059 ! s.suppress_warnings)
f76427a2 2060 s.print_warning ("eliding unused variable '" + l->name + "'", l->tok);
a9e8f7e0 2061 else if (s.verbose>2)
cbfbbf69
FCE
2062 clog << "Eliding unused global variable "
2063 << l->name << endl;
c3a3c0c9 2064 if (s.tapset_compile_coverage) {
0a102c82 2065 s.unused_globals.push_back(s.globals[i]);
c3a3c0c9 2066 }
0a102c82
SC
2067 s.globals.erase(s.globals.begin() + i);
2068 relaxed_p = false;
2069 // don't increment i
cbfbbf69
FCE
2070 }
2071 else
27d24ae2 2072 {
cfd621bc
FCE
2073 if (vut.written.find (l) == vut.written.end() && ! l->init) // no initializer
2074 if (iterations == 0 && ! s.suppress_warnings)
2075 {
2076 stringstream o;
2077 vector<vardecl*>::iterator it;
2078 for (it = s.globals.begin(); it != s.globals.end(); it++)
2079 if (l->name != (*it)->name)
2080 o << " " << (*it)->name;
57148ee7 2081
cfd621bc
FCE
2082 s.print_warning ("read-only global variable '" + l->name + "' " +
2083 (o.str() == "" ? "" : ("(alternatives:" + o.str() + ")")), l->tok);
2084 }
2085
27d24ae2
FCE
2086 i++;
2087 }
cbfbbf69
FCE
2088 }
2089}
2090
2091
2092// ------------------------------------------------------------------------
2093
8bda6498 2094struct dead_assignment_remover: public update_visitor
cbfbbf69
FCE
2095{
2096 systemtap_session& session;
2097 bool& relaxed_p;
2098 const varuse_collecting_visitor& vut;
cbfbbf69
FCE
2099
2100 dead_assignment_remover(systemtap_session& s, bool& r,
57148ee7 2101 const varuse_collecting_visitor& v):
8bda6498 2102 session(s), relaxed_p(r), vut(v) {}
cbfbbf69
FCE
2103
2104 void visit_assignment (assignment* e);
2105};
2106
2107
cbfbbf69
FCE
2108void
2109dead_assignment_remover::visit_assignment (assignment* e)
2110{
8bda6498
JS
2111 e->left = require (e->left);
2112 e->right = require (e->right);
2113
cbfbbf69 2114 symbol* left = get_symbol_within_expression (e->left);
b0be9bdb 2115 vardecl* leftvar = left->referent; // NB: may be 0 for unresolved $target
8bda6498 2116 if (leftvar) // not unresolved $target, so intended sideeffect may be elided
cbfbbf69 2117 {
cbfbbf69
FCE
2118 if (vut.read.find(leftvar) == vut.read.end()) // var never read?
2119 {
cf9ff341
FCE
2120 // NB: Not so fast! The left side could be an array whose
2121 // index expressions may have side-effects. This would be
57148ee7 2122 // OK if we could replace the array assignment with a
cf9ff341
FCE
2123 // statement-expression containing all the index expressions
2124 // and the rvalue... but we can't.
0a102c82
SC
2125 // Another possibility is that we have an unread global variable
2126 // which are kept for probe end value display.
2127
2128 bool is_global = false;
2129 vector<vardecl*>::iterator it;
2130 for (it = session.globals.begin(); it != session.globals.end(); it++)
2131 if (leftvar->name == (*it)->name)
2132 {
2133 is_global = true;
2134 break;
2135 }
cf9ff341 2136
8bda6498
JS
2137 varuse_collecting_visitor lvut;
2138 e->left->visit (& lvut);
2139 if (lvut.side_effect_free () && !is_global) // XXX: use _wrt() once we track focal_vars
cf9ff341 2140 {
a9e8f7e0
FCE
2141 /* PR 1119: NB: This is not necessary here. A write-only
2142 variable will also be elided soon at the next _opt2 iteration.
2143 if (e->left->tok->location.file == session.user_file->name && // !tapset
2144 ! session.suppress_warnings)
2145 clog << "WARNING: eliding write-only " << *e->left->tok << endl;
2146 else
2147 */
cf9ff341 2148 if (session.verbose>2)
57148ee7 2149 clog << "Eliding assignment to " << leftvar->name
cf9ff341 2150 << " at " << *e->tok << endl;
57148ee7 2151
8bda6498 2152 provide (e->right); // goodbye assignment*
cf9ff341 2153 relaxed_p = false;
8bda6498 2154 return;
cf9ff341 2155 }
cbfbbf69
FCE
2156 }
2157 }
8bda6498 2158 provide (e);
e7625481 2159}
cbfbbf69
FCE
2160
2161// Let's remove assignments to variables that are never read. We
2162// rewrite "(foo = expr)" as "(expr)". This makes foo a candidate to
2163// be optimized away as an unused variable, and expr a candidate to be
2164// removed as a side-effect-free statement expression. Wahoo!
2165void semantic_pass_opt3 (systemtap_session& s, bool& relaxed_p)
2166{
2167 // Recompute the varuse data, which will probably match the opt2
2168 // copy of the computation, except for those totally unused
2169 // variables that opt2 removed.
2170 varuse_collecting_visitor vut;
2171 for (unsigned i=0; i<s.probes.size(); i++)
2172 s.probes[i]->body->visit (& vut); // includes reachable functions too
2173
2174 dead_assignment_remover dar (s, relaxed_p, vut);
2175 // This instance may be reused for multiple probe/function body trims.
2176
2177 for (unsigned i=0; i<s.probes.size(); i++)
8bda6498
JS
2178 s.probes[i]->body = dar.require (s.probes[i]->body);
2179 for (map<string,functiondecl*>::iterator it = s.functions.begin();
2180 it != s.functions.end(); it++)
2181 it->second->body = dar.require (it->second->body);
cbfbbf69 2182 // The rewrite operation is performed within the visitor.
27d24ae2
FCE
2183
2184 // XXX: we could also zap write-only globals here
cbfbbf69
FCE
2185}
2186
2187
2188// ------------------------------------------------------------------------
2189
2190struct dead_stmtexpr_remover: public traversing_visitor
2191{
2192 systemtap_session& session;
2193 bool& relaxed_p;
2194 statement** current_stmt; // pointer to current stmt* being iterated
1b07c728 2195 set<vardecl*> focal_vars; // vars considered subject to side-effects
cbfbbf69 2196
57148ee7 2197 dead_stmtexpr_remover(systemtap_session& s, bool& r):
cbfbbf69
FCE
2198 session(s), relaxed_p(r), current_stmt(0) {}
2199
2200 void visit_block (block *s);
ba6f838d 2201 void visit_null_statement (null_statement *s);
739a3e81
FCE
2202 void visit_if_statement (if_statement* s);
2203 void visit_foreach_loop (foreach_loop *s);
2204 void visit_for_loop (for_loop *s);
cbfbbf69
FCE
2205 // XXX: and other places where stmt_expr's might be nested
2206
2207 void visit_expr_statement (expr_statement *s);
2208};
2209
2210
ba6f838d
FCE
2211void
2212dead_stmtexpr_remover::visit_null_statement (null_statement *s)
2213{
2214 // easy!
2215 if (session.verbose>2)
2216 clog << "Eliding side-effect-free null statement " << *s->tok << endl;
2217 *current_stmt = 0;
2218}
2219
2220
cbfbbf69
FCE
2221void
2222dead_stmtexpr_remover::visit_block (block *s)
2223{
ba6f838d
FCE
2224 vector<statement*> new_stmts;
2225 for (unsigned i=0; i<s->statements.size(); i++ )
cbfbbf69
FCE
2226 {
2227 statement** last_stmt = current_stmt;
2228 current_stmt = & s->statements[i];
2229 s->statements[i]->visit (this);
57148ee7 2230 if (*current_stmt != 0)
bea72737
JS
2231 {
2232 // flatten nested blocks into this one
2233 block *b = dynamic_cast<block *>(*current_stmt);
2234 if (b)
2235 {
2236 if (session.verbose>2)
2237 clog << "Flattening nested block " << *b->tok << endl;
2238 new_stmts.insert(new_stmts.end(),
2239 b->statements.begin(), b->statements.end());
2240 relaxed_p = false;
2241 }
2242 else
2243 new_stmts.push_back (*current_stmt);
2244 }
cbfbbf69
FCE
2245 current_stmt = last_stmt;
2246 }
ba6f838d
FCE
2247 if (new_stmts.size() == 0)
2248 {
2249 if (session.verbose>2)
2250 clog << "Eliding side-effect-free empty block " << *s->tok << endl;
2251 *current_stmt = 0;
2252 }
2253 else if (new_stmts.size() == 1)
2254 {
2255 if (session.verbose>2)
2256 clog << "Eliding side-effect-free singleton block " << *s->tok << endl;
2257 *current_stmt = new_stmts[0];
2258 }
2259 else
2260 {
2261 s->statements = new_stmts;
2262 }
cbfbbf69
FCE
2263}
2264
739a3e81
FCE
2265void
2266dead_stmtexpr_remover::visit_if_statement (if_statement *s)
2267{
2268 statement** last_stmt = current_stmt;
2269 current_stmt = & s->thenblock;
2270 s->thenblock->visit (this);
ba6f838d 2271
739a3e81
FCE
2272 if (s->elseblock)
2273 {
2274 current_stmt = & s->elseblock;
2275 s->elseblock->visit (this);
ba6f838d 2276 // null *current_stmt is OK here.
739a3e81
FCE
2277 }
2278 current_stmt = last_stmt;
ba6f838d 2279
bea72737 2280 if (s->thenblock == 0)
ba6f838d 2281 {
bea72737
JS
2282 if (s->elseblock == 0)
2283 {
2284 // We may be able to elide this statement, if the condition
2285 // expression is side-effect-free.
2286 varuse_collecting_visitor vct;
2287 s->condition->visit(& vct);
2288 if (vct.side_effect_free ())
2289 {
2290 if (session.verbose>2)
2291 clog << "Eliding side-effect-free if statement "
2292 << *s->tok << endl;
2293 *current_stmt = 0; // yeah, baby
2294 }
2295 else
2296 {
2297 // We can still turn it into a simple expr_statement though...
2298 if (session.verbose>2)
2299 clog << "Creating simple evaluation from if statement "
2300 << *s->tok << endl;
2301 expr_statement *es = new expr_statement;
2302 es->value = s->condition;
2303 es->tok = es->value->tok;
2304 *current_stmt = es;
2305 }
2306 }
2307 else
ba6f838d 2308 {
bea72737
JS
2309 // For an else without a then, we can invert the condition logic to
2310 // avoid having a null statement in the thenblock
ba6f838d 2311 if (session.verbose>2)
bea72737
JS
2312 clog << "Inverting the condition of if statement "
2313 << *s->tok << endl;
2314 unary_expression *ue = new unary_expression;
2315 ue->operand = s->condition;
2316 ue->tok = ue->operand->tok;
2317 ue->op = "!";
2318 s->condition = ue;
2319 s->thenblock = s->elseblock;
2320 s->elseblock = 0;
ba6f838d
FCE
2321 }
2322 }
739a3e81
FCE
2323}
2324
2325void
2326dead_stmtexpr_remover::visit_foreach_loop (foreach_loop *s)
2327{
2328 statement** last_stmt = current_stmt;
2329 current_stmt = & s->block;
2330 s->block->visit (this);
2331 current_stmt = last_stmt;
ba6f838d
FCE
2332
2333 if (s->block == 0)
2334 {
2335 if (session.verbose>2)
2336 clog << "Eliding side-effect-free foreach statement " << *s->tok << endl;
2337 *current_stmt = 0; // yeah, baby
2338 }
739a3e81
FCE
2339}
2340
2341void
2342dead_stmtexpr_remover::visit_for_loop (for_loop *s)
2343{
2344 statement** last_stmt = current_stmt;
2345 current_stmt = & s->block;
2346 s->block->visit (this);
2347 current_stmt = last_stmt;
ba6f838d
FCE
2348
2349 if (s->block == 0)
2350 {
2351 // We may be able to elide this statement, if the condition
2352 // expression is side-effect-free.
2353 varuse_collecting_visitor vct;
2354 if (s->init) s->init->visit(& vct);
2355 s->cond->visit(& vct);
2356 if (s->incr) s->incr->visit(& vct);
2357 if (vct.side_effect_free ())
2358 {
2359 if (session.verbose>2)
2360 clog << "Eliding side-effect-free for statement " << *s->tok << endl;
2361 *current_stmt = 0; // yeah, baby
2362 return;
2363 }
2364
2365 // Can't elide this whole statement; put a null in there.
2366 s->block = new null_statement();
2367 s->block->tok = s->tok;
2368 }
739a3e81
FCE
2369}
2370
2371
cbfbbf69
FCE
2372
2373void
2374dead_stmtexpr_remover::visit_expr_statement (expr_statement *s)
2375{
2376 // Run a varuse query against the operand expression. If it has no
2377 // side-effects, replace the entire statement expression by a null
2378 // statement. This replacement is done by overwriting the
2379 // current_stmt pointer.
2380 //
2381 // Unlike many other visitors, we do *not* traverse this outermost
2382 // one into the expression subtrees. There is no need - no
2383 // expr_statement nodes will be found there. (Function bodies
2384 // need to be visited explicitly by our caller.)
2385 //
2386 // NB. While we don't share nodes in the parse tree, let's not
2387 // deallocate *s anyway, just in case...
2388
2389 varuse_collecting_visitor vut;
2390 s->value->visit (& vut);
57148ee7 2391
0a102c82 2392 if (vut.side_effect_free_wrt (focal_vars) &&
57148ee7 2393 *current_stmt == s) // we're not nested any deeper than expected
cbfbbf69 2394 {
a9e8f7e0
FCE
2395 /* PR 1119: NB: this message is not a good idea here. It can
2396 name some arbitrary RHS expression of an assignment.
2397 if (s->value->tok->location.file == session.user_file->name && // not tapset
2398 ! session.suppress_warnings)
2399 clog << "WARNING: eliding read-only " << *s->value->tok << endl;
57148ee7 2400 else
a9e8f7e0 2401 */
b0ee93c4 2402 if (session.verbose>2)
cbfbbf69
FCE
2403 clog << "Eliding side-effect-free expression "
2404 << *s->tok << endl;
2405
ba6f838d
FCE
2406 // NB: this 0 pointer is invalid to leave around for any length of
2407 // time, but the parent parse tree objects above handle it.
2408 * current_stmt = 0;
2409
cbfbbf69
FCE
2410 relaxed_p = false;
2411 }
2412}
2413
2414
2415void semantic_pass_opt4 (systemtap_session& s, bool& relaxed_p)
2416{
2417 // Finally, let's remove some statement-expressions that have no
2418 // side-effect. These should be exactly those whose private varuse
2419 // visitors come back with an empty "written" and "embedded" lists.
57148ee7 2420
cbfbbf69
FCE
2421 dead_stmtexpr_remover duv (s, relaxed_p);
2422 // This instance may be reused for multiple probe/function body trims.
2423
2424 for (unsigned i=0; i<s.probes.size(); i++)
1b07c728 2425 {
f76427a2
FCE
2426 if (pending_interrupts) break;
2427
ba6f838d
FCE
2428 derived_probe* p = s.probes[i];
2429
1b07c728
FCE
2430 duv.focal_vars.clear ();
2431 duv.focal_vars.insert (s.globals.begin(),
2432 s.globals.end());
ba6f838d
FCE
2433 duv.focal_vars.insert (p->locals.begin(),
2434 p->locals.end());
2435
2436 duv.current_stmt = & p->body;
2437 p->body->visit (& duv);
2438 if (p->body == 0)
2439 {
2440 if (! s.suppress_warnings)
cfd621bc 2441 s.print_warning ("side-effect-free probe '" + p->name + "'", p->tok);
ba6f838d
FCE
2442
2443 p->body = new null_statement();
2444 p->body->tok = p->tok;
27d24ae2
FCE
2445
2446 // XXX: possible duplicate warnings; see below
ba6f838d 2447 }
1b07c728 2448 }
f76427a2 2449 for (map<string,functiondecl*>::iterator it = s.functions.begin(); it != s.functions.end(); it++)
1b07c728 2450 {
f76427a2
FCE
2451 if (pending_interrupts) break;
2452
2453 functiondecl* fn = it->second;
1b07c728 2454 duv.focal_vars.clear ();
ba6f838d
FCE
2455 duv.focal_vars.insert (fn->locals.begin(),
2456 fn->locals.end());
2457 duv.focal_vars.insert (fn->formal_args.begin(),
2458 fn->formal_args.end());
1b07c728
FCE
2459 duv.focal_vars.insert (s.globals.begin(),
2460 s.globals.end());
ba6f838d
FCE
2461
2462 duv.current_stmt = & fn->body;
2463 fn->body->visit (& duv);
2464 if (fn->body == 0)
2465 {
2466 if (! s.suppress_warnings)
cfd621bc 2467 s.print_warning ("side-effect-free function '" + fn->name + "'", fn->tok);
ba6f838d
FCE
2468
2469 fn->body = new null_statement();
2470 fn->body->tok = fn->tok;
27d24ae2
FCE
2471
2472 // XXX: the next iteration of the outer optimization loop may
2473 // take this new null_statement away again, and thus give us a
2474 // fresh warning. It would be better if this fixup was performed
2475 // only after the relaxation iterations.
2476 // XXX: or else see bug #6469.
ba6f838d 2477 }
1b07c728 2478 }
cbfbbf69
FCE
2479}
2480
bea72737
JS
2481
2482// ------------------------------------------------------------------------
2483
2484// The goal of this visitor is to reduce top-level expressions in void context
2485// into separate statements that evaluate each subcomponent of the expression.
2486// The dead-statement-remover can later remove some parts if they have no side
2487// effects.
2488struct void_statement_reducer: public traversing_visitor
2489{
2490 systemtap_session& session;
2491 bool& relaxed_p;
2492 statement** current_stmt; // pointer to current stmt* being iterated
133c7b1d 2493 expr_statement* current_expr; // pointer to current expr being iterated
bea72737
JS
2494 set<vardecl*> focal_vars; // vars considered subject to side-effects
2495
2496 void_statement_reducer(systemtap_session& s, bool& r):
133c7b1d 2497 session(s), relaxed_p(r), current_stmt(0), current_expr(0) {}
bea72737
JS
2498
2499 // these just maintain current_stmt while recursing, but don't visit
2500 // expressions in the conditional / loop controls.
133c7b1d 2501 void visit_expr_statement (expr_statement* s);
bea72737
JS
2502 void visit_block (block *s);
2503 void visit_if_statement (if_statement* s);
2504 void visit_for_loop (for_loop* s);
2505 void visit_foreach_loop (foreach_loop* s);
2506
2507 // these expressions get rewritten into their statement equivalents
2508 void visit_logical_or_expr (logical_or_expr* e);
2509 void visit_logical_and_expr (logical_and_expr* e);
2510 void visit_ternary_expression (ternary_expression* e);
2511
2512 // all of these can be reduced into simpler statements
2513 void visit_binary_expression (binary_expression* e);
2514 void visit_unary_expression (unary_expression* e);
2515 void visit_comparison (comparison* e);
2516 void visit_concatenation (concatenation* e);
2517 void visit_functioncall (functioncall* e);
2518 void visit_print_format (print_format* e);
2519
2520 // these are a bit hairy to grok due to the intricacies of indexables and
2521 // stats, so I'm chickening out and skipping them...
2522 void visit_array_in (array_in* e) {}
2523 void visit_arrayindex (arrayindex* e) {}
2524 void visit_stat_op (stat_op* e) {}
2525 void visit_hist_op (hist_op* e) {}
2526
2527 // these can't be reduced because they always have an effect
2528 void visit_return_statement (return_statement* s) {}
2529 void visit_delete_statement (delete_statement* s) {}
2530 void visit_pre_crement (pre_crement* e) {}
2531 void visit_post_crement (post_crement* e) {}
2532 void visit_assignment (assignment* e) {}
2533};
2534
2535
133c7b1d
JS
2536void
2537void_statement_reducer::visit_expr_statement (expr_statement* s)
2538{
2539 assert(!current_expr); // it shouldn't be possible to have nested expr's
2540 current_expr = s;
2541 s->value->visit (this);
2542 current_expr = NULL;
2543}
2544
bea72737
JS
2545void
2546void_statement_reducer::visit_block (block *s)
2547{
2548 statement** last_stmt = current_stmt;
2549 for (unsigned i=0; i<s->statements.size(); i++ )
2550 {
2551 current_stmt = & s->statements[i];
2552 s->statements[i]->visit (this);
2553 }
2554 current_stmt = last_stmt;
2555}
2556
2557void
2558void_statement_reducer::visit_if_statement (if_statement* s)
2559{
2560 statement** last_stmt = current_stmt;
2561 current_stmt = & s->thenblock;
2562 s->thenblock->visit (this);
2563
2564 if (s->elseblock)
2565 {
2566 current_stmt = & s->elseblock;
2567 s->elseblock->visit (this);
2568 }
2569 current_stmt = last_stmt;
2570}
2571
2572void
2573void_statement_reducer::visit_for_loop (for_loop* s)
2574{
2575 statement** last_stmt = current_stmt;
2576 current_stmt = & s->block;
2577 s->block->visit (this);
2578 current_stmt = last_stmt;
2579}
2580
2581void
2582void_statement_reducer::visit_foreach_loop (foreach_loop* s)
2583{
2584 statement** last_stmt = current_stmt;
2585 current_stmt = & s->block;
2586 s->block->visit (this);
2587 current_stmt = last_stmt;
2588}
2589
2590void
2591void_statement_reducer::visit_logical_or_expr (logical_or_expr* e)
2592{
2593 // In void context, the evaluation of "a || b" is exactly like
2594 // "if (!a) b", so let's do that instead.
2595
133c7b1d 2596 assert(current_expr && current_expr->value == e);
bea72737
JS
2597
2598 if (session.verbose>2)
2599 clog << "Creating if statement from unused logical-or "
2600 << *e->tok << endl;
2601
2602 if_statement *is = new if_statement;
2603 is->tok = e->tok;
2604 is->elseblock = 0;
2605 *current_stmt = is;
133c7b1d 2606 current_expr = NULL;
bea72737
JS
2607
2608 unary_expression *ue = new unary_expression;
2609 ue->operand = e->left;
2610 ue->tok = e->tok;
2611 ue->op = "!";
2612 is->condition = ue;
2613
133c7b1d 2614 expr_statement *es = new expr_statement;
bea72737
JS
2615 es->value = e->right;
2616 es->tok = es->value->tok;
2617 is->thenblock = es;
2618
2619 is->visit(this);
2620 relaxed_p = false;
2621}
2622
2623void
2624void_statement_reducer::visit_logical_and_expr (logical_and_expr* e)
2625{
2626 // In void context, the evaluation of "a && b" is exactly like
2627 // "if (a) b", so let's do that instead.
2628
133c7b1d 2629 assert(current_expr && current_expr->value == e);
bea72737
JS
2630
2631 if (session.verbose>2)
2632 clog << "Creating if statement from unused logical-and "
2633 << *e->tok << endl;
2634
2635 if_statement *is = new if_statement;
2636 is->tok = e->tok;
2637 is->elseblock = 0;
2638 is->condition = e->left;
2639 *current_stmt = is;
133c7b1d 2640 current_expr = NULL;
bea72737 2641
133c7b1d 2642 expr_statement *es = new expr_statement;
bea72737
JS
2643 es->value = e->right;
2644 es->tok = es->value->tok;
2645 is->thenblock = es;
2646
2647 is->visit(this);
2648 relaxed_p = false;
2649}
2650
2651void
2652void_statement_reducer::visit_ternary_expression (ternary_expression* e)
2653{
2654 // In void context, the evaluation of "a ? b : c" is exactly like
2655 // "if (a) b else c", so let's do that instead.
2656
133c7b1d 2657 assert(current_expr && current_expr->value == e);
bea72737
JS
2658
2659 if (session.verbose>2)
2660 clog << "Creating if statement from unused ternary expression "
2661 << *e->tok << endl;
2662
2663 if_statement *is = new if_statement;
2664 is->tok = e->tok;
2665 is->condition = e->cond;
2666 *current_stmt = is;
133c7b1d 2667 current_expr = NULL;
bea72737 2668
133c7b1d 2669 expr_statement *es = new expr_statement;
bea72737
JS
2670 es->value = e->truevalue;
2671 es->tok = es->value->tok;
2672 is->thenblock = es;
2673
2674 es = new expr_statement;
2675 es->value = e->falsevalue;
2676 es->tok = es->value->tok;
2677 is->elseblock = es;
2678
2679 is->visit(this);
2680 relaxed_p = false;
2681}
2682
2683void
2684void_statement_reducer::visit_binary_expression (binary_expression* e)
2685{
2686 // When the result of a binary operation isn't needed, it's just as good to
2687 // evaluate the operands as sequential statements in a block.
2688
133c7b1d 2689 assert(current_expr && current_expr->value == e);
bea72737
JS
2690
2691 if (session.verbose>2)
2692 clog << "Eliding unused binary " << *e->tok << endl;
2693
2694 block *b = new block;
133c7b1d 2695 b->tok = current_expr->tok;
bea72737 2696 *current_stmt = b;
133c7b1d 2697 current_expr = NULL;
bea72737 2698
133c7b1d 2699 expr_statement *es = new expr_statement;
bea72737
JS
2700 es->value = e->left;
2701 es->tok = es->value->tok;
2702 b->statements.push_back(es);
2703
2704 es = new expr_statement;
2705 es->value = e->right;
2706 es->tok = es->value->tok;
2707 b->statements.push_back(es);
2708
2709 b->visit(this);
2710 relaxed_p = false;
2711}
2712
2713void
2714void_statement_reducer::visit_unary_expression (unary_expression* e)
2715{
2716 // When the result of a unary operation isn't needed, it's just as good to
2717 // evaluate the operand directly
2718
133c7b1d 2719 assert(current_expr && current_expr->value == e);
bea72737
JS
2720
2721 if (session.verbose>2)
2722 clog << "Eliding unused unary " << *e->tok << endl;
2723
133c7b1d
JS
2724 current_expr->value = e->operand;
2725 current_expr->tok = current_expr->value->tok;
2726 current_expr->value->visit(this);
bea72737
JS
2727
2728 relaxed_p = false;
2729}
2730
2731void
2732void_statement_reducer::visit_comparison (comparison* e)
2733{
2734 visit_binary_expression(e);
2735}
2736
2737void
2738void_statement_reducer::visit_concatenation (concatenation* e)
2739{
2740 visit_binary_expression(e);
2741}
2742
2743void
2744void_statement_reducer::visit_functioncall (functioncall* e)
2745{
2746 // If a function call is pure and its result ignored, we can elide the call
c7d47935 2747 // and just evaluate the arguments in sequence
bea72737
JS
2748
2749 if (!e->args.size())
2750 return;
2751
2752 varuse_collecting_visitor vut;
2753 vut.traversed.insert (e->referent);
2754 vut.current_function = e->referent;
2755 e->referent->body->visit (& vut);
2756 if (!vut.side_effect_free_wrt (focal_vars))
2757 return;
2758
133c7b1d 2759 assert(current_expr && current_expr->value == e);
bea72737
JS
2760
2761 if (session.verbose>2)
2762 clog << "Eliding side-effect-free function call " << *e->tok << endl;
2763
133c7b1d
JS
2764 block *b = new block;
2765 b->tok = e->tok;
2766 *current_stmt = b;
2767 current_expr = NULL;
bea72737 2768
133c7b1d 2769 for (unsigned i=0; i<e->args.size(); i++ )
bea72737 2770 {
133c7b1d
JS
2771 expr_statement *es = new expr_statement;
2772 es->value = e->args[i];
2773 es->tok = es->value->tok;
bea72737 2774 b->statements.push_back(es);
bea72737
JS
2775 }
2776
133c7b1d 2777 b->visit(this);
bea72737
JS
2778 relaxed_p = false;
2779}
2780
2781void
2782void_statement_reducer::visit_print_format (print_format* e)
2783{
2784 // When an sprint's return value is ignored, we can simply evaluate the
2785 // arguments in sequence
2786
2787 if (e->print_to_stream || !e->args.size())
2788 return;
2789
133c7b1d 2790 assert(current_expr && current_expr->value == e);
bea72737
JS
2791
2792 if (session.verbose>2)
2793 clog << "Eliding unused print " << *e->tok << endl;
2794
133c7b1d
JS
2795 block *b = new block;
2796 b->tok = e->tok;
2797 *current_stmt = b;
2798 current_expr = NULL;
bea72737 2799
133c7b1d 2800 for (unsigned i=0; i<e->args.size(); i++ )
bea72737 2801 {
133c7b1d
JS
2802 expr_statement *es = new expr_statement;
2803 es->value = e->args[i];
2804 es->tok = es->value->tok;
bea72737 2805 b->statements.push_back(es);
bea72737
JS
2806 }
2807
133c7b1d 2808 b->visit(this);
bea72737
JS
2809 relaxed_p = false;
2810}
2811
2812
2813void semantic_pass_opt5 (systemtap_session& s, bool& relaxed_p)
2814{
2815 // Let's simplify statements with unused computed values.
2816
2817 void_statement_reducer vuv (s, relaxed_p);
2818 // This instance may be reused for multiple probe/function body trims.
2819
2820 vuv.focal_vars.insert (s.globals.begin(), s.globals.end());
2821
2822 for (unsigned i=0; i<s.probes.size(); i++)
2823 {
2824 derived_probe* p = s.probes[i];
2825 vuv.current_stmt = & p->body;
2826 p->body->visit (& vuv);
2827 }
f76427a2 2828 for (map<string,functiondecl*>::iterator it = s.functions.begin(); it != s.functions.end(); it++)
bea72737 2829 {
f76427a2 2830 functiondecl* fn = it->second;
bea72737
JS
2831 vuv.current_stmt = & fn->body;
2832 fn->body->visit (& vuv);
2833 }
2834}
2835
2836
88bbd60d
DS
2837struct duplicate_function_remover: public functioncall_traversing_visitor
2838{
2839 systemtap_session& s;
88bbd60d
DS
2840 map<functiondecl*, functiondecl*>& duplicate_function_map;
2841
c214bd6a 2842 duplicate_function_remover(systemtap_session& sess,
88bbd60d 2843 map<functiondecl*, functiondecl*>&dfm):
c214bd6a 2844 s(sess), duplicate_function_map(dfm) {};
88bbd60d
DS
2845
2846 void visit_functioncall (functioncall* e);
2847};
2848
2849void
2850duplicate_function_remover::visit_functioncall (functioncall *e)
2851{
2852 functioncall_traversing_visitor::visit_functioncall (e);
2853
2854 // If the current function call reference points to a function that
2855 // is a duplicate, replace it.
2856 if (duplicate_function_map.count(e->referent) != 0)
2857 {
2858 if (s.verbose>2)
2859 clog << "Changing " << e->referent->name
2860 << " reference to "
2861 << duplicate_function_map[e->referent]->name
2862 << " reference\n";
2863 e->tok = duplicate_function_map[e->referent]->tok;
2864 e->function = duplicate_function_map[e->referent]->name;
2865 e->referent = duplicate_function_map[e->referent];
88bbd60d
DS
2866 }
2867}
2868
2869static string
2870get_functionsig (functiondecl* f)
2871{
2872 ostringstream s;
2873
2874 // Get the "name:args body" of the function in s. We have to
2875 // include the args since the function 'x1(a, b)' is different than
2876 // the function 'x2(b, a)' even if the bodies of the two functions
2877 // are exactly the same.
2878 f->printsig(s);
2879 f->body->print(s);
2880
2881 // printsig puts f->name + ':' on the front. Remove this
2882 // (otherwise, functions would never compare equal).
2883 string str = s.str().erase(0, f->name.size() + 1);
2884
2885 // Return the function signature.
2886 return str;
2887}
2888
bea72737 2889void semantic_pass_opt6 (systemtap_session& s, bool& relaxed_p)
88bbd60d
DS
2890{
2891 // Walk through all the functions, looking for duplicates.
2892 map<string, functiondecl*> functionsig_map;
2893 map<functiondecl*, functiondecl*> duplicate_function_map;
f76427a2
FCE
2894
2895
2896 vector<functiondecl*> newly_zapped_functions;
2897 for (map<string,functiondecl*>::iterator it = s.functions.begin(); it != s.functions.end(); it++)
88bbd60d 2898 {
f76427a2
FCE
2899 functiondecl *fd = it->second;
2900 string functionsig = get_functionsig(fd);
88bbd60d
DS
2901
2902 if (functionsig_map.count(functionsig) == 0)
c214bd6a
DS
2903 {
2904 // This function is unique. Remember it.
f76427a2 2905 functionsig_map[functionsig] = fd;
c214bd6a 2906 }
88bbd60d 2907 else
c214bd6a
DS
2908 {
2909 // This function is a duplicate.
f76427a2
FCE
2910 duplicate_function_map[fd] = functionsig_map[functionsig];
2911 newly_zapped_functions.push_back (fd);
c214bd6a 2912 relaxed_p = false;
c214bd6a 2913 }
88bbd60d 2914 }
f76427a2
FCE
2915 for (unsigned i=0; i<newly_zapped_functions.size(); i++)
2916 {
2917 map<string,functiondecl*>::iterator where = s.functions.find (newly_zapped_functions[i]->name);
2918 assert (where != s.functions.end());
2919 s.functions.erase (where);
2920 }
2921
88bbd60d
DS
2922
2923 // If we have duplicate functions, traverse down the tree, replacing
2924 // the appropriate function calls.
2925 // duplicate_function_remover::visit_functioncall() handles the
c214bd6a 2926 // details of replacing the function calls.
88bbd60d
DS
2927 if (duplicate_function_map.size() != 0)
2928 {
c214bd6a 2929 duplicate_function_remover dfr (s, duplicate_function_map);
88bbd60d
DS
2930
2931 for (unsigned i=0; i < s.probes.size(); i++)
2932 s.probes[i]->body->visit(&dfr);
2933 }
2934}
2935
cbfbbf69
FCE
2936
2937static int
c214bd6a 2938semantic_pass_optimize1 (systemtap_session& s)
cbfbbf69
FCE
2939{
2940 // In this pass, we attempt to rewrite probe/function bodies to
2941 // eliminate some blatantly unnecessary code. This is run before
2942 // type inference, but after symbol resolution and derived_probe
2943 // creation. We run an outer "relaxation" loop that repeats the
2944 // optimizations until none of them find anything to remove.
2945
2946 int rc = 0;
2947
2948 bool relaxed_p = false;
cfd621bc 2949 unsigned iterations = 0;
cbfbbf69
FCE
2950 while (! relaxed_p)
2951 {
49abf162
FCE
2952 if (pending_interrupts) break;
2953
cbfbbf69
FCE
2954 relaxed_p = true; // until proven otherwise
2955
2956 semantic_pass_opt1 (s, relaxed_p);
cfd621bc 2957 semantic_pass_opt2 (s, relaxed_p, iterations); // produce some warnings only on iteration=0
cbfbbf69
FCE
2958 semantic_pass_opt3 (s, relaxed_p);
2959 semantic_pass_opt4 (s, relaxed_p);
bea72737 2960 semantic_pass_opt5 (s, relaxed_p);
cfd621bc
FCE
2961
2962 iterations ++;
c214bd6a
DS
2963 }
2964
c214bd6a
DS
2965 return rc;
2966}
2967
2968
2969static int
2970semantic_pass_optimize2 (systemtap_session& s)
2971{
2972 // This is run after type inference. We run an outer "relaxation"
2973 // loop that repeats the optimizations until none of them find
2974 // anything to remove.
2975
2976 int rc = 0;
2977
2978 bool relaxed_p = false;
2979 while (! relaxed_p)
2980 {
49abf162 2981 if (pending_interrupts) break;
c214bd6a
DS
2982 relaxed_p = true; // until proven otherwise
2983
bea72737 2984 semantic_pass_opt6 (s, relaxed_p);
cbfbbf69
FCE
2985 }
2986
cbfbbf69
FCE
2987 return rc;
2988}
2989
2990
2991
2b066ec1
FCE
2992// ------------------------------------------------------------------------
2993// type resolution
2994
2995
2996static int
2997semantic_pass_types (systemtap_session& s)
2998{
2999 int rc = 0;
3000
3001 // next pass: type inference
3002 unsigned iterations = 0;
3003 typeresolution_info ti (s);
57148ee7 3004
2b066ec1
FCE
3005 ti.assert_resolvability = false;
3006 // XXX: maybe convert to exception-based error signalling
3007 while (1)
3008 {
49abf162
FCE
3009 if (pending_interrupts) break;
3010
2b066ec1 3011 iterations ++;
2b066ec1
FCE
3012 ti.num_newly_resolved = 0;
3013 ti.num_still_unresolved = 0;
3014
f76427a2 3015 for (map<string,functiondecl*>::iterator it = s.functions.begin(); it != s.functions.end(); it++)
2b066ec1 3016 {
49abf162
FCE
3017 if (pending_interrupts) break;
3018
f76427a2 3019 functiondecl* fd = it->second;
bdef2583 3020 ti.current_probe = 0;
f76427a2 3021 ti.current_function = fd;
8a43522c 3022 ti.t = pe_unknown;
f76427a2 3023 fd->body->visit (& ti);
8a43522c
GH
3024 // NB: we don't have to assert a known type for
3025 // functions here, to permit a "void" function.
3026 // The translator phase will omit the "retvalue".
3027 //
f76427a2
FCE
3028 // if (fd->type == pe_unknown)
3029 // ti.unresolved (fd->tok);
57148ee7 3030 }
2b066ec1
FCE
3031
3032 for (unsigned j=0; j<s.probes.size(); j++)
3033 {
49abf162
FCE
3034 if (pending_interrupts) break;
3035
2b066ec1
FCE
3036 derived_probe* pn = s.probes[j];
3037 ti.current_function = 0;
bdef2583 3038 ti.current_probe = pn;
2b066ec1
FCE
3039 ti.t = pe_unknown;
3040 pn->body->visit (& ti);
5d23847d
FCE
3041
3042 probe_point* pp = pn->sole_location();
3043 if (pp->condition)
3044 {
3045 ti.current_function = 0;
3046 ti.current_probe = 0;
3047 ti.t = pe_long; // NB: expected type
3048 pp->condition->visit (& ti);
3049 }
2b066ec1
FCE
3050 }
3051
3052 for (unsigned j=0; j<s.globals.size(); j++)
3053 {
3054 vardecl* gd = s.globals[j];
3055 if (gd->type == pe_unknown)
3056 ti.unresolved (gd->tok);
3057 }
57148ee7 3058
2b066ec1 3059 if (ti.num_newly_resolved == 0) // converged
78f6bba6
FCE
3060 {
3061 if (ti.num_still_unresolved == 0)
3062 break; // successfully
3063 else if (! ti.assert_resolvability)
3064 ti.assert_resolvability = true; // last pass, with error msgs
3065 else
3066 { // unsuccessful conclusion
3067 rc ++;
3068 break;
3069 }
3070 }
2b066ec1 3071 }
57148ee7 3072
7e41d3dc 3073 return rc + s.num_errors();
2b066ec1
FCE
3074}
3075
3076
bdef2583
FCE
3077
3078typeresolution_info::typeresolution_info (systemtap_session& s):
3079 session(s), current_function(0), current_probe(0)
3080{
3081}
3082
3083
2b066ec1
FCE
3084void
3085typeresolution_info::visit_literal_number (literal_number* e)
3086{
3087 assert (e->type == pe_long);
3088 if ((t == e->type) || (t == pe_unknown))
3089 return;
3090
3091 mismatch (e->tok, e->type, t);
3092}
3093
3094
3095void
3096typeresolution_info::visit_literal_string (literal_string* e)
3097{
3098 assert (e->type == pe_string);
3099 if ((t == e->type) || (t == pe_unknown))
3100 return;
3101
3102 mismatch (e->tok, e->type, t);
3103}
3104
3105
3106void
3107typeresolution_info::visit_logical_or_expr (logical_or_expr *e)
3108{
3109 visit_binary_expression (e);
3110}
3111
3112
3113void
3114typeresolution_info::visit_logical_and_expr (logical_and_expr *e)
3115{
3116 visit_binary_expression (e);
3117}
3118
3119
3120void
3121typeresolution_info::visit_comparison (comparison *e)
3122{
d5d7c2cc 3123 // NB: result of any comparison is an integer!
553d27a5
FCE
3124 if (t == pe_stats || t == pe_string)
3125 invalid (e->tok, t);
3126
3127 t = (e->right->type != pe_unknown) ? e->right->type : pe_unknown;
3128 e->left->visit (this);
3129 t = (e->left->type != pe_unknown) ? e->left->type : pe_unknown;
3130 e->right->visit (this);
57148ee7 3131
553d27a5
FCE
3132 if (e->left->type != pe_unknown &&
3133 e->right->type != pe_unknown &&
3134 e->left->type != e->right->type)
3135 mismatch (e->tok, e->left->type, e->right->type);
57148ee7 3136
553d27a5
FCE
3137 if (e->type == pe_unknown)
3138 {
3139 e->type = pe_long;
3140 resolved (e->tok, e->type);
3141 }
2b066ec1
FCE
3142}
3143
3144
3145void
3146typeresolution_info::visit_concatenation (concatenation *e)
3147{
553d27a5
FCE
3148 if (t != pe_unknown && t != pe_string)
3149 invalid (e->tok, t);
3150
3151 t = pe_string;
3152 e->left->visit (this);
3153 t = pe_string;
3154 e->right->visit (this);
3155
3156 if (e->type == pe_unknown)
3157 {
3158 e->type = pe_string;
3159 resolved (e->tok, e->type);
3160 }
2b066ec1
FCE
3161}
3162
3163
2b066ec1
FCE
3164void
3165typeresolution_info::visit_assignment (assignment *e)
3166{
553d27a5
FCE
3167 if (t == pe_stats)
3168 invalid (e->tok, t);
2b066ec1 3169
2b066ec1
FCE
3170 if (e->op == "<<<") // stats aggregation
3171 {
553d27a5
FCE
3172 if (t == pe_string)
3173 invalid (e->tok, t);
3174
2b066ec1
FCE
3175 t = pe_stats;
3176 e->left->visit (this);
3177 t = pe_long;
3178 e->right->visit (this);
57b73400
GH
3179 if (e->type == pe_unknown ||
3180 e->type == pe_stats)
2b066ec1
FCE
3181 {
3182 e->type = pe_long;
3183 resolved (e->tok, e->type);
3184 }
3185 }
57b73400
GH
3186
3187 else if (e->left->type == pe_stats)
3188 invalid (e->left->tok, e->left->type);
3189
3190 else if (e->right->type == pe_stats)
3191 invalid (e->right->tok, e->right->type);
3192
553d27a5 3193 else if (e->op == "+=" || // numeric only
d5d7c2cc
FCE
3194 e->op == "-=" ||
3195 e->op == "*=" ||
3196 e->op == "/=" ||
3197 e->op == "%=" ||
3198 e->op == "&=" ||
3199 e->op == "^=" ||
3200 e->op == "|=" ||
3201 e->op == "<<=" ||
3202 e->op == ">>=" ||
553d27a5 3203 false)
2b066ec1 3204 {
553d27a5 3205 visit_binary_expression (e);
2b066ec1 3206 }
d5d7c2cc
FCE
3207 else if (e->op == ".=" || // string only
3208 false)
3209 {
3210 if (t == pe_long || t == pe_stats)
3211 invalid (e->tok, t);
3212
3213 t = pe_string;
3214 e->left->visit (this);
3215 t = pe_string;
3216 e->right->visit (this);
3217 if (e->type == pe_unknown)
3218 {
3219 e->type = pe_string;
3220 resolved (e->tok, e->type);
3221 }
3222 }
3223 else if (e->op == "=") // overloaded = for string & numeric operands
2b066ec1 3224 {
553d27a5 3225 // logic similar to ternary_expression
2b066ec1 3226 exp_type sub_type = t;
553d27a5
FCE
3227
3228 // Infer types across the l/r values
3229 if (sub_type == pe_unknown && e->type != pe_unknown)
2b066ec1 3230 sub_type = e->type;
553d27a5
FCE
3231
3232 t = (sub_type != pe_unknown) ? sub_type :
3233 (e->right->type != pe_unknown) ? e->right->type :
3234 pe_unknown;
2b066ec1 3235 e->left->visit (this);
553d27a5
FCE
3236 t = (sub_type != pe_unknown) ? sub_type :
3237 (e->left->type != pe_unknown) ? e->left->type :
3238 pe_unknown;
2b066ec1 3239 e->right->visit (this);
57148ee7 3240
553d27a5 3241 if ((sub_type != pe_unknown) && (e->type == pe_unknown))
2b066ec1
FCE
3242 {
3243 e->type = sub_type;
3244 resolved (e->tok, e->type);
3245 }
553d27a5 3246 if ((sub_type == pe_unknown) && (e->left->type != pe_unknown))
2b066ec1
FCE
3247 {
3248 e->type = e->left->type;
3249 resolved (e->tok, e->type);
3250 }
553d27a5
FCE
3251
3252 if (e->left->type != pe_unknown &&
3253 e->right->type != pe_unknown &&
3254 e->left->type != e->right->type)
3255 mismatch (e->tok, e->left->type, e->right->type);
d02548c0 3256
553d27a5 3257 }
d5d7c2cc
FCE
3258 else
3259 throw semantic_error ("unsupported assignment operator " + e->op);
553d27a5
FCE
3260}
3261
3262
3263void
3264typeresolution_info::visit_binary_expression (binary_expression* e)
3265{
3266 if (t == pe_stats || t == pe_string)
3267 invalid (e->tok, t);
3268
3269 t = pe_long;
3270 e->left->visit (this);
3271 t = pe_long;
3272 e->right->visit (this);
3273
3274 if (e->left->type != pe_unknown &&
3275 e->right->type != pe_unknown &&
3276 e->left->type != e->right->type)
3277 mismatch (e->tok, e->left->type, e->right->type);
57148ee7 3278
553d27a5
FCE
3279 if (e->type == pe_unknown)
3280 {
3281 e->type = pe_long;
3282 resolved (e->tok, e->type);
2b066ec1
FCE
3283 }
3284}
3285
3286
3287void
3288typeresolution_info::visit_pre_crement (pre_crement *e)
3289{
3290 visit_unary_expression (e);
3291}
3292
3293
3294void
3295typeresolution_info::visit_post_crement (post_crement *e)
3296{
3297 visit_unary_expression (e);
3298}
3299
3300
3301void
3302typeresolution_info::visit_unary_expression (unary_expression* e)
3303{
553d27a5
FCE
3304 if (t == pe_stats || t == pe_string)
3305 invalid (e->tok, t);
3306
2b066ec1
FCE
3307 t = pe_long;
3308 e->operand->visit (this);
3309
553d27a5 3310 if (e->type == pe_unknown)
2b066ec1
FCE
3311 {
3312 e->type = pe_long;
3313 resolved (e->tok, e->type);
3314 }
3315}
3316
3317
2b066ec1
FCE
3318void
3319typeresolution_info::visit_ternary_expression (ternary_expression* e)
3320{
3321 exp_type sub_type = t;
3322
3323 t = pe_long;
3324 e->cond->visit (this);
3325
553d27a5 3326 // Infer types across the true/false arms of the ternary expression.
2b066ec1
FCE
3327
3328 if (sub_type == pe_unknown && e->type != pe_unknown)
3329 sub_type = e->type;
3330 t = sub_type;
3331 e->truevalue->visit (this);
3332 t = sub_type;
3333 e->falsevalue->visit (this);
3334
3335 if ((sub_type == pe_unknown) && (e->type != pe_unknown))
3336 ; // already resolved
3337 else if ((sub_type != pe_unknown) && (e->type == pe_unknown))
3338 {
3339 e->type = sub_type;
3340 resolved (e->tok, e->type);
3341 }
3342 else if ((sub_type == pe_unknown) && (e->truevalue->type != pe_unknown))
3343 {
3344 e->type = e->truevalue->type;
3345 resolved (e->tok, e->type);
3346 }
3347 else if ((sub_type == pe_unknown) && (e->falsevalue->type != pe_unknown))
3348 {
3349 e->type = e->falsevalue->type;
3350 resolved (e->tok, e->type);
3351 }
3352 else if (e->type != sub_type)
3353 mismatch (e->tok, sub_type, e->type);
3354}
3355
3356
3357template <class Referrer, class Referent>
3358void resolve_2types (Referrer* referrer, Referent* referent,
31966088 3359 typeresolution_info* r, exp_type t, bool accept_unknown = false)
2b066ec1
FCE
3360{
3361 exp_type& re_type = referrer->type;
3362 const token* re_tok = referrer->tok;
3363 exp_type& te_type = referent->type;
3364 const token* te_tok = referent->tok;
3365
3366 if (t != pe_unknown && re_type == t && re_type == te_type)
3367 ; // do nothing: all three e->types in agreement
3368 else if (t == pe_unknown && re_type != pe_unknown && re_type == te_type)
3369 ; // do nothing: two known e->types in agreement
3370 else if (re_type != pe_unknown && te_type != pe_unknown && re_type != te_type)
3371 r->mismatch (re_tok, re_type, te_type);
3372 else if (re_type != pe_unknown && t != pe_unknown && re_type != t)
3373 r->mismatch (re_tok, re_type, t);
3374 else if (te_type != pe_unknown && t != pe_unknown && te_type != t)
3375 r->mismatch (te_tok, te_type, t);
3376 else if (re_type == pe_unknown && t != pe_unknown)
3377 {
3378 // propagate from upstream
3379 re_type = t;
3380 r->resolved (re_tok, re_type);
3381 // catch re_type/te_type mismatch later
3382 }
3383 else if (re_type == pe_unknown && te_type != pe_unknown)
3384 {
3385 // propagate from referent
3386 re_type = te_type;
3387 r->resolved (re_tok, re_type);
3388 // catch re_type/t mismatch later
3389 }
3390 else if (re_type != pe_unknown && te_type == pe_unknown)
3391 {
3392 // propagate to referent
3393 te_type = re_type;
3394 r->resolved (te_tok, te_type);
3395 // catch re_type/t mismatch later
3396 }
31966088 3397 else if (! accept_unknown)
2b066ec1
FCE
3398 r->unresolved (re_tok);
3399}
3400
3401
3402void
3403typeresolution_info::visit_symbol (symbol* e)
3404{
3405 assert (e->referent != 0);
d02548c0 3406 resolve_2types (e, e->referent, this, t);
2b066ec1
FCE
3407}
3408
3409
d7f3e0c5
GH
3410void
3411typeresolution_info::visit_target_symbol (target_symbol* e)
3412{
cbfbbf69
FCE
3413 // This occurs only if a target symbol was not resolved over in
3414 // tapset.cxx land, that error was properly suppressed, and the
3415 // later unused-expression-elimination pass didn't get rid of it
3416 // either. So we have a target symbol that is believed to be of
3417 // genuine use, yet unresolved by the provider.
ba6f838d
FCE
3418
3419 if (session.verbose > 2)
3420 {
3421 clog << "Resolution problem with ";
3422 if (current_function)
3423 {
3424 clog << "function " << current_function->name << endl;
3425 current_function->body->print (clog);
3426 clog << endl;
3427 }
3428 else if (current_probe)
3429 {
3430 clog << "probe " << current_probe->name << endl;
3431 current_probe->body->print (clog);
3432 clog << endl;
3433 }
57148ee7 3434 else
ba6f838d
FCE
3435 clog << "other" << endl;
3436 }
3437
9b48ce88
FCE
3438 if (e->saved_conversion_error)
3439 throw (* (e->saved_conversion_error));
3440 else
3441 throw semantic_error("unresolved target-symbol expression", e->tok);
d7f3e0c5
GH
3442}
3443
3444
2b066ec1
FCE
3445void
3446typeresolution_info::visit_arrayindex (arrayindex* e)
3447{
2b066ec1 3448
d02548c0
GH
3449 symbol *array = NULL;
3450 hist_op *hist = NULL;
3451 classify_indexable(e->base, array, hist);
57148ee7 3452
d02548c0
GH
3453 // Every hist_op has type [int]:int, that is to say, every hist_op
3454 // is a pseudo-one-dimensional integer array type indexed by
3455 // integers (bucket numbers).
3456
3457 if (hist)
3458 {
3459 if (e->indexes.size() != 1)
3460 unresolved (e->tok);
3461 t = pe_long;
3462 e->indexes[0]->visit (this);
3463 if (e->indexes[0]->type != pe_long)
3464 unresolved (e->tok);
a4636912 3465 hist->visit (this);
1bbeef03
GH
3466 if (e->type != pe_long)
3467 {
3468 e->type = pe_long;
3469 resolved (e->tok, pe_long);
3470 }
d02548c0
GH
3471 return;
3472 }
3473
3474 // Now we are left with "normal" map inference and index checking.
3475
3476 assert (array);
3477 assert (array->referent != 0);
3478 resolve_2types (e, array->referent, this, t);
2b066ec1
FCE
3479
3480 // now resolve the array indexes
69c68955
FCE
3481
3482 // if (e->referent->index_types.size() == 0)
3483 // // redesignate referent as array
3484 // e->referent->set_arity (e->indexes.size ());
2b066ec1 3485
d02548c0 3486 if (e->indexes.size() != array->referent->index_types.size())
2b066ec1
FCE
3487 unresolved (e->tok); // symbol resolution should prevent this
3488 else for (unsigned i=0; i<e->indexes.size(); i++)
3489 {
3490 expression* ee = e->indexes[i];
d02548c0 3491 exp_type& ft = array->referent->index_types [i];
2b066ec1
FCE
3492 t = ft;
3493 ee->visit (this);
3494 exp_type at = ee->type;
3495
3496 if ((at == pe_string || at == pe_long) && ft == pe_unknown)
3497 {
3498 // propagate to formal type
3499 ft = at;
d02548c0 3500 resolved (array->referent->tok, ft);
2b066ec1
FCE
3501 // uses array decl as there is no token for "formal type"
3502 }
3503 if (at == pe_stats)
3504 invalid (ee->tok, at);
3505 if (ft == pe_stats)
3506 invalid (ee->tok, ft);
3507 if (at != pe_unknown && ft != pe_unknown && ft != at)
3508 mismatch (e->tok, at, ft);
3509 if (at == pe_unknown)
313b2f74 3510 unresolved (ee->tok);
2b066ec1
FCE
3511 }
3512}
3513
3514
3515void
3516typeresolution_info::visit_functioncall (functioncall* e)
3517{
3518 assert (e->referent != 0);
3519
57148ee7 3520 resolve_2types (e, e->referent, this, t, true); // accept unknown type
2b066ec1
FCE
3521
3522 if (e->type == pe_stats)
3523 invalid (e->tok, e->type);
3524
2b066ec1
FCE
3525 // now resolve the function parameters
3526 if (e->args.size() != e->referent->formal_args.size())
3527 unresolved (e->tok); // symbol resolution should prevent this
3528 else for (unsigned i=0; i<e->args.size(); i++)
3529 {
3530 expression* ee = e->args[i];
3531 exp_type& ft = e->referent->formal_args[i]->type;
3532 const token* fe_tok = e->referent->formal_args[i]->tok;
3533 t = ft;
3534 ee->visit (this);
3535 exp_type at = ee->type;
57148ee7 3536
2b066ec1
FCE
3537 if (((at == pe_string) || (at == pe_long)) && ft == pe_unknown)
3538 {
3539 // propagate to formal arg
3540 ft = at;
3541 resolved (e->referent->formal_args[i]->tok, ft);
3542 }
3543 if (at == pe_stats)
3544 invalid (e->tok, at);
3545 if (ft == pe_stats)
3546 invalid (fe_tok, ft);
3547 if (at != pe_unknown && ft != pe_unknown && ft != at)
3548 mismatch (e->tok, at, ft);
3549 if (at == pe_unknown)
3550 unresolved (e->tok);
3551 }
3552}
3553
3554
3555void
3556typeresolution_info::visit_block (block* e)
3557{
3558 for (unsigned i=0; i<e->statements.size(); i++)
3559 {
57148ee7 3560 try
2b066ec1
FCE
3561 {
3562 t = pe_unknown;
3563 e->statements[i]->visit (this);
3564 }
3565 catch (const semantic_error& e)
3566 {
3567 session.print_error (e);
3568 }
3569 }
3570}
3571
3572
54dfabe9 3573void
78f6bba6 3574typeresolution_info::visit_embeddedcode (embeddedcode*)
54dfabe9
FCE
3575{
3576}
3577
3578
2b066ec1
FCE
3579void
3580typeresolution_info::visit_if_statement (if_statement* e)
3581{
3582 t = pe_long;
3583 e->condition->visit (this);
3584
3585 t = pe_unknown;
3586 e->thenblock->visit (this);
3587
3588 if (e->elseblock)
3589 {
3590 t = pe_unknown;
3591 e->elseblock->visit (this);
3592 }
3593}
3594
3595
3596void
3597typeresolution_info::visit_for_loop (for_loop* e)
3598{
3599 t = pe_unknown;
cbfbbf69 3600 if (e->init) e->init->visit (this);
2b066ec1
FCE
3601 t = pe_long;
3602 e->cond->visit (this);
3603 t = pe_unknown;
57148ee7 3604 if (e->incr) e->incr->visit (this);
2b066ec1 3605 t = pe_unknown;
57148ee7 3606 e->block->visit (this);
2b066ec1
FCE
3607}
3608
3609
69c68955
FCE
3610void
3611typeresolution_info::visit_foreach_loop (foreach_loop* e)
3612{
3613 // See also visit_arrayindex.
3614 // This is different in that, being a statement, we can't assign
3615 // a type to the outer array, only propagate to/from the indexes
3616
3617 // if (e->referent->index_types.size() == 0)
3618 // // redesignate referent as array
3619 // e->referent->set_arity (e->indexes.size ());
3620
d02548c0
GH
3621 symbol *array = NULL;
3622 hist_op *hist = NULL;
3623 classify_indexable(e->base, array, hist);
69c68955 3624
d02548c0 3625 if (hist)
57148ee7 3626 {
d02548c0
GH
3627 if (e->indexes.size() != 1)
3628 unresolved (e->tok);
3629 t = pe_long;
3630 e->indexes[0]->visit (this);
3631 if (e->indexes[0]->type != pe_long)
3632 unresolved (e->tok);
a4636912 3633 hist->visit (this);
d02548c0
GH
3634 }
3635 else
3636 {
57148ee7 3637 assert (array);
d02548c0
GH
3638 if (e->indexes.size() != array->referent->index_types.size())
3639 unresolved (e->tok); // symbol resolution should prevent this
3640 else for (unsigned i=0; i<e->indexes.size(); i++)
3641 {
3642 expression* ee = e->indexes[i];
3643 exp_type& ft = array->referent->index_types [i];
3644 t = ft;
3645 ee->visit (this);
3646 exp_type at = ee->type;
57148ee7 3647
d02548c0
GH
3648 if ((at == pe_string || at == pe_long) && ft == pe_unknown)
3649 {
3650 // propagate to formal type
3651 ft = at;
3652 resolved (array->referent->tok, ft);
3653 // uses array decl as there is no token for "formal type"
3654 }
3655 if (at == pe_stats)
3656 invalid (ee->tok, at);
3657 if (ft == pe_stats)
3658 invalid (ee->tok, ft);
3659 if (at != pe_unknown && ft != pe_unknown && ft != at)
3660 mismatch (e->tok, at, ft);
3661 if (at == pe_unknown)
3662 unresolved (ee->tok);
3663 }
69c68955
FCE
3664 }
3665
27f21e8c
DS
3666 if (e->limit)
3667 {
3668 t = pe_long;
3669 e->limit->visit (this);
3670 }
3671
69c68955 3672 t = pe_unknown;
57148ee7 3673 e->block->visit (this);
69c68955
FCE
3674}
3675
3676
2b066ec1 3677void
78f6bba6 3678typeresolution_info::visit_null_statement (null_statement*)
2b066ec1
FCE
3679{
3680}
3681
3682
3683void
3684typeresolution_info::visit_expr_statement (expr_statement* e)
3685{
3686 t = pe_unknown;
3687 e->value->visit (this);
3688}
3689
3690
57148ee7 3691struct delete_statement_typeresolution_info:
d98d459c
GH
3692 public throwing_visitor
3693{
3694 typeresolution_info *parent;
3695 delete_statement_typeresolution_info (typeresolution_info *p):
3696 throwing_visitor ("invalid operand of delete expression"),
3697 parent (p)
3698 {}
3699
3700 void visit_arrayindex (arrayindex* e)
3701 {
3702 parent->visit_arrayindex (e);
3703 }
57148ee7 3704
d98d459c
GH
3705 void visit_symbol (symbol* e)
3706 {
3707 exp_type ignored = pe_unknown;
57148ee7 3708 assert (e->referent != 0);
d98d459c
GH
3709 resolve_2types (e, e->referent, parent, ignored);
3710 }
3711};
3712
3713
2b066ec1
FCE
3714void
3715typeresolution_info::visit_delete_statement (delete_statement* e)
3716{
d98d459c
GH
3717 delete_statement_typeresolution_info di (this);
3718 t = pe_unknown;
3719 e->value->visit (&di);
2b066ec1
FCE
3720}
3721
3722
f3c26ea5 3723void
78f6bba6 3724typeresolution_info::visit_next_statement (next_statement*)
f3c26ea5
FCE
3725{
3726}
3727
3728
3729void
78f6bba6 3730typeresolution_info::visit_break_statement (break_statement*)
f3c26ea5
FCE
3731{
3732}
3733
3734
3735void
78f6bba6 3736typeresolution_info::visit_continue_statement (continue_statement*)
f3c26ea5
FCE
3737{
3738}
3739
3740
2b066ec1
FCE
3741void
3742typeresolution_info::visit_array_in (array_in* e)
3743{
ce10591c
FCE
3744 // all unary operators only work on numerics
3745 exp_type t1 = t;
3746 t = pe_unknown; // array value can be anything
3747 e->operand->visit (this);
3748
3749 if (t1 == pe_unknown && e->type != pe_unknown)
3750 ; // already resolved
3751 else if (t1 == pe_string || t1 == pe_stats)
3752 mismatch (e->tok, t1, pe_long);
3753 else if (e->type == pe_unknown)
3754 {
3755 e->type = pe_long;
3756 resolved (e->tok, e->type);
3757 }
2b066ec1
FCE
3758}
3759
3760
3761void
3762typeresolution_info::visit_return_statement (return_statement* e)
3763{
3764 // This is like symbol, where the referent is
3765 // the return value of the function.
3766
57148ee7 3767 // translation pass will print error
2b066ec1 3768 if (current_function == 0)
22f46231 3769 return;
2b066ec1
FCE
3770
3771 exp_type& e_type = current_function->type;
3772 t = current_function->type;
3773 e->value->visit (this);
3774
3775 if (e_type != pe_unknown && e->value->type != pe_unknown
3776 && e_type != e->value->type)
3777 mismatch (current_function->tok, e_type, e->value->type);
57148ee7 3778 if (e_type == pe_unknown &&
2b066ec1
FCE
3779 (e->value->type == pe_long || e->value->type == pe_string))
3780 {
3781 // propagate non-statistics from value
3782 e_type = e->value->type;
3783 resolved (current_function->tok, e->value->type);
3784 }
3785 if (e->value->type == pe_stats)
3786 invalid (e->value->tok, e->value->type);
3787}
3788
57148ee7 3789void
d02548c0
GH
3790typeresolution_info::visit_print_format (print_format* e)
3791{
3792 size_t unresolved_args = 0;
3793
1bbeef03
GH
3794 if (e->hist)
3795 {
3796 e->hist->visit(this);
3797 }
3798
3799 else if (e->print_with_format)
d02548c0
GH
3800 {
3801 // If there's a format string, we can do both inference *and*
3802 // checking.
3803
3804 // First we extract the subsequence of formatting components
3805 // which are conversions (not just literal string components)
3806
34201621 3807 unsigned expected_num_args = 0;
d02548c0
GH
3808 std::vector<print_format::format_component> components;
3809 for (size_t i = 0; i < e->components.size(); ++i)
3810 {
3811 if (e->components[i].type == print_format::conv_unspecified)
3812 throw semantic_error ("Unspecified conversion in print operator format string",
3813 e->tok);
b5852334 3814 else if (e->components[i].type == print_format::conv_literal)
d02548c0
GH
3815 continue;
3816 components.push_back(e->components[i]);
34201621
DB
3817 ++expected_num_args;
3818 if (e->components[i].widthtype == print_format::width_dynamic)
3819 ++expected_num_args;
3820 if (e->components[i].prectype == print_format::prec_dynamic)
3821 ++expected_num_args;
d02548c0
GH
3822 }
3823
3824 // Then we check that the number of conversions and the number
3825 // of args agree.
3826
34201621 3827 if (expected_num_args != e->args.size())
d02548c0
GH
3828 throw semantic_error ("Wrong number of args to formatted print operator",
3829 e->tok);
3830
3831 // Then we check that the types of the conversions match the types
3832 // of the args.
34201621 3833 unsigned argno = 0;
d02548c0
GH
3834 for (size_t i = 0; i < components.size(); ++i)
3835 {
34201621
DB
3836 // Check the dynamic width, if specified
3837 if (components[i].widthtype == print_format::width_dynamic)
3838 {
3839 check_arg_type (pe_long, e->args[argno]);
3840 ++argno;
3841 }
3842
3843 // Check the dynamic precision, if specified
3844 if (components[i].prectype == print_format::prec_dynamic)
3845 {
3846 check_arg_type (pe_long, e->args[argno]);
3847 ++argno;
3848 }
3849
d02548c0
GH
3850 exp_type wanted = pe_unknown;
3851
3852 switch (components[i].type)
3853 {
d02548c0
GH
3854 case print_format::conv_unspecified:
3855 case print_format::conv_literal:
3856 assert (false);
3857 break;
3858
3859 case print_format::conv_signed_decimal:
3860 case print_format::conv_unsigned_decimal:
3861 case print_format::conv_unsigned_octal:
58cf0567 3862 case print_format::conv_unsigned_ptr:
d02548c0
GH
3863 case print_format::conv_unsigned_uppercase_hex:
3864 case print_format::conv_unsigned_lowercase_hex:
dc0b623a 3865 case print_format::conv_binary:
fecccf83 3866 case print_format::conv_char:
ec03bd4b 3867 case print_format::conv_memory:
30c94a80 3868 case print_format::conv_memory_hex:
d02548c0
GH
3869 wanted = pe_long;
3870 break;
3871
3872 case print_format::conv_string:
3873 wanted = pe_string;
3874 break;
3875 }
3876
3877 assert (wanted != pe_unknown);
34201621
DB
3878 check_arg_type (wanted, e->args[argno]);
3879 ++argno;
d02548c0
GH
3880 }
3881 }
3882 else
3883 {
3884 // Without a format string, the best we can do is require that
3885 // each argument resolve to a concrete type.
3886 for (size_t i = 0; i < e->args.size(); ++i)
3887 {
3888 t = pe_unknown;
3889 e->args[i]->visit (this);
3890 if (e->args[i]->type == pe_unknown)
3891 {
3892 unresolved (e->args[i]->tok);
3893 ++unresolved_args;
3894 }
3895 }
3896 }
57148ee7 3897
d02548c0
GH
3898 if (unresolved_args == 0)
3899 {
3900 if (e->type == pe_unknown)
3901 {
3902 if (e->print_to_stream)
3903 e->type = pe_long;
3904 else
57148ee7 3905 e->type = pe_string;
d02548c0
GH
3906 resolved (e->tok, e->type);
3907 }
3908 }
3909 else
3910 {
3911 e->type = pe_unknown;
3912 unresolved (e->tok);
3913 }
3914}
3915
3916
57148ee7 3917void
d02548c0
GH
3918typeresolution_info::visit_stat_op (stat_op* e)
3919{
3920 t = pe_stats;
3921 e->stat->visit (this);
3922 if (e->type == pe_unknown)
3923 {
3924 e->type = pe_long;
3925 resolved (e->tok, e->type);
3926 }
07c17d67 3927 else if (e->type != pe_long)
d02548c0
GH
3928 mismatch (e->tok, e->type, pe_long);
3929}
3930
57148ee7 3931void
d02548c0
GH
3932typeresolution_info::visit_hist_op (hist_op* e)
3933{
3934 t = pe_stats;
3935 e->stat->visit (this);
3936}
3937
2b066ec1 3938
34201621
DB
3939void
3940typeresolution_info::check_arg_type (exp_type wanted, expression* arg)
3941{
3942 t = wanted;
3943 arg->visit (this);
3944
3945 if (arg->type == pe_unknown)
3946 {
3947 arg->type = wanted;
3948 resolved (arg->tok, wanted);
3949 }
3950 else if (arg->type != wanted)
3951 {
3952 mismatch (arg->tok, arg->type, wanted);
3953 }
3954}
3955
3956
2b066ec1
FCE
3957void
3958typeresolution_info::unresolved (const token* tok)
3959{
3960 num_still_unresolved ++;
3961
3962 if (assert_resolvability)
3963 {
6c543717 3964 stringstream msg;
bdef2583
FCE
3965 string nm = (current_function ? current_function->name :
3966 current_probe ? current_probe->name :
5d23847d 3967 "probe condition");
6c543717
FCE
3968 msg << nm + " with unresolved type";
3969 session.print_error (semantic_error (msg.str(), tok));
2b066ec1
FCE
3970 }
3971}
3972
3973
3974void
3975typeresolution_info::invalid (const token* tok, exp_type pe)
3976{
3977 num_still_unresolved ++;
3978
3979 if (assert_resolvability)
3980 {
6c543717 3981 stringstream msg;
bdef2583
FCE
3982 string nm = (current_function ? current_function->name :
3983 current_probe ? current_probe->name :
5d23847d 3984 "probe condition");
022b623f 3985 if (tok && tok->type == tok_operator)
6c543717 3986 msg << nm + " uses invalid operator";
2b066ec1 3987 else
6c543717
FCE
3988 msg << nm + " with invalid type " << pe;
3989 session.print_error (semantic_error (msg.str(), tok));
2b066ec1
FCE
3990 }
3991}
3992
3993
3994void
3995typeresolution_info::mismatch (const token* tok, exp_type t1, exp_type t2)
3996{
3997 num_still_unresolved ++;
3998
3999 if (assert_resolvability)
4000 {
6c543717 4001 stringstream msg;
bdef2583
FCE
4002 string nm = (current_function ? current_function->name :
4003 current_probe ? current_probe->name :
5d23847d 4004 "probe condition");
6c543717
FCE
4005 msg << nm + " with type mismatch (" << t1 << " vs. " << t2 << ")";
4006 session.print_error (semantic_error (msg.str(), tok));
2b066ec1
FCE
4007 }
4008}
4009
4010
4011void
78f6bba6 4012typeresolution_info::resolved (const token*, exp_type)
2b066ec1
FCE
4013{
4014 num_newly_resolved ++;
2b066ec1
FCE
4015}
4016
73267b89 4017/* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
This page took 0.574689 seconds and 5 git commands to generate.