mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 06:38:20 +00:00
"-O validate-ZAM" option to validate generated ZAM instructions
This commit is contained in:
parent
db22448270
commit
1457099df3
7 changed files with 134 additions and 5 deletions
|
@ -446,6 +446,7 @@ set(MAIN_SRCS
|
||||||
script_opt/ZAM/Profile.cc
|
script_opt/ZAM/Profile.cc
|
||||||
script_opt/ZAM/Stmt.cc
|
script_opt/ZAM/Stmt.cc
|
||||||
script_opt/ZAM/Support.cc
|
script_opt/ZAM/Support.cc
|
||||||
|
script_opt/ZAM/Validate.cc
|
||||||
script_opt/ZAM/Vars.cc
|
script_opt/ZAM/Vars.cc
|
||||||
script_opt/ZAM/ZBody.cc
|
script_opt/ZAM/ZBody.cc
|
||||||
script_opt/ZAM/ZInst.cc
|
script_opt/ZAM/ZInst.cc
|
||||||
|
|
|
@ -194,6 +194,7 @@ static void print_analysis_help() {
|
||||||
fprintf(stderr, " optimize-AST optimize the (transformed) AST; implies xform\n");
|
fprintf(stderr, " optimize-AST optimize the (transformed) AST; implies xform\n");
|
||||||
fprintf(stderr, " profile-ZAM generate to zprof.out a ZAM execution profile; implies -O ZAM\n");
|
fprintf(stderr, " profile-ZAM generate to zprof.out a ZAM execution profile; implies -O ZAM\n");
|
||||||
fprintf(stderr, " report-recursive report on recursive functions and exit\n");
|
fprintf(stderr, " report-recursive report on recursive functions and exit\n");
|
||||||
|
fprintf(stderr, " validate-ZAM perform internal assessment of synthesized ZAM instructions and exit\n");
|
||||||
fprintf(stderr, " xform transform scripts to \"reduced\" form\n");
|
fprintf(stderr, " xform transform scripts to \"reduced\" form\n");
|
||||||
|
|
||||||
fprintf(stderr, "\n--optimize options when generating C++:\n");
|
fprintf(stderr, "\n--optimize options when generating C++:\n");
|
||||||
|
@ -220,14 +221,14 @@ static void set_analysis_option(const char* opt, Options& opts) {
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( util::streq(opt, "dump-uds") )
|
if ( util::streq(opt, "allow-cond") )
|
||||||
|
a_o.allow_cond = true;
|
||||||
|
else if ( util::streq(opt, "dump-uds") )
|
||||||
a_o.activate = a_o.dump_uds = true;
|
a_o.activate = a_o.dump_uds = true;
|
||||||
else if ( util::streq(opt, "dump-xform") )
|
else if ( util::streq(opt, "dump-xform") )
|
||||||
a_o.activate = a_o.dump_xform = true;
|
a_o.activate = a_o.dump_xform = true;
|
||||||
else if ( util::streq(opt, "dump-ZAM") )
|
else if ( util::streq(opt, "dump-ZAM") )
|
||||||
a_o.activate = a_o.dump_ZAM = true;
|
a_o.activate = a_o.dump_ZAM = true;
|
||||||
else if ( util::streq(opt, "allow-cond") )
|
|
||||||
a_o.allow_cond = true;
|
|
||||||
else if ( util::streq(opt, "gen-C++") )
|
else if ( util::streq(opt, "gen-C++") )
|
||||||
a_o.gen_CPP = true;
|
a_o.gen_CPP = true;
|
||||||
else if ( util::streq(opt, "gen-standalone-C++") )
|
else if ( util::streq(opt, "gen-standalone-C++") )
|
||||||
|
@ -254,6 +255,8 @@ static void set_analysis_option(const char* opt, Options& opts) {
|
||||||
a_o.report_uncompilable = true;
|
a_o.report_uncompilable = true;
|
||||||
else if ( util::streq(opt, "use-C++") )
|
else if ( util::streq(opt, "use-C++") )
|
||||||
a_o.use_CPP = true;
|
a_o.use_CPP = true;
|
||||||
|
else if ( util::streq(opt, "validate-ZAM") )
|
||||||
|
a_o.validate_ZAM = true;
|
||||||
else if ( util::streq(opt, "xform") )
|
else if ( util::streq(opt, "xform") )
|
||||||
a_o.activate = true;
|
a_o.activate = true;
|
||||||
|
|
||||||
|
|
|
@ -558,6 +558,11 @@ void clear_script_analysis() {
|
||||||
void analyze_scripts(bool no_unused_warnings) {
|
void analyze_scripts(bool no_unused_warnings) {
|
||||||
init_options();
|
init_options();
|
||||||
|
|
||||||
|
if ( analysis_options.validate_ZAM ) {
|
||||||
|
validate_ZAM_insts();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Any standalone compiled scripts have already been instantiated
|
// Any standalone compiled scripts have already been instantiated
|
||||||
// at this point, but may require post-loading-of-scripts finalization.
|
// at this point, but may require post-loading-of-scripts finalization.
|
||||||
for ( auto cb : standalone_finalizations )
|
for ( auto cb : standalone_finalizations )
|
||||||
|
|
|
@ -61,6 +61,10 @@ struct AnalyOpt {
|
||||||
// recursive, and exit. Only germane if running the inliner.
|
// recursive, and exit. Only germane if running the inliner.
|
||||||
bool report_recursive = false;
|
bool report_recursive = false;
|
||||||
|
|
||||||
|
// If true, assess the instructions generated from ZAM templates
|
||||||
|
// for validity, and exit.
|
||||||
|
bool validate_ZAM = false;
|
||||||
|
|
||||||
// If true, generate ZAM code for applicable function bodies,
|
// If true, generate ZAM code for applicable function bodies,
|
||||||
// activating all optimizations.
|
// activating all optimizations.
|
||||||
bool gen_ZAM = false;
|
bool gen_ZAM = false;
|
||||||
|
@ -244,6 +248,11 @@ extern bool should_analyze(const ScriptFuncPtr& f, const StmtPtr& body);
|
||||||
// suppressed by the flag) and optimization.
|
// suppressed by the flag) and optimization.
|
||||||
extern void analyze_scripts(bool no_unused_warnings);
|
extern void analyze_scripts(bool no_unused_warnings);
|
||||||
|
|
||||||
|
// Conduct internal validation of ZAM instructions. Upon success, generates
|
||||||
|
// a terse report to stdout. Exits with an internal error if a problem is
|
||||||
|
// encountered.
|
||||||
|
extern void validate_ZAM_insts();
|
||||||
|
|
||||||
// Called when all script processing is complete and we can discard
|
// Called when all script processing is complete and we can discard
|
||||||
// unused ASTs and associated state.
|
// unused ASTs and associated state.
|
||||||
extern void clear_script_analysis();
|
extern void clear_script_analysis();
|
||||||
|
|
|
@ -100,6 +100,7 @@ issues:
|
||||||
|`profile-ZAM` | Generate to "zprof.out" a ZAM execution profile. (Requires configuring with `--enable-ZAM-profiling` or `--enable-debug`.)|
|
|`profile-ZAM` | Generate to "zprof.out" a ZAM execution profile. (Requires configuring with `--enable-ZAM-profiling` or `--enable-debug`.)|
|
||||||
|`report-recursive` | Report on recursive functions and exit.|
|
|`report-recursive` | Report on recursive functions and exit.|
|
||||||
|`report-uncompilable` | Report on uncompilable functions and exit. For ZAM, all functions should be compilable.|
|
|`report-uncompilable` | Report on uncompilable functions and exit. For ZAM, all functions should be compilable.|
|
||||||
|
|`validate-ZAM` | Perform internal validation of ZAM instructions and exit.|
|
||||||
|`xform` | Transform scripts to "reduced" form.|
|
|`xform` | Transform scripts to "reduced" form.|
|
||||||
|
|
||||||
<a name="ZAM-profiling"></a>
|
<a name="ZAM-profiling"></a>
|
||||||
|
|
110
src/script_opt/ZAM/Validate.cc
Normal file
110
src/script_opt/ZAM/Validate.cc
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
// See the file "COPYING" in the main distribution directory for copyright.
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "zeek/script_opt/ZAM/ZBody.h"
|
||||||
|
#include "zeek/script_opt/ZAM/ZOp.h"
|
||||||
|
|
||||||
|
using std::string;
|
||||||
|
|
||||||
|
namespace zeek::detail {
|
||||||
|
|
||||||
|
std::unordered_map<ZOp, ZAMInstDesc> zam_inst_desc = {
|
||||||
|
|
||||||
|
#include "ZAM-Desc.h"
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// While the following has commonalities that could be factored out,
|
||||||
|
// for now we keep this form because it provides flexibility for
|
||||||
|
// accommodating other forms of accessors.
|
||||||
|
static std::map<char, string> type_pats = {
|
||||||
|
{'A', "Addr"}, {'a', "Any"}, {'D', "Double"}, {'F', "Func"}, {'I', "Int"}, {'L', "List"}, {'N', "SubNet"},
|
||||||
|
{'P', "Pattern"}, {'R', "Record"}, {'S', "String"}, {'T', "Table"}, {'t', "Type"}, {'U', "Count"}, {'V', "Vector"},
|
||||||
|
};
|
||||||
|
|
||||||
|
static int num_valid = 0;
|
||||||
|
static int num_tested = 0;
|
||||||
|
static int num_skipped = 0;
|
||||||
|
|
||||||
|
void analyze_ZAM_inst(const char* op_name, const ZAMInstDesc& zid) {
|
||||||
|
auto& oc = zid.op_class;
|
||||||
|
auto& ot = zid.op_types;
|
||||||
|
auto& eval = zid.op_eval;
|
||||||
|
|
||||||
|
bool have_ot = ! ot.empty();
|
||||||
|
|
||||||
|
if ( have_ot && oc.size() != ot.size() )
|
||||||
|
reporter->InternalError("%s: instruction class/types mismatch (%s/%s)", op_name, oc.c_str(), ot.c_str());
|
||||||
|
|
||||||
|
int nslot = 0;
|
||||||
|
|
||||||
|
for ( size_t i = 0; i < oc.size(); ++i ) {
|
||||||
|
auto oc_i = oc[i];
|
||||||
|
|
||||||
|
string op;
|
||||||
|
|
||||||
|
switch ( oc_i ) {
|
||||||
|
case 'V':
|
||||||
|
case 'R': op = "frame\\[z\\.v" + std::to_string(++nslot) + "\\]"; break;
|
||||||
|
|
||||||
|
case 'b':
|
||||||
|
case 'f':
|
||||||
|
case 'g':
|
||||||
|
case 's':
|
||||||
|
case 'i': op = "z\\.v" + std::to_string(++nslot); break;
|
||||||
|
|
||||||
|
case 'C': op = "z\\.c"; break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if ( have_ot && ot[i] != 'X' )
|
||||||
|
reporter->InternalError("instruction types mismatch: %s (%c)", op_name, oc_i);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto match_pat = op;
|
||||||
|
if ( have_ot ) {
|
||||||
|
auto ot_i = ot[i];
|
||||||
|
|
||||||
|
bool bare_int = std::string("bfgis").find(oc_i) != std::string::npos;
|
||||||
|
|
||||||
|
if ( ot_i == 'X' || bare_int ) {
|
||||||
|
if ( ot_i == 'X' && bare_int )
|
||||||
|
reporter->InternalError("empty instruction type for '%c' class element: %s", oc_i, op_name);
|
||||||
|
|
||||||
|
if ( ! std::regex_search(eval, std::regex(op)) )
|
||||||
|
reporter->InternalError("%s: operand %s not found", op_name, op.c_str());
|
||||||
|
|
||||||
|
++num_skipped;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto tp = type_pats.find(ot_i);
|
||||||
|
if ( tp == type_pats.end() )
|
||||||
|
reporter->InternalError("%s: instruction type %c not found", op_name, ot_i);
|
||||||
|
match_pat += ".As" + tp->second + "(Ref)?\\(\\)";
|
||||||
|
++num_tested;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! std::regex_search(eval, std::regex(match_pat)) )
|
||||||
|
reporter->InternalError("%s: did not find /%s/ in %s", op_name, match_pat.c_str(), eval.c_str());
|
||||||
|
}
|
||||||
|
++num_valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
void validate_ZAM_insts() {
|
||||||
|
// The following primes a data structure we access.
|
||||||
|
(void)AssignmentFlavor(OP_NOP, TYPE_VOID, false);
|
||||||
|
|
||||||
|
for ( int i = 0; i < int(OP_NOP); ++i ) {
|
||||||
|
auto zop = ZOp(i);
|
||||||
|
if ( zam_inst_desc.find(zop) == zam_inst_desc.end() && assignment_flavor.find(zop) == assignment_flavor.end() )
|
||||||
|
reporter->InternalError("op %s missing from description", ZOP_name(zop));
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( auto& zid : zam_inst_desc )
|
||||||
|
analyze_ZAM_inst(ZOP_name(zid.first), zid.second);
|
||||||
|
|
||||||
|
printf("%d valid, %d tested, %d skipped\n", num_valid, num_tested, num_skipped);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace zeek::detail
|
|
@ -917,8 +917,8 @@ SetupResult setup(int argc, char** argv, Options* zopts) {
|
||||||
|
|
||||||
analyze_scripts(options.no_unused_warnings);
|
analyze_scripts(options.no_unused_warnings);
|
||||||
|
|
||||||
if ( analysis_options.report_recursive ) {
|
if ( analysis_options.report_recursive || analysis_options.validate_ZAM ) {
|
||||||
// This option is report-and-exit.
|
// These options are report-and-exit.
|
||||||
early_shutdown();
|
early_shutdown();
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue