-O gen-C++ refinements for BiF failures, negative vector indices, boolean vector operations

This commit is contained in:
Vern Paxson 2023-06-15 11:08:14 -07:00
parent f64304067b
commit 18be4ba91b
9 changed files with 94 additions and 30 deletions

View file

@ -776,7 +776,7 @@ private:
std::string GenConstExpr(const ConstExpr* c, GenType gt); std::string GenConstExpr(const ConstExpr* c, GenType gt);
std::string GenIncrExpr(const Expr* e, GenType gt, bool is_incr, bool top_level); std::string GenIncrExpr(const Expr* e, GenType gt, bool is_incr, bool top_level);
std::string GenCondExpr(const Expr* e, GenType gt); std::string GenCondExpr(const Expr* e, GenType gt);
std::string GenCallExpr(const CallExpr* c, GenType gt); std::string GenCallExpr(const CallExpr* c, GenType gt, bool top_level);
std::string GenInExpr(const Expr* e, GenType gt); std::string GenInExpr(const Expr* e, GenType gt);
std::string GenFieldExpr(const FieldExpr* fe, GenType gt); std::string GenFieldExpr(const FieldExpr* fe, GenType gt);
std::string GenHasFieldExpr(const HasFieldExpr* hfe, GenType gt); std::string GenHasFieldExpr(const HasFieldExpr* hfe, GenType gt);

View file

@ -114,7 +114,7 @@ string CPPCompile::GenExpr(const Expr* e, GenType gt, bool top_level)
case EXPR_COND: case EXPR_COND:
return GenCondExpr(e, gt); return GenCondExpr(e, gt);
case EXPR_CALL: case EXPR_CALL:
return GenCallExpr(e->AsCallExpr(), gt); return GenCallExpr(e->AsCallExpr(), gt, top_level);
case EXPR_LIST: case EXPR_LIST:
return GenListExpr(e, gt, false); return GenListExpr(e, gt, false);
case EXPR_IN: case EXPR_IN:
@ -291,7 +291,7 @@ string CPPCompile::GenCondExpr(const Expr* e, GenType gt)
return string("(") + gen1 + ") ? (" + gen2 + ") : (" + gen3 + ")"; return string("(") + gen1 + ") ? (" + gen2 + ") : (" + gen3 + ")";
} }
string CPPCompile::GenCallExpr(const CallExpr* c, GenType gt) string CPPCompile::GenCallExpr(const CallExpr* c, GenType gt, bool top_level)
{ {
const auto& t = c->GetType(); const auto& t = c->GetType();
auto f = c->Func(); auto f = c->Func();
@ -347,7 +347,18 @@ string CPPCompile::GenCallExpr(const CallExpr* c, GenType gt)
// Indirect call. // Indirect call.
gen = string("(") + gen + ")->AsFunc()"; gen = string("(") + gen + ")->AsFunc()";
string invoke_func = is_async ? "when_invoke__CPP" : "invoke__CPP"; string invoke_func;
if ( is_async )
invoke_func = "when_invoke__CPP";
else if ( t->Tag() == TYPE_VOID )
{
ASSERT(top_level);
invoke_func = "invoke_void__CPP";
}
else
invoke_func = "invoke__CPP";
auto args_list = string(", {") + GenExpr(args_l, GEN_VAL_PTR) + "}"; auto args_list = string(", {") + GenExpr(args_l, GEN_VAL_PTR) + "}";
auto invoker = invoke_func + "(" + gen + args_list + ", f__CPP"; auto invoker = invoke_func + "(" + gen + args_list + ", f__CPP";
@ -356,6 +367,10 @@ string CPPCompile::GenCallExpr(const CallExpr* c, GenType gt)
invoker += ")"; invoker += ")";
if ( top_level )
// No need to use accessor.
return invoker;
if ( IsNativeType(t) && gt != GEN_VAL_PTR ) if ( IsNativeType(t) && gt != GEN_VAL_PTR )
return invoker + NativeAccessor(t); return invoker + NativeAccessor(t);

View file

@ -51,9 +51,13 @@ ValPtr index_table__CPP(const TableValPtr& t, vector<ValPtr> indices)
ValPtr index_vec__CPP(const VectorValPtr& vec, int index) ValPtr index_vec__CPP(const VectorValPtr& vec, int index)
{ {
if ( index < 0 )
index += vec->Size();
auto v = vec->ValAt(index); auto v = vec->ValAt(index);
if ( ! v ) if ( ! v )
reporter->CPPRuntimeError("no such index"); reporter->CPPRuntimeError("no such index");
return v; return v;
} }

View file

@ -48,12 +48,28 @@ extern ValPtr when_index_vec__CPP(const VectorValPtr& vec, int index);
// custom one for those occurring inside a "when" clause. // custom one for those occurring inside a "when" clause.
extern ValPtr when_index_slice__CPP(VectorVal* vec, const ListVal* lv); 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<ValPtr> args, Frame* frame)
{
return f->Invoke(&args, frame);
}
// Used for error propagation by failed calls.
class CPPInterpreterException : public InterpreterException
{
};
// Calls out to the given script or BiF function. A separate function because // Calls out to the given script or BiF function. A separate function because
// of the need to (1) construct the "args" vector using {} initializers, // of the need to (1) construct the "args" vector using {} initializers,
// but (2) needing to have the address of that vector. // but (2) needing to have the address of that vector.
inline ValPtr invoke__CPP(Func* f, std::vector<ValPtr> args, Frame* frame) inline ValPtr invoke__CPP(Func* f, std::vector<ValPtr> args, Frame* frame)
{ {
return f->Invoke(&args, frame); auto v = f->Invoke(&args, frame);
if ( ! v )
throw CPPInterpreterException();
return v;
} }
// The same, but raises an interpreter exception if the function does // The same, but raises an interpreter exception if the function does

View file

@ -26,12 +26,17 @@ static bool check_vec_sizes__CPP(const VectorValPtr& v1, const VectorValPtr& v2)
// (for example, adding one vector of "interval" to another), which // (for example, adding one vector of "interval" to another), which
// we want to do using the low-level representations. We'll later // we want to do using the low-level representations. We'll later
// convert the vector to the high-level representation if needed. // convert the vector to the high-level representation if needed.
static VectorTypePtr base_vector_type__CPP(const VectorTypePtr& vt) //
// One exception: for booleans ("is_bool" is true), we use those directly.
static VectorTypePtr base_vector_type__CPP(const VectorTypePtr& vt, bool is_bool = false)
{ {
switch ( vt->Yield()->InternalType() ) switch ( vt->Yield()->InternalType() )
{ {
case TYPE_INTERNAL_INT: case TYPE_INTERNAL_INT:
return make_intrusive<VectorType>(base_type(TYPE_INT)); {
auto base_tag = is_bool ? TYPE_BOOL : TYPE_INT;
return make_intrusive<VectorType>(base_type(base_tag));
}
case TYPE_INTERNAL_UNSIGNED: case TYPE_INTERNAL_UNSIGNED:
return make_intrusive<VectorType>(base_type(TYPE_COUNT)); return make_intrusive<VectorType>(base_type(TYPE_COUNT));
@ -119,36 +124,27 @@ VEC_OP1(comp, ~, )
} }
// Analogous to VEC_OP1, instantiates a function for a given binary operation, // Analogous to VEC_OP1, instantiates a function for a given binary operation,
// which might-or-might-not be supported for low-level "double" types. // with customimzable kernels for "int" and "double" operations.
// This version is for operations whose result type is the same as the // This version is for operations whose result type is the same as the
// operand type. // operand type.
#define VEC_OP2(name, op, double_kernel, zero_check) \ #define VEC_OP2(name, op, int_kernel, double_kernel, zero_check, is_bool) \
VectorValPtr vec_op_##name##__CPP(const VectorValPtr& v1, const VectorValPtr& v2) \ VectorValPtr vec_op_##name##__CPP(const VectorValPtr& v1, const VectorValPtr& v2) \
{ \ { \
if ( ! check_vec_sizes__CPP(v1, v2) ) \ if ( ! check_vec_sizes__CPP(v1, v2) ) \
return nullptr; \ return nullptr; \
\ \
auto vt = base_vector_type__CPP(v1->GetType<VectorType>()); \ auto vt = base_vector_type__CPP(v1->GetType<VectorType>(), is_bool); \
auto v_result = make_intrusive<VectorVal>(vt); \ auto v_result = make_intrusive<VectorVal>(vt); \
\ \
switch ( vt->Yield()->InternalType() ) \ switch ( vt->Yield()->InternalType() ) \
{ \ { \
case TYPE_INTERNAL_INT: \
{ \
if ( vt->Yield()->Tag() == TYPE_BOOL ) \
VEC_OP2_KERNEL(AsBool, BoolVal, op, zero_check) \
else \
VEC_OP2_KERNEL(AsInt, IntVal, op, zero_check) \
break; \
} \
\
case TYPE_INTERNAL_UNSIGNED: \ case TYPE_INTERNAL_UNSIGNED: \
{ \ { \
VEC_OP2_KERNEL(AsCount, CountVal, op, zero_check) \ VEC_OP2_KERNEL(AsCount, CountVal, op, zero_check) \
break; \ break; \
} \ } \
\ \
double_kernel \ int_kernel double_kernel \
\ \
default : break; \ default : break; \
} \ } \
@ -156,9 +152,29 @@ VEC_OP1(comp, ~, )
return v_result; \ return v_result; \
} }
// Instantiates a regular int_kernel for a binary operation.
#define VEC_OP2_WITH_INT(name, op, double_kernel, zero_check) \
VEC_OP2( \
name, op, case TYPE_INTERNAL_INT \
: { \
VEC_OP2_KERNEL(AsInt, IntVal, op, zero_check) \
break; \
}, \
double_kernel, zero_check, false)
// Instantiates an int_kernel for boolean operations.
#define VEC_OP2_WITH_BOOL(name, op, zero_check) \
VEC_OP2( \
name, op, case TYPE_INTERNAL_INT \
: { \
VEC_OP2_KERNEL(AsBool, BoolVal, op, zero_check) \
break; \
}, \
, zero_check, true)
// Instantiates a double_kernel for a binary operation. // Instantiates a double_kernel for a binary operation.
#define VEC_OP2_WITH_DOUBLE(name, op, zero_check) \ #define VEC_OP2_WITH_DOUBLE(name, op, zero_check) \
VEC_OP2( \ VEC_OP2_WITH_INT( \
name, op, case TYPE_INTERNAL_DOUBLE \ name, op, case TYPE_INTERNAL_DOUBLE \
: { \ : { \
VEC_OP2_KERNEL(AsDouble, DoubleVal, op, zero_check) \ VEC_OP2_KERNEL(AsDouble, DoubleVal, op, zero_check) \
@ -171,14 +187,14 @@ VEC_OP2_WITH_DOUBLE(add, +, 0)
VEC_OP2_WITH_DOUBLE(sub, -, 0) VEC_OP2_WITH_DOUBLE(sub, -, 0)
VEC_OP2_WITH_DOUBLE(mul, *, 0) VEC_OP2_WITH_DOUBLE(mul, *, 0)
VEC_OP2_WITH_DOUBLE(div, /, 1) VEC_OP2_WITH_DOUBLE(div, /, 1)
VEC_OP2(mod, %, , 1) VEC_OP2_WITH_INT(mod, %, , 1)
VEC_OP2(and, &, , 0) VEC_OP2_WITH_INT(and, &, , 0)
VEC_OP2(or, |, , 0) VEC_OP2_WITH_INT(or, |, , 0)
VEC_OP2(xor, ^, , 0) VEC_OP2_WITH_INT(xor, ^, , 0)
VEC_OP2(andand, &&, , 0) VEC_OP2_WITH_BOOL(andand, &&, 0)
VEC_OP2(oror, ||, , 0) VEC_OP2_WITH_BOOL(oror, ||, 0)
VEC_OP2(lshift, <<, , 0) VEC_OP2_WITH_INT(lshift, <<, , 0)
VEC_OP2(rshift, >>, , 0) VEC_OP2_WITH_INT(rshift, >>, , 0)
// A version of VEC_OP2 that instead supports relational operations, so // A version of VEC_OP2 that instead supports relational operations, so
// the result type is always vector-of-bool. // the result type is always vector-of-bool.

View file

@ -34,7 +34,9 @@ The maintenance workflow:
5. Run "check-CPP-gen.sh" for each Zeek file that passed "check-zeek.sh". 5. Run "check-CPP-gen.sh" for each Zeek file that passed "check-zeek.sh".
This will generate a corresponding file in CPP-test/out* indicating whether This will generate a corresponding file in CPP-test/out* indicating whether
"-O gen-C++" can successfully run on the input. Presently, it should "-O gen-C++" can successfully run on the input. Presently, it should
be able to do so for all of them. be able to do so for all of them except a few that have conditional code,
which I've left active (no @TEST-REQUIRES to prune) given hopes of
soon being able to support (most) conditional code for C++ compilation.
This step is parallelizable, say using xargs -P 10 -n 1. This step is parallelizable, say using xargs -P 10 -n 1.

View file

@ -0,0 +1,5 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
error in <...>/publish-hrw-type-check.zeek (C++), line 13: expected type Cluster::Pool for pool (<___>testing_btest__tmp_scripts_base_frameworks_cluster_publish_hrw_type_check_publish_hrw_type_check_zeek__zeek_init__34__zf())
error in <...>/publish-hrw-type-check.zeek (C++), line 13: expected type Cluster::Pool for pool (<___>testing_btest__tmp_scripts_base_frameworks_cluster_publish_hrw_type_check_publish_hrw_type_check_zeek__zeek_init__34__zf())
error in <...>/publish-hrw-type-check.zeek (C++), line 13: expected type Cluster::Pool for pool (<___>testing_btest__tmp_scripts_base_frameworks_cluster_publish_hrw_type_check_publish_hrw_type_check_zeek__zeek_init__34__zf())
error in <...>/publish-hrw-type-check.zeek (C++), line 13: expected type string for key, got port (<___>testing_btest__tmp_scripts_base_frameworks_cluster_publish_hrw_type_check_publish_hrw_type_check_zeek__zeek_init__34__zf())

View file

@ -1,3 +1,6 @@
# Not compatible with -O C++ testing since includes two distinct scripts.
# @TEST-REQUIRES: test "${ZEEK_USE_CPP}" != "1"
#
# @TEST-GROUP: broker # @TEST-GROUP: broker
# #
# @TEST-PORT: BROKER_PORT # @TEST-PORT: BROKER_PORT

View file

@ -1,3 +1,6 @@
# Not compatible with -O C++ testing since includes two distinct scripts.
# @TEST-REQUIRES: test "${ZEEK_USE_CPP}" != "1"
#
# @TEST-GROUP: broker # @TEST-GROUP: broker
# #
# @TEST-PORT: BROKER_PORT # @TEST-PORT: BROKER_PORT