mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 14:48:21 +00:00
reductions of expressions in ASTs - code compiles but doesn't yet link
This commit is contained in:
parent
6aa84087b0
commit
10e80dfcd3
8 changed files with 3264 additions and 164 deletions
288
src/Expr.cc
288
src/Expr.cc
|
@ -41,6 +41,10 @@ const char* expr_name(BroExprTag t)
|
|||
"coerce", "record_coerce", "table_coerce", "vector_coerce",
|
||||
"sizeof", "cast", "is", "[:]=",
|
||||
"inline()",
|
||||
"[]=", "$=",
|
||||
"vec+=",
|
||||
"to_any_coerce", "from_any_coerce",
|
||||
"any[]",
|
||||
"nop",
|
||||
|
||||
};
|
||||
|
@ -95,12 +99,24 @@ NameExpr* Expr::AsNameExpr()
|
|||
return (NameExpr*) this;
|
||||
}
|
||||
|
||||
NameExprPtr Expr::AsNameExprPtr()
|
||||
{
|
||||
CHECK_TAG(tag, EXPR_NAME, "ExprVal::AsNameExpr", expr_name)
|
||||
return {NewRef{}, (NameExpr*) this};
|
||||
}
|
||||
|
||||
const ConstExpr* Expr::AsConstExpr() const
|
||||
{
|
||||
CHECK_TAG(tag, EXPR_CONST, "ExprVal::AsConstExpr", expr_name)
|
||||
return (const ConstExpr*) this;
|
||||
}
|
||||
|
||||
ConstExprPtr Expr::AsConstExprPtr()
|
||||
{
|
||||
CHECK_TAG(tag, EXPR_CONST, "ExprVal::AsConstExpr", expr_name)
|
||||
return {NewRef{}, (ConstExpr*) this};
|
||||
}
|
||||
|
||||
const CallExpr* Expr::AsCallExpr() const
|
||||
{
|
||||
CHECK_TAG(tag, EXPR_CALL, "ExprVal::AsCallExpr", expr_name)
|
||||
|
@ -143,6 +159,12 @@ EventExprPtr Expr::AsEventExprPtr()
|
|||
return {NewRef{}, (EventExpr*) this};
|
||||
}
|
||||
|
||||
RefExprPtr Expr::AsRefExprPtr()
|
||||
{
|
||||
CHECK_TAG(tag, EXPR_REF, "ExprVal::AsRefExpr", expr_name)
|
||||
return {NewRef{}, (RefExpr*) this};
|
||||
}
|
||||
|
||||
bool Expr::CanAdd() const
|
||||
{
|
||||
return false;
|
||||
|
@ -182,6 +204,132 @@ void Expr::Assign(Frame* /* f */, ValPtr /* v */)
|
|||
Internal("Expr::Assign called");
|
||||
}
|
||||
|
||||
void Expr::AssignToIndex(ValPtr v1, ValPtr v2, ValPtr v3) const
|
||||
{
|
||||
bool iterators_invalidated;
|
||||
|
||||
auto error_msg = assign_to_index(v1, v2, v3, iterators_invalidated);
|
||||
|
||||
if ( iterators_invalidated )
|
||||
{
|
||||
ODesc d;
|
||||
Describe(&d);
|
||||
reporter->PushLocation(GetLocationInfo());
|
||||
reporter->Warning("possible loop/iterator invalidation caused by expression: %s", d.Description());
|
||||
reporter->PopLocation();
|
||||
}
|
||||
|
||||
if ( error_msg )
|
||||
RuntimeErrorWithCallStack(error_msg);
|
||||
}
|
||||
|
||||
static int get_slice_index(int idx, int len)
|
||||
{
|
||||
if ( abs(idx) > len )
|
||||
idx = idx > 0 ? len : 0; // Clamp maximum positive/negative indices.
|
||||
else if ( idx < 0 )
|
||||
idx += len; // Map to a positive index.
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
const char* assign_to_index(ValPtr v1, ValPtr v2, ValPtr v3,
|
||||
bool& iterators_invalidated)
|
||||
{
|
||||
iterators_invalidated = false;
|
||||
|
||||
if ( ! v1 || ! v2 || ! v3 )
|
||||
return nullptr;
|
||||
|
||||
// Hold an extra reference to 'arg_v' in case the ownership transfer
|
||||
// to the table/vector goes wrong and we still want to obtain
|
||||
// diagnostic info from the original value after the assignment
|
||||
// already unref'd.
|
||||
auto v_extra = v3;
|
||||
|
||||
switch ( v1->GetType()->Tag() ) {
|
||||
case TYPE_VECTOR:
|
||||
{
|
||||
const ListVal* lv = v2->AsListVal();
|
||||
VectorVal* v1_vect = v1->AsVectorVal();
|
||||
|
||||
if ( lv->Length() > 1 )
|
||||
{
|
||||
auto len = v1_vect->Size();
|
||||
bro_int_t first = get_slice_index(lv->Idx(0)->CoerceToInt(), len);
|
||||
bro_int_t last = get_slice_index(lv->Idx(1)->CoerceToInt(), len);
|
||||
|
||||
// Remove the elements from the vector within the slice.
|
||||
for ( auto idx = first; idx < last; idx++ )
|
||||
v1_vect->Remove(first);
|
||||
|
||||
// Insert the new elements starting at the first
|
||||
// position.
|
||||
|
||||
VectorVal* v_vect = v3->AsVectorVal();
|
||||
|
||||
for ( auto idx = 0u; idx < v_vect->Size();
|
||||
idx++, first++ )
|
||||
v1_vect->Insert(first, v_vect->At(idx));
|
||||
}
|
||||
|
||||
else if ( ! v1_vect->Assign(lv->Idx(0)->CoerceToUnsigned(), std::move(v3)) )
|
||||
{
|
||||
v3 = std::move(v_extra);
|
||||
|
||||
if ( v3 )
|
||||
{
|
||||
ODesc d;
|
||||
v3->Describe(&d);
|
||||
const auto& vt = v3->GetType();
|
||||
auto vtt = vt->Tag();
|
||||
std::string tn = vtt == TYPE_RECORD ?
|
||||
vt->GetName() : type_name(vtt);
|
||||
return util::fmt("vector index assignment failed for invalid type '%s', value: %s",
|
||||
tn.data(), d.Description());
|
||||
}
|
||||
else
|
||||
return "assignment failed with null value";
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case TYPE_TABLE:
|
||||
{
|
||||
if ( ! v1->AsTableVal()->Assign(std::move(v2), std::move(v3), true, &iterators_invalidated) )
|
||||
{
|
||||
v3 = std::move(v_extra);
|
||||
|
||||
if ( v3 )
|
||||
{
|
||||
ODesc d;
|
||||
v3->Describe(&d);
|
||||
const auto& vt = v3->GetType();
|
||||
auto vtt = vt->Tag();
|
||||
std::string tn = vtt == TYPE_RECORD ?
|
||||
vt->GetName() : type_name(vtt);
|
||||
return util::fmt("table index assignment failed for invalid type '%s', value: %s",
|
||||
tn.data(), d.Description());
|
||||
}
|
||||
else
|
||||
return "assignment failed with null value";
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case TYPE_STRING:
|
||||
return "assignment via string index accessor not allowed";
|
||||
break;
|
||||
|
||||
default:
|
||||
return "bad index expression type in assignment";
|
||||
break;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TypePtr Expr::InitType() const
|
||||
{
|
||||
return type;
|
||||
|
@ -312,6 +460,12 @@ NameExpr::NameExpr(IDPtr arg_id, bool const_init)
|
|||
h->SetUsed();
|
||||
}
|
||||
|
||||
// This isn't in-lined to avoid needing to pull in ID.h.
|
||||
IDPtr NameExpr::IdPtr()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
ValPtr NameExpr::Eval(Frame* f) const
|
||||
{
|
||||
ValPtr v;
|
||||
|
@ -436,7 +590,14 @@ ValPtr UnaryExpr::Eval(Frame* f) const
|
|||
if ( ! v )
|
||||
return nullptr;
|
||||
|
||||
if ( is_vector(v) && Tag() != EXPR_IS && Tag() != EXPR_CAST )
|
||||
if ( is_vector(v) && Tag() != EXPR_IS && Tag() != EXPR_CAST &&
|
||||
// The following allows passing vectors-by-reference to
|
||||
// functions that use vector-of-any for generic vector
|
||||
// manipulation ...
|
||||
Tag() != EXPR_TO_ANY_COERCE &&
|
||||
// ... and the following to avoid vectorizing operations
|
||||
// on vector-of-any's
|
||||
Tag() != EXPR_FROM_ANY_COERCE )
|
||||
{
|
||||
VectorVal* v_op = v->AsVectorVal();
|
||||
VectorTypePtr out_t;
|
||||
|
@ -457,10 +618,8 @@ ValPtr UnaryExpr::Eval(Frame* f) const
|
|||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Fold(v.get());
|
||||
}
|
||||
}
|
||||
|
||||
bool UnaryExpr::IsPure() const
|
||||
{
|
||||
|
@ -2129,7 +2288,8 @@ void RefExpr::Assign(Frame* f, ValPtr v)
|
|||
AssignExpr::AssignExpr(ExprPtr arg_op1,
|
||||
ExprPtr arg_op2,
|
||||
bool arg_is_init, ValPtr arg_val,
|
||||
const AttributesPtr& attrs)
|
||||
const AttributesPtr& attrs,
|
||||
bool typecheck)
|
||||
: BinaryExpr(EXPR_ASSIGN, arg_is_init ?
|
||||
std::move(arg_op1) : arg_op1->MakeLvalue(),
|
||||
std::move(arg_op2))
|
||||
|
@ -2152,6 +2312,7 @@ AssignExpr::AssignExpr(ExprPtr arg_op1,
|
|||
return;
|
||||
}
|
||||
|
||||
if ( typecheck )
|
||||
// We discard the status from TypeCheck since it has already
|
||||
// generated error messages.
|
||||
(void) TypeCheck(attrs);
|
||||
|
@ -2754,16 +2915,6 @@ ValPtr IndexExpr::Eval(Frame* f) const
|
|||
return Fold(v1.get(), v2.get());
|
||||
}
|
||||
|
||||
static int get_slice_index(int idx, int len)
|
||||
{
|
||||
if ( abs(idx) > len )
|
||||
idx = idx > 0 ? len : 0; // Clamp maximum positive/negative indices.
|
||||
else if ( idx < 0 )
|
||||
idx += len; // Map to a positive index.
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
ValPtr IndexExpr::Fold(Val* v1, Val* v2) const
|
||||
{
|
||||
if ( IsError() )
|
||||
|
@ -2855,105 +3006,9 @@ void IndexExpr::Assign(Frame* f, ValPtr v)
|
|||
return;
|
||||
|
||||
auto v1 = op1->Eval(f);
|
||||
|
||||
if ( ! v1 )
|
||||
return;
|
||||
|
||||
auto v2 = op2->Eval(f);
|
||||
|
||||
if ( ! v1 || ! v2 )
|
||||
return;
|
||||
|
||||
// Hold an extra reference to 'arg_v' in case the ownership transfer to
|
||||
// the table/vector goes wrong and we still want to obtain diagnostic info
|
||||
// from the original value after the assignment already unref'd.
|
||||
auto v_extra = v;
|
||||
|
||||
switch ( v1->GetType()->Tag() ) {
|
||||
case TYPE_VECTOR:
|
||||
{
|
||||
const ListVal* lv = v2->AsListVal();
|
||||
VectorVal* v1_vect = v1->AsVectorVal();
|
||||
|
||||
if ( lv->Length() > 1 )
|
||||
{
|
||||
auto len = v1_vect->Size();
|
||||
bro_int_t first = get_slice_index(lv->Idx(0)->CoerceToInt(), len);
|
||||
bro_int_t last = get_slice_index(lv->Idx(1)->CoerceToInt(), len);
|
||||
|
||||
// Remove the elements from the vector within the slice
|
||||
for ( auto idx = first; idx < last; idx++ )
|
||||
v1_vect->Remove(first);
|
||||
|
||||
// Insert the new elements starting at the first position
|
||||
VectorVal* v_vect = v->AsVectorVal();
|
||||
|
||||
for ( auto idx = 0u; idx < v_vect->Size(); idx++, first++ )
|
||||
v1_vect->Insert(first, v_vect->At(idx));
|
||||
}
|
||||
else if ( ! v1_vect->Assign(lv->Idx(0)->CoerceToUnsigned(), std::move(v)) )
|
||||
{
|
||||
v = std::move(v_extra);
|
||||
|
||||
if ( v )
|
||||
{
|
||||
ODesc d;
|
||||
v->Describe(&d);
|
||||
const auto& vt = v->GetType();
|
||||
auto vtt = vt->Tag();
|
||||
std::string tn = vtt == TYPE_RECORD ? vt->GetName() : type_name(vtt);
|
||||
RuntimeErrorWithCallStack(util::fmt(
|
||||
"vector index assignment failed for invalid type '%s', value: %s",
|
||||
tn.data(), d.Description()));
|
||||
}
|
||||
else
|
||||
RuntimeErrorWithCallStack("assignment failed with null value");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case TYPE_TABLE:
|
||||
{
|
||||
bool iterators_invalidated = false;
|
||||
|
||||
if ( ! v1->AsTableVal()->Assign(std::move(v2), std::move(v), true, &iterators_invalidated) )
|
||||
{
|
||||
v = std::move(v_extra);
|
||||
|
||||
if ( v )
|
||||
{
|
||||
ODesc d;
|
||||
v->Describe(&d);
|
||||
const auto& vt = v->GetType();
|
||||
auto vtt = vt->Tag();
|
||||
std::string tn = vtt == TYPE_RECORD ? vt->GetName() : type_name(vtt);
|
||||
RuntimeErrorWithCallStack(util::fmt(
|
||||
"table index assignment failed for invalid type '%s', value: %s",
|
||||
tn.data(), d.Description()));
|
||||
}
|
||||
else
|
||||
RuntimeErrorWithCallStack("assignment failed with null value");
|
||||
}
|
||||
|
||||
if ( iterators_invalidated )
|
||||
{
|
||||
ODesc d;
|
||||
Describe(&d);
|
||||
reporter->PushLocation(GetLocationInfo());
|
||||
reporter->Warning("possible loop/iterator invalidation caused by expression: %s", d.Description());
|
||||
reporter->PopLocation();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TYPE_STRING:
|
||||
RuntimeErrorWithCallStack("assignment via string index accessor not allowed");
|
||||
break;
|
||||
|
||||
default:
|
||||
RuntimeErrorWithCallStack("bad index expression type in assignment");
|
||||
break;
|
||||
}
|
||||
AssignToIndex(v1, v2, v);
|
||||
}
|
||||
|
||||
void IndexExpr::ExprDescribe(ODesc* d) const
|
||||
|
@ -5168,7 +5223,16 @@ bool check_and_promote_args(ListExpr* const args, RecordType* types)
|
|||
return false;
|
||||
}
|
||||
|
||||
def_elements.push_front(def_attr->GetExpr().get());
|
||||
// Don't use the default expression directly, as
|
||||
// doing so will wind up sharing its code across
|
||||
// different invocations that use the default
|
||||
// argument. That works okay for the interpreter,
|
||||
// but if we transform the code we want that done
|
||||
// separately for each instance, rather than
|
||||
// one instance inheriting the transformed version
|
||||
// from another.
|
||||
auto e = def_attr->GetExpr();
|
||||
def_elements.push_front(e->Duplicate().release());
|
||||
}
|
||||
|
||||
for ( const auto& elem : def_elements )
|
||||
|
|
508
src/Expr.h
508
src/Expr.h
|
@ -68,6 +68,15 @@ enum BroExprTag : int {
|
|||
EXPR_IS,
|
||||
EXPR_INDEX_SLICE_ASSIGN,
|
||||
EXPR_INLINE,
|
||||
|
||||
// The following types of expressions are only created for
|
||||
// ASTs transformed to reduced form; they aren't germane for
|
||||
// ASTs produced by parsing .zeek script files.
|
||||
EXPR_INDEX_ASSIGN, EXPR_FIELD_LHS_ASSIGN,
|
||||
EXPR_APPEND_TO,
|
||||
EXPR_TO_ANY_COERCE, EXPR_FROM_ANY_COERCE,
|
||||
EXPR_ANY_INDEX,
|
||||
|
||||
EXPR_NOP,
|
||||
|
||||
#define NUM_EXPRS (int(EXPR_NOP) + 1)
|
||||
|
@ -75,18 +84,27 @@ enum BroExprTag : int {
|
|||
|
||||
extern const char* expr_name(BroExprTag t);
|
||||
|
||||
class ListExpr;
|
||||
class NameExpr;
|
||||
class ConstExpr;
|
||||
class IndexExpr;
|
||||
class AssignExpr;
|
||||
class CallExpr;
|
||||
class ConstExpr;
|
||||
class EventExpr;
|
||||
class Stmt;
|
||||
class FieldAssignExpr;
|
||||
class FieldExpr;
|
||||
class ForExpr;
|
||||
class IndexExpr;
|
||||
class ListExpr;
|
||||
class NameExpr;
|
||||
class RefExpr;
|
||||
|
||||
class Expr;
|
||||
using ExprPtr = IntrusivePtr<Expr>;
|
||||
using CallExprPtr = IntrusivePtr<CallExpr>;
|
||||
using ConstExprPtr = IntrusivePtr<ConstExpr>;
|
||||
using EventExprPtr = IntrusivePtr<EventExpr>;
|
||||
using ExprPtr = IntrusivePtr<Expr>;
|
||||
using NameExprPtr = IntrusivePtr<NameExpr>;
|
||||
using RefExprPtr = IntrusivePtr<RefExpr>;
|
||||
|
||||
class Stmt;
|
||||
using StmtPtr = IntrusivePtr<Stmt>;
|
||||
|
||||
class Expr : public Obj {
|
||||
|
@ -182,13 +200,17 @@ public:
|
|||
ctype* As ## ctype (); \
|
||||
IntrusivePtr<ctype> As ## ctype ## Ptr ();
|
||||
|
||||
ZEEK_EXPR_ACCESSOR_DECLS(AssignExpr)
|
||||
ZEEK_EXPR_ACCESSOR_DECLS(CallExpr)
|
||||
ZEEK_EXPR_ACCESSOR_DECLS(ConstExpr)
|
||||
ZEEK_EXPR_ACCESSOR_DECLS(EventExpr)
|
||||
ZEEK_EXPR_ACCESSOR_DECLS(FieldAssignExpr)
|
||||
ZEEK_EXPR_ACCESSOR_DECLS(FieldExpr)
|
||||
ZEEK_EXPR_ACCESSOR_DECLS(ForExpr)
|
||||
ZEEK_EXPR_ACCESSOR_DECLS(IndexExpr)
|
||||
ZEEK_EXPR_ACCESSOR_DECLS(ListExpr)
|
||||
ZEEK_EXPR_ACCESSOR_DECLS(NameExpr)
|
||||
ZEEK_EXPR_ACCESSOR_DECLS(ConstExpr)
|
||||
ZEEK_EXPR_ACCESSOR_DECLS(CallExpr)
|
||||
ZEEK_EXPR_ACCESSOR_DECLS(AssignExpr)
|
||||
ZEEK_EXPR_ACCESSOR_DECLS(IndexExpr)
|
||||
ZEEK_EXPR_ACCESSOR_DECLS(EventExpr)
|
||||
ZEEK_EXPR_ACCESSOR_DECLS(RefExpr)
|
||||
|
||||
void Describe(ODesc* d) const override final;
|
||||
|
||||
|
@ -200,6 +222,117 @@ public:
|
|||
// Recursively traverses the AST to inline eligible function calls.
|
||||
virtual ExprPtr Inline(Inliner* inl) { return ThisPtr(); }
|
||||
|
||||
// True if the expression can serve as an operand to a reduced
|
||||
// expression.
|
||||
bool IsSingleton(Reducer* r) const
|
||||
{
|
||||
return (tag == EXPR_NAME && IsReduced(r)) || tag == EXPR_CONST;
|
||||
}
|
||||
|
||||
// True if the expression has no side effects, false otherwise.
|
||||
virtual bool HasNoSideEffects() const { return IsPure(); }
|
||||
|
||||
// True if the expression is in fully reduced form: a singleton
|
||||
// or an assignment to an operator with singleton operands.
|
||||
virtual bool IsReduced(Reducer* c) const;
|
||||
|
||||
// True if the expression's operands are singletons.
|
||||
virtual bool HasReducedOps(Reducer* c) const;
|
||||
|
||||
// True if (a) the expression has at least one operand, and (b) all
|
||||
// of its operands are constant.
|
||||
bool HasConstantOps() const
|
||||
{
|
||||
return GetOp1() && GetOp1()->IsConst() &&
|
||||
(! GetOp2() ||
|
||||
(GetOp2()->IsConst() &&
|
||||
(! GetOp3() || GetOp3()->IsConst())));
|
||||
}
|
||||
|
||||
// True if the expression is reduced to a form that can be
|
||||
// used in a conditional.
|
||||
bool IsReducedConditional(Reducer* c) const;
|
||||
|
||||
// True if the expression is reduced to a form that can be
|
||||
// used in a field assignment.
|
||||
bool IsReducedFieldAssignment(Reducer* c) const;
|
||||
|
||||
// True if this expression can be the RHS for a field assignment.
|
||||
bool IsFieldAssignable(const Expr* e) const;
|
||||
|
||||
// True if the expression will transform to one of another type
|
||||
// upon reduction, for non-constant operands. "Transform" means
|
||||
// something beyond assignment to a temporary. Necessary so that
|
||||
// we know to fully reduce such expressions if they're the RHS
|
||||
// of an assignment.
|
||||
virtual bool WillTransform(Reducer* c) const { return false; }
|
||||
|
||||
// The same, but for the expression when used in a conditional context.
|
||||
virtual bool WillTransformInConditional(Reducer* c) const
|
||||
{ return false; }
|
||||
|
||||
// Returns the current expression transformed into "new_me".
|
||||
// Takes a bare pointer for "new_me" since often it's newly
|
||||
// allocated.
|
||||
ExprPtr TransformMe(Expr* new_me, Reducer* c, StmtPtr& red_stmt);
|
||||
ExprPtr TransformMe(ExprPtr new_me, Reducer* c, StmtPtr& red_stmt)
|
||||
{ return TransformMe(new_me.get(), c, red_stmt); }
|
||||
|
||||
// Returns a set of predecessor statements in red_stmt (which might
|
||||
// be nil if no reduction necessary), and the reduced version of
|
||||
// the expression, suitable for replacing previous uses. The
|
||||
// second version always yields a singleton suitable for use
|
||||
// as an operand. The first version does this too except
|
||||
// for assignment statements; thus, its form is not guarantee
|
||||
// suitable for use as an operand.
|
||||
virtual ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt);
|
||||
virtual ExprPtr ReduceToSingleton(Reducer* c, StmtPtr& red_stmt)
|
||||
{ return Reduce(c, red_stmt); }
|
||||
|
||||
// Reduces the expression to one whose operands are singletons.
|
||||
// Returns a predecessor statement (which might be a StmtList), if any.
|
||||
virtual StmtPtr ReduceToSingletons(Reducer* c);
|
||||
|
||||
// Reduces the expression to one that can appear as a conditional.
|
||||
ExprPtr ReduceToConditional(Reducer* c, StmtPtr& red_stmt);
|
||||
|
||||
// Reduces the expression to one that can appear as a field
|
||||
// assignment.
|
||||
ExprPtr ReduceToFieldAssignment(Reducer* c, StmtPtr& red_stmt);
|
||||
|
||||
// Helper function for factoring out complexities related to
|
||||
// index-based assignment.
|
||||
void AssignToIndex(ValPtr v1, ValPtr v2, ValPtr v3) const;
|
||||
|
||||
// Returns a new expression corresponding to a temporary
|
||||
// that's been assigned to the given expression via red_stmt.
|
||||
ExprPtr AssignToTemporary(ExprPtr e, Reducer* c, StmtPtr& red_stmt);
|
||||
// Same but for this expression.
|
||||
ExprPtr AssignToTemporary(Reducer* c, StmtPtr& red_stmt)
|
||||
{ return AssignToTemporary(ThisPtr(), c, red_stmt); }
|
||||
|
||||
// If the expression always evaluates to the same value, returns
|
||||
// that value. Otherwise, returns nullptr.
|
||||
virtual ValPtr FoldVal() const { return nullptr; }
|
||||
|
||||
// Returns a Val or a constant Expr corresponding to zero.
|
||||
ValPtr MakeZero(TypeTag t) const;
|
||||
ConstExprPtr MakeZeroExpr(TypeTag t) const;
|
||||
|
||||
// Returns the expression's operands, or nil if it doesn't
|
||||
// have the given operand.
|
||||
virtual ExprPtr GetOp1() const;
|
||||
virtual ExprPtr GetOp2() const;
|
||||
virtual ExprPtr GetOp3() const;
|
||||
|
||||
// Sets the operands to new values.
|
||||
virtual void SetOp1(ExprPtr new_op);
|
||||
virtual void SetOp2(ExprPtr new_op);
|
||||
virtual void SetOp3(ExprPtr new_op);
|
||||
|
||||
// Helper function to reduce boring code runs.
|
||||
StmtPtr MergeStmts(StmtPtr s1, StmtPtr s2, StmtPtr s3 = nullptr) const;
|
||||
|
||||
// Access to the original expression from which this one is derived,
|
||||
// or this one if we don't have an original. Returns a bare pointer
|
||||
// rather than an ExprPtr to emphasize that the access is read-only.
|
||||
|
@ -272,6 +405,7 @@ public:
|
|||
explicit NameExpr(IDPtr id, bool const_init = false);
|
||||
|
||||
ID* Id() const { return id.get(); }
|
||||
IDPtr IdPtr();
|
||||
|
||||
ValPtr Eval(Frame* f) const override;
|
||||
void Assign(Frame* f, ValPtr v) override;
|
||||
|
@ -282,10 +416,20 @@ public:
|
|||
|
||||
// Optimization-related:
|
||||
ExprPtr Duplicate() override;
|
||||
bool HasNoSideEffects() const override { return true; }
|
||||
bool IsReduced(Reducer* c) const override;
|
||||
bool HasReducedOps(Reducer* c) const override { return IsReduced(c); }
|
||||
bool WillTransform(Reducer* c) const override { return ! IsReduced(c); }
|
||||
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||
ValPtr FoldVal() const override;
|
||||
|
||||
protected:
|
||||
void ExprDescribe(ODesc* d) const override;
|
||||
|
||||
// Returns true if our identifier is a global with a constant value
|
||||
// that can be propagated; used for optimization.
|
||||
bool FoldableGlobal() const;
|
||||
|
||||
IDPtr id;
|
||||
bool in_const_init;
|
||||
};
|
||||
|
@ -303,6 +447,7 @@ public:
|
|||
|
||||
// Optimization-related:
|
||||
ExprPtr Duplicate() override;
|
||||
ValPtr FoldVal() const override { return val; }
|
||||
|
||||
protected:
|
||||
void ExprDescribe(ODesc* d) const override;
|
||||
|
@ -325,6 +470,14 @@ public:
|
|||
// Optimization-related:
|
||||
ExprPtr Inline(Inliner* inl) override;
|
||||
|
||||
bool HasNoSideEffects() const override;
|
||||
bool IsReduced(Reducer* c) const override;
|
||||
bool HasReducedOps(Reducer* c) const override;
|
||||
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||
|
||||
ExprPtr GetOp1() const override final { return op; }
|
||||
void SetOp1(ExprPtr _op) override final { op = std::move(_op); }
|
||||
|
||||
protected:
|
||||
UnaryExpr(BroExprTag arg_tag, ExprPtr arg_op);
|
||||
|
||||
|
@ -353,6 +506,17 @@ public:
|
|||
// Optimization-related:
|
||||
ExprPtr Inline(Inliner* inl) override;
|
||||
|
||||
bool HasNoSideEffects() const override;
|
||||
bool IsReduced(Reducer* c) const override;
|
||||
bool HasReducedOps(Reducer* c) const override;
|
||||
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||
|
||||
ExprPtr GetOp1() const override final { return op1; }
|
||||
ExprPtr GetOp2() const override final { return op2; }
|
||||
|
||||
void SetOp1(ExprPtr _op) override final { std::move(op1 = _op); }
|
||||
void SetOp2(ExprPtr _op) override final { std::move(op2 = _op); }
|
||||
|
||||
protected:
|
||||
BinaryExpr(BroExprTag arg_tag,
|
||||
ExprPtr arg_op1, ExprPtr arg_op2)
|
||||
|
@ -425,6 +589,12 @@ public:
|
|||
|
||||
// Optimization-related:
|
||||
ExprPtr Duplicate() override;
|
||||
bool HasNoSideEffects() const override;
|
||||
bool WillTransform(Reducer* c) const override { return true; }
|
||||
bool IsReduced(Reducer* c) const override;
|
||||
bool HasReducedOps(Reducer* c) const override { return false; }
|
||||
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||
ExprPtr ReduceToSingleton(Reducer* c, StmtPtr& red_stmt) override;
|
||||
};
|
||||
|
||||
class ComplementExpr final : public UnaryExpr {
|
||||
|
@ -433,6 +603,8 @@ public:
|
|||
|
||||
// Optimization-related:
|
||||
ExprPtr Duplicate() override;
|
||||
bool WillTransform(Reducer* c) const override;
|
||||
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||
|
||||
protected:
|
||||
ValPtr Fold(Val* v) const override;
|
||||
|
@ -444,6 +616,8 @@ public:
|
|||
|
||||
// Optimization-related:
|
||||
ExprPtr Duplicate() override;
|
||||
bool WillTransform(Reducer* c) const override;
|
||||
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||
|
||||
protected:
|
||||
ValPtr Fold(Val* v) const override;
|
||||
|
@ -455,6 +629,8 @@ public:
|
|||
|
||||
// Optimization-related:
|
||||
ExprPtr Duplicate() override;
|
||||
bool WillTransform(Reducer* c) const override;
|
||||
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||
|
||||
protected:
|
||||
ValPtr Fold(Val* v) const override;
|
||||
|
@ -466,6 +642,8 @@ public:
|
|||
|
||||
// Optimization-related:
|
||||
ExprPtr Duplicate() override;
|
||||
bool WillTransform(Reducer* c) const override;
|
||||
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||
|
||||
protected:
|
||||
ValPtr Fold(Val* v) const override;
|
||||
|
@ -490,6 +668,11 @@ public:
|
|||
|
||||
// Optimization-related:
|
||||
ExprPtr Duplicate() override;
|
||||
bool WillTransform(Reducer* c) const override;
|
||||
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||
|
||||
protected:
|
||||
ExprPtr BuildSub(const ExprPtr& op1, const ExprPtr& op2);
|
||||
};
|
||||
|
||||
class AddToExpr final : public BinaryExpr {
|
||||
|
@ -499,6 +682,8 @@ public:
|
|||
|
||||
// Optimization-related:
|
||||
ExprPtr Duplicate() override;
|
||||
bool WillTransform(Reducer* c) const override { return true; }
|
||||
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||
};
|
||||
|
||||
class RemoveFromExpr final : public BinaryExpr {
|
||||
|
@ -508,6 +693,8 @@ public:
|
|||
|
||||
// Optimization-related:
|
||||
ExprPtr Duplicate() override;
|
||||
bool WillTransform(Reducer* c) const override { return true; }
|
||||
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||
};
|
||||
|
||||
class SubExpr final : public BinaryExpr {
|
||||
|
@ -516,6 +703,8 @@ public:
|
|||
|
||||
// Optimization-related:
|
||||
ExprPtr Duplicate() override;
|
||||
bool WillTransform(Reducer* c) const override;
|
||||
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||
};
|
||||
|
||||
class TimesExpr final : public BinaryExpr {
|
||||
|
@ -525,6 +714,8 @@ public:
|
|||
|
||||
// Optimization-related:
|
||||
ExprPtr Duplicate() override;
|
||||
bool WillTransform(Reducer* c) const override;
|
||||
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||
};
|
||||
|
||||
class DivideExpr final : public BinaryExpr {
|
||||
|
@ -533,6 +724,8 @@ public:
|
|||
|
||||
// Optimization-related:
|
||||
ExprPtr Duplicate() override;
|
||||
bool WillTransform(Reducer* c) const override;
|
||||
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||
|
||||
protected:
|
||||
ValPtr AddrFold(Val* v1, Val* v2) const override;
|
||||
|
@ -555,6 +748,13 @@ public:
|
|||
|
||||
// Optimization-related:
|
||||
ExprPtr Duplicate() override;
|
||||
bool WillTransform(Reducer* c) const override { return true; }
|
||||
bool WillTransformInConditional(Reducer* c) const override;
|
||||
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||
|
||||
protected:
|
||||
bool IsTrue(const ExprPtr& e) const;
|
||||
bool IsFalse(const ExprPtr& e) const;
|
||||
};
|
||||
|
||||
class BitExpr final : public BinaryExpr {
|
||||
|
@ -563,6 +763,8 @@ public:
|
|||
|
||||
// Optimization-related:
|
||||
ExprPtr Duplicate() override;
|
||||
bool WillTransform(Reducer* c) const override;
|
||||
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||
};
|
||||
|
||||
class EqExpr final : public BinaryExpr {
|
||||
|
@ -572,6 +774,8 @@ public:
|
|||
|
||||
// Optimization-related:
|
||||
ExprPtr Duplicate() override;
|
||||
bool WillTransform(Reducer* c) const override;
|
||||
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||
|
||||
protected:
|
||||
ValPtr Fold(Val* v1, Val* v2) const override;
|
||||
|
@ -584,6 +788,8 @@ public:
|
|||
|
||||
// Optimization-related:
|
||||
ExprPtr Duplicate() override;
|
||||
bool WillTransform(Reducer* c) const override;
|
||||
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||
};
|
||||
|
||||
class CondExpr final : public Expr {
|
||||
|
@ -603,6 +809,20 @@ public:
|
|||
ExprPtr Duplicate() override;
|
||||
ExprPtr Inline(Inliner* inl) override;
|
||||
|
||||
bool WillTransform(Reducer* c) const override;
|
||||
bool IsReduced(Reducer* c) const override;
|
||||
bool HasReducedOps(Reducer* c) const override;
|
||||
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||
StmtPtr ReduceToSingletons(Reducer* c) override;
|
||||
|
||||
ExprPtr GetOp1() const override final { return op1; }
|
||||
ExprPtr GetOp2() const override final { return op2; }
|
||||
ExprPtr GetOp3() const override final { return op3; }
|
||||
|
||||
void SetOp1(ExprPtr _op) override final { op1 = std::move(_op); }
|
||||
void SetOp2(ExprPtr _op) override final { op2 = std::move(_op); }
|
||||
void SetOp3(ExprPtr _op) override final { op3 = std::move(_op); }
|
||||
|
||||
protected:
|
||||
void ExprDescribe(ODesc* d) const override;
|
||||
|
||||
|
@ -620,6 +840,14 @@ public:
|
|||
|
||||
// Optimization-related:
|
||||
ExprPtr Duplicate() override;
|
||||
|
||||
bool WillTransform(Reducer* c) const override;
|
||||
bool IsReduced(Reducer* c) const override;
|
||||
bool HasReducedOps(Reducer* c) const override;
|
||||
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||
|
||||
// Reduce to simplifed LHS form, i.e., a reference to only a name.
|
||||
StmtPtr ReduceToLHS(Reducer* c);
|
||||
};
|
||||
|
||||
class AssignExpr : public BinaryExpr {
|
||||
|
@ -628,7 +856,8 @@ public:
|
|||
// yet still perform the assignment. Used for triggers.
|
||||
AssignExpr(ExprPtr op1, ExprPtr op2, bool is_init,
|
||||
ValPtr val = nullptr,
|
||||
const AttributesPtr& attrs = nullptr);
|
||||
const AttributesPtr& attrs = nullptr,
|
||||
bool type_check = true);
|
||||
|
||||
ValPtr Eval(Frame* f) const override;
|
||||
void EvalIntoAggregate(const zeek::Type* t, Val* aggr, Frame* f) const override;
|
||||
|
@ -637,20 +866,29 @@ public:
|
|||
ValPtr InitVal(const zeek::Type* t, ValPtr aggr) const override;
|
||||
bool IsPure() const override;
|
||||
|
||||
void SetOp2(ExprPtr e)
|
||||
{
|
||||
op2 = std::move(e);
|
||||
}
|
||||
|
||||
// Optimization-related:
|
||||
ExprPtr Duplicate() override;
|
||||
|
||||
bool HasNoSideEffects() const override;
|
||||
bool WillTransform(Reducer* c) const override { return true; }
|
||||
bool IsReduced(Reducer* c) const override;
|
||||
bool HasReducedOps(Reducer* c) const override;
|
||||
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||
ExprPtr ReduceToSingleton(Reducer* c, StmtPtr& red_stmt) override;
|
||||
|
||||
// Whether this is an assignment to a temporary.
|
||||
bool IsTemp() const { return is_temp; }
|
||||
void SetIsTemp() { is_temp = true; }
|
||||
|
||||
protected:
|
||||
bool TypeCheck(const AttributesPtr& attrs = nullptr);
|
||||
bool TypeCheckArithmetics(TypeTag bt1, TypeTag bt2);
|
||||
|
||||
bool is_init;
|
||||
ValPtr val; // optional
|
||||
|
||||
// Optimization-related:
|
||||
bool is_temp = false;
|
||||
};
|
||||
|
||||
class IndexSliceAssignExpr final : public AssignExpr {
|
||||
|
@ -688,6 +926,9 @@ public:
|
|||
// Optimization-related:
|
||||
ExprPtr Duplicate() override;
|
||||
|
||||
bool HasReducedOps(Reducer* c) const override;
|
||||
StmtPtr ReduceToSingletons(Reducer* c) override;
|
||||
|
||||
protected:
|
||||
ValPtr Fold(Val* v1, Val* v2) const override;
|
||||
|
||||
|
@ -797,6 +1038,10 @@ public:
|
|||
// Optimization-related:
|
||||
ExprPtr Duplicate() override;
|
||||
|
||||
bool HasReducedOps(Reducer* c) const override;
|
||||
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||
StmtPtr ReduceToSingletons(Reducer* c) override;
|
||||
|
||||
protected:
|
||||
ValPtr InitVal(const zeek::Type* t, ValPtr aggr) const override;
|
||||
|
||||
|
@ -823,6 +1068,10 @@ public:
|
|||
// Optimization-related:
|
||||
ExprPtr Duplicate() override;
|
||||
|
||||
bool HasReducedOps(Reducer* c) const override;
|
||||
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||
StmtPtr ReduceToSingletons(Reducer* c) override;
|
||||
|
||||
protected:
|
||||
ValPtr InitVal(const zeek::Type* t, ValPtr aggr) const override;
|
||||
|
||||
|
@ -849,6 +1098,10 @@ public:
|
|||
// Optimization-related:
|
||||
ExprPtr Duplicate() override;
|
||||
|
||||
bool HasReducedOps(Reducer* c) const override;
|
||||
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||
StmtPtr ReduceToSingletons(Reducer* c) override;
|
||||
|
||||
protected:
|
||||
ValPtr InitVal(const zeek::Type* t, ValPtr aggr) const override;
|
||||
|
||||
|
@ -867,6 +1120,8 @@ public:
|
|||
// Optimization-related:
|
||||
ExprPtr Duplicate() override;
|
||||
|
||||
bool HasReducedOps(Reducer* c) const override;
|
||||
|
||||
protected:
|
||||
ValPtr InitVal(const zeek::Type* t, ValPtr aggr) const override;
|
||||
|
||||
|
@ -885,6 +1140,9 @@ public:
|
|||
// Optimization-related:
|
||||
ExprPtr Duplicate() override;
|
||||
|
||||
bool WillTransform(Reducer* c) const override { return true; }
|
||||
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||
|
||||
protected:
|
||||
void ExprDescribe(ODesc* d) const override;
|
||||
|
||||
|
@ -898,6 +1156,9 @@ public:
|
|||
// Optimization-related:
|
||||
ExprPtr Duplicate() override;
|
||||
|
||||
bool WillTransform(Reducer* c) const override;
|
||||
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||
|
||||
protected:
|
||||
ValPtr FoldSingleVal(Val* v, InternalTypeTag t) const;
|
||||
ValPtr Fold(Val* v) const override;
|
||||
|
@ -974,6 +1235,16 @@ public:
|
|||
ExprPtr Duplicate() override;
|
||||
ExprPtr Inline(Inliner* inl) override;
|
||||
|
||||
bool IsReduced(Reducer* c) const override;
|
||||
bool HasReducedOps(Reducer* c) const override;
|
||||
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||
|
||||
ExprPtr GetOp1() const override final;
|
||||
ExprPtr GetOp2() const override final;
|
||||
|
||||
void SetOp1(ExprPtr _op) override final;
|
||||
void SetOp2(ExprPtr _op) override final;
|
||||
|
||||
protected:
|
||||
void ExprDescribe(ODesc* d) const override;
|
||||
|
||||
|
@ -988,6 +1259,8 @@ public:
|
|||
// Optimization-related:
|
||||
ExprPtr Duplicate() override;
|
||||
|
||||
bool HasReducedOps(Reducer* c) const override;
|
||||
|
||||
protected:
|
||||
ValPtr Fold(Val* v1, Val* v2) const override;
|
||||
|
||||
|
@ -1011,6 +1284,11 @@ public:
|
|||
ExprPtr Duplicate() override;
|
||||
ExprPtr Inline(Inliner* inl) override;
|
||||
|
||||
bool IsReduced(Reducer* c) const override;
|
||||
bool HasReducedOps(Reducer* c) const override;
|
||||
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||
StmtPtr ReduceToSingletons(Reducer* c) override;
|
||||
|
||||
protected:
|
||||
void ExprDescribe(ODesc* d) const override;
|
||||
|
||||
|
@ -1038,6 +1316,8 @@ public:
|
|||
ExprPtr Duplicate() override;
|
||||
ExprPtr Inline(Inliner* inl) override;
|
||||
|
||||
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||
|
||||
protected:
|
||||
void ExprDescribe(ODesc* d) const override;
|
||||
|
||||
|
@ -1048,30 +1328,8 @@ private:
|
|||
std::string my_name;
|
||||
};
|
||||
|
||||
class EventExpr final : public Expr {
|
||||
public:
|
||||
EventExpr(const char* name, ListExprPtr args);
|
||||
|
||||
const char* Name() const { return name.c_str(); }
|
||||
ListExpr* Args() const { return args.get(); }
|
||||
EventHandlerPtr Handler() const { return handler; }
|
||||
|
||||
ValPtr Eval(Frame* f) const override;
|
||||
|
||||
TraversalCode Traverse(TraversalCallback* cb) const override;
|
||||
|
||||
// Optimization-related:
|
||||
ExprPtr Duplicate() override;
|
||||
ExprPtr Inline(Inliner* inl) override;
|
||||
|
||||
protected:
|
||||
void ExprDescribe(ODesc* d) const override;
|
||||
|
||||
std::string name;
|
||||
EventHandlerPtr handler;
|
||||
ListExprPtr args;
|
||||
};
|
||||
|
||||
// This comes before EventExpr so that EventExpr::GetOp1 can return its
|
||||
// arguments as convertible to ExprPtr.
|
||||
class ListExpr : public Expr {
|
||||
public:
|
||||
ListExpr();
|
||||
|
@ -1099,6 +1357,11 @@ public:
|
|||
ExprPtr Duplicate() override;
|
||||
ExprPtr Inline(Inliner* inl) override;
|
||||
|
||||
bool IsReduced(Reducer* c) const override;
|
||||
bool HasReducedOps(Reducer* c) const override;
|
||||
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||
StmtPtr ReduceToSingletons(Reducer* c) override;
|
||||
|
||||
protected:
|
||||
ValPtr AddSetInit(const zeek::Type* t, ValPtr aggr) const;
|
||||
|
||||
|
@ -1107,6 +1370,38 @@ protected:
|
|||
ExprPList exprs;
|
||||
};
|
||||
|
||||
class EventExpr final : public Expr {
|
||||
public:
|
||||
EventExpr(const char* name, ListExprPtr args);
|
||||
|
||||
const char* Name() const { return name.c_str(); }
|
||||
ListExpr* Args() const { return args.get(); }
|
||||
EventHandlerPtr Handler() const { return handler; }
|
||||
|
||||
ValPtr Eval(Frame* f) const override;
|
||||
|
||||
TraversalCode Traverse(TraversalCallback* cb) const override;
|
||||
|
||||
// Optimization-related:
|
||||
ExprPtr Duplicate() override;
|
||||
ExprPtr Inline(Inliner* inl) override;
|
||||
|
||||
bool IsReduced(Reducer* c) const override;
|
||||
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||
StmtPtr ReduceToSingletons(Reducer* c) override;
|
||||
|
||||
ExprPtr GetOp1() const override final { return args; }
|
||||
void SetOp1(ExprPtr _op) override final
|
||||
{ args = {NewRef{}, _op->AsListExpr()}; }
|
||||
|
||||
protected:
|
||||
void ExprDescribe(ODesc* d) const override;
|
||||
|
||||
std::string name;
|
||||
EventHandlerPtr handler;
|
||||
ListExprPtr args;
|
||||
};
|
||||
|
||||
|
||||
class RecordAssignExpr final : public ListExpr {
|
||||
public:
|
||||
|
@ -1155,6 +1450,9 @@ public:
|
|||
|
||||
ExprPtr Duplicate() override;
|
||||
|
||||
bool IsReduced(Reducer* c) const override;
|
||||
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||
|
||||
TraversalCode Traverse(TraversalCallback* cb) const override;
|
||||
|
||||
protected:
|
||||
|
@ -1166,6 +1464,134 @@ protected:
|
|||
StmtPtr body;
|
||||
};
|
||||
|
||||
// A companion to AddToExpr that's for vector-append, instantiated during
|
||||
// the reduction process.
|
||||
class AppendToExpr : public BinaryExpr {
|
||||
public:
|
||||
AppendToExpr(ExprPtr op1, ExprPtr op2);
|
||||
ValPtr Eval(Frame* f) const override;
|
||||
|
||||
bool IsReduced(Reducer* c) const override;
|
||||
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||
|
||||
ExprPtr Duplicate() override;
|
||||
};
|
||||
|
||||
// An internal class for reduced form.
|
||||
class IndexAssignExpr : public BinaryExpr {
|
||||
public:
|
||||
// "op1[op2] = op3", all reduced.
|
||||
IndexAssignExpr(ExprPtr op1, ExprPtr op2, ExprPtr op3);
|
||||
|
||||
ValPtr Eval(Frame* f) const override;
|
||||
|
||||
ExprPtr Duplicate() override;
|
||||
|
||||
bool IsReduced(Reducer* c) const override;
|
||||
bool HasReducedOps(Reducer* c) const override;
|
||||
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||
ExprPtr ReduceToSingleton(Reducer* c, StmtPtr& red_stmt) override;
|
||||
|
||||
ExprPtr GetOp3() const override final { return op3; }
|
||||
void SetOp3(ExprPtr _op) override final { op3 = _op; }
|
||||
|
||||
TraversalCode Traverse(TraversalCallback* cb) const override;
|
||||
|
||||
protected:
|
||||
void ExprDescribe(ODesc* d) const override;
|
||||
|
||||
ExprPtr op3; // assignment RHS
|
||||
};
|
||||
|
||||
// An internal class for reduced form.
|
||||
class FieldLHSAssignExpr : public BinaryExpr {
|
||||
public:
|
||||
// "op1$field = RHS", where RHS is reduced with respect to
|
||||
// ReduceToFieldAssignment().
|
||||
FieldLHSAssignExpr(ExprPtr op1, ExprPtr op2, const char* field_name,
|
||||
int field);
|
||||
|
||||
const char* FieldName() const { return field_name; }
|
||||
int Field() const { return field; }
|
||||
|
||||
ValPtr Eval(Frame* f) const override;
|
||||
|
||||
ExprPtr Duplicate() override;
|
||||
|
||||
bool IsReduced(Reducer* c) const override;
|
||||
bool HasReducedOps(Reducer* c) const override;
|
||||
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||
ExprPtr ReduceToSingleton(Reducer* c, StmtPtr& red_stmt) override;
|
||||
|
||||
protected:
|
||||
void ExprDescribe(ODesc* d) const override;
|
||||
|
||||
const char* field_name;
|
||||
int field;
|
||||
};
|
||||
|
||||
// Expression to explicitly capture conversion to an "any" type, rather
|
||||
// than it occurring implicitly during script interpretation.
|
||||
class CoerceToAnyExpr : public UnaryExpr {
|
||||
public:
|
||||
CoerceToAnyExpr(ExprPtr op);
|
||||
|
||||
protected:
|
||||
ValPtr Fold(Val* v) const override;
|
||||
|
||||
ExprPtr Duplicate() override;
|
||||
};
|
||||
|
||||
// Same, but for conversion from an "any" type.
|
||||
class CoerceFromAnyExpr : public UnaryExpr {
|
||||
public:
|
||||
CoerceFromAnyExpr(ExprPtr op, TypePtr to_type);
|
||||
|
||||
protected:
|
||||
ValPtr Fold(Val* v) const override;
|
||||
|
||||
ExprPtr Duplicate() override;
|
||||
};
|
||||
|
||||
// Expression used to explicitly capture [a, b, c, ...] = x assignments.
|
||||
class AnyIndexExpr : public UnaryExpr {
|
||||
public:
|
||||
AnyIndexExpr(ExprPtr op, int index);
|
||||
|
||||
int Index() const { return index; }
|
||||
|
||||
protected:
|
||||
ValPtr Fold(Val* v) const override;
|
||||
|
||||
void ExprDescribe(ODesc* d) const override;
|
||||
|
||||
ExprPtr Duplicate() override;
|
||||
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
|
||||
|
||||
int index;
|
||||
};
|
||||
|
||||
// Used internally for optimization, when a placeholder is needed.
|
||||
class NopExpr : public Expr {
|
||||
public:
|
||||
explicit NopExpr() : Expr(EXPR_NOP) { }
|
||||
|
||||
ValPtr Eval(Frame* f) const override;
|
||||
|
||||
ExprPtr Duplicate() override;
|
||||
|
||||
TraversalCode Traverse(TraversalCallback* cb) const override;
|
||||
|
||||
protected:
|
||||
void ExprDescribe(ODesc* d) const override;
|
||||
};
|
||||
|
||||
|
||||
// Assigns v1[v2] = v3. Returns an error message, or nullptr on success.
|
||||
// Factored out so that compiled code can call it as well as the interpreter.
|
||||
extern const char* assign_to_index(ValPtr v1, ValPtr v2, ValPtr v3,
|
||||
bool& iterators_invalidated);
|
||||
|
||||
|
||||
inline Val* Expr::ExprVal() const
|
||||
{
|
||||
|
|
76
src/Stmt.h
76
src/Stmt.h
|
@ -11,9 +11,12 @@
|
|||
#include "zeek/ID.h"
|
||||
|
||||
ZEEK_FORWARD_DECLARE_NAMESPACED(CompositeHash, zeek::detail);
|
||||
ZEEK_FORWARD_DECLARE_NAMESPACED(NameExpr, zeek::detail);
|
||||
|
||||
namespace zeek::detail {
|
||||
|
||||
using NameExprPtr = IntrusivePtr<zeek::detail::NameExpr>;
|
||||
|
||||
class ExprListStmt : public Stmt {
|
||||
public:
|
||||
const ListExpr* ExprList() const { return l.get(); }
|
||||
|
@ -366,6 +369,11 @@ public:
|
|||
StmtPtr Duplicate() override;
|
||||
void Inline(Inliner* inl) override;
|
||||
|
||||
// Idioms commonly used in reduction.
|
||||
StmtList(StmtPtr s1, Stmt* s2);
|
||||
StmtList(StmtPtr s1, StmtPtr s2);
|
||||
StmtList(StmtPtr s1, StmtPtr s2, StmtPtr s3);
|
||||
|
||||
protected:
|
||||
bool IsPure() const override;
|
||||
|
||||
|
@ -439,6 +447,74 @@ protected:
|
|||
bool is_return;
|
||||
};
|
||||
|
||||
|
||||
// Internal statement used for inlining. Executes a block and stops
|
||||
// the propagation of any "return" inside the block. Generated in
|
||||
// an already-reduced state.
|
||||
class CatchReturnStmt : public Stmt {
|
||||
public:
|
||||
explicit CatchReturnStmt(StmtPtr block, NameExprPtr ret_var);
|
||||
|
||||
StmtPtr Block() const { return block; }
|
||||
|
||||
// This returns a bare pointer rather than a NameExprPtr only
|
||||
// because we don't want to have to include Expr.h in this header.
|
||||
const NameExpr* RetVar() const { return ret_var.get(); }
|
||||
|
||||
// The assignment statement this statement transformed into,
|
||||
// or nil if it hasn't (the common case).
|
||||
StmtPtr AssignStmt() const { return assign_stmt; }
|
||||
|
||||
ValPtr Exec(Frame* f, StmtFlowType& flow) const override;
|
||||
|
||||
bool IsPure() const override;
|
||||
|
||||
// Even though these objects are generated in reduced form, we still
|
||||
// have a reduction method to support the subsequent optimizer pass.
|
||||
StmtPtr DoReduce(Reducer* c) override;
|
||||
|
||||
// Note, no need for a NoFlowAfter() method because anything that
|
||||
// has "NoFlowAfter" inside the body still gets caught and we
|
||||
// continue afterwards.
|
||||
|
||||
StmtPtr Duplicate() override;
|
||||
|
||||
void StmtDescribe(ODesc* d) const override;
|
||||
|
||||
TraversalCode Traverse(TraversalCallback* cb) const override;
|
||||
|
||||
protected:
|
||||
// The inlined function body.
|
||||
StmtPtr block;
|
||||
|
||||
// Expression that holds the return value. Only used for compiling.
|
||||
NameExprPtr ret_var;
|
||||
|
||||
// If this statement transformed into an assignment, that
|
||||
// corresponding statement.
|
||||
StmtPtr assign_stmt;
|
||||
};
|
||||
|
||||
// Statement that makes sure at run-time that an "any" type has the
|
||||
// correct number of (list) entries to enable sub-assigning to it via
|
||||
// statements like "[a, b, c] = x;". Generated in an already-reduced state.
|
||||
class CheckAnyLenStmt : public ExprStmt {
|
||||
public:
|
||||
explicit CheckAnyLenStmt(ExprPtr e, int expected_len);
|
||||
|
||||
ValPtr Exec(Frame* f, StmtFlowType& flow) const override;
|
||||
|
||||
StmtPtr Duplicate() override;
|
||||
|
||||
bool IsReduced(Reducer* c) const override;
|
||||
StmtPtr DoReduce(Reducer* c) override;
|
||||
|
||||
void StmtDescribe(ODesc* d) const override;
|
||||
|
||||
protected:
|
||||
int expected_len;
|
||||
};
|
||||
|
||||
} // namespace zeek::detail
|
||||
|
||||
using ExprListStmt [[deprecated("Remove in v4.1. Use zeek::detail::ExprListStmt instead.")]] = zeek::detail::ExprListStmt;
|
||||
|
|
|
@ -24,11 +24,13 @@ using ValPtr = IntrusivePtr<Val>;
|
|||
|
||||
namespace zeek::detail {
|
||||
|
||||
class StmtList;
|
||||
class ExprStmt;
|
||||
class ForStmt;
|
||||
class InitStmt;
|
||||
class WhenStmt;
|
||||
class ReturnStmt;
|
||||
class StmtList;
|
||||
class SwitchStmt;
|
||||
class WhenStmt;
|
||||
|
||||
class EventExpr;
|
||||
class ListExpr;
|
||||
|
@ -37,6 +39,7 @@ using EventExprPtr = IntrusivePtr<EventExpr>;
|
|||
using ListExprPtr = IntrusivePtr<ListExpr>;
|
||||
|
||||
class Inliner;
|
||||
class Reducer;
|
||||
|
||||
class Stmt;
|
||||
using StmtPtr = IntrusivePtr<Stmt>;
|
||||
|
@ -50,6 +53,7 @@ public:
|
|||
virtual ValPtr Exec(Frame* f, StmtFlowType& flow) const = 0;
|
||||
|
||||
Stmt* Ref() { zeek::Ref(this); return this; }
|
||||
StmtPtr ThisPtr() { return {NewRef{}, this}; }
|
||||
|
||||
bool SetLocationInfo(const Location* loc) override
|
||||
{ return Stmt::SetLocationInfo(loc, loc); }
|
||||
|
@ -64,7 +68,9 @@ public:
|
|||
ForStmt* AsForStmt();
|
||||
const ForStmt* AsForStmt() const;
|
||||
|
||||
const ExprStmt* AsExprStmt() const;
|
||||
const InitStmt* AsInitStmt() const;
|
||||
const ReturnStmt* AsReturnStmt() const;
|
||||
const WhenStmt* AsWhenStmt() const;
|
||||
const SwitchStmt* AsSwitchStmt() const;
|
||||
|
||||
|
@ -81,12 +87,37 @@ public:
|
|||
|
||||
virtual TraversalCode Traverse(TraversalCallback* cb) const = 0;
|
||||
|
||||
// Returns a duplicate of the statement.
|
||||
// Returns a duplicate of the statement so that modifications
|
||||
// can be made to statements from inlining function bodies - or
|
||||
// to the originals - without affecting other instances.
|
||||
//
|
||||
// It's tempting to think that there are some statements that
|
||||
// are safe to share across multiple functions and could just
|
||||
// return references to themselves - but since we associate
|
||||
// information for script optimization with individual statements
|
||||
// nodes, even these need to be duplicated.
|
||||
virtual StmtPtr Duplicate() = 0;
|
||||
|
||||
// Recursively traverses the AST to inline eligible function calls.
|
||||
virtual void Inline(Inliner* inl) { }
|
||||
|
||||
// True if the statement is in reduced form.
|
||||
virtual bool IsReduced(Reducer* c) const;
|
||||
|
||||
// Returns a reduced version of the statement, as managed by
|
||||
// the given Reducer.
|
||||
StmtPtr Reduce(Reducer* c);
|
||||
virtual StmtPtr DoReduce(Reducer* c) { return ThisPtr(); }
|
||||
|
||||
// True if there's definitely no control flow past the statement.
|
||||
// The argument governs whether to ignore "break" statements, given
|
||||
// they mean two different things depending on whether they're in
|
||||
// a loop or a switch. Also, if we want to know whether flow reaches
|
||||
// the *end* of a loop, then we also want to ignore break's, as
|
||||
// in that case, they do lead to flow reaching the end.
|
||||
virtual bool NoFlowAfter(bool ignore_break) const
|
||||
{ return false; }
|
||||
|
||||
// Access to the original statement from which this one is derived,
|
||||
// or this one if we don't have an original. Returns a bare pointer
|
||||
// rather than a StmtPtr to emphasize that the access is read-only.
|
||||
|
@ -124,6 +155,11 @@ public:
|
|||
protected:
|
||||
explicit Stmt(StmtTag arg_tag);
|
||||
|
||||
// Helper function called after reductions to perform canonical
|
||||
// actions. Takes a bare pointer for new_me because usually
|
||||
// it's been newly new'd, so this keeps down code clutter.
|
||||
StmtPtr TransformMe(Stmt* new_me, Reducer* c);
|
||||
|
||||
void AddTag(ODesc* d) const;
|
||||
virtual void StmtDescribe(ODesc* d) const;
|
||||
void DescribeDone(ODesc* d) const;
|
||||
|
|
File diff suppressed because it is too large
Load diff
186
src/script_opt/Reduce.h
Normal file
186
src/script_opt/Reduce.h
Normal file
|
@ -0,0 +1,186 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "zeek/IntrusivePtr.h"
|
||||
|
||||
namespace zeek::detail {
|
||||
|
||||
class Expr;
|
||||
class TempVar;
|
||||
class ProfileFunc;
|
||||
|
||||
class Reducer {
|
||||
public:
|
||||
Reducer(Scope* s);
|
||||
~Reducer();
|
||||
|
||||
StmtPtr Reduce(StmtPtr s)
|
||||
{
|
||||
return s->Reduce(this);
|
||||
}
|
||||
|
||||
ExprPtr GenTemporaryExpr(const TypePtr& t, ExprPtr rhs);
|
||||
|
||||
NameExpr* UpdateName(NameExpr* n);
|
||||
bool NameIsReduced(const NameExpr* n) const;
|
||||
|
||||
void UpdateIDs(IDPList* ids);
|
||||
bool IDsAreReduced(const IDPList* ids) const;
|
||||
|
||||
void UpdateIDs(std::vector<IDPtr>& ids);
|
||||
bool IDsAreReduced(const std::vector<IDPtr>& ids) const;
|
||||
|
||||
IDPtr UpdateID(IDPtr id);
|
||||
bool ID_IsReduced(const IDPtr& id) const
|
||||
{ return ID_IsReduced(id.get()); }
|
||||
bool ID_IsReduced(const ID* id) const;
|
||||
|
||||
// This is called *prior* to pushing a new inline block, in
|
||||
// order to generate the equivalent of function parameters.
|
||||
NameExprPtr GenInlineBlockName(IDPtr id);
|
||||
|
||||
int NumNewLocals() const { return new_locals.size(); }
|
||||
|
||||
// Returns the name of a temporary for holding the return
|
||||
// value of the block, or nil if the type indicates there's
|
||||
// o return value.
|
||||
NameExprPtr PushInlineBlock(TypePtr type);
|
||||
void PopInlineBlock();
|
||||
|
||||
// Whether it's okay to split a statement into two copies for if-else
|
||||
// expansion. We only allow this to a particular depth because
|
||||
// beyond that a function body can get too large to analyze.
|
||||
bool BifurcationOkay() const { return bifurcation_level <= 12; }
|
||||
int BifurcationLevel() const { return bifurcation_level; }
|
||||
|
||||
void PushBifurcation() { ++bifurcation_level; }
|
||||
void PopBifurcation() { --bifurcation_level; }
|
||||
|
||||
int NumTemps() const { return temps.length(); }
|
||||
|
||||
// True if this name already reflects the replacement.
|
||||
bool IsNewLocal(const NameExpr* n) const
|
||||
{ return IsNewLocal(n->Id()); }
|
||||
bool IsNewLocal(const ID* id) const;
|
||||
|
||||
bool IsTemporary(const ID* id) const
|
||||
{ return FindTemporary(id) != nullptr; }
|
||||
|
||||
// This is a stub for now, since it's not relevant for AST
|
||||
// reduction by itself. However, many of the Reduce methods
|
||||
// ultimately will call this predicate to control how they
|
||||
// function during the second traversal used to optimize
|
||||
// the reduced form, so we provide the hook now.
|
||||
bool Optimizing() const { return false; }
|
||||
|
||||
// A stub for now, but ultimately a predicate that indicates whether
|
||||
// a given reduction pass is being made to prune unused statements.
|
||||
bool IsPruning() const { return false; }
|
||||
|
||||
// A stub for now, ultimately a predicate that returns true if
|
||||
// the given statement should be removed due to AST optimization.
|
||||
bool ShouldOmitStmt(const StmtPtr& s) const { return false; }
|
||||
|
||||
// A stub for now, ultimately provides a replacement for the
|
||||
// given statement due to AST optimization, or nil if there's
|
||||
// no replacement.
|
||||
StmtPtr ReplacementStmt(const StmtPtr& s) const { return nullptr; }
|
||||
|
||||
// NOT YET IMPLEMENTED, SO CURRENTLY A STUB:
|
||||
// Given the LHS and RHS of an assignment, returns true
|
||||
// if the RHS is a common subexpression (meaning that the
|
||||
// current assignment statement should be deleted). In
|
||||
// that case, has the side effect of associating an alias
|
||||
// for the LHS with the temporary holding the equivalent RHS.
|
||||
//
|
||||
// Assumes reduction (including alias propagation) has
|
||||
// already been applied.
|
||||
bool IsCSE(const AssignExpr* a, const NameExpr* lhs, const Expr* rhs)
|
||||
{ return false; }
|
||||
|
||||
// Given an lhs=rhs statement followed by succ_stmt, returns
|
||||
// a (new) merge of the two if they're of the form tmp=rhs, var=tmp;
|
||||
// otherwise, nil.
|
||||
Stmt* MergeStmts(const NameExpr* lhs, ExprPtr rhs, Stmt* succ_stmt);
|
||||
|
||||
// The following two methods will, in the future, update expressions
|
||||
// with optimized versions. They are distinct because the first
|
||||
// one (meant for calls in a Stmt reduction context) will also Reduce
|
||||
// the expression, whereas the second one (meant for calls in an Expr
|
||||
// context) does not, to avoid circularity.
|
||||
//
|
||||
// For now, they are stubs.
|
||||
//
|
||||
// These two are used for use in optimizing expressions that appear in
|
||||
// a Stmt context.
|
||||
ExprPtr OptExpr(Expr* e) { return {NewRef{}, e}; }
|
||||
ExprPtr OptExpr(ExprPtr e) { return e; }
|
||||
// This one for expressions appearing in an Expr context.
|
||||
ExprPtr UpdateExpr(ExprPtr e) { return e; }
|
||||
|
||||
const Scope* FuncScope() const { return scope; }
|
||||
|
||||
protected:
|
||||
bool SameVal(const Val* v1, const Val* v2) const;
|
||||
|
||||
IDPtr GenTemporary(const TypePtr& t, ExprPtr rhs);
|
||||
TempVar* FindTemporary(const ID* id) const;
|
||||
|
||||
// Retrieve the identifier corresponding to the new local for
|
||||
// the given expression. Creates the local if necessary.
|
||||
IDPtr FindNewLocal(ID* id);
|
||||
IDPtr FindNewLocal(const NameExpr* n)
|
||||
{ return FindNewLocal(n->Id()); }
|
||||
|
||||
// Generate a new local to use in lieu of the original (seen
|
||||
// in an inlined block). The difference is that the new
|
||||
// version has a distinct name and has a correct frame offset
|
||||
// for the current function.
|
||||
IDPtr GenLocal(ID* orig);
|
||||
|
||||
// Track that we're replacing instances of "orig" with a new
|
||||
// expression. This allows us to locate the RDs associated
|
||||
// with "orig" in the context of the new expression, without
|
||||
// requiring an additional RD propagation pass.
|
||||
void TrackExprReplacement(const Expr* orig, const Expr* e);
|
||||
|
||||
Scope* scope;
|
||||
PList<TempVar> temps;
|
||||
|
||||
// Temps for which we've processed their associated expression
|
||||
// (and they didn't wind up being aliases).
|
||||
PList<TempVar> expr_temps;
|
||||
|
||||
// Let's us go from an identifier to an associated temporary
|
||||
// variable, if it corresponds to one.
|
||||
std::unordered_map<const ID*, TempVar*> ids_to_temps;
|
||||
|
||||
std::unordered_set<ID*> new_locals;
|
||||
std::unordered_map<const ID*, IDPtr> orig_to_new_locals;
|
||||
|
||||
// Tracks whether we're inside an inline block, and if so then
|
||||
// how deeply.
|
||||
int inline_block_level = 0;
|
||||
|
||||
// Tracks how deeply we are in "bifurcation", i.e., duplicating
|
||||
// code for if-else cascades. We need to cap this at a certain
|
||||
// depth or else we can get functions whose size blows up
|
||||
// exponentially.
|
||||
int bifurcation_level = 0;
|
||||
|
||||
// For a new expression we've created, map it to the expression
|
||||
// it's replacing. This allows us to locate the RDs associated
|
||||
// with the usage.
|
||||
std::unordered_map<const Expr*, const Expr*> new_expr_to_orig;
|
||||
};
|
||||
|
||||
// Used for debugging, to communicate which expression wasn't
|
||||
// reduced when we expected them all to be.
|
||||
extern const Expr* non_reduced_perp;
|
||||
extern bool checking_reduction;
|
||||
|
||||
// Used to report a non-reduced expression.
|
||||
extern bool NonReduced(const Expr* perp);
|
||||
|
||||
} // zeek::detail
|
|
@ -1,7 +1,7 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#include "TempVar.h"
|
||||
#include "Reporter.h"
|
||||
#include "zeek/script_opt/TempVar.h"
|
||||
#include "zeek/Reporter.h"
|
||||
|
||||
|
||||
namespace zeek::detail {
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
// Class for managing temporary variables created during statement reduction
|
||||
// for compilation.
|
||||
|
||||
#include "ID.h"
|
||||
#include "Expr.h"
|
||||
#include "zeek/ID.h"
|
||||
#include "zeek/Expr.h"
|
||||
|
||||
|
||||
namespace zeek::detail {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue