mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 06:38:20 +00:00
optimization of scripting idioms - min/max, has-elements
This commit is contained in:
parent
e38053ee3c
commit
5445e8c7ff
5 changed files with 194 additions and 8 deletions
|
@ -883,6 +883,9 @@ public:
|
||||||
protected:
|
protected:
|
||||||
void ExprDescribe(ODesc* d) const override;
|
void ExprDescribe(ODesc* d) const override;
|
||||||
|
|
||||||
|
bool IsMinOrMax(Reducer* c) const;
|
||||||
|
ExprPtr TransformToMinOrMax() const;
|
||||||
|
|
||||||
ExprPtr op1;
|
ExprPtr op1;
|
||||||
ExprPtr op2;
|
ExprPtr op2;
|
||||||
ExprPtr op3;
|
ExprPtr op3;
|
||||||
|
|
|
@ -128,6 +128,9 @@ protected:
|
||||||
ValPtr DoExec(Frame* f, Val* v, StmtFlowType& flow) override;
|
ValPtr DoExec(Frame* f, Val* v, StmtFlowType& flow) override;
|
||||||
bool IsPure() const override;
|
bool IsPure() const override;
|
||||||
|
|
||||||
|
bool IsMinMaxConstruct() const;
|
||||||
|
StmtPtr ConvertToMinMaxConstruct();
|
||||||
|
|
||||||
StmtPtr s1;
|
StmtPtr s1;
|
||||||
StmtPtr s2;
|
StmtPtr s2;
|
||||||
};
|
};
|
||||||
|
|
|
@ -166,7 +166,7 @@ void IfStmt::Inline(Inliner* inl) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IfStmt::IsReduced(Reducer* c) const {
|
bool IfStmt::IsReduced(Reducer* c) const {
|
||||||
if ( e->IsConst() || ! e->IsReducedConditional(c) )
|
if ( e->IsConst() || ! e->IsReducedConditional(c) || IsMinMaxConstruct() )
|
||||||
return NonReduced(e.get());
|
return NonReduced(e.get());
|
||||||
|
|
||||||
return s1->IsReduced(c) && s2->IsReduced(c);
|
return s1->IsReduced(c) && s2->IsReduced(c);
|
||||||
|
@ -179,11 +179,11 @@ StmtPtr IfStmt::DoReduce(Reducer* c) {
|
||||||
e = e->ReduceToConditional(c, red_e_stmt);
|
e = e->ReduceToConditional(c, red_e_stmt);
|
||||||
|
|
||||||
// First, assess some fundamental transformations.
|
// First, assess some fundamental transformations.
|
||||||
if ( e->Tag() == EXPR_NOT ) { // Change "if ( ! x ) s1 else s2" to "if ( x ) s2 else s1".
|
if ( IsMinMaxConstruct() )
|
||||||
auto s1_orig = s1;
|
return ConvertToMinMaxConstruct()->Reduce(c);
|
||||||
s1 = s2;
|
|
||||||
s2 = s1_orig;
|
|
||||||
|
|
||||||
|
if ( e->Tag() == EXPR_NOT ) { // Change "if ( ! x ) s1 else s2" to "if ( x ) s2 else s1".
|
||||||
|
std::swap(s1, s2);
|
||||||
e = e->GetOp1();
|
e = e->GetOp1();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -274,6 +274,81 @@ bool IfStmt::CouldReturn(bool ignore_break) const {
|
||||||
return (s1 && s1->CouldReturn(ignore_break)) || (s2 && s2->CouldReturn(ignore_break));
|
return (s1 && s1->CouldReturn(ignore_break)) || (s2 && s2->CouldReturn(ignore_break));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IfStmt::IsMinMaxConstruct() const {
|
||||||
|
if ( ! s1 || ! s2 )
|
||||||
|
// not an if-else construct
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ( s1->Tag() != STMT_EXPR || s2->Tag() != STMT_EXPR )
|
||||||
|
// definitely not if-else assignments
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto es1 = s1->AsExprStmt()->StmtExpr();
|
||||||
|
auto es2 = s2->AsExprStmt()->StmtExpr();
|
||||||
|
|
||||||
|
if ( es1->Tag() != EXPR_ASSIGN || es2->Tag() != EXPR_ASSIGN )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
switch ( e->Tag() ) {
|
||||||
|
case EXPR_LT:
|
||||||
|
case EXPR_LE:
|
||||||
|
case EXPR_GE:
|
||||||
|
case EXPR_GT: break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Not an apt conditional.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto a1 = es1->AsAssignExpr();
|
||||||
|
auto a2 = es2->AsAssignExpr();
|
||||||
|
auto a1_lhs = a1->GetOp1();
|
||||||
|
auto a2_lhs = a2->GetOp1();
|
||||||
|
|
||||||
|
if ( ! same_expr(a1_lhs, a2_lhs) )
|
||||||
|
// if-else assignments are not to the same variable
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto a1_rhs = a1->GetOp2();
|
||||||
|
auto a2_rhs = a2->GetOp2();
|
||||||
|
auto op1 = e->GetOp1();
|
||||||
|
auto op2 = e->GetOp2();
|
||||||
|
|
||||||
|
if ( ! same_expr(op1, a1_rhs) && ! same_expr(op1, a2_rhs) )
|
||||||
|
// Operand does not appear in the assignment RHS.
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ( ! same_expr(op2, a1_rhs) && ! same_expr(op2, a2_rhs) )
|
||||||
|
// Operand does not appear in the assignment RHS.
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ( same_expr(op1, op2) )
|
||||||
|
// This is degenerate and should be found by other reductions.
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
StmtPtr IfStmt::ConvertToMinMaxConstruct() {
|
||||||
|
auto relop1 = e->GetOp1();
|
||||||
|
auto relop2 = e->GetOp2();
|
||||||
|
|
||||||
|
auto is_min = (e->Tag() == EXPR_LT || e->Tag() == EXPR_LE);
|
||||||
|
auto assign2 = s2->AsExprStmt()->StmtExpr();
|
||||||
|
auto lhs2 = assign2->GetOp1();
|
||||||
|
auto rhs2 = assign2->GetOp2();
|
||||||
|
|
||||||
|
if ( same_expr(relop1, rhs2) )
|
||||||
|
is_min = ! is_min;
|
||||||
|
|
||||||
|
auto built_in = is_min ? ScriptOptBuiltinExpr::MINIMUM : ScriptOptBuiltinExpr::MAXIMUM;
|
||||||
|
|
||||||
|
auto bi = with_location_of(make_intrusive<ScriptOptBuiltinExpr>(built_in, relop1, relop2), this);
|
||||||
|
auto new_assign = with_location_of(make_intrusive<AssignExpr>(lhs2, bi, false), this);
|
||||||
|
|
||||||
|
return with_location_of(make_intrusive<ExprStmt>(new_assign), this);
|
||||||
|
}
|
||||||
|
|
||||||
IntrusivePtr<Case> Case::Duplicate() {
|
IntrusivePtr<Case> Case::Duplicate() {
|
||||||
if ( expr_cases ) {
|
if ( expr_cases ) {
|
||||||
auto new_exprs = expr_cases->Duplicate()->AsListExprPtr();
|
auto new_exprs = expr_cases->Duplicate()->AsListExprPtr();
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#include "zeek/Desc.h"
|
#include "zeek/Desc.h"
|
||||||
#include "zeek/Reporter.h"
|
#include "zeek/Reporter.h"
|
||||||
|
#include "zeek/script_opt/ZAM/BuiltIn.h"
|
||||||
#include "zeek/script_opt/ZAM/Compile.h"
|
#include "zeek/script_opt/ZAM/Compile.h"
|
||||||
|
|
||||||
namespace zeek::detail {
|
namespace zeek::detail {
|
||||||
|
@ -134,8 +135,12 @@ const ZAMStmt ZAMCompiler::CompileAssignExpr(const AssignExpr* e) {
|
||||||
auto op2 = e->GetOp2();
|
auto op2 = e->GetOp2();
|
||||||
|
|
||||||
auto lhs = op1->AsRefExpr()->GetOp1()->AsNameExpr();
|
auto lhs = op1->AsRefExpr()->GetOp1()->AsNameExpr();
|
||||||
auto lt = lhs->GetType().get();
|
|
||||||
auto rhs = op2.get();
|
auto rhs = op2.get();
|
||||||
|
|
||||||
|
if ( rhs->Tag() == EXPR_SCRIPT_OPT_BUILTIN )
|
||||||
|
return CompileZAMBuiltin(lhs, static_cast<const ScriptOptBuiltinExpr*>(rhs));
|
||||||
|
|
||||||
|
auto lt = lhs->GetType().get();
|
||||||
auto r1 = rhs->GetOp1();
|
auto r1 = rhs->GetOp1();
|
||||||
|
|
||||||
if ( rhs->Tag() == EXPR_INDEX && (r1->Tag() == EXPR_NAME || r1->Tag() == EXPR_CONST) )
|
if ( rhs->Tag() == EXPR_INDEX && (r1->Tag() == EXPR_NAME || r1->Tag() == EXPR_CONST) )
|
||||||
|
@ -178,8 +183,10 @@ const ZAMStmt ZAMCompiler::CompileAssignExpr(const AssignExpr* e) {
|
||||||
return L_In_VecVLC(lhs, r1->AsListExpr(), r2c);
|
return L_In_VecVLC(lhs, r1->AsListExpr(), r2c);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( rhs->Tag() == EXPR_ANY_INDEX )
|
if ( rhs->Tag() == EXPR_ANY_INDEX ) {
|
||||||
return AnyIndexVVi(lhs, r1->AsNameExpr(), rhs->AsAnyIndexExpr()->Index());
|
auto rhs_as_any = static_cast<const AnyIndexExpr*>(rhs);
|
||||||
|
return AnyIndexVVi(lhs, r1->AsNameExpr(), rhs_as_any->Index());
|
||||||
|
}
|
||||||
|
|
||||||
if ( rhs->Tag() == EXPR_LAMBDA )
|
if ( rhs->Tag() == EXPR_LAMBDA )
|
||||||
return BuildLambda(lhs, rhs->AsLambdaExpr());
|
return BuildLambda(lhs, rhs->AsLambdaExpr());
|
||||||
|
@ -220,6 +227,72 @@ const ZAMStmt ZAMCompiler::CompileAssignExpr(const AssignExpr* e) {
|
||||||
#include "ZAM-GenExprsDefsV.h"
|
#include "ZAM-GenExprsDefsV.h"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ZAMStmt ZAMCompiler::CompileZAMBuiltin(const NameExpr* lhs, const ScriptOptBuiltinExpr* zbi) {
|
||||||
|
auto op1 = zbi->GetOp1();
|
||||||
|
auto op2 = zbi->GetOp2();
|
||||||
|
|
||||||
|
switch ( zbi->Tag() ) {
|
||||||
|
case ScriptOptBuiltinExpr::MINIMUM:
|
||||||
|
case ScriptOptBuiltinExpr::MAXIMUM: {
|
||||||
|
auto t1 = op1->GetType()->InternalType();
|
||||||
|
ASSERT(t1 == op2->GetType()->InternalType());
|
||||||
|
|
||||||
|
bool is_min = zbi->Tag() == ScriptOptBuiltinExpr::MINIMUM;
|
||||||
|
// Canonicalize to have constant as second op.
|
||||||
|
if ( op1->Tag() == EXPR_CONST ) {
|
||||||
|
ASSERT(op2->Tag() != EXPR_CONST);
|
||||||
|
std::swap(op1, op2);
|
||||||
|
is_min = ! is_min;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZOp op;
|
||||||
|
|
||||||
|
auto n1 = op1->AsNameExpr();
|
||||||
|
auto n2 = op2->Tag() == EXPR_NAME ? op2->AsNameExpr() : nullptr;
|
||||||
|
auto c = op2->Tag() == EXPR_CONST ? op2->AsConstExpr() : nullptr;
|
||||||
|
|
||||||
|
if ( c ) {
|
||||||
|
if ( t1 == TYPE_INTERNAL_UNSIGNED )
|
||||||
|
op = is_min ? OP_MINU_VVC : OP_MAXU_VVC;
|
||||||
|
else if ( t1 == TYPE_INTERNAL_INT )
|
||||||
|
op = is_min ? OP_MINI_VVC : OP_MAXI_VVC;
|
||||||
|
else {
|
||||||
|
ASSERT(t1 == TYPE_INTERNAL_DOUBLE);
|
||||||
|
op = is_min ? OP_MIND_VVC : OP_MAXD_VVC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if ( t1 == TYPE_INTERNAL_UNSIGNED )
|
||||||
|
op = is_min ? OP_MINU_VVV : OP_MAXU_VVV;
|
||||||
|
else if ( t1 == TYPE_INTERNAL_INT )
|
||||||
|
op = is_min ? OP_MINI_VVV : OP_MAXI_VVV;
|
||||||
|
else {
|
||||||
|
ASSERT(t1 == TYPE_INTERNAL_DOUBLE);
|
||||||
|
op = is_min ? OP_MIND_VVV : OP_MAXD_VVV;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( c )
|
||||||
|
return AddInst(GenInst(op, lhs, n1, c));
|
||||||
|
else
|
||||||
|
return AddInst(GenInst(op, lhs, n1, n2));
|
||||||
|
}
|
||||||
|
|
||||||
|
case ScriptOptBuiltinExpr::HAS_ELEMENTS: {
|
||||||
|
auto n = op1->AsNameExpr();
|
||||||
|
auto op = op1->GetType()->Tag() == TYPE_TABLE ? OP_TABLE_HAS_ELEMENTS_VV : OP_VECTOR_HAS_ELEMENTS_VV;
|
||||||
|
return AddInst(GenInst(op, lhs, n));
|
||||||
|
}
|
||||||
|
|
||||||
|
case ScriptOptBuiltinExpr::FUNC_ID_STRING: {
|
||||||
|
auto n = op1->AsNameExpr();
|
||||||
|
return AddInst(GenInst(OP_FUNC_ID_STRING_VV, lhs, n));
|
||||||
|
}
|
||||||
|
|
||||||
|
default: reporter->InternalError("bad built-in tag in ZAMCompiler::CompileZAMBuiltin");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const ZAMStmt ZAMCompiler::CompileAssignToIndex(const NameExpr* lhs, const IndexExpr* rhs) {
|
const ZAMStmt ZAMCompiler::CompileAssignToIndex(const NameExpr* lhs, const IndexExpr* rhs) {
|
||||||
auto aggr = rhs->GetOp1();
|
auto aggr = rhs->GetOp1();
|
||||||
auto const_aggr = aggr->Tag() == EXPR_CONST;
|
auto const_aggr = aggr->Tag() == EXPR_CONST;
|
||||||
|
|
|
@ -666,6 +666,38 @@ type VVV
|
||||||
eval if ( frame[z.v1].record_val->HasField(z.v2) )
|
eval if ( frame[z.v1].record_val->HasField(z.v2) )
|
||||||
BRANCH(v3)
|
BRANCH(v3)
|
||||||
|
|
||||||
|
internal-op Table-Has-Elements
|
||||||
|
type VV
|
||||||
|
eval frame[z.v1].int_val = frame[z.v2].table_val->Size() > 0;
|
||||||
|
|
||||||
|
internal-op Table-Has-Elements-Cond
|
||||||
|
op1-read
|
||||||
|
type VV
|
||||||
|
eval if ( frame[z.v1].table_val->Size() == 0 )
|
||||||
|
BRANCH(v2)
|
||||||
|
|
||||||
|
internal-op Not-Table-Has-Elements-Cond
|
||||||
|
op1-read
|
||||||
|
type VV
|
||||||
|
eval if ( frame[z.v1].table_val->Size() > 0 )
|
||||||
|
BRANCH(v2)
|
||||||
|
|
||||||
|
internal-op Vector-Has-Elements
|
||||||
|
type VV
|
||||||
|
eval frame[z.v1].int_val = frame[z.v2].vector_val->Size() > 0;
|
||||||
|
|
||||||
|
internal-op Vector-Has-Elements-Cond
|
||||||
|
op1-read
|
||||||
|
type VV
|
||||||
|
eval if ( frame[z.v1].vector_val->Size() == 0 )
|
||||||
|
BRANCH(v2)
|
||||||
|
|
||||||
|
internal-op Not-Vector-Has-Elements-Cond
|
||||||
|
op1-read
|
||||||
|
type VV
|
||||||
|
eval if ( frame[z.v1].vector_val->Size() > 0 )
|
||||||
|
BRANCH(v2)
|
||||||
|
|
||||||
expr-op In
|
expr-op In
|
||||||
type VVV
|
type VVV
|
||||||
custom-method return CompileInExpr(n1, n2, n3);
|
custom-method return CompileInExpr(n1, n2, n3);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue