From 769a3d958a88708cf3c184e5a54c47a610191b87 Mon Sep 17 00:00:00 2001 From: Vern Paxson Date: Tue, 13 Aug 2024 14:29:26 -0700 Subject: [PATCH] some minor tidying of -O gen-C++ sources --- src/script_opt/CPP/Driver.cc | 7 ++--- src/script_opt/CPP/Exprs.cc | 2 +- src/script_opt/CPP/Func.h | 14 ++-------- src/script_opt/CPP/InitsInfo.h | 25 ++++++++++++------ src/script_opt/CPP/RuntimeOps.cc | 2 +- src/script_opt/CPP/RuntimeOps.h | 44 +++++++++++++++++++------------- src/script_opt/CPP/RuntimeVec.cc | 2 +- src/script_opt/CPP/Stmts.cc | 2 +- src/script_opt/ScriptOpt.cc | 4 ++- 9 files changed, 56 insertions(+), 46 deletions(-) diff --git a/src/script_opt/CPP/Driver.cc b/src/script_opt/CPP/Driver.cc index 3dc7e991fc..95061a1f7c 100644 --- a/src/script_opt/CPP/Driver.cc +++ b/src/script_opt/CPP/Driver.cc @@ -37,11 +37,12 @@ void CPPCompile::Compile(bool report_uncompilable) { // previously compiled instances of those if present. for ( auto& func : funcs ) { const auto& f = func.Func(); + auto& body = func.Body(); auto& ofiles = analysis_options.only_files; auto allow_cond = analysis_options.allow_cond; - string fn = func.Body()->GetLocationInfo()->filename; + string fn = body->GetLocationInfo()->filename; if ( ! allow_cond && ! func.ShouldSkip() && ! ofiles.empty() && files_with_conditionals.count(fn) > 0 ) { if ( report_uncompilable ) @@ -184,8 +185,8 @@ void CPPCompile::GenProlog() { Emit("namespace CPP_%s { // %s\n", Fmt(total_hash), string(working_dir)); // The following might-or-might-not wind up being populated/used. - Emit("std::vector field_mapping;"); - Emit("std::vector enum_mapping;"); + Emit("std::vector field_mapping;"); + Emit("std::vector enum_mapping;"); NL(); const_info[TYPE_BOOL] = CreateConstInitInfo("Bool", "ValPtr", "bool"); diff --git a/src/script_opt/CPP/Exprs.cc b/src/script_opt/CPP/Exprs.cc index 40eba322b6..9628801e48 100644 --- a/src/script_opt/CPP/Exprs.cc +++ b/src/script_opt/CPP/Exprs.cc @@ -1248,7 +1248,7 @@ string CPPCompile::GenEnum(const TypePtr& t, const ValPtr& ev) { if ( ! et->HasRedefs() ) // Can use direct access. - return std::to_string(v); + return "zeek_int_t(" + std::to_string(v) + ")"; // Need to dynamically map the access. int mapping_slot; diff --git a/src/script_opt/CPP/Func.h b/src/script_opt/CPP/Func.h index 5b37866783..4642c2fdaa 100644 --- a/src/script_opt/CPP/Func.h +++ b/src/script_opt/CPP/Func.h @@ -8,9 +8,7 @@ #include "zeek/Func.h" #include "zeek/script_opt/ProfileFunc.h" -namespace zeek { - -namespace detail { +namespace zeek::detail { // A subclass of Func used for lambdas that the compiler creates for // complex initializations (expressions used in type attributes). @@ -42,11 +40,6 @@ public: const std::string& Name() { return name; } - // Sets/returns a hash associated with this statement. A value - // of 0 means "not set". - p_hash_type GetHash() const { return hash; } - void SetHash(p_hash_type h) { hash = h; } - // The following only get defined by lambda bodies. virtual void SetLambdaCaptures(Frame* f) {} virtual std::vector SerializeLambdaCaptures() const { return std::vector{}; } @@ -64,7 +57,6 @@ protected: TraversalCode Traverse(TraversalCallback* cb) const override { return TC_CONTINUE; } std::string name; - p_hash_type hash = 0ULL; // A pseudo AST "call" node, used to support error localization. CallExprPtr ce; @@ -117,6 +109,4 @@ extern std::unordered_map standalone_callbacks; // Callbacks to finalize initialization of standalone compiled scripts. extern std::vector standalone_finalizations; -} // namespace detail - -} // namespace zeek +} // namespace zeek::detail diff --git a/src/script_opt/CPP/InitsInfo.h b/src/script_opt/CPP/InitsInfo.h index cbdaaf806d..c2bba9fbd6 100644 --- a/src/script_opt/CPP/InitsInfo.h +++ b/src/script_opt/CPP/InitsInfo.h @@ -18,7 +18,7 @@ // standalone globals (for example, one for each BiF that a compiled script // may call). // -// For each of these types of initialization, our general approach is to a +// For each of these types of initialization, our general approach is to have a // class that manages a single instance of that type, and an an object that // manages all of those instances collectively. The latter object will, for // example, attend to determining the offset into the run-time vector associated @@ -48,8 +48,15 @@ // safely use cohort(X) = cohort(Y).) We then execute run-time initialization // in waves, one cohort at a time. // +// Many forms of initialization are specified in terms of indices into globals +// that hold items of various types. Thus, the most common initialization +// information is a vector of integers/indices. These data structures can +// be recursive, too, namely we sometimes associate an index with a vector +// of integers/indices and then we can track multiple such vectors using +// another vector of integers/indices. +// // Because C++ compilers can struggle when trying to optimize large quantities -// of code - clang in particular could take many CPU *hours* back when our +// of code - clang in particular could take many CPU *hours* back when the // compiler just generated C++ code snippets for each initialization - rather // than producing code that directly executes each given initialization, we // instead employ a table-driven approach. The C++ initializers for the @@ -58,12 +65,14 @@ // cohort at a time) to obtain the information needed to initialize any given // item. // -// Many forms of initialization are specified in terms of indices into globals -// that hold items of various types. Thus, the most common initialization -// information is a vector of integers/indices. These data structures can -// be recursive, too, namely we sometimes associate an index with a vector -// of integers/indices and then we can track multiple such vectors using -// another vector of integers/indices. +// Even this has headaches for very large initializations: both clang and g++ +// are *much* slower to initialize large vectors of simple template types +// (such as std::pair) than non-template types (such as a struct with two +// fields, which is all std::pair is, at the end of the day). A similar problem +// holds for initializing vectors-of-vectors-of-vectors, so we reduce these +// cases to simpler forms (structs for the first example, a single vector +// with information embedded within it for how to expand its values into +// a vector-of-vector-of-vector fr the second). #include "zeek/File.h" #include "zeek/Val.h" diff --git a/src/script_opt/CPP/RuntimeOps.cc b/src/script_opt/CPP/RuntimeOps.cc index 680f4648cc..b6bfde35b8 100644 --- a/src/script_opt/CPP/RuntimeOps.cc +++ b/src/script_opt/CPP/RuntimeOps.cc @@ -91,7 +91,7 @@ ValPtr when_index_slice__CPP(VectorVal* vec, const ListVal* lv) { return v; } -ValPtr when_invoke__CPP(Func* f, std::vector args, Frame* frame, void* caller_addr) { +ValPtr when_invoke__CPP(Func* f, ValVec args, Frame* frame, void* caller_addr) { auto trigger = frame->GetTrigger(); if ( trigger ) { diff --git a/src/script_opt/CPP/RuntimeOps.h b/src/script_opt/CPP/RuntimeOps.h index 5ef5ba0efa..1722f4c9bc 100644 --- a/src/script_opt/CPP/RuntimeOps.h +++ b/src/script_opt/CPP/RuntimeOps.h @@ -10,6 +10,8 @@ namespace zeek { +using IntVec = std::vector; +using ValVec = std::vector; using SubNetValPtr = IntrusivePtr; namespace detail { @@ -27,21 +29,21 @@ extern bool str_in__CPP(const String* s1, const String* s2); // Converts a vector of individual ValPtr's into a single ListValPtr // suitable for indexing an aggregate. -extern ListValPtr index_val__CPP(std::vector indices); +extern ListValPtr index_val__CPP(ValVec indices); // Returns the value corresponding to indexing the given table/vector/string // with the given set of indices. These are functions rather than something // generated directly so that they can package up the error handling for // the case where there's no such index. "patstr" refers to indexing a // table[pattern] of X with a string value. -extern ValPtr index_table__CPP(const TableValPtr& t, std::vector indices); -extern ValPtr index_patstr_table__CPP(const TableValPtr& t, std::vector indices); +extern ValPtr index_table__CPP(const TableValPtr& t, ValVec indices); +extern ValPtr index_patstr_table__CPP(const TableValPtr& t, ValVec indices); extern ValPtr index_vec__CPP(const VectorValPtr& vec, int index); -extern ValPtr index_string__CPP(const StringValPtr& svp, std::vector indices); +extern ValPtr index_string__CPP(const StringValPtr& svp, ValVec indices); // The same, but for indexing happening inside a "when" clause. -extern ValPtr when_index_table__CPP(const TableValPtr& t, std::vector indices); -extern ValPtr when_index_patstr__CPP(const TableValPtr& t, std::vector indices); +extern ValPtr when_index_table__CPP(const TableValPtr& t, ValVec indices); +extern ValPtr when_index_patstr__CPP(const TableValPtr& t, ValVec indices); extern ValPtr when_index_vec__CPP(const VectorValPtr& vec, int index); // For vector slices, we use the existing index_slice(), but we need a @@ -50,7 +52,7 @@ extern ValPtr when_index_slice__CPP(VectorVal* vec, const ListVal* lv); // Calls out to the given script or BiF function, which does not return // a value. -inline ValPtr invoke_void__CPP(Func* f, std::vector args, Frame* frame) { return f->Invoke(&args, frame); } +inline ValPtr invoke_void__CPP(Func* f, ValVec args, Frame* frame) { return f->Invoke(&args, frame); } // Used for error propagation by failed calls. class CPPInterpreterException : public InterpreterException {}; @@ -58,7 +60,7 @@ class CPPInterpreterException : public InterpreterException {}; // Calls out to the given script or BiF function. A separate function because // of the need to (1) construct the "args" vector using {} initializers, // but (2) needing to have the address of that vector. -inline ValPtr invoke__CPP(Func* f, std::vector args, Frame* frame) { +inline ValPtr invoke__CPP(Func* f, ValVec args, Frame* frame) { auto v = f->Invoke(&args, frame); if ( ! v ) throw CPPInterpreterException(); @@ -71,7 +73,7 @@ inline ValPtr invoke__CPP(Func* f, std::vector args, Frame* frame) { // last argument is the address of the calling function; we just need // it to be distinct to the call, so we can associate a Trigger cache // with it. -extern ValPtr when_invoke__CPP(Func* f, std::vector args, Frame* frame, void* caller_addr); +extern ValPtr when_invoke__CPP(Func* f, ValVec args, Frame* frame, void* caller_addr); // Thrown when a call inside a "when" delays. class CPPDelayedCallException : public InterpreterException {}; @@ -201,29 +203,35 @@ inline VectorValPtr vector_coerce__CPP(const ValPtr& v, const TypePtr& t) { return make_intrusive(cast_intrusive(t)); } +// Takes parallel vectors of attribute tags and values and returns a +// collective AttributesPtr corresponding to those instantiated attributes. +// For attributes that don't have associated expressions, the corresponding +// value should be nil. + +extern AttributesPtr build_attrs__CPP(IntVec attr_tags, std::vector attr_vals); + // Constructs a set of the given type, containing the given elements, and // with the associated attributes. -extern TableValPtr set_constructor__CPP(std::vector elements, TableTypePtr t, std::vector attr_tags, - std::vector attr_vals); +extern TableValPtr set_constructor__CPP(ValVec elements, TableTypePtr t, IntVec attr_tags, ValVec attr_vals); // Constructs a table of the given type, containing the given elements // (specified as parallel index/value vectors), and with the associated // attributes. -extern TableValPtr table_constructor__CPP(std::vector indices, std::vector vals, TableTypePtr t, - std::vector attr_tags, std::vector attr_vals); +extern TableValPtr table_constructor__CPP(ValVec indices, ValVec vals, TableTypePtr t, IntVec attr_tags, + ValVec attr_vals); // Assigns a set of attributes to an identifier. -extern void assign_attrs__CPP(IDPtr id, std::vector attr_tags, std::vector attr_vals); +extern void assign_attrs__CPP(IDPtr id, IntVec attr_tags, ValVec attr_vals); // Constructs a record of the given type, whose (ordered) fields are // assigned to the corresponding elements of the given vector of values. -extern RecordValPtr record_constructor__CPP(std::vector vals, RecordTypePtr t); +extern RecordValPtr record_constructor__CPP(ValVec vals, RecordTypePtr t); // Same, but with a map when using a named constructor. -extern RecordValPtr record_constructor_map__CPP(std::vector vals, std::vector map, RecordTypePtr t); +extern RecordValPtr record_constructor_map__CPP(ValVec vals, IntVec map, RecordTypePtr t); // Constructs a vector of the given type, populated with the given values. -extern VectorValPtr vector_constructor__CPP(std::vector vals, VectorTypePtr t); +extern VectorValPtr vector_constructor__CPP(ValVec vals, VectorTypePtr t); // For patterns, executes p1 += p2. inline PatternValPtr re_append__CPP(const PatternValPtr& p1, const PatternValPtr& p2) { @@ -234,7 +242,7 @@ inline PatternValPtr re_append__CPP(const PatternValPtr& p1, const PatternValPtr // Schedules an event to occur at the given absolute time, parameterized // with the given set of values. A separate function to facilitate avoiding // the scheduling if Zeek is terminating. -extern ValPtr schedule__CPP(double dt, EventHandlerPtr event, std::vector args); +extern ValPtr schedule__CPP(double dt, EventHandlerPtr event, ValVec args); // Simple helper functions for supporting absolute value. inline zeek_uint_t iabs__CPP(zeek_int_t v) { return v < 0 ? -v : v; } diff --git a/src/script_opt/CPP/RuntimeVec.cc b/src/script_opt/CPP/RuntimeVec.cc index 4a06800de3..62eed2dde2 100644 --- a/src/script_opt/CPP/RuntimeVec.cc +++ b/src/script_opt/CPP/RuntimeVec.cc @@ -109,7 +109,7 @@ VEC_OP1(comp, ~, ) } // Analogous to VEC_OP1, instantiates a function for a given binary operation, -// with customimzable kernels for "int" and "double" operations. +// with customizable kernels for "int" and "double" operations. // This version is for operations whose result type is the same as the // operand type. #define VEC_OP2(name, op, int_kernel, double_kernel, zero_check, is_bool) \ diff --git a/src/script_opt/CPP/Stmts.cc b/src/script_opt/CPP/Stmts.cc index 06837fcf87..fe8d66fbe0 100644 --- a/src/script_opt/CPP/Stmts.cc +++ b/src/script_opt/CPP/Stmts.cc @@ -352,7 +352,7 @@ void CPPCompile::GenWhenStmt(const WhenStmt* w) { if ( ret_type && ret_type->Tag() != TYPE_VOID ) { // Note, ret_type can be active but we *still* don't have - // a return type, due to the faked-up "any" return type + // a return value, due to the faked-up "any" return type // associated with "when" lambdas, so check for that case. Emit("if ( curr_t )"); StartBlock(); diff --git a/src/script_opt/ScriptOpt.cc b/src/script_opt/ScriptOpt.cc index d09e9dd25b..bc3dd6d1bc 100644 --- a/src/script_opt/ScriptOpt.cc +++ b/src/script_opt/ScriptOpt.cc @@ -401,7 +401,6 @@ static void use_CPP() { ++num_used; auto b = s->second.body; - b->SetHash(hash); // We may have already updated the body if // we're using code compiled for standalone. @@ -532,6 +531,9 @@ static void analyze_scripts_for_ZAM() { } void clear_script_analysis() { + if ( analysis_options.gen_CPP ) + return; + IDOptInfo::ClearGlobalInitExprs(); // We need to explicitly clear out the optimization information