Reformat the world

This commit is contained in:
Tim Wojtulewicz 2021-09-16 15:35:39 -07:00
parent 194cb24547
commit b2f171ec69
714 changed files with 35149 additions and 35203 deletions

View file

@ -4,14 +4,15 @@
// i.e., code improvement that's done after the compiler has generated
// an initial, complete intermediary function body.
#include "zeek/input.h"
#include "zeek/Reporter.h"
#include "zeek/Desc.h"
#include "zeek/Reporter.h"
#include "zeek/input.h"
#include "zeek/script_opt/Reduce.h"
#include "zeek/script_opt/ScriptOpt.h"
#include "zeek/script_opt/ZAM/Compile.h"
namespace zeek::detail {
namespace zeek::detail
{
// Tracks per function its maximum remapped interpreter frame size. We
// can't do this when compiling individual functions since for event handlers
@ -42,8 +43,7 @@ void finalize_functions(const std::vector<FuncInfo>& funcs)
// preserve the size they need.
int size = func->FrameSize();
if ( f.Body()->Tag() != STMT_ZAM &&
remapped_intrp_frame_sizes.count(func) > 0 &&
if ( f.Body()->Tag() != STMT_ZAM && remapped_intrp_frame_sizes.count(func) > 0 &&
size > remapped_intrp_frame_sizes[func] )
remapped_intrp_frame_sizes[func] = size;
}
@ -63,7 +63,6 @@ void finalize_functions(const std::vector<FuncInfo>& funcs)
}
}
// The following is for activating detailed dumping for debugging
// optimizer problems.
static bool dump_intermediaries = false;
@ -133,15 +132,13 @@ void ZAMCompiler::OptimizeInsts()
DumpInsts1(nullptr);
}
}
}
while ( something_changed );
} while ( something_changed );
ReMapFrame();
ReMapInterpreterFrame();
}
template<typename T>
void ZAMCompiler::TallySwitchTargets(const CaseMapsI<T>& switches)
template <typename T> void ZAMCompiler::TallySwitchTargets(const CaseMapsI<T>& switches)
{
for ( auto& targs : switches )
for ( auto& targ : targs )
@ -177,8 +174,7 @@ bool ZAMCompiler::RemoveDeadCode()
continue;
}
if ( t && t->inst_num > i0->inst_num &&
(! i1 || t->inst_num <= i1->inst_num) )
if ( t && t->inst_num > i0->inst_num && (! i1 || t->inst_num <= i1->inst_num) )
{
// This is effectively a branch to the next
// instruction. Even if i0 is conditional, there's
@ -362,106 +358,105 @@ void ZAMCompiler::ComputeFrameLifetimes()
CheckSlotAssignment(inst->v1, inst);
// Some special-casing.
switch ( inst->op ) {
case OP_NEXT_TABLE_ITER_VV:
case OP_NEXT_TABLE_ITER_VAL_VAR_VVV:
switch ( inst->op )
{
// These assign to an arbitrary long list of variables.
auto& iter_vars = inst->aux->loop_vars;
auto depth = inst->loop_depth;
case OP_NEXT_TABLE_ITER_VV:
case OP_NEXT_TABLE_ITER_VAL_VAR_VVV:
{
// These assign to an arbitrary long list of variables.
auto& iter_vars = inst->aux->loop_vars;
auto depth = inst->loop_depth;
for ( auto v : iter_vars )
{
CheckSlotAssignment(v, inst);
for ( auto v : iter_vars )
{
CheckSlotAssignment(v, inst);
// Also mark it as usage throughout the
// loop. Otherwise, we risk pruning the
// variable if it happens to not be used
// (which will mess up the iteration logic)
// or doubling it up with some other value
// inside the loop (which will fail when
// the loop var has memory management
// associated with it).
ExtendLifetime(v, EndOfLoop(inst, depth));
}
// Also mark it as usage throughout the
// loop. Otherwise, we risk pruning the
// variable if it happens to not be used
// (which will mess up the iteration logic)
// or doubling it up with some other value
// inside the loop (which will fail when
// the loop var has memory management
// associated with it).
ExtendLifetime(v, EndOfLoop(inst, depth));
}
// No need to check the additional "var" associated
// with OP_NEXT_TABLE_ITER_VAL_VAR_VVV as that's
// a slot-1 assignment. However, similar to other
// loop variables, mark this as a usage.
if ( inst->op == OP_NEXT_TABLE_ITER_VAL_VAR_VVV )
ExtendLifetime(inst->v1, EndOfLoop(inst, depth));
}
break;
case OP_NEXT_TABLE_ITER_NO_VARS_VV:
break;
case OP_NEXT_TABLE_ITER_VAL_VAR_NO_VARS_VVV:
{
auto depth = inst->loop_depth;
ExtendLifetime(inst->v1, EndOfLoop(inst, depth));
}
break;
case OP_NEXT_VECTOR_ITER_VVV:
case OP_NEXT_STRING_ITER_VVV:
// Sometimes loops are written that don't actually
// use the iteration variable. However, we still
// need to mark the variable as having usage
// throughout the loop, lest we elide the iteration
// instruction. An alternative would be to transform
// such iterators into variable-less versions. That
// optimization hardly seems worth the trouble, though,
// given the presumed rarity of such loops.
ExtendLifetime(inst->v1,
EndOfLoop(inst, inst->loop_depth));
break;
case OP_INIT_TABLE_LOOP_VV:
case OP_INIT_VECTOR_LOOP_VV:
case OP_INIT_STRING_LOOP_VV:
{
// For all of these, the scope of the aggregate being
// looped over is the entire loop, even if it doesn't
// directly appear in it, and not just the initializer.
// For all three, the aggregate is in v1.
ASSERT(i < insts1.size() - 1);
auto succ = insts1[i+1];
ASSERT(succ->live);
auto depth = succ->loop_depth;
ExtendLifetime(inst->v1, EndOfLoop(succ, depth));
// Important: we skip the usual UsesSlots analysis
// below since we've already set it, and don't want
// to perturb ExtendLifetime's consistency check.
continue;
}
case OP_STORE_GLOBAL_V:
{
// Use of the global goes to here.
auto slot = frame_layout1[globalsI[inst->v1].id.get()];
ExtendLifetime(slot, EndOfLoop(inst, 1));
break;
}
default:
// Look for slots in auxiliary information.
auto aux = inst->aux;
if ( ! aux || ! aux->slots )
// No need to check the additional "var" associated
// with OP_NEXT_TABLE_ITER_VAL_VAR_VVV as that's
// a slot-1 assignment. However, similar to other
// loop variables, mark this as a usage.
if ( inst->op == OP_NEXT_TABLE_ITER_VAL_VAR_VVV )
ExtendLifetime(inst->v1, EndOfLoop(inst, depth));
}
break;
for ( auto j = 0; j < aux->n; ++j )
{
if ( aux->slots[j] < 0 )
continue;
case OP_NEXT_TABLE_ITER_NO_VARS_VV:
break;
ExtendLifetime(aux->slots[j],
EndOfLoop(inst, 1));
}
break;
}
case OP_NEXT_TABLE_ITER_VAL_VAR_NO_VARS_VVV:
{
auto depth = inst->loop_depth;
ExtendLifetime(inst->v1, EndOfLoop(inst, depth));
}
break;
case OP_NEXT_VECTOR_ITER_VVV:
case OP_NEXT_STRING_ITER_VVV:
// Sometimes loops are written that don't actually
// use the iteration variable. However, we still
// need to mark the variable as having usage
// throughout the loop, lest we elide the iteration
// instruction. An alternative would be to transform
// such iterators into variable-less versions. That
// optimization hardly seems worth the trouble, though,
// given the presumed rarity of such loops.
ExtendLifetime(inst->v1, EndOfLoop(inst, inst->loop_depth));
break;
case OP_INIT_TABLE_LOOP_VV:
case OP_INIT_VECTOR_LOOP_VV:
case OP_INIT_STRING_LOOP_VV:
{
// For all of these, the scope of the aggregate being
// looped over is the entire loop, even if it doesn't
// directly appear in it, and not just the initializer.
// For all three, the aggregate is in v1.
ASSERT(i < insts1.size() - 1);
auto succ = insts1[i + 1];
ASSERT(succ->live);
auto depth = succ->loop_depth;
ExtendLifetime(inst->v1, EndOfLoop(succ, depth));
// Important: we skip the usual UsesSlots analysis
// below since we've already set it, and don't want
// to perturb ExtendLifetime's consistency check.
continue;
}
case OP_STORE_GLOBAL_V:
{
// Use of the global goes to here.
auto slot = frame_layout1[globalsI[inst->v1].id.get()];
ExtendLifetime(slot, EndOfLoop(inst, 1));
break;
}
default:
// Look for slots in auxiliary information.
auto aux = inst->aux;
if ( ! aux || ! aux->slots )
break;
for ( auto j = 0; j < aux->n; ++j )
{
if ( aux->slots[j] < 0 )
continue;
ExtendLifetime(aux->slots[j], EndOfLoop(inst, 1));
}
break;
}
int s1, s2, s3, s4;
@ -560,47 +555,49 @@ void ZAMCompiler::ReMapFrame()
}
// Handle special cases.
switch ( inst->op ) {
case OP_NEXT_TABLE_ITER_VV:
case OP_NEXT_TABLE_ITER_VAL_VAR_VVV:
switch ( inst->op )
{
// Rewrite iteration variables.
auto& iter_vars = inst->aux->loop_vars;
for ( auto& v : iter_vars )
{
ASSERT(v >= 0 && v < n1_slots);
v = frame1_to_frame2[v];
}
}
break;
default:
// Update slots in auxiliary information.
auto aux = inst->aux;
if ( ! aux || ! aux->slots )
case OP_NEXT_TABLE_ITER_VV:
case OP_NEXT_TABLE_ITER_VAL_VAR_VVV:
{
// Rewrite iteration variables.
auto& iter_vars = inst->aux->loop_vars;
for ( auto& v : iter_vars )
{
ASSERT(v >= 0 && v < n1_slots);
v = frame1_to_frame2[v];
}
}
break;
for ( auto j = 0; j < aux->n; ++j )
{
auto& slot = aux->slots[j];
default:
// Update slots in auxiliary information.
auto aux = inst->aux;
if ( ! aux || ! aux->slots )
break;
if ( slot < 0 )
// This is instead a constant.
continue;
auto new_slot = frame1_to_frame2[slot];
if ( new_slot < 0 )
for ( auto j = 0; j < aux->n; ++j )
{
ODesc d;
inst->stmt->GetLocationInfo()->Describe(&d);
reporter->Error("%s: value used but not set: %s", d.Description(), frame_denizens[slot]->Name());
}
auto& slot = aux->slots[j];
slot = new_slot;
}
break;
}
if ( slot < 0 )
// This is instead a constant.
continue;
auto new_slot = frame1_to_frame2[slot];
if ( new_slot < 0 )
{
ODesc d;
inst->stmt->GetLocationInfo()->Describe(&d);
reporter->Error("%s: value used but not set: %s", d.Description(),
frame_denizens[slot]->Name());
}
slot = new_slot;
}
break;
}
if ( inst->IsGlobalLoad() )
{
@ -686,8 +683,7 @@ void ZAMCompiler::ReMapVar(ID* id, int slot, bro_uint_t inst)
// ZAM instructions are careful to allow operands and
// assignment destinations to refer to the same slot.
if ( s.scope_end <= static_cast<int>(inst) &&
s.is_managed == is_managed )
if ( s.scope_end <= static_cast<int>(inst) && s.is_managed == is_managed )
{ // It's compatible.
if ( s.scope_end == static_cast<int>(inst) )
{ // It ends right on the money.
@ -728,8 +724,7 @@ void ZAMCompiler::ReMapVar(ID* id, int slot, bro_uint_t inst)
void ZAMCompiler::CheckSlotAssignment(int slot, const ZInstI* inst)
{
ASSERT(slot >= 0 &&
static_cast<bro_uint_t>(slot) < frame_denizens.size());
ASSERT(slot >= 0 && static_cast<bro_uint_t>(slot) < frame_denizens.size());
// We construct temporaries such that their values are never used
// earlier than their definitions in loop bodies. For other
@ -774,7 +769,8 @@ void ZAMCompiler::CheckSlotUse(int slot, const ZInstI* inst)
{
ODesc d;
inst->stmt->GetLocationInfo()->Describe(&d);
reporter->Error("%s: value used but not set: %s", d.Description(), frame_denizens[slot]->Name());
reporter->Error("%s: value used but not set: %s", d.Description(),
frame_denizens[slot]->Name());
}
// See comment above about temporaries not having their values
@ -808,17 +804,15 @@ void ZAMCompiler::ExtendLifetime(int slot, const ZInstI* inst)
// extended lifetimes, as that can happen if they're
// used as a "for" loop-over target, which already
// extends lifetime across the body of the loop.
if ( inst->loop_depth > 0 &&
reducer->IsTemporary(frame_denizens[slot]) &&
if ( inst->loop_depth > 0 && reducer->IsTemporary(frame_denizens[slot]) &&
old_inst->inst_num >= inst->inst_num )
return;
// We expect to only be increasing the slot's lifetime ...
// *unless* we're inside a nested loop, in which case
// *unless* we're inside a nested loop, in which case
// the slot might have already been extended to the
// end of the outer loop.
ASSERT(old_inst->inst_num <= inst->inst_num ||
inst->loop_depth > 1);
ASSERT(old_inst->inst_num <= inst->inst_num || inst->loop_depth > 1);
if ( old_inst->inst_num < inst->inst_num )
{ // Extend.
@ -898,8 +892,7 @@ bool ZAMCompiler::VarIsAssigned(int slot, const ZInstI* i) const
// Special-case for table iterators, which assign to a bunch
// of variables but they're not immediately visible in the
// instruction layout.
if ( i->op == OP_NEXT_TABLE_ITER_VAL_VAR_VVV ||
i->op == OP_NEXT_TABLE_ITER_VV )
if ( i->op == OP_NEXT_TABLE_ITER_VAL_VAR_VVV || i->op == OP_NEXT_TABLE_ITER_VV )
{
auto& iter_vars = i->aux->loop_vars;
for ( auto v : iter_vars )
@ -1061,4 +1054,4 @@ void ZAMCompiler::KillInsts(bro_uint_t i)
}
}
} // zeek::detail
} // zeek::detail

View file

@ -2,12 +2,12 @@
// Methods for dealing with ZAM branches.
#include "zeek/Reporter.h"
#include "zeek/Desc.h"
#include "zeek/Reporter.h"
#include "zeek/script_opt/ZAM/Compile.h"
namespace zeek::detail {
namespace zeek::detail
{
void ZAMCompiler::PushGoTos(GoToSets& gotos)
{
@ -63,7 +63,7 @@ InstLabel ZAMCompiler::GoToTargetBeyond(const ZAMStmt s)
return pending_inst;
}
return insts1[n+1];
return insts1[n + 1];
}
void ZAMCompiler::SetTarget(ZInstI* inst, const InstLabel l, int slot)
@ -89,10 +89,9 @@ ZInstI* ZAMCompiler::FindLiveTarget(ZInstI* goto_target)
return insts1[idx];
}
void ZAMCompiler::ConcretizeBranch(ZInstI* inst, ZInstI* target,
int target_slot)
void ZAMCompiler::ConcretizeBranch(ZInstI* inst, ZInstI* target, int target_slot)
{
int t; // instruction number of target
int t; // instruction number of target
if ( target == pending_inst )
{
@ -106,15 +105,24 @@ void ZAMCompiler::ConcretizeBranch(ZInstI* inst, ZInstI* target,
else
t = target->inst_num;
switch ( target_slot ) {
case 1: inst->v1 = t; break;
case 2: inst->v2 = t; break;
case 3: inst->v3 = t; break;
case 4: inst->v4 = t; break;
switch ( target_slot )
{
case 1:
inst->v1 = t;
break;
case 2:
inst->v2 = t;
break;
case 3:
inst->v3 = t;
break;
case 4:
inst->v4 = t;
break;
default:
reporter->InternalError("bad GoTo target");
}
default:
reporter->InternalError("bad GoTo target");
}
}
void ZAMCompiler::SetV1(ZAMStmt s, const InstLabel l)
@ -168,4 +176,4 @@ void ZAMCompiler::SetV4(ZAMStmt s, const InstLabel l)
inst->op_type = OP_VVVV_I4;
}
} // zeek::detail
} // zeek::detail

View file

@ -7,7 +7,8 @@
#include "zeek/Reporter.h"
#include "zeek/script_opt/ZAM/Compile.h"
namespace zeek::detail {
namespace zeek::detail
{
bool ZAMCompiler::IsZAM_BuiltIn(const Expr* e)
{
@ -36,44 +37,36 @@ bool ZAMCompiler::IsZAM_BuiltIn(const Expr* e)
auto& args = c->Args()->Exprs();
const NameExpr* n = nullptr; // name to assign to, if any
const NameExpr* n = nullptr; // name to assign to, if any
if ( e->Tag() != EXPR_CALL )
n = e->GetOp1()->AsRefExpr()->GetOp1()->AsNameExpr();
using GenBuiltIn = bool (ZAMCompiler::*)(const NameExpr* n,
const ExprPList& args);
using GenBuiltIn = bool (ZAMCompiler::*)(const NameExpr* n, const ExprPList& args);
static std::vector<std::pair<const char*, GenBuiltIn>> builtins = {
{ "Analyzer::__name", &ZAMCompiler::BuiltIn_Analyzer__name },
{ "Broker::__flush_logs",
&ZAMCompiler::BuiltIn_Broker__flush_logs },
{ "Files::__enable_reassembly",
&ZAMCompiler::BuiltIn_Files__enable_reassembly },
{ "Files::__set_reassembly_buffer",
&ZAMCompiler::BuiltIn_Files__set_reassembly_buffer },
{ "Log::__write", &ZAMCompiler::BuiltIn_Log__write },
{ "current_time", &ZAMCompiler::BuiltIn_current_time },
{ "get_port_transport_proto",
&ZAMCompiler::BuiltIn_get_port_etc },
{ "network_time", &ZAMCompiler::BuiltIn_network_time },
{ "reading_live_traffic",
&ZAMCompiler::BuiltIn_reading_live_traffic },
{ "reading_traces", &ZAMCompiler::BuiltIn_reading_traces },
{ "strstr", &ZAMCompiler::BuiltIn_strstr },
{ "sub_bytes", &ZAMCompiler::BuiltIn_sub_bytes },
{ "to_lower", &ZAMCompiler::BuiltIn_to_lower },
{"Analyzer::__name", &ZAMCompiler::BuiltIn_Analyzer__name},
{"Broker::__flush_logs", &ZAMCompiler::BuiltIn_Broker__flush_logs},
{"Files::__enable_reassembly", &ZAMCompiler::BuiltIn_Files__enable_reassembly},
{"Files::__set_reassembly_buffer", &ZAMCompiler::BuiltIn_Files__set_reassembly_buffer},
{"Log::__write", &ZAMCompiler::BuiltIn_Log__write},
{"current_time", &ZAMCompiler::BuiltIn_current_time},
{"get_port_transport_proto", &ZAMCompiler::BuiltIn_get_port_etc},
{"network_time", &ZAMCompiler::BuiltIn_network_time},
{"reading_live_traffic", &ZAMCompiler::BuiltIn_reading_live_traffic},
{"reading_traces", &ZAMCompiler::BuiltIn_reading_traces},
{"strstr", &ZAMCompiler::BuiltIn_strstr},
{"sub_bytes", &ZAMCompiler::BuiltIn_sub_bytes},
{"to_lower", &ZAMCompiler::BuiltIn_to_lower},
};
for ( auto& b : builtins )
if ( util::streq(func->Name(), b.first) )
return (this->*(b.second))(n ,args);
return (this->*(b.second))(n, args);
return false;
}
bool ZAMCompiler::BuiltIn_Analyzer__name(const NameExpr* n,
const ExprPList& args)
bool ZAMCompiler::BuiltIn_Analyzer__name(const NameExpr* n, const ExprPList& args)
{
if ( ! n )
{
@ -97,20 +90,17 @@ bool ZAMCompiler::BuiltIn_Analyzer__name(const NameExpr* n,
return true;
}
bool ZAMCompiler::BuiltIn_Broker__flush_logs(const NameExpr* n,
const ExprPList& args)
bool ZAMCompiler::BuiltIn_Broker__flush_logs(const NameExpr* n, const ExprPList& args)
{
if ( n )
AddInst(ZInstI(OP_BROKER_FLUSH_LOGS_V,
Frame1Slot(n, OP1_WRITE)));
AddInst(ZInstI(OP_BROKER_FLUSH_LOGS_V, Frame1Slot(n, OP1_WRITE)));
else
AddInst(ZInstI(OP_BROKER_FLUSH_LOGS_X));
return true;
}
bool ZAMCompiler::BuiltIn_Files__enable_reassembly(const NameExpr* n,
const ExprPList& args)
bool ZAMCompiler::BuiltIn_Files__enable_reassembly(const NameExpr* n, const ExprPList& args)
{
if ( n )
// While this built-in nominally returns a value, existing
@ -129,8 +119,7 @@ bool ZAMCompiler::BuiltIn_Files__enable_reassembly(const NameExpr* n,
return true;
}
bool ZAMCompiler::BuiltIn_Files__set_reassembly_buffer(const NameExpr* n,
const ExprPList& args)
bool ZAMCompiler::BuiltIn_Files__set_reassembly_buffer(const NameExpr* n, const ExprPList& args)
{
if ( n )
// See above for enable_reassembly
@ -151,8 +140,7 @@ bool ZAMCompiler::BuiltIn_Files__set_reassembly_buffer(const NameExpr* n,
z.op_type = OP_VV_I2;
}
else
z = ZInstI(OP_FILES__SET_REASSEMBLY_BUFFER_VV, arg_f,
FrameSlot(args[1]->AsNameExpr()));
z = ZInstI(OP_FILES__SET_REASSEMBLY_BUFFER_VV, arg_f, FrameSlot(args[1]->AsNameExpr()));
AddInst(z);
@ -191,8 +179,7 @@ bool ZAMCompiler::BuiltIn_Log__write(const NameExpr* n, const ExprPList& args)
z.aux = aux;
}
else
z = ZInstI(OP_LOG_WRITE_VVV, nslot,
FrameSlot(id->AsNameExpr()), col_slot);
z = ZInstI(OP_LOG_WRITE_VVV, nslot, FrameSlot(id->AsNameExpr()), col_slot);
}
else
{
@ -202,8 +189,7 @@ bool ZAMCompiler::BuiltIn_Log__write(const NameExpr* n, const ExprPList& args)
z.aux = aux;
}
else
z = ZInstI(OP_LOG_WRITE_VV, FrameSlot(id->AsNameExpr()),
col_slot);
z = ZInstI(OP_LOG_WRITE_VV, FrameSlot(id->AsNameExpr()), col_slot);
}
z.SetType(columns_n->GetType());
@ -264,8 +250,7 @@ bool ZAMCompiler::BuiltIn_network_time(const NameExpr* n, const ExprPList& args)
return true;
}
bool ZAMCompiler::BuiltIn_reading_live_traffic(const NameExpr* n,
const ExprPList& args)
bool ZAMCompiler::BuiltIn_reading_live_traffic(const NameExpr* n, const ExprPList& args)
{
if ( ! n )
{
@ -280,8 +265,7 @@ bool ZAMCompiler::BuiltIn_reading_live_traffic(const NameExpr* n,
return true;
}
bool ZAMCompiler::BuiltIn_reading_traces(const NameExpr* n,
const ExprPList& args)
bool ZAMCompiler::BuiltIn_reading_traces(const NameExpr* n, const ExprPList& args)
{
if ( ! n )
{
@ -308,8 +292,7 @@ bool ZAMCompiler::BuiltIn_strstr(const NameExpr* n, const ExprPList& args)
auto little = args[1];
auto big_n = big->Tag() == EXPR_NAME ? big->AsNameExpr() : nullptr;
auto little_n = little->Tag() == EXPR_NAME ?
little->AsNameExpr() : nullptr;
auto little_n = little->Tag() == EXPR_NAME ? little->AsNameExpr() : nullptr;
ZInstI z;
@ -349,54 +332,55 @@ bool ZAMCompiler::BuiltIn_sub_bytes(const NameExpr* n, const ExprPList& args)
ZInstI z;
switch ( ConstArgsMask(args, 3) ) {
case 0x0: // all variable
z = ZInstI(OP_SUB_BYTES_VVVV, nslot, v2, v3, v4);
z.op_type = OP_VVVV;
break;
switch ( ConstArgsMask(args, 3) )
{
case 0x0: // all variable
z = ZInstI(OP_SUB_BYTES_VVVV, nslot, v2, v3, v4);
z.op_type = OP_VVVV;
break;
case 0x1: // last argument a constant
z = ZInstI(OP_SUB_BYTES_VVVi, nslot, v2, v3, v4);
z.op_type = OP_VVVV_I4;
break;
case 0x1: // last argument a constant
z = ZInstI(OP_SUB_BYTES_VVVi, nslot, v2, v3, v4);
z.op_type = OP_VVVV_I4;
break;
case 0x2: // 2nd argument a constant; flip!
z = ZInstI(OP_SUB_BYTES_VViV, nslot, v2, v4, v3);
z.op_type = OP_VVVV_I4;
break;
case 0x2: // 2nd argument a constant; flip!
z = ZInstI(OP_SUB_BYTES_VViV, nslot, v2, v4, v3);
z.op_type = OP_VVVV_I4;
break;
case 0x3: // both 2nd and third are constants
z = ZInstI(OP_SUB_BYTES_VVii, nslot, v2, v3, v4);
z.op_type = OP_VVVV_I3_I4;
break;
case 0x3: // both 2nd and third are constants
z = ZInstI(OP_SUB_BYTES_VVii, nslot, v2, v3, v4);
z.op_type = OP_VVVV_I3_I4;
break;
case 0x4: // first argument a constant
ASSERT(c);
z = ZInstI(OP_SUB_BYTES_VVVC, nslot, v3, v4, c);
z.op_type = OP_VVVC;
break;
case 0x4: // first argument a constant
ASSERT(c);
z = ZInstI(OP_SUB_BYTES_VVVC, nslot, v3, v4, c);
z.op_type = OP_VVVC;
break;
case 0x5: // first and third constant
ASSERT(c);
z = ZInstI(OP_SUB_BYTES_VViC, nslot, v3, v4, c);
z.op_type = OP_VVVC_I3;
break;
case 0x5: // first and third constant
ASSERT(c);
z = ZInstI(OP_SUB_BYTES_VViC, nslot, v3, v4, c);
z.op_type = OP_VVVC_I3;
break;
case 0x6: // first and second constant - flip!
ASSERT(c);
z = ZInstI(OP_SUB_BYTES_ViVC, nslot, v4, v3, c);
z.op_type = OP_VVVC_I3;
break;
case 0x6: // first and second constant - flip!
ASSERT(c);
z = ZInstI(OP_SUB_BYTES_ViVC, nslot, v4, v3, c);
z.op_type = OP_VVVC_I3;
break;
case 0x7: // whole shebang
ASSERT(c);
z = ZInstI(OP_SUB_BYTES_ViiC, nslot, v3, v4, c);
z.op_type = OP_VVVC_I2_I3;
break;
case 0x7: // whole shebang
ASSERT(c);
z = ZInstI(OP_SUB_BYTES_ViiC, nslot, v3, v4, c);
z.op_type = OP_VVVC_I2_I3;
break;
default:
reporter->InternalError("bad constant mask");
}
default:
reporter->InternalError("bad constant mask");
}
AddInst(z);
@ -448,4 +432,4 @@ bro_uint_t ZAMCompiler::ConstArgsMask(const ExprPList& args, int nargs) const
return mask;
}
} // zeek::detail
} // zeek::detail

View file

@ -8,11 +8,13 @@
#include "zeek/script_opt/UseDefs.h"
#include "zeek/script_opt/ZAM/ZBody.h"
namespace zeek {
namespace zeek
{
class EventHandler;
}
}
namespace zeek::detail {
namespace zeek::detail
{
class NameExpr;
class ConstExpr;
@ -31,50 +33,48 @@ using InstLabel = ZInstI*;
// but related to, the ZAM instruction(s) generated for that compilation.)
// Designed to be fully opaque, but also effective without requiring pointer
// management.
class ZAMStmt {
class ZAMStmt
{
protected:
friend class ZAMCompiler;
ZAMStmt() { stmt_num = -1; /* flag that it needs to be set */ }
ZAMStmt(int _stmt_num) { stmt_num = _stmt_num; }
ZAMStmt() { stmt_num = -1; /* flag that it needs to be set */ }
ZAMStmt(int _stmt_num) { stmt_num = _stmt_num; }
int stmt_num;
};
};
// Class that holds values that only have meaning to the ZAM compiler,
// but that needs to be held (opaquely, via a pointer) by external
// objects.
class OpaqueVals {
class OpaqueVals
{
public:
OpaqueVals(ZInstAux* _aux) { aux = _aux; }
OpaqueVals(ZInstAux* _aux) { aux = _aux; }
ZInstAux* aux;
};
};
class ZAMCompiler {
class ZAMCompiler
{
public:
ZAMCompiler(ScriptFunc* f, std::shared_ptr<ProfileFunc> pf,
ScopePtr scope, StmtPtr body, std::shared_ptr<UseDefs> ud,
std::shared_ptr<Reducer> rd);
ZAMCompiler(ScriptFunc* f, std::shared_ptr<ProfileFunc> pf, ScopePtr scope, StmtPtr body,
std::shared_ptr<UseDefs> ud, std::shared_ptr<Reducer> rd);
StmtPtr CompileBody();
const FrameReMap& FrameDenizens() const
{ return shared_frame_denizens_final; }
const FrameReMap& FrameDenizens() const { return shared_frame_denizens_final; }
const std::vector<int>& ManagedSlots() const
{ return managed_slotsI; }
const std::vector<int>& ManagedSlots() const { return managed_slotsI; }
const std::vector<GlobalInfo>& Globals() const
{ return globalsI; }
const std::vector<GlobalInfo>& Globals() const { return globalsI; }
bool NonRecursive() const { return non_recursive; }
bool NonRecursive() const { return non_recursive; }
const TableIterVec& GetTableIters() const { return table_iters; }
int NumStepIters() const { return num_step_iters; }
const TableIterVec& GetTableIters() const { return table_iters; }
int NumStepIters() const { return num_step_iters; }
template <typename T>
const CaseMaps<T>& GetCases() const
template <typename T> const CaseMaps<T>& GetCases() const
{
if constexpr ( std::is_same_v<T, bro_int_t> )
return int_cases;
@ -109,24 +109,21 @@ private:
// switches.
// See ZBody.h for their concrete counterparts, which we've
// already #include'd.
template<typename T> using CaseMapI = std::map<T, InstLabel>;
template<typename T> using CaseMapsI = std::vector<CaseMapI<T>>;
template <typename T> using CaseMapI = std::map<T, InstLabel>;
template <typename T> using CaseMapsI = std::vector<CaseMapI<T>>;
template <typename T>
void ConcretizeSwitchTables(const CaseMapsI<T>& abstract_cases,
CaseMaps<T>& concrete_cases);
void ConcretizeSwitchTables(const CaseMapsI<T>& abstract_cases, CaseMaps<T>& concrete_cases);
template <typename T>
void DumpCases(const T& cases, const char* type_name) const;
template <typename T> void DumpCases(const T& cases, const char* type_name) const;
void DumpInsts1(const FrameReMap* remappings);
#include "zeek/ZAM-MethodDecls.h"
const ZAMStmt CompileStmt(const StmtPtr& body)
{ return CompileStmt(body.get()); }
const ZAMStmt CompileStmt(const StmtPtr& body) { return CompileStmt(body.get()); }
const ZAMStmt CompileStmt(const Stmt* body);
void SetCurrStmt(const Stmt* stmt) { curr_stmt = stmt; }
void SetCurrStmt(const Stmt* stmt) { curr_stmt = stmt; }
const ZAMStmt CompilePrint(const PrintStmt* ps);
const ZAMStmt CompileExpr(const ExprStmt* es);
@ -142,105 +139,89 @@ private:
const ZAMStmt CompileInit(const InitStmt* is);
const ZAMStmt CompileWhen(const WhenStmt* ws);
const ZAMStmt CompileNext()
{ return GenGoTo(nexts.back()); }
const ZAMStmt CompileBreak()
{ return GenGoTo(breaks.back()); }
const ZAMStmt CompileFallThrough()
{ return GenGoTo(fallthroughs.back()); }
const ZAMStmt CompileCatchReturn()
{ return GenGoTo(catches.back()); }
const ZAMStmt CompileNext() { return GenGoTo(nexts.back()); }
const ZAMStmt CompileBreak() { return GenGoTo(breaks.back()); }
const ZAMStmt CompileFallThrough() { return GenGoTo(fallthroughs.back()); }
const ZAMStmt CompileCatchReturn() { return GenGoTo(catches.back()); }
const ZAMStmt IfElse(const Expr* e, const Stmt* s1, const Stmt* s2);
const ZAMStmt While(const Stmt* cond_stmt, const Expr* cond,
const Stmt* body);
const ZAMStmt While(const Stmt* cond_stmt, const Expr* cond, const Stmt* body);
const ZAMStmt InitRecord(IDPtr id, RecordType* rt);
const ZAMStmt InitVector(IDPtr id, VectorType* vt);
const ZAMStmt InitTable(IDPtr id, TableType* tt, Attributes* attrs);
const ZAMStmt ValueSwitch(const SwitchStmt* sw, const NameExpr* v,
const ConstExpr* c);
const ZAMStmt TypeSwitch(const SwitchStmt* sw, const NameExpr* v,
const ConstExpr* c);
const ZAMStmt ValueSwitch(const SwitchStmt* sw, const NameExpr* v, const ConstExpr* c);
const ZAMStmt TypeSwitch(const SwitchStmt* sw, const NameExpr* v, const ConstExpr* c);
void PushNexts() { PushGoTos(nexts); }
void PushBreaks() { PushGoTos(breaks); }
void PushFallThroughs() { PushGoTos(fallthroughs); }
void PushCatchReturns() { PushGoTos(catches); }
void ResolveNexts(const InstLabel l)
{ ResolveGoTos(nexts, l); }
void ResolveBreaks(const InstLabel l)
{ ResolveGoTos(breaks, l); }
void ResolveFallThroughs(const InstLabel l)
{ ResolveGoTos(fallthroughs, l); }
void ResolveCatchReturns(const InstLabel l)
{ ResolveGoTos(catches, l); }
void PushNexts() { PushGoTos(nexts); }
void PushBreaks() { PushGoTos(breaks); }
void PushFallThroughs() { PushGoTos(fallthroughs); }
void PushCatchReturns() { PushGoTos(catches); }
void ResolveNexts(const InstLabel l) { ResolveGoTos(nexts, l); }
void ResolveBreaks(const InstLabel l) { ResolveGoTos(breaks, l); }
void ResolveFallThroughs(const InstLabel l) { ResolveGoTos(fallthroughs, l); }
void ResolveCatchReturns(const InstLabel l) { ResolveGoTos(catches, l); }
const ZAMStmt LoopOverTable(const ForStmt* f, const NameExpr* val);
const ZAMStmt LoopOverVector(const ForStmt* f, const NameExpr* val);
const ZAMStmt LoopOverString(const ForStmt* f, const Expr* e);
const ZAMStmt FinishLoop(const ZAMStmt iter_head, ZInstI& iter_stmt,
const Stmt* body, int iter_slot,
bool is_table);
const ZAMStmt FinishLoop(const ZAMStmt iter_head, ZInstI& iter_stmt, const Stmt* body,
int iter_slot, bool is_table);
const ZAMStmt Loop(const Stmt* body);
const ZAMStmt CompileExpr(const ExprPtr& e)
{ return CompileExpr(e.get()); }
const ZAMStmt CompileExpr(const ExprPtr& e) { return CompileExpr(e.get()); }
const ZAMStmt CompileExpr(const Expr* body);
const ZAMStmt CompileIncrExpr(const IncrExpr* e);
const ZAMStmt CompileAppendToExpr(const AppendToExpr* e);
const ZAMStmt CompileAssignExpr(const AssignExpr* e);
const ZAMStmt CompileAssignToIndex(const NameExpr* lhs,
const IndexExpr* rhs);
const ZAMStmt CompileAssignToIndex(const NameExpr* lhs, const IndexExpr* rhs);
const ZAMStmt CompileFieldLHSAssignExpr(const FieldLHSAssignExpr* e);
const ZAMStmt CompileScheduleExpr(const ScheduleExpr* e);
const ZAMStmt CompileSchedule(const NameExpr* n, const ConstExpr* c,
int is_interval, EventHandler* h,
const ListExpr* l);
const ZAMStmt CompileSchedule(const NameExpr* n, const ConstExpr* c, int is_interval,
EventHandler* h, const ListExpr* l);
const ZAMStmt CompileEvent(EventHandler* h, const ListExpr* l);
const ZAMStmt CompileInExpr(const NameExpr* n1, const NameExpr* n2,
const NameExpr* n3)
{ return CompileInExpr(n1, n2, nullptr, n3, nullptr); }
const ZAMStmt CompileInExpr(const NameExpr* n1, const NameExpr* n2, const NameExpr* n3)
{
return CompileInExpr(n1, n2, nullptr, n3, nullptr);
}
const ZAMStmt CompileInExpr(const NameExpr* n1, const NameExpr* n2,
const ConstExpr* c)
{ return CompileInExpr(n1, n2, nullptr, nullptr, c); }
const ZAMStmt CompileInExpr(const NameExpr* n1, const NameExpr* n2, const ConstExpr* c)
{
return CompileInExpr(n1, n2, nullptr, nullptr, c);
}
const ZAMStmt CompileInExpr(const NameExpr* n1, const ConstExpr* c,
const NameExpr* n3)
{ return CompileInExpr(n1, nullptr, c, n3, nullptr); }
const ZAMStmt CompileInExpr(const NameExpr* n1, const ConstExpr* c, const NameExpr* n3)
{
return CompileInExpr(n1, nullptr, c, n3, nullptr);
}
// In the following, one of n2 or c2 (likewise, n3/c3) will be nil.
const ZAMStmt CompileInExpr(const NameExpr* n1, const NameExpr* n2,
const ConstExpr* c2, const NameExpr* n3,
const ConstExpr* c3);
const ZAMStmt CompileInExpr(const NameExpr* n1, const NameExpr* n2, const ConstExpr* c2,
const NameExpr* n3, const ConstExpr* c3);
const ZAMStmt CompileInExpr(const NameExpr* n1, const ListExpr* l,
const NameExpr* n2)
{ return CompileInExpr(n1, l, n2, nullptr); }
const ZAMStmt CompileInExpr(const NameExpr* n1, const ListExpr* l, const NameExpr* n2)
{
return CompileInExpr(n1, l, n2, nullptr);
}
const ZAMStmt CompileInExpr(const NameExpr* n, const ListExpr* l,
const ConstExpr* c)
{ return CompileInExpr(n, l, nullptr, c); }
const ZAMStmt CompileInExpr(const NameExpr* n, const ListExpr* l, const ConstExpr* c)
{
return CompileInExpr(n, l, nullptr, c);
}
const ZAMStmt CompileInExpr(const NameExpr* n1, const ListExpr* l,
const NameExpr* n2, const ConstExpr* c);
const ZAMStmt CompileInExpr(const NameExpr* n1, const ListExpr* l, const NameExpr* n2,
const ConstExpr* c);
const ZAMStmt CompileIndex(const NameExpr* n1, const NameExpr* n2,
const ZAMStmt CompileIndex(const NameExpr* n1, const NameExpr* n2, const ListExpr* l);
const ZAMStmt CompileIndex(const NameExpr* n1, const ConstExpr* c, const ListExpr* l);
const ZAMStmt CompileIndex(const NameExpr* n1, int n2_slot, const TypePtr& n2_type,
const ListExpr* l);
const ZAMStmt CompileIndex(const NameExpr* n1, const ConstExpr* c,
const ListExpr* l);
const ZAMStmt CompileIndex(const NameExpr* n1, int n2_slot,
const TypePtr& n2_type, const ListExpr* l);
// Second argument is which instruction slot holds the branch target.
const ZAMStmt GenCond(const Expr* e, int& branch_v);
@ -252,8 +233,8 @@ private:
const ZAMStmt AssignVecElems(const Expr* e);
const ZAMStmt AssignTableElem(const Expr* e);
const ZAMStmt AppendToField(const NameExpr* n1, const NameExpr* n2,
const ConstExpr* c, int offset);
const ZAMStmt AppendToField(const NameExpr* n1, const NameExpr* n2, const ConstExpr* c,
int offset);
const ZAMStmt ConstructTable(const NameExpr* n, const Expr* e);
const ZAMStmt ConstructSet(const NameExpr* n, const Expr* e);
@ -267,9 +248,8 @@ private:
const ZAMStmt Is(const NameExpr* n, const Expr* e);
#include "zeek/script_opt/ZAM/Inst-Gen.h"
#include "zeek/script_opt/ZAM/BuiltIn.h"
#include "zeek/script_opt/ZAM/Inst-Gen.h"
// A bit weird, but handy for switch statements used in built-in
// operations: returns a bit mask of which of the arguments in the
@ -295,7 +275,6 @@ private:
return e->AsConstExpr()->Value()->AsCount();
}
using GoToSet = std::vector<ZAMStmt>;
using GoToSets = std::vector<GoToSet>;
@ -335,9 +314,7 @@ private:
void SetV2(ZAMStmt s, const InstLabel l);
void SetV3(ZAMStmt s, const InstLabel l);
void SetV4(ZAMStmt s, const InstLabel l);
void SetGoTo(ZAMStmt s, const InstLabel targ)
{ SetV1(s, targ); }
void SetGoTo(ZAMStmt s, const InstLabel targ) { SetV1(s, targ); }
const ZAMStmt StartingBlock();
const ZAMStmt FinishBlock(const ZAMStmt start);
@ -368,8 +345,7 @@ private:
// Returns the most recent added instruction *other* than those
// added for bookkeeping.
ZInstI* TopMainInst() { return insts1[top_main_inst]; }
ZInstI* TopMainInst() { return insts1[top_main_inst]; }
bool IsUnused(const IDPtr& id, const Stmt* where) const;
@ -378,7 +354,7 @@ private:
int AddToFrame(ID*);
int FrameSlot(const IDPtr& id) { return FrameSlot(id.get()); }
int FrameSlot(const IDPtr& id) { return FrameSlot(id.get()); }
int FrameSlot(const ID* id);
int FrameSlotIfName(const Expr* e)
{
@ -386,25 +362,20 @@ private:
return n ? FrameSlot(n->Id()) : 0;
}
int FrameSlot(const NameExpr* id)
{ return FrameSlot(id->AsNameExpr()->Id()); }
int Frame1Slot(const NameExpr* id, ZOp op)
{ return Frame1Slot(id->AsNameExpr()->Id(), op); }
int FrameSlot(const NameExpr* id) { return FrameSlot(id->AsNameExpr()->Id()); }
int Frame1Slot(const NameExpr* id, ZOp op) { return Frame1Slot(id->AsNameExpr()->Id(), op); }
int Frame1Slot(const ID* id, ZOp op)
{ return Frame1Slot(id, op1_flavor[op]); }
int Frame1Slot(const NameExpr* n, ZAMOp1Flavor fl)
{ return Frame1Slot(n->Id(), fl); }
int Frame1Slot(const ID* id, ZOp op) { return Frame1Slot(id, op1_flavor[op]); }
int Frame1Slot(const NameExpr* n, ZAMOp1Flavor fl) { return Frame1Slot(n->Id(), fl); }
int Frame1Slot(const ID* id, ZAMOp1Flavor fl);
// The slot without doing any global-related checking.
int RawSlot(const NameExpr* n) { return RawSlot(n->Id()); }
int RawSlot(const NameExpr* n) { return RawSlot(n->Id()); }
int RawSlot(const ID* id);
bool HasFrameSlot(const ID* id) const;
int NewSlot(const TypePtr& t)
{ return NewSlot(ZVal::IsManagedType(t)); }
int NewSlot(const TypePtr& t) { return NewSlot(ZVal::IsManagedType(t)); }
int NewSlot(bool is_managed);
int TempForConst(const ConstExpr* c);
@ -421,8 +392,7 @@ private:
// Tracks which instructions can be branched to via the given
// set of switches.
template<typename T>
void TallySwitchTargets(const CaseMapsI<T>& switches);
template <typename T> void TallySwitchTargets(const CaseMapsI<T>& switches);
// Remove code that can't be reached. True if some removal happened.
bool RemoveDeadCode();
@ -504,18 +474,20 @@ private:
return FirstLiveInst(insts1[i->inst_num + 1], follow_gotos);
}
int NextLiveInst(int i, bool follow_gotos = false)
{ return FirstLiveInst(i + 1, follow_gotos); }
{
return FirstLiveInst(i + 1, follow_gotos);
}
// Mark an instruction as unnecessary and remove its influence on
// other statements. The instruction is indicated as an offset
// into insts1; any labels associated with it are transferred
// to its next live successor, if any.
void KillInst(ZInstI* i) { KillInst(i->inst_num); }
void KillInst(ZInstI* i) { KillInst(i->inst_num); }
void KillInst(bro_uint_t i);
// The same, but kills any successor instructions until finding
// one that's labeled.
void KillInsts(ZInstI* i) { KillInsts(i->inst_num); }
void KillInsts(ZInstI* i) { KillInsts(i->inst_num); }
void KillInsts(bro_uint_t i);
// The first of these is used as we compile down to ZInstI's.
@ -569,8 +541,7 @@ private:
// A type for mapping an instruction to a set of locals associated
// with it.
using AssociatedLocals =
std::unordered_map<const ZInstI*, std::unordered_set<ID*>>;
using AssociatedLocals = std::unordered_map<const ZInstI*, std::unordered_set<ID*>>;
// Maps (live) instructions to which frame denizens begin their
// lifetime via an initialization at that instruction, if any ...
@ -595,7 +566,7 @@ private:
// values that get finalized when constructing the corresponding
// ZBody.
std::vector<GlobalInfo> globalsI;
std::unordered_map<const ID*, int> global_id_to_info; // inverse
std::unordered_map<const ID*, int> global_id_to_info; // inverse
// Intermediary switch tables (branching to ZInst's rather
// than concrete instruction offsets).
@ -629,11 +600,10 @@ private:
// AddInst. If >= 0, then upon adding the next instruction,
// it should be followed by Store-Global for the given slot.
int pending_global_store = -1;
};
};
// Invokes after compiling all of the function bodies.
class FuncInfo;
extern void finalize_functions(const std::vector<FuncInfo>& funcs);
} // namespace zeek::detail
} // namespace zeek::detail

View file

@ -3,23 +3,20 @@
// Driver (and other high-level) methods for ZAM compilation.
#include "zeek/CompHash.h"
#include "zeek/RE.h"
#include "zeek/Frame.h"
#include "zeek/module_util.h"
#include "zeek/Scope.h"
#include "zeek/RE.h"
#include "zeek/Reporter.h"
#include "zeek/script_opt/ScriptOpt.h"
#include "zeek/Scope.h"
#include "zeek/module_util.h"
#include "zeek/script_opt/ProfileFunc.h"
#include "zeek/script_opt/ScriptOpt.h"
#include "zeek/script_opt/ZAM/Compile.h"
namespace zeek::detail
{
namespace zeek::detail {
ZAMCompiler::ZAMCompiler(ScriptFunc* f, std::shared_ptr<ProfileFunc> _pf,
ScopePtr _scope, StmtPtr _body,
std::shared_ptr<UseDefs> _ud,
std::shared_ptr<Reducer> _rd)
ZAMCompiler::ZAMCompiler(ScriptFunc* f, std::shared_ptr<ProfileFunc> _pf, ScopePtr _scope,
StmtPtr _body, std::shared_ptr<UseDefs> _ud, std::shared_ptr<Reducer> _rd)
{
func = f;
pf = std::move(_pf);
@ -71,8 +68,7 @@ void ZAMCompiler::InitGlobals()
void ZAMCompiler::InitArgs()
{
auto uds = ud->HasUsage(body.get()) ? ud->GetUsage(body.get()) :
nullptr;
auto uds = ud->HasUsage(body.get()) ? ud->GetUsage(body.get()) : nullptr;
auto args = scope->OrderedVars();
int nparam = func->GetType()->Params()->NumFields();
@ -108,7 +104,7 @@ void ZAMCompiler::InitLocals()
// Don't worry about unused variables, those will get
// removed during low-level ZAM optimization.
if ( ! HasFrameSlot(non_const_l) )
(void) AddToFrame(non_const_l);
(void)AddToFrame(non_const_l);
}
}
@ -131,7 +127,7 @@ StmtPtr ZAMCompiler::CompileBody()
if ( func->Flavor() == FUNC_FLAVOR_HOOK )
PushBreaks();
(void) CompileStmt(body);
(void)CompileStmt(body);
if ( reporter->Errors() > 0 )
return nullptr;
@ -265,8 +261,7 @@ void ZAMCompiler::ComputeLoopLevels()
// We're extending an existing loop. Find
// its current end.
auto depth = t->loop_depth;
while ( j < i &&
insts1[j]->loop_depth == depth )
while ( j < i && insts1[j]->loop_depth == depth )
++j;
ASSERT(insts1[j]->loop_depth == depth - 1);
@ -315,8 +310,7 @@ void ZAMCompiler::RemapFrameDenizens(const std::vector<int>& inst1_to_inst2)
// the form "slotX = slotX". In that
// case, look forward for the next viable
// instruction.
while ( start < insts1.size() &&
inst1_to_inst2[start] == -1 )
while ( start < insts1.size() && inst1_to_inst2[start] == -1 )
++start;
ASSERT(start < insts1.size());
@ -356,7 +350,7 @@ void ZAMCompiler::ConcretizeSwitches()
template <typename T>
void ZAMCompiler::ConcretizeSwitchTables(const CaseMapsI<T>& abstract_cases,
CaseMaps<T>& concrete_cases)
CaseMaps<T>& concrete_cases)
{
for ( auto& targs : abstract_cases )
{
@ -367,10 +361,8 @@ void ZAMCompiler::ConcretizeSwitchTables(const CaseMapsI<T>& abstract_cases,
}
}
#include "ZAM-MethodDefs.h"
void ZAMCompiler::Dump()
{
bool remapped_frame = ! analysis_options.no_ZAM_opt;
@ -440,8 +432,7 @@ void ZAMCompiler::Dump()
DumpCases(str_casesI, "str");
}
template <typename T>
void ZAMCompiler::DumpCases(const T& cases, const char* type_name) const
template <typename T> void ZAMCompiler::DumpCases(const T& cases, const char* type_name) const
{
for ( auto i = 0U; i < cases.size(); ++i )
{
@ -451,8 +442,7 @@ void ZAMCompiler::DumpCases(const T& cases, const char* type_name) const
std::string case_val;
if constexpr ( std::is_same_v<T, std::string> )
case_val = m.first;
else if constexpr ( std::is_same_v<T, bro_int_t> ||
std::is_same_v<T, bro_uint_t> ||
else if constexpr ( std::is_same_v<T, bro_int_t> || std::is_same_v<T, bro_uint_t> ||
std::is_same_v<T, double> )
case_val = std::to_string(m.first);
@ -471,7 +461,7 @@ void ZAMCompiler::DumpInsts1(const FrameReMap* remappings)
if ( inst->target )
// To get meaningful branch information in the dump,
// we need to concretize the branch slots
ConcretizeBranch(inst, inst->target, inst->target_slot);
ConcretizeBranch(inst, inst->target, inst->target_slot);
std::string liveness, depth;
@ -489,5 +479,4 @@ void ZAMCompiler::DumpInsts1(const FrameReMap* remappings)
}
}
} // zeek::detail
} // zeek::detail

View file

@ -2,56 +2,58 @@
// Methods for traversing Expr AST nodes to generate ZAM code.
#include "zeek/script_opt/ZAM/Compile.h"
#include "zeek/Reporter.h"
#include "zeek/Desc.h"
#include "zeek/Reporter.h"
#include "zeek/script_opt/ZAM/Compile.h"
namespace zeek::detail {
namespace zeek::detail
{
const ZAMStmt ZAMCompiler::CompileExpr(const Expr* e)
{
switch ( e->Tag() ) {
case EXPR_INCR:
case EXPR_DECR:
return CompileIncrExpr(static_cast<const IncrExpr*>(e));
case EXPR_APPEND_TO:
return CompileAppendToExpr(static_cast<const AppendToExpr*>(e));
case EXPR_ASSIGN:
return CompileAssignExpr(static_cast<const AssignExpr*>(e));
case EXPR_INDEX_ASSIGN:
switch ( e->Tag() )
{
auto iae = static_cast<const IndexAssignExpr*>(e);
auto t = iae->GetOp1()->GetType()->Tag();
if ( t == TYPE_VECTOR )
return AssignVecElems(iae);
case EXPR_INCR:
case EXPR_DECR:
return CompileIncrExpr(static_cast<const IncrExpr*>(e));
ASSERT(t == TYPE_TABLE);
return AssignTableElem(iae);
case EXPR_APPEND_TO:
return CompileAppendToExpr(static_cast<const AppendToExpr*>(e));
case EXPR_ASSIGN:
return CompileAssignExpr(static_cast<const AssignExpr*>(e));
case EXPR_INDEX_ASSIGN:
{
auto iae = static_cast<const IndexAssignExpr*>(e);
auto t = iae->GetOp1()->GetType()->Tag();
if ( t == TYPE_VECTOR )
return AssignVecElems(iae);
ASSERT(t == TYPE_TABLE);
return AssignTableElem(iae);
}
case EXPR_FIELD_LHS_ASSIGN:
{
auto flhs = static_cast<const FieldLHSAssignExpr*>(e);
return CompileFieldLHSAssignExpr(flhs);
}
case EXPR_SCHEDULE:
return CompileScheduleExpr(static_cast<const ScheduleExpr*>(e));
case EXPR_EVENT:
{
auto ee = static_cast<const EventExpr*>(e);
auto h = ee->Handler().Ptr();
auto args = ee->Args();
return EventHL(h, args);
}
default:
reporter->InternalError("bad statement type in ZAMCompile::CompileExpr");
}
case EXPR_FIELD_LHS_ASSIGN:
{
auto flhs = static_cast<const FieldLHSAssignExpr*>(e);
return CompileFieldLHSAssignExpr(flhs);
}
case EXPR_SCHEDULE:
return CompileScheduleExpr(static_cast<const ScheduleExpr*>(e));
case EXPR_EVENT:
{
auto ee = static_cast<const EventExpr*>(e);
auto h = ee->Handler().Ptr();
auto args = ee->Args();
return EventHL(h, args);
}
default:
reporter->InternalError("bad statement type in ZAMCompile::CompileExpr");
}
}
const ZAMStmt ZAMCompiler::CompileIncrExpr(const IncrExpr* e)
@ -92,15 +94,14 @@ const ZAMStmt ZAMCompiler::CompileAppendToExpr(const AppendToExpr* e)
return n2 ? AppendToVV(n1, n2) : AppendToVC(n1, cc);
}
const ZAMStmt ZAMCompiler::AppendToField(const NameExpr* n1, const NameExpr* n2,
const ConstExpr* c, int offset)
const ZAMStmt ZAMCompiler::AppendToField(const NameExpr* n1, const NameExpr* n2, const ConstExpr* c,
int offset)
{
ZInstI z;
if ( n2 )
{
z = ZInstI(OP_APPENDTOFIELD_VVi, FrameSlot(n1), FrameSlot(n2),
offset);
z = ZInstI(OP_APPENDTOFIELD_VVi, FrameSlot(n1), FrameSlot(n2), offset);
z.op_type = OP_VVV_I3;
}
else
@ -125,16 +126,16 @@ const ZAMStmt ZAMCompiler::CompileAssignExpr(const AssignExpr* e)
auto rhs = op2.get();
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) )
return CompileAssignToIndex(lhs, rhs->AsIndexExpr());
switch ( rhs->Tag() ) {
switch ( rhs->Tag() )
{
#include "ZAM-DirectDefs.h"
default:
break;
}
default:
break;
}
auto rt = rhs->GetType();
@ -176,13 +177,10 @@ const ZAMStmt ZAMCompiler::CompileAssignExpr(const AssignExpr* e)
}
if ( rhs->Tag() == EXPR_ANY_INDEX )
return AnyIndexVVi(lhs, r1->AsNameExpr(),
rhs->AsAnyIndexExpr()->Index());
return AnyIndexVVi(lhs, r1->AsNameExpr(), rhs->AsAnyIndexExpr()->Index());
if ( rhs->Tag() == EXPR_COND && r1->GetType()->Tag() == TYPE_VECTOR )
return Bool_Vec_CondVVVV(lhs, r1->AsNameExpr(),
r2->AsNameExpr(),
r3->AsNameExpr());
return Bool_Vec_CondVVVV(lhs, r1->AsNameExpr(), r2->AsNameExpr(), r3->AsNameExpr());
if ( rhs->Tag() == EXPR_COND && r2->IsConst() && r3->IsConst() )
{
@ -191,7 +189,7 @@ const ZAMStmt ZAMCompiler::CompileAssignExpr(const AssignExpr* e)
auto n1 = r1->AsNameExpr();
auto c2 = r2->AsConstExpr();
auto c3 = r3->AsConstExpr();
(void) CondC1VVC(lhs, n1, c2);
(void)CondC1VVC(lhs, n1, c2);
return CondC2VVC(lhs, n1, c3);
}
@ -202,7 +200,8 @@ const ZAMStmt ZAMCompiler::CompileAssignExpr(const AssignExpr* e)
if ( v1 != v2 && rhs->Tag() != EXPR_IN )
{
reporter->Error("deprecated mixed vector/scalar operation not supported for ZAM compiling");
reporter->Error(
"deprecated mixed vector/scalar operation not supported for ZAM compiling");
return ErrorStmt();
}
}
@ -210,18 +209,17 @@ const ZAMStmt ZAMCompiler::CompileAssignExpr(const AssignExpr* e)
if ( r1 && r1->IsConst() )
#include "ZAM-GenExprsDefsC1.h"
else if ( r2 && r2->IsConst() )
else if ( r2 && r2->IsConst() )
#include "ZAM-GenExprsDefsC2.h"
else if ( r3 && r3->IsConst() )
else if ( r3 && r3->IsConst() )
#include "ZAM-GenExprsDefsC3.h"
else
else
#include "ZAM-GenExprsDefsV.h"
}
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 const_aggr = aggr->Tag() == EXPR_CONST;
@ -232,8 +230,7 @@ const ZAMStmt ZAMCompiler::CompileAssignToIndex(const NameExpr* lhs,
auto n = const_aggr ? nullptr : aggr->AsNameExpr();
auto con = const_aggr ? aggr->AsConstExpr() : nullptr;
if ( indexes.length() == 1 &&
indexes[0]->GetType()->Tag() == TYPE_VECTOR )
if ( indexes.length() == 1 && indexes[0]->GetType()->Tag() == TYPE_VECTOR )
{
auto index1 = indexes[0];
if ( index1->Tag() == EXPR_CONST )
@ -246,16 +243,14 @@ const ZAMStmt ZAMCompiler::CompileAssignToIndex(const NameExpr* lhs,
auto ind_t = index->GetType()->AsVectorType();
if ( IsBool(ind_t->Yield()->Tag()) )
return const_aggr ?
IndexVecBoolSelectVCV(lhs, con, index) :
IndexVecBoolSelectVVV(lhs, n, index);
return const_aggr ? IndexVecBoolSelectVCV(lhs, con, index)
: IndexVecBoolSelectVVV(lhs, n, index);
return const_aggr ? IndexVecIntSelectVCV(lhs, con, index) :
IndexVecIntSelectVVV(lhs, n, index);
return const_aggr ? IndexVecIntSelectVCV(lhs, con, index)
: IndexVecIntSelectVVV(lhs, n, index);
}
return const_aggr ? IndexVCL(lhs, con, indexes_expr) :
IndexVVL(lhs, n, indexes_expr);
return const_aggr ? IndexVCL(lhs, con, indexes_expr) : IndexVVL(lhs, n, indexes_expr);
}
const ZAMStmt ZAMCompiler::CompileFieldLHSAssignExpr(const FieldLHSAssignExpr* e)
@ -277,20 +272,18 @@ const ZAMStmt ZAMCompiler::CompileFieldLHSAssignExpr(const FieldLHSAssignExpr* e
{
auto rhs_f = rhs->AsFieldExpr();
if ( r1->Tag() == EXPR_NAME )
return Field_LHS_AssignFVi(e, r1->AsNameExpr(),
rhs_f->Field());
return Field_LHS_AssignFVi(e, r1->AsNameExpr(), rhs_f->Field());
return Field_LHS_AssignFCi(e, r1->AsConstExpr(),
rhs_f->Field());
return Field_LHS_AssignFCi(e, r1->AsConstExpr(), rhs_f->Field());
}
if ( r1 && r1->IsConst() )
#include "ZAM-GenFieldsDefsC1.h"
else if ( r2 && r2->IsConst() )
else if ( r2 && r2->IsConst() )
#include "ZAM-GenFieldsDefsC2.h"
else
else
#include "ZAM-GenFieldsDefsV.h"
}
@ -305,15 +298,12 @@ const ZAMStmt ZAMCompiler::CompileScheduleExpr(const ScheduleExpr* e)
bool is_interval = when->GetType()->Tag() == TYPE_INTERVAL;
if ( when->Tag() == EXPR_NAME )
return ScheduleViHL(when->AsNameExpr(), is_interval,
handler.Ptr(), event_args);
return ScheduleViHL(when->AsNameExpr(), is_interval, handler.Ptr(), event_args);
else
return ScheduleCiHL(when->AsConstExpr(), is_interval,
handler.Ptr(), event_args);
return ScheduleCiHL(when->AsConstExpr(), is_interval, handler.Ptr(), event_args);
}
const ZAMStmt ZAMCompiler::CompileSchedule(const NameExpr* n,
const ConstExpr* c, int is_interval,
const ZAMStmt ZAMCompiler::CompileSchedule(const NameExpr* n, const ConstExpr* c, int is_interval,
EventHandler* h, const ListExpr* l)
{
int len = l->Exprs().length();
@ -321,8 +311,8 @@ const ZAMStmt ZAMCompiler::CompileSchedule(const NameExpr* n,
if ( len == 0 )
{
z = n ? ZInstI(OP_SCHEDULE0_ViH, FrameSlot(n), is_interval) :
ZInstI(OP_SCHEDULE0_CiH, is_interval, c);
z = n ? ZInstI(OP_SCHEDULE0_ViH, FrameSlot(n), is_interval)
: ZInstI(OP_SCHEDULE0_CiH, is_interval, c);
z.op_type = n ? OP_VV_I2 : OP_VC_I1;
}
@ -429,17 +419,17 @@ const ZAMStmt ZAMCompiler::CompileEvent(EventHandler* h, const ListExpr* l)
return AddInst(z);
}
const ZAMStmt ZAMCompiler::CompileInExpr(const NameExpr* n1,
const NameExpr* n2,
const ConstExpr* c2,
const NameExpr* n3,
const ZAMStmt ZAMCompiler::CompileInExpr(const NameExpr* n1, const NameExpr* n2,
const ConstExpr* c2, const NameExpr* n3,
const ConstExpr* c3)
{
const Expr* op2 = n2;
const Expr* op3 = n3;
if ( ! op2 ) op2 = c2;
if ( ! op3 ) op3 = c3;
if ( ! op2 )
op2 = c2;
if ( ! op3 )
op3 = c3;
ZOp a;
@ -449,8 +439,7 @@ const ZAMStmt ZAMCompiler::CompileInExpr(const NameExpr* n1,
else if ( op2->GetType()->Tag() == TYPE_STRING )
a = n2 ? (n3 ? OP_S_IN_S_VVV : OP_S_IN_S_VVC) : OP_S_IN_S_VCV;
else if ( op2->GetType()->Tag() == TYPE_ADDR &&
op3->GetType()->Tag() == TYPE_SUBNET )
else if ( op2->GetType()->Tag() == TYPE_ADDR && op3->GetType()->Tag() == TYPE_SUBNET )
a = n2 ? (n3 ? OP_A_IN_S_VVV : OP_A_IN_S_VVC) : OP_A_IN_S_VCV;
else if ( op3->GetType()->Tag() == TYPE_TABLE )
@ -489,8 +478,8 @@ const ZAMStmt ZAMCompiler::CompileInExpr(const NameExpr* n1,
return AddInst(z);
}
const ZAMStmt ZAMCompiler::CompileInExpr(const NameExpr* n1, const ListExpr* l,
const NameExpr* n2, const ConstExpr* c)
const ZAMStmt ZAMCompiler::CompileInExpr(const NameExpr* n1, const ListExpr* l, const NameExpr* n2,
const ConstExpr* c)
{
auto& l_e = l->Exprs();
int n = l_e.length();
@ -505,16 +494,14 @@ const ZAMStmt ZAMCompiler::CompileInExpr(const NameExpr* n1, const ListExpr* l,
if ( l_e[0]->Tag() == EXPR_NAME )
{
auto l_e0_n = l_e[0]->AsNameExpr();
ZOp op = is_vec ? OP_VAL_IS_IN_VECTOR_VVV :
OP_VAL_IS_IN_TABLE_VVV;
ZOp op = is_vec ? OP_VAL_IS_IN_VECTOR_VVV : OP_VAL_IS_IN_TABLE_VVV;
z = GenInst(op, n1, l_e0_n, n2);
}
else
{
auto l_e0_c = l_e[0]->AsConstExpr();
ZOp op = is_vec ? OP_CONST_IS_IN_VECTOR_VCV :
OP_CONST_IS_IN_TABLE_VCV;
ZOp op = is_vec ? OP_CONST_IS_IN_VECTOR_VCV : OP_CONST_IS_IN_TABLE_VCV;
z = GenInst(op, n1, l_e0_c, n2);
}
@ -525,8 +512,7 @@ const ZAMStmt ZAMCompiler::CompileInExpr(const NameExpr* n1, const ListExpr* l,
// Also somewhat common is a 2-element index. Here, one or both of
// the elements might be a constant, which makes things messier.
if ( n == 2 && n2 &&
(l_e[0]->Tag() == EXPR_NAME || l_e[1]->Tag() == EXPR_NAME) )
if ( n == 2 && n2 && (l_e[0]->Tag() == EXPR_NAME || l_e[1]->Tag() == EXPR_NAME) )
{
auto is_name0 = l_e[0]->Tag() == EXPR_NAME;
auto is_name1 = l_e[1]->Tag() == EXPR_NAME;
@ -541,8 +527,7 @@ const ZAMStmt ZAMCompiler::CompileInExpr(const NameExpr* n1, const ListExpr* l,
if ( l_e0_n && l_e1_n )
{
z = GenInst(OP_VAL2_IS_IN_TABLE_VVVV,
n1, l_e0_n, l_e1_n, n2);
z = GenInst(OP_VAL2_IS_IN_TABLE_VVVV, n1, l_e0_n, l_e1_n, n2);
z.t2 = l_e0_n->GetType();
}
@ -550,8 +535,7 @@ const ZAMStmt ZAMCompiler::CompileInExpr(const NameExpr* n1, const ListExpr* l,
{
ASSERT(l_e1_c);
z = GenInst(OP_VAL2_IS_IN_TABLE_VVVC,
n1, l_e0_n, n2, l_e1_c);
z = GenInst(OP_VAL2_IS_IN_TABLE_VVVC, n1, l_e0_n, n2, l_e1_c);
z.t2 = l_e0_n->GetType();
}
@ -559,21 +543,19 @@ const ZAMStmt ZAMCompiler::CompileInExpr(const NameExpr* n1, const ListExpr* l,
{
ASSERT(l_e0_c);
z = GenInst(OP_VAL2_IS_IN_TABLE_VVCV,
n1, l_e1_n, n2, l_e0_c);
z = GenInst(OP_VAL2_IS_IN_TABLE_VVCV, n1, l_e1_n, n2, l_e0_c);
z.t2 = l_e1_n->GetType();
}
else
{
// Ugh, both are constants. Assign first to
// a temporary.
// a temporary.
ASSERT(l_e0_c);
ASSERT(l_e1_c);
auto slot = TempForConst(l_e0_c);
z = ZInstI(OP_VAL2_IS_IN_TABLE_VVVC, FrameSlot(n1),
slot, FrameSlot(n2), l_e1_c);
z = ZInstI(OP_VAL2_IS_IN_TABLE_VVVC, FrameSlot(n1), slot, FrameSlot(n2), l_e1_c);
z.op_type = OP_VVVC;
z.t2 = l_e0_c->GetType();
}
@ -581,7 +563,7 @@ const ZAMStmt ZAMCompiler::CompileInExpr(const NameExpr* n1, const ListExpr* l,
return AddInst(z);
}
auto aggr = n2 ? (Expr*) n2 : (Expr*) c;
auto aggr = n2 ? (Expr*)n2 : (Expr*)c;
ASSERT(aggr->GetType()->Tag() != TYPE_VECTOR);
@ -599,21 +581,19 @@ const ZAMStmt ZAMCompiler::CompileInExpr(const NameExpr* n1, const ListExpr* l,
return AddInst(z);
}
const ZAMStmt ZAMCompiler::CompileIndex(const NameExpr* n1, const NameExpr* n2,
const ListExpr* l)
const ZAMStmt ZAMCompiler::CompileIndex(const NameExpr* n1, const NameExpr* n2, const ListExpr* l)
{
return CompileIndex(n1, FrameSlot(n2), n2->GetType(), l);
}
const ZAMStmt ZAMCompiler::CompileIndex(const NameExpr* n, const ConstExpr* c,
const ListExpr* l)
const ZAMStmt ZAMCompiler::CompileIndex(const NameExpr* n, const ConstExpr* c, const ListExpr* l)
{
auto tmp = TempForConst(c);
return CompileIndex(n, tmp, c->GetType(), l);
}
const ZAMStmt ZAMCompiler::CompileIndex(const NameExpr* n1, int n2_slot,
const TypePtr& n2t, const ListExpr* l)
const ZAMStmt ZAMCompiler::CompileIndex(const NameExpr* n1, int n2_slot, const TypePtr& n2t,
const ListExpr* l)
{
ZInstI z;
@ -642,14 +622,12 @@ const ZAMStmt ZAMCompiler::CompileIndex(const NameExpr* n1, int n2_slot,
{
int n3_slot = FrameSlot(n3);
auto zop = OP_INDEX_STRING_VVV;
z = ZInstI(zop, Frame1Slot(n1, zop),
n2_slot, n3_slot);
z = ZInstI(zop, Frame1Slot(n1, zop), n2_slot, n3_slot);
}
else
{
auto zop = OP_INDEX_STRINGC_VVV;
z = ZInstI(zop, Frame1Slot(n1, zop),
n2_slot, c);
z = ZInstI(zop, Frame1Slot(n1, zop), n2_slot, c);
z.op_type = OP_VVV_I3;
}
@ -664,15 +642,12 @@ const ZAMStmt ZAMCompiler::CompileIndex(const NameExpr* n1, int n2_slot,
if ( n3 )
{
int n3_slot = FrameSlot(n3);
auto zop = is_any ? OP_INDEX_ANY_VEC_VVV :
OP_INDEX_VEC_VVV;
z = ZInstI(zop, Frame1Slot(n1, zop),
n2_slot, n3_slot);
auto zop = is_any ? OP_INDEX_ANY_VEC_VVV : OP_INDEX_VEC_VVV;
z = ZInstI(zop, Frame1Slot(n1, zop), n2_slot, n3_slot);
}
else
{
auto zop = is_any ? OP_INDEX_ANY_VECC_VVV :
OP_INDEX_VECC_VVV;
auto zop = is_any ? OP_INDEX_ANY_VECC_VVV : OP_INDEX_VECC_VVV;
z = ZInstI(zop, Frame1Slot(n1, zop), n2_slot, c);
z.op_type = OP_VVV_I3;
}
@ -686,10 +661,8 @@ const ZAMStmt ZAMCompiler::CompileIndex(const NameExpr* n1, int n2_slot,
if ( n3 )
{
int n3_slot = FrameSlot(n3);
auto zop = AssignmentFlavor(OP_TABLE_INDEX1_VVV,
n1->GetType()->Tag());
z = ZInstI(zop, Frame1Slot(n1, zop), n2_slot,
n3_slot);
auto zop = AssignmentFlavor(OP_TABLE_INDEX1_VVV, n1->GetType()->Tag());
z = ZInstI(zop, Frame1Slot(n1, zop), n2_slot, n3_slot);
z.SetType(n3->GetType());
}
@ -697,10 +670,8 @@ const ZAMStmt ZAMCompiler::CompileIndex(const NameExpr* n1, int n2_slot,
{
ASSERT(c3);
auto zop = AssignmentFlavor(OP_TABLE_INDEX1_VVC,
n1->GetType()->Tag());
z = ZInstI(zop, Frame1Slot(n1, zop),
n2_slot, c3);
auto zop = AssignmentFlavor(OP_TABLE_INDEX1_VVC, n1->GetType()->Tag());
z = ZInstI(zop, Frame1Slot(n1, zop), n2_slot, c3);
}
return AddInst(z);
@ -711,28 +682,29 @@ const ZAMStmt ZAMCompiler::CompileIndex(const NameExpr* n1, int n2_slot,
ZOp op;
switch ( n2tag ) {
case TYPE_VECTOR:
op = OP_INDEX_VEC_SLICE_VV;
z = ZInstI(op, Frame1Slot(n1, op), n2_slot);
z.SetType(n2t);
break;
switch ( n2tag )
{
case TYPE_VECTOR:
op = OP_INDEX_VEC_SLICE_VV;
z = ZInstI(op, Frame1Slot(n1, op), n2_slot);
z.SetType(n2t);
break;
case TYPE_TABLE:
op = OP_TABLE_INDEX_VV;
z = ZInstI(op, Frame1Slot(n1, op), n2_slot);
z.SetType(n1->GetType());
break;
case TYPE_TABLE:
op = OP_TABLE_INDEX_VV;
z = ZInstI(op, Frame1Slot(n1, op), n2_slot);
z.SetType(n1->GetType());
break;
case TYPE_STRING:
op = OP_INDEX_STRING_SLICE_VV;
z = ZInstI(op, Frame1Slot(n1, op), n2_slot);
z.SetType(n1->GetType());
break;
case TYPE_STRING:
op = OP_INDEX_STRING_SLICE_VV;
z = ZInstI(op, Frame1Slot(n1, op), n2_slot);
z.SetType(n1->GetType());
break;
default:
reporter->InternalError("bad aggregate type when compiling index");
}
default:
reporter->InternalError("bad aggregate type when compiling index");
}
z.aux = InternalBuildVals(l);
z.CheckIfManaged(n1->GetType());
@ -763,8 +735,7 @@ const ZAMStmt ZAMCompiler::AssignVecElems(const Expr* e)
ASSERT(t1->Tag() == TYPE_VECTOR);
ASSERT(t3->Tag() == TYPE_VECTOR);
auto z = GenInst(OP_VECTOR_SLICE_ASSIGN_VV,
lhs, op3->AsNameExpr());
auto z = GenInst(OP_VECTOR_SLICE_ASSIGN_VV, lhs, op3->AsNameExpr());
z.aux = InternalBuildVals(indexes_expr);
@ -784,11 +755,9 @@ const ZAMStmt ZAMCompiler::AssignVecElems(const Expr* e)
auto c = op2->AsConstExpr();
auto tmp = TempForConst(c);
auto zop = any_vec ? OP_ANY_VECTOR_ELEM_ASSIGN_VVC :
OP_VECTOR_ELEM_ASSIGN_VVC;
auto zop = any_vec ? OP_ANY_VECTOR_ELEM_ASSIGN_VVC : OP_VECTOR_ELEM_ASSIGN_VVC;
return AddInst(ZInstI(zop, Frame1Slot(lhs, zop), tmp,
op3->AsConstExpr()));
return AddInst(ZInstI(zop, Frame1Slot(lhs, zop), tmp, op3->AsConstExpr()));
}
if ( op2->Tag() == EXPR_NAME )
@ -892,7 +861,7 @@ const ZAMStmt ZAMCompiler::DoCall(const CallExpr* c, const NameExpr* n)
bool indirect = ! func_id->IsGlobal() || ! func_id->GetVal();
if ( indirect )
call_case = -1; // force default of CallN
call_case = -1; // force default of CallN
auto nt = n ? n->GetType()->Tag() : TYPE_VOID;
auto n_slot = n ? Frame1Slot(n, OP1_WRITE) : -1;
@ -910,21 +879,17 @@ const ZAMStmt ZAMCompiler::DoCall(const CallExpr* c, const NameExpr* n)
else if ( call_case == 1 )
{
auto arg0 = args[0];
auto n0 = arg0->Tag() == EXPR_NAME ?
arg0->AsNameExpr() : nullptr;
auto c0 = arg0->Tag() == EXPR_CONST ?
arg0->AsConstExpr() : nullptr;
auto n0 = arg0->Tag() == EXPR_NAME ? arg0->AsNameExpr() : nullptr;
auto c0 = arg0->Tag() == EXPR_CONST ? arg0->AsConstExpr() : nullptr;
if ( n )
{
if ( n0 )
z = ZInstI(AssignmentFlavor(OP_CALL1_VV, nt),
n_slot, FrameSlot(n0));
z = ZInstI(AssignmentFlavor(OP_CALL1_VV, nt), n_slot, FrameSlot(n0));
else
{
ASSERT(c0);
z = ZInstI(AssignmentFlavor(OP_CALL1_VC, nt),
n_slot, c0);
z = ZInstI(AssignmentFlavor(OP_CALL1_VC, nt), n_slot, c0);
}
}
else
@ -957,19 +922,28 @@ const ZAMStmt ZAMCompiler::DoCall(const CallExpr* c, const NameExpr* n)
ZOp op;
switch ( call_case ) {
case 2: op = n ? OP_CALL2_V : OP_CALL2_X; break;
case 3: op = n ? OP_CALL3_V : OP_CALL3_X; break;
case 4: op = n ? OP_CALL4_V : OP_CALL4_X; break;
case 5: op = n ? OP_CALL5_V : OP_CALL5_X; break;
switch ( call_case )
{
case 2:
op = n ? OP_CALL2_V : OP_CALL2_X;
break;
case 3:
op = n ? OP_CALL3_V : OP_CALL3_X;
break;
case 4:
op = n ? OP_CALL4_V : OP_CALL4_X;
break;
case 5:
op = n ? OP_CALL5_V : OP_CALL5_X;
break;
default:
if ( indirect )
op = n ? OP_INDCALLN_VV : OP_INDCALLN_V;
else
op = n ? OP_CALLN_V : OP_CALLN_X;
break;
}
default:
if ( indirect )
op = n ? OP_INDCALLN_VV : OP_INDCALLN_V;
else
op = n ? OP_CALLN_V : OP_CALLN_X;
break;
}
if ( n )
{
@ -1134,37 +1108,38 @@ const ZAMStmt ZAMCompiler::ArithCoerce(const NameExpr* n, const Expr* e)
ZOp a;
switch ( targ_it ) {
case TYPE_INTERNAL_DOUBLE:
switch ( targ_it )
{
if ( op_it == TYPE_INTERNAL_INT )
a = nt_is_vec ? OP_COERCE_DI_VEC_VV : OP_COERCE_DI_VV;
else
a = nt_is_vec ? OP_COERCE_DU_VEC_VV : OP_COERCE_DU_VV;
break;
}
case TYPE_INTERNAL_DOUBLE:
{
if ( op_it == TYPE_INTERNAL_INT )
a = nt_is_vec ? OP_COERCE_DI_VEC_VV : OP_COERCE_DI_VV;
else
a = nt_is_vec ? OP_COERCE_DU_VEC_VV : OP_COERCE_DU_VV;
break;
}
case TYPE_INTERNAL_INT:
{
if ( op_it == TYPE_INTERNAL_UNSIGNED )
a = nt_is_vec ? OP_COERCE_IU_VEC_VV : OP_COERCE_IU_VV;
else
a = nt_is_vec ? OP_COERCE_ID_VEC_VV : OP_COERCE_ID_VV;
break;
}
case TYPE_INTERNAL_INT:
{
if ( op_it == TYPE_INTERNAL_UNSIGNED )
a = nt_is_vec ? OP_COERCE_IU_VEC_VV : OP_COERCE_IU_VV;
else
a = nt_is_vec ? OP_COERCE_ID_VEC_VV : OP_COERCE_ID_VV;
break;
}
case TYPE_INTERNAL_UNSIGNED:
{
if ( op_it == TYPE_INTERNAL_INT )
a = nt_is_vec ? OP_COERCE_UI_VEC_VV : OP_COERCE_UI_VV;
else
a = nt_is_vec ? OP_COERCE_UD_VEC_VV : OP_COERCE_UD_VV;
break;
}
case TYPE_INTERNAL_UNSIGNED:
{
if ( op_it == TYPE_INTERNAL_INT )
a = nt_is_vec ? OP_COERCE_UI_VEC_VV : OP_COERCE_UI_VV;
else
a = nt_is_vec ? OP_COERCE_UD_VEC_VV : OP_COERCE_UD_VV;
break;
}
default:
reporter->InternalError("bad target internal type in coercion");
}
default:
reporter->InternalError("bad target internal type in coercion");
}
return AddInst(GenInst(a, n, op->AsNameExpr()));
}
@ -1232,4 +1207,4 @@ const ZAMStmt ZAMCompiler::Is(const NameExpr* n, const Expr* e)
return AddInst(z);
}
} // zeek::detail
} // zeek::detail

File diff suppressed because it is too large Load diff

View file

@ -10,48 +10,51 @@
#pragma once
#include <assert.h>
#include <map>
#include <memory>
#include <string>
#include <vector>
#include <map>
#include <unordered_set>
#include <unordered_map>
#include <unordered_set>
#include <vector>
using std::string;
using std::vector;
// An instruction can have one of four basic classes.
enum ZAM_InstClass {
ZIC_REGULAR, // a non-complicated instruction
ZIC_COND, // a conditional branch
ZIC_VEC, // a vector operation
ZIC_FIELD, // a record field assignment
};
enum ZAM_InstClass
{
ZIC_REGULAR, // a non-complicated instruction
ZIC_COND, // a conditional branch
ZIC_VEC, // a vector operation
ZIC_FIELD, // a record field assignment
};
// For a given instruction operand, its general type.
enum ZAM_OperandType {
ZAM_OT_CONSTANT, // uses the instruction's associated constant
ZAM_OT_EVENT_HANDLER, // uses the associated event handler
ZAM_OT_INT, // directly specified integer
ZAM_OT_VAR, // frame slot associated with a variable
enum ZAM_OperandType
{
ZAM_OT_CONSTANT, // uses the instruction's associated constant
ZAM_OT_EVENT_HANDLER, // uses the associated event handler
ZAM_OT_INT, // directly specified integer
ZAM_OT_VAR, // frame slot associated with a variable
ZAM_OT_ASSIGN_FIELD, // record field offset to assign to
ZAM_OT_RECORD_FIELD, // record field offset to access
ZAM_OT_ASSIGN_FIELD, // record field offset to assign to
ZAM_OT_RECORD_FIELD, // record field offset to access
// The following wind up the same in the ultimate instruction,
// but they differ in the calling sequences used to generate
// the instruction.
ZAM_OT_AUX, // uses the instruction's "aux" field
ZAM_OT_LIST, // a list, managed via the "aux" field
ZAM_OT_AUX, // uses the instruction's "aux" field
ZAM_OT_LIST, // a list, managed via the "aux" field
ZAM_OT_NONE, // instruction has no direct operands
};
ZAM_OT_NONE, // instruction has no direct operands
};
// For instructions corresponding to evaluating expressions, the type
// of a given operand. The generator uses these to transform the operand's
// low-level ZVal into a higher-level type expected by the associated
// evaluation code.
enum ZAM_ExprType {
enum ZAM_ExprType
{
ZAM_EXPR_TYPE_ADDR,
ZAM_EXPR_TYPE_ANY,
ZAM_EXPR_TYPE_DOUBLE,
@ -77,7 +80,7 @@ enum ZAM_ExprType {
// expression deals directly with the operand's ZVal, rather
// than the generator providing a higher-level version.
ZAM_EXPR_TYPE_NONE,
};
};
// We only use the following in the context where the vector's elements
// are individual words from the same line. We don't use it in other
@ -85,15 +88,17 @@ enum ZAM_ExprType {
using Words = vector<string>;
// Used for error-reporting.
struct InputLoc {
struct InputLoc
{
const char* file_name;
int line_num = 0;
};
};
// An EmitTarget is a generated file to which code will be emitted.
// The different values are used to instruct the generator which target
// is currently of interest.
enum EmitTarget {
enum EmitTarget
{
// Indicates that no generated file has yet been specified.
None,
@ -169,12 +174,13 @@ enum EmitTarget {
// output. For example, for OP_NEGATE_VV_I the corresponding
// string is "negate-VV-I".
OpName,
};
};
// A helper class for managing the (ordered) collection of ZAM_OperandType's
// associated with an instruction in order to generate C++ calling sequences
// (both parameters for declarations, and arguments for invocations).
class ArgsManager {
class ArgsManager
{
public:
// Constructed by providing the various ZAM_OperandType's along
// with the instruction's class.
@ -183,15 +189,15 @@ public:
// Returns a string defining the parameters for a declaration;
// these have full C++ type information along with the parameter
// name.
string Decls() const { return full_decl; }
string Decls() const { return full_decl; }
// Returns a string for passing the parameters in a function
// call. This is a comma-separated list of the parameter names,
// with no associated C++ types.
string Params() const { return full_params; }
string Params() const { return full_params; }
// Returns the name of the given parameter, indexed starting with 0.
const string& NthParam(int n) const { return params[n]; }
const string& NthParam(int n) const { return params[n]; }
private:
// Makes sure that each parameter has a unique name. For any
@ -201,20 +207,20 @@ private:
// Maps ZAM_OperandType's to their associated C++ type and
// canonical parameter name.
static std::unordered_map<ZAM_OperandType,
std::pair<const char*, const char*>> ot_to_args;
static std::unordered_map<ZAM_OperandType, std::pair<const char*, const char*>> ot_to_args;
// For a single argument/parameter, tracks its declaration name,
// C++ type, and the name to use when providing it as a parameter.
// These last two names are potentially distinct when we're
// assigning to record field (which is tracked by the is_field
// member variable), hence the need to track both.
struct Arg {
struct Arg
{
string decl_name;
string decl_type;
string param_name;
bool is_field;
};
};
// All of the argument/parameters associated with the collection
// of ZAM_OperandType's.
@ -226,7 +232,7 @@ private:
// See Decls() and Params() above.
string full_decl;
string full_params;
};
};
// There are two mutually interacting classes: ZAMGen is the overall
// driver for the ZAM generator, while ZAM_OpTemplate represents a
@ -234,12 +240,13 @@ private:
// operations.
class ZAMGen;
class ZAM_OpTemplate {
class ZAM_OpTemplate
{
public:
// Instantiated by passing in the ZAMGen driver and the generic
// name for the operation.
ZAM_OpTemplate(ZAMGen* _g, string _base_name);
virtual ~ZAM_OpTemplate() { }
virtual ~ZAM_OpTemplate() { }
// Constructs the template's data structures by parsing its
// description (beyond the initial description of the type of
@ -251,70 +258,64 @@ public:
virtual void Instantiate();
// Returns the generic name for the operation.
const string& BaseName() const { return base_name; }
const string& BaseName() const { return base_name; }
// Returns the canonical name for the operation. This is a
// version of the name that, for expression-based operations,
// can be concatenated with "EXPR_" to get the name of the
// corresponding AST node.
const string& CanonicalName() const { return cname; }
const string& CanonicalName() const { return cname; }
// Returns a string version of the ZAMOp1Flavor associated
// with this operation.
const string& GetOp1Flavor() const { return op1_flavor; }
const string& GetOp1Flavor() const { return op1_flavor; }
// True if this is an operation with side effects (see OpSideEffects
// above).
bool HasSideEffects() const { return has_side_effects; }
bool HasSideEffects() const { return has_side_effects; }
protected:
// Append to the list of operand types associated with this operation.
void AddOpType(ZAM_OperandType ot)
{ op_types.push_back(ot); }
void AddOpType(ZAM_OperandType ot) { op_types.push_back(ot); }
// Retrieve the list of operand types associated with this operation.
const vector<ZAM_OperandType>& OperandTypes() const
{ return op_types; }
const vector<ZAM_OperandType>& OperandTypes() const { return op_types; }
// Specify the ZAMOp1Flavor associated with this operation. See
// GetOp1Flavor() above for the corresponding accessor.
void SetOp1Flavor(string fl) { op1_flavor = fl; }
void SetOp1Flavor(string fl) { op1_flavor = fl; }
// Specify/fetch the parameter (operand) from which to take the
// primary type of this operation.
void SetTypeParam(int param) { type_param = param; }
int GetTypeParam() const { return type_param; }
void SetTypeParam(int param) { type_param = param; }
int GetTypeParam() const { return type_param; }
// Specify/fetch the parameter (operand) from which to take the
// secondary type of this operation.
void SetType2Param(int param) { type2_param = param; }
int GetType2Param() const { return type2_param; }
void SetType2Param(int param) { type2_param = param; }
int GetType2Param() const { return type2_param; }
// Tracking of assignment values (C++ variables that hold the
// value that should be assigned to usual frame slot).
void SetAssignVal(string _av) { av = _av; }
bool HasAssignVal() const { return ! av.empty(); }
const string& GetAssignVal() const { return av; }
void SetAssignVal(string _av) { av = _av; }
bool HasAssignVal() const { return ! av.empty(); }
const string& GetAssignVal() const { return av; }
// Management of C++ evaluation blocks. These are built up
// line-by-line.
void AddEval(string line) { eval += line; }
bool HasEval() const { return ! eval.empty(); }
const string& GetEval() const { return eval; }
void AddEval(string line) { eval += line; }
bool HasEval() const { return ! eval.empty(); }
const string& GetEval() const { return eval; }
// Management of custom methods to be used rather than generating
// a method.
void SetCustomMethod(string cm) { custom_method = SkipWS(cm); }
bool HasCustomMethod() const
{ return ! custom_method.empty(); }
const string& GetCustomMethod() const
{ return custom_method; }
void SetCustomMethod(string cm) { custom_method = SkipWS(cm); }
bool HasCustomMethod() const { return ! custom_method.empty(); }
const string& GetCustomMethod() const { return custom_method; }
// Management of code to execute at the end of a generated method.
void SetPostMethod(string cm) { post_method = SkipWS(cm); }
bool HasPostMethod() const
{ return ! post_method.empty(); }
const string& GetPostMethod() const
{ return post_method; }
void SetPostMethod(string cm) { post_method = SkipWS(cm); }
bool HasPostMethod() const { return ! post_method.empty(); }
const string& GetPostMethod() const { return post_method; }
// Predicates indicating whether a subclass supports a given
// property. These are whether the operation: (1) should include
@ -323,45 +324,42 @@ protected:
// not have a corresponding AST node, (4) is a direct assignment
// (not an assignment to an expression), (5) is a direct assignment
// to a record field.
virtual bool IncludesFieldOp() const { return false; }
virtual bool IsConditionalOp() const { return false; }
virtual bool IsInternalOp() const { return false; }
virtual bool IsAssignOp() const { return false; }
virtual bool IsFieldOp() const { return false; }
virtual bool IncludesFieldOp() const { return false; }
virtual bool IsConditionalOp() const { return false; }
virtual bool IsInternalOp() const { return false; }
virtual bool IsAssignOp() const { return false; }
virtual bool IsFieldOp() const { return false; }
// Whether this operation does not have any C++ evaluation associated
// with it. Used for custom methods that compile into internal
// ZAM operations.
bool NoEval() const { return no_eval; }
void SetNoEval() { no_eval = true; }
bool NoEval() const { return no_eval; }
void SetNoEval() { no_eval = true; }
// Whether this operation does not have a version where one of
// its operands is a constant.
bool NoConst() const { return no_const; }
void SetNoConst() { no_const = true; }
bool NoConst() const { return no_const; }
void SetNoConst() { no_const = true; }
// Whether this operation also has a vectorized form.
bool IncludesVectorOp() const { return includes_vector_op; }
void SetIncludesVectorOp() { includes_vector_op = true; }
bool IncludesVectorOp() const { return includes_vector_op; }
void SetIncludesVectorOp() { includes_vector_op = true; }
// Whether this operation has side effects, and thus should
// not be elided even if its result is used in a dead assignment.
void SetHasSideEffects() { has_side_effects = true; }
void SetHasSideEffects() { has_side_effects = true; }
// An "assignment-less" operation is one that, if its result
// is used in a dead assignment, should be converted to a different
// operation that explictly omits any assignment.
bool HasAssignmentLess() const
{ return ! assignment_less_op.empty(); }
bool HasAssignmentLess() const { return ! assignment_less_op.empty(); }
void SetAssignmentLess(string op, string op_type)
{
assignment_less_op = op;
assignment_less_op_type = op_type;
}
const string& AssignmentLessOp() const
{ return assignment_less_op; }
const string& AssignmentLessOpType() const
{ return assignment_less_op_type; }
const string& AssignmentLessOp() const { return assignment_less_op; }
const string& AssignmentLessOpType() const { return assignment_less_op_type; }
// Builds the instructions associated with this operation, assuming
// a single operand.
@ -373,8 +371,7 @@ protected:
// for parsing when that's necessary, and for error reporting.
// "words" is "line" split into a vector of whitespace-delimited
// words.
virtual void Parse(const string& attr, const string& line,
const Words& words);
virtual void Parse(const string& attr, const string& line, const Words& words);
// Scans in a C++ evaluation block, which continues until encountering
// a line that does not start with whitespace, or that's empty.
@ -391,8 +388,7 @@ protected:
// Generates one specific flavor ("zc") of the given operation,
// using a method named 'm', the given operand types, and the class.
void InstantiateOp(const string& m, const vector<ZAM_OperandType>& ot,
ZAM_InstClass zc);
void InstantiateOp(const string& m, const vector<ZAM_OperandType>& ot, ZAM_InstClass zc);
// Generates the "assignment-less" version of the given op-code.
void GenAssignmentlessVersion(string op);
@ -401,56 +397,49 @@ protected:
// a (potentially empty) string differentiating the method from
// others for that operation, and "ot" and "zc" are the same
// as above.
void InstantiateMethod(const string& m, const string& suffix,
const vector<ZAM_OperandType>& ot,
void InstantiateMethod(const string& m, const string& suffix, const vector<ZAM_OperandType>& ot,
ZAM_InstClass zc);
// Generates the main logic of an operation's method, given the
// specific operand types, an associated suffix for differentiating
// ZAM instructions, and the instruction class.
void InstantiateMethodCore(const vector<ZAM_OperandType>& ot,
string suffix, ZAM_InstClass zc);
void InstantiateMethodCore(const vector<ZAM_OperandType>& ot, string suffix, ZAM_InstClass zc);
// Generates the specific code to create a ZInst for the given
// operation, operands, parameters to "GenInst", and suffix and
// class per the above.
virtual void BuildInstruction(const vector<ZAM_OperandType>& ot,
const string& params,
virtual void BuildInstruction(const vector<ZAM_OperandType>& ot, const string& params,
const string& suffix, ZAM_InstClass zc);
// Top-level driver for generating the C++ evaluation code for
// a given flavor of operation.
virtual void InstantiateEval(const vector<ZAM_OperandType>& ot,
const string& suffix, ZAM_InstClass zc);
virtual void InstantiateEval(const vector<ZAM_OperandType>& ot, const string& suffix,
ZAM_InstClass zc);
// Generates the C++ case statement for evaluating the given flavor
// of operation.
void InstantiateEval(EmitTarget et, const string& op_suffix,
const string& eval, ZAM_InstClass zc);
void InstantiateEval(EmitTarget et, const string& op_suffix, const string& eval,
ZAM_InstClass zc);
// Generates a set of assignment C++ evaluations, one per each
// possible Zeek scripting type of operand.
void InstantiateAssignOp(const vector<ZAM_OperandType>& ot,
const string& suffix);
void InstantiateAssignOp(const vector<ZAM_OperandType>& ot, const string& suffix);
// Generates a C++ evaluation for an assignment of the type
// corresponding to "accessor". If "is_managed" is true then
// generates the associated memory management, too.
void GenAssignOpCore(const vector<ZAM_OperandType>& ot,
const string& eval, const string& accessor,
bool is_managed);
void GenAssignOpCore(const vector<ZAM_OperandType>& ot, const string& eval,
const string& accessor, bool is_managed);
// The same, but for when there's an explicit assignment value.
void GenAssignOpValCore(const string& eval, const string& accessor,
bool is_managed);
void GenAssignOpValCore(const string& eval, const string& accessor, bool is_managed);
// Returns the name of the method associated with the particular
// list of operand types.
string MethodName(const vector<ZAM_OperandType>& ot) const;
// Returns the parameter declarations to use in declaring a method.
string MethodDeclare(const vector<ZAM_OperandType>& ot,
ZAM_InstClass zc);
string MethodDeclare(const vector<ZAM_OperandType>& ot, ZAM_InstClass zc);
// Returns a suffix that differentiates an operation name for
// a specific list of operand types.
@ -461,7 +450,7 @@ protected:
string SkipWS(const string& s) const;
// Set the target to use for subsequent code emission.
void EmitTo(EmitTarget et) { curr_et = et; }
void EmitTo(EmitTarget et) { curr_et = et; }
// Emit the given string to the currently selected EmitTarget.
void Emit(const string& s);
@ -479,15 +468,22 @@ protected:
// Emit a newline. Implementation doesn't actually include a
// newline since that's implicit in a call to Emit().
void NL() { Emit(""); }
void NL() { Emit(""); }
// Increase/decrease the indentation level, with the last two
// being used for brace-delimited code blocks.
void IndentUp();
void IndentDown();
void BeginBlock() { IndentUp(); Emit("{"); }
void EndBlock() { Emit("}"); IndentDown(); }
void BeginBlock()
{
IndentUp();
Emit("{");
}
void EndBlock()
{
Emit("}");
IndentDown();
}
// Maps an operand type to a character mnemonic used to distinguish
// it from others.
@ -517,7 +513,7 @@ protected:
// Tracks the result of ExtractTypeParam() used for "type" and
// "type2" attributes.
int type_param = 0; // 0 = not set
int type_param = 0; // 0 = not set
int type2_param = 0;
// If non-empty, the value to assign to the target in an assignment
@ -553,24 +549,27 @@ protected:
// and the operand type (like "OP_V") of that associated operation.
string assignment_less_op;
string assignment_less_op_type;
};
};
// A subclass used for "unary-op" templates.
class ZAM_UnaryOpTemplate : public ZAM_OpTemplate {
class ZAM_UnaryOpTemplate : public ZAM_OpTemplate
{
public:
ZAM_UnaryOpTemplate(ZAMGen* _g, string _base_name)
: ZAM_OpTemplate(_g, _base_name) { }
ZAM_UnaryOpTemplate(ZAMGen* _g, string _base_name) : ZAM_OpTemplate(_g, _base_name) { }
protected:
void Instantiate() override;
};
};
// A subclass for unary operations that are directly instantiated using
// custom methods.
class ZAM_DirectUnaryOpTemplate : public ZAM_OpTemplate {
class ZAM_DirectUnaryOpTemplate : public ZAM_OpTemplate
{
public:
ZAM_DirectUnaryOpTemplate(ZAMGen* _g, string _base_name, string _direct)
: ZAM_OpTemplate(_g, _base_name), direct(_direct) { }
: ZAM_OpTemplate(_g, _base_name), direct(_direct)
{
}
protected:
void Instantiate() override;
@ -578,12 +577,13 @@ protected:
private:
// The ZAMCompiler method to call to compile the operation.
string direct;
};
};
// A helper class for the ZAM_ExprOpTemplate class (which follows).
// This class tracks a single instance of creating an evaluation for
// an AST expression.
class EvalInstance {
class EvalInstance
{
public:
// Initialized using the types of the LHS (result) and the
// first and second operand. Often all three types are the
@ -592,8 +592,8 @@ public:
// "is_def" is true if this instance is for the default catch-all
// where the operand types don't match any of the explicitly
// specified evaluations;
EvalInstance(ZAM_ExprType lhs_et, ZAM_ExprType op1_et,
ZAM_ExprType op2_et, string eval, bool is_def);
EvalInstance(ZAM_ExprType lhs_et, ZAM_ExprType op1_et, ZAM_ExprType op2_et, string eval,
bool is_def);
// Returns the accessor to use for assigning to the LHS. "is_ptr"
// indicates whether the value to which we're applying the
@ -601,10 +601,8 @@ public:
string LHSAccessor(bool is_ptr = false) const;
// Same but for access to the first or second operand.
string Op1Accessor(bool is_ptr = false) const
{ return Accessor(op1_et, is_ptr); }
string Op2Accessor(bool is_ptr = false) const
{ return Accessor(op2_et, is_ptr); }
string Op1Accessor(bool is_ptr = false) const { return Accessor(op1_et, is_ptr); }
string Op2Accessor(bool is_ptr = false) const { return Accessor(op2_et, is_ptr); }
// Provides an accessor for an operand of the given type.
string Accessor(ZAM_ExprType et, bool is_ptr = false) const;
@ -613,9 +611,9 @@ public:
// flavor of expression-evaluation instruction.
string OpMarker() const;
const string& Eval() const { return eval; }
ZAM_ExprType LHS_ET() const { return lhs_et; }
bool IsDefault() const { return is_def; }
const string& Eval() const { return eval; }
ZAM_ExprType LHS_ET() const { return lhs_et; }
bool IsDefault() const { return is_def; }
private:
ZAM_ExprType lhs_et;
@ -623,37 +621,37 @@ private:
ZAM_ExprType op2_et;
string eval;
bool is_def;
};
};
// A subclass for AST "Expr" nodes in reduced form.
class ZAM_ExprOpTemplate : public ZAM_OpTemplate {
class ZAM_ExprOpTemplate : public ZAM_OpTemplate
{
public:
ZAM_ExprOpTemplate(ZAMGen* _g, string _base_name);
// The number of operands the operation takes (not including its
// assignment target). A value of 0 is used for expressions that
// require special handling.
virtual int Arity() const { return 0; }
virtual int Arity() const { return 0; }
int HasExplicitResultType() const { return explicit_res_type; }
void SetHasExplicitResultType() { explicit_res_type = true; }
int HasExplicitResultType() const { return explicit_res_type; }
void SetHasExplicitResultType() { explicit_res_type = true; }
void AddExprType(ZAM_ExprType et)
{ expr_types.insert(et); }
const std::unordered_set<ZAM_ExprType>& ExprTypes() const
{ return expr_types; }
void AddExprType(ZAM_ExprType et) { expr_types.insert(et); }
const std::unordered_set<ZAM_ExprType>& ExprTypes() const { return expr_types; }
void AddEvalSet(ZAM_ExprType et, string ev)
{ eval_set[et] += ev; }
void AddEvalSet(ZAM_ExprType et, string ev) { eval_set[et] += ev; }
void AddEvalSet(ZAM_ExprType et1, ZAM_ExprType et2, string ev)
{ eval_mixed_set[et1][et2] += ev; }
{
eval_mixed_set[et1][et2] += ev;
}
bool IncludesFieldOp() const override { return includes_field_op; }
void SetIncludesFieldOp() { includes_field_op = true; }
bool IncludesFieldOp() const override { return includes_field_op; }
void SetIncludesFieldOp() { includes_field_op = true; }
bool HasPreEval() const { return ! pre_eval.empty(); }
void SetPreEval(string pe) { pre_eval = SkipWS(pe); }
const string& GetPreEval() const { return pre_eval; }
bool HasPreEval() const { return ! pre_eval.empty(); }
void SetPreEval(string pe) { pre_eval = SkipWS(pe); }
const string& GetPreEval() const { return pre_eval; }
protected:
// Returns a regular expression used to access the value of the
@ -670,8 +668,7 @@ protected:
// Instantiates versions of the operation that have a constant
// as the first, second, or third operand ...
void InstantiateC1(const vector<ZAM_OperandType>& ots, int arity,
bool do_vec = false);
void InstantiateC1(const vector<ZAM_OperandType>& ots, int arity, bool do_vec = false);
void InstantiateC2(const vector<ZAM_OperandType>& ots, int arity);
void InstantiateC3(const vector<ZAM_OperandType>& ots);
@ -685,17 +682,15 @@ protected:
// Iterates over the different Zeek types specified for an expression's
// operands and generates instructions for each.
void BuildInstructionCore(const string& params, const string& suffix,
ZAM_InstClass zc);
void BuildInstructionCore(const string& params, const string& suffix, ZAM_InstClass zc);
// Generates an if-else cascade element that matches one of the
// specific Zeek types associated with the instruction.
void GenMethodTest(ZAM_ExprType et1, ZAM_ExprType et2,
const string& params, const string& suffix,
bool do_else, ZAM_InstClass zc);
void GenMethodTest(ZAM_ExprType et1, ZAM_ExprType et2, const string& params,
const string& suffix, bool do_else, ZAM_InstClass zc);
void InstantiateEval(const vector<ZAM_OperandType>& ot,
const string& suffix, ZAM_InstClass zc) override;
void InstantiateEval(const vector<ZAM_OperandType>& ot, const string& suffix,
ZAM_InstClass zc) override;
private:
// The Zeek types that can appear as operands for the expression.
@ -706,9 +701,7 @@ private:
// Some expressions take two operands of different types. This
// holds their C++ evaluation template.
std::unordered_map<ZAM_ExprType,
std::unordered_map<ZAM_ExprType, string>>
eval_mixed_set;
std::unordered_map<ZAM_ExprType, std::unordered_map<ZAM_ExprType, string>> eval_mixed_set;
// Whether this expression's operand is a field access (and thus
// needs both the record as an operand and an additional constant
@ -721,38 +714,37 @@ private:
// If true, then the evaluations will take care of ensuring
// proper result types when assigning to $$.
bool explicit_res_type = false;
};
};
// A version of ZAM_ExprOpTemplate for unary expressions.
class ZAM_UnaryExprOpTemplate : public ZAM_ExprOpTemplate {
class ZAM_UnaryExprOpTemplate : public ZAM_ExprOpTemplate
{
public:
ZAM_UnaryExprOpTemplate(ZAMGen* _g, string _base_name)
: ZAM_ExprOpTemplate(_g, _base_name) { }
ZAM_UnaryExprOpTemplate(ZAMGen* _g, string _base_name) : ZAM_ExprOpTemplate(_g, _base_name) { }
bool IncludesFieldOp() const override
{ return ExprTypes().count(ZAM_EXPR_TYPE_NONE) == 0; }
bool IncludesFieldOp() const override { return ExprTypes().count(ZAM_EXPR_TYPE_NONE) == 0; }
int Arity() const override { return 1; }
int Arity() const override { return 1; }
protected:
void Parse(const string& attr, const string& line, const Words& words) override;
void Instantiate() override;
void BuildInstruction(const vector<ZAM_OperandType>& ot,
const string& params, const string& suffix,
ZAM_InstClass zc) override;
};
void BuildInstruction(const vector<ZAM_OperandType>& ot, const string& params,
const string& suffix, ZAM_InstClass zc) override;
};
// A version of ZAM_UnaryExprOpTemplate where the point of the expression
// is to capture a direct assignment operation.
class ZAM_AssignOpTemplate : public ZAM_UnaryExprOpTemplate {
class ZAM_AssignOpTemplate : public ZAM_UnaryExprOpTemplate
{
public:
ZAM_AssignOpTemplate(ZAMGen* _g, string _base_name);
bool IsAssignOp() const override { return true; }
bool IncludesFieldOp() const override { return false; }
bool IsFieldOp() const override { return field_op; }
void SetFieldOp() { field_op = true; }
bool IsAssignOp() const override { return true; }
bool IncludesFieldOp() const override { return false; }
bool IsFieldOp() const override { return field_op; }
void SetFieldOp() { field_op = true; }
protected:
void Parse(const string& attr, const string& line, const Words& words) override;
@ -760,34 +752,36 @@ protected:
private:
bool field_op = false;
};
};
// A version of ZAM_ExprOpTemplate for binary expressions.
class ZAM_BinaryExprOpTemplate : public ZAM_ExprOpTemplate {
class ZAM_BinaryExprOpTemplate : public ZAM_ExprOpTemplate
{
public:
ZAM_BinaryExprOpTemplate(ZAMGen* _g, string _base_name)
: ZAM_ExprOpTemplate(_g, _base_name) { }
ZAM_BinaryExprOpTemplate(ZAMGen* _g, string _base_name) : ZAM_ExprOpTemplate(_g, _base_name) { }
bool IncludesFieldOp() const override { return true; }
bool IncludesFieldOp() const override { return true; }
int Arity() const override { return 2; }
int Arity() const override { return 2; }
protected:
void Instantiate() override;
void BuildInstruction(const vector<ZAM_OperandType>& ot,
const string& params, const string& suffix,
ZAM_InstClass zc) override;
};
void BuildInstruction(const vector<ZAM_OperandType>& ot, const string& params,
const string& suffix, ZAM_InstClass zc) override;
};
// A version of ZAM_BinaryExprOpTemplate for relationals.
class ZAM_RelationalExprOpTemplate : public ZAM_BinaryExprOpTemplate {
class ZAM_RelationalExprOpTemplate : public ZAM_BinaryExprOpTemplate
{
public:
ZAM_RelationalExprOpTemplate(ZAMGen* _g, string _base_name)
: ZAM_BinaryExprOpTemplate(_g, _base_name) { }
: ZAM_BinaryExprOpTemplate(_g, _base_name)
{
}
bool IncludesFieldOp() const override { return false; }
bool IsConditionalOp() const override { return true; }
bool IncludesFieldOp() const override { return false; }
bool IsConditionalOp() const override { return true; }
protected:
const char* VecEvalRE(bool have_target) const override
@ -800,49 +794,51 @@ protected:
void Instantiate() override;
void BuildInstruction(const vector<ZAM_OperandType>& ot,
const string& params, const string& suffix,
ZAM_InstClass zc) override;
};
void BuildInstruction(const vector<ZAM_OperandType>& ot, const string& params,
const string& suffix, ZAM_InstClass zc) override;
};
// A version of ZAM_BinaryExprOpTemplate for binary operations generated
// by custom methods rather than directly from the AST.
class ZAM_InternalBinaryOpTemplate : public ZAM_BinaryExprOpTemplate {
class ZAM_InternalBinaryOpTemplate : public ZAM_BinaryExprOpTemplate
{
public:
ZAM_InternalBinaryOpTemplate(ZAMGen* _g, string _base_name)
: ZAM_BinaryExprOpTemplate(_g, _base_name) { }
: ZAM_BinaryExprOpTemplate(_g, _base_name)
{
}
bool IsInternalOp() const override { return true; }
bool IsInternalOp() const override { return true; }
// The accessors used to get to the underlying Zeek script value
// of the first and second operand.
void SetOp1Accessor(string accessor) { op1_accessor = accessor; }
void SetOp2Accessor(string accessor) { op2_accessor = accessor; }
void SetOp1Accessor(string accessor) { op1_accessor = accessor; }
void SetOp2Accessor(string accessor) { op2_accessor = accessor; }
void SetOpAccessor(string accessor)
{
SetOp1Accessor(accessor);
SetOp1Accessor(accessor);
SetOp2Accessor(accessor);
}
protected:
void Parse(const string& attr, const string& line, const Words& words) override;
void InstantiateEval(const vector<ZAM_OperandType>& ot,
const string& suffix, ZAM_InstClass zc) override;
void InstantiateEval(const vector<ZAM_OperandType>& ot, const string& suffix,
ZAM_InstClass zc) override;
private:
string op1_accessor;
string op2_accessor;
};
};
// A version of ZAM_OpTemplate for operations used internally (and not
// corresponding to AST elements).
class ZAM_InternalOpTemplate : public ZAM_OpTemplate {
class ZAM_InternalOpTemplate : public ZAM_OpTemplate
{
public:
ZAM_InternalOpTemplate(ZAMGen* _g, string _base_name)
: ZAM_OpTemplate(_g, _base_name) { }
ZAM_InternalOpTemplate(ZAMGen* _g, string _base_name) : ZAM_OpTemplate(_g, _base_name) { }
bool IsInternalOp() const override { return true; }
bool IsInternalOp() const override { return true; }
protected:
void Parse(const string& attr, const string& line, const Words& words) override;
@ -851,31 +847,34 @@ private:
// True if the internal operation corresponds to an indirect call,
// i.e., one through a variable rather than one directly specified.
bool is_indirect_call = false;
};
};
// An internal operation that assigns a result to a frame element.
class ZAM_InternalAssignOpTemplate : public ZAM_InternalOpTemplate {
class ZAM_InternalAssignOpTemplate : public ZAM_InternalOpTemplate
{
public:
ZAM_InternalAssignOpTemplate(ZAMGen* _g, string _base_name)
: ZAM_InternalOpTemplate(_g, _base_name) { }
bool IsAssignOp() const override { return true; }
};
: ZAM_InternalOpTemplate(_g, _base_name)
{
}
bool IsAssignOp() const override { return true; }
};
// Helper classes for managing input from the template file, including
// low-level scanning.
class TemplateInput {
class TemplateInput
{
public:
// Program name and file name are for generating error messages.
TemplateInput(FILE* _f, const char* _prog_name, const char* _file_name)
: f(_f), prog_name(_prog_name)
: f(_f), prog_name(_prog_name)
{
loc.file_name = _file_name;
}
const InputLoc& CurrLoc() const { return loc; }
const InputLoc& CurrLoc() const { return loc; }
// Fetch the next line of input, including trailing newline.
// Returns true on success, false on EOF or error. Skips over
@ -891,24 +890,24 @@ public:
// Puts back the given line so that the next call to ScanLine will
// return it. Does not nest.
void PutBack(const string& line) { put_back = line; }
void PutBack(const string& line) { put_back = line; }
// Report an error and exit.
[[noreturn]] void Gripe(const char* msg, const string& input) const;
[[noreturn]] void Gripe(const char* msg, const InputLoc& loc) const;
private:
string put_back; // if non-empty, use this for the next ScanLine
string put_back; // if non-empty, use this for the next ScanLine
FILE* f;
const char* prog_name;
InputLoc loc;
};
};
// Driver class for the ZAM instruction generator.
class ZAMGen {
class ZAMGen
{
public:
ZAMGen(int argc, char** argv);
@ -928,25 +927,21 @@ public:
// These methods provide low-level parsing (and error-reporting)
// access to ZAM_OpTemplate objects.
const InputLoc& CurrLoc() const { return ti->CurrLoc(); }
bool ScanLine(string& line) { return ti->ScanLine(line); }
Words SplitIntoWords(const string& line) const
{ return ti->SplitIntoWords(line); }
string SkipWords(const string& line, int n) const
{ return ti->SkipWords(line, n); }
void PutBack(const string& line) { ti->PutBack(line); }
const InputLoc& CurrLoc() const { return ti->CurrLoc(); }
bool ScanLine(string& line) { return ti->ScanLine(line); }
Words SplitIntoWords(const string& line) const { return ti->SplitIntoWords(line); }
string SkipWords(const string& line, int n) const { return ti->SkipWords(line, n); }
void PutBack(const string& line) { ti->PutBack(line); }
// Methods made public to ZAM_OpTemplate objects for emitting code.
void Emit(EmitTarget et, const string& s);
void IndentUp() { ++indent_level; }
void IndentDown() { --indent_level; }
void SetNoNL(bool _no_NL) { no_NL = _no_NL; }
void IndentUp() { ++indent_level; }
void IndentDown() { --indent_level; }
void SetNoNL(bool _no_NL) { no_NL = _no_NL; }
[[noreturn]] void Gripe(const char* msg, const string& input) const
{ ti->Gripe(msg, input); }
[[noreturn]] void Gripe(const char* msg, const InputLoc& loc) const
{ ti->Gripe(msg, loc); }
[[noreturn]] void Gripe(const char* msg, const string& input) const { ti->Gripe(msg, input); }
[[noreturn]] void Gripe(const char* msg, const InputLoc& loc) const { ti->Gripe(msg, loc); }
private:
// Opens all of the code generation targets, and creates prologs
@ -988,4 +983,4 @@ private:
// If true, refrain from appending a newline to any emitted lines.
bool no_NL = false;
};
};

View file

@ -4,8 +4,8 @@
#include "zeek/script_opt/ZAM/Compile.h"
namespace zeek::detail {
namespace zeek::detail
{
ZInstI ZAMCompiler::GenInst(ZOp op)
{
@ -24,8 +24,7 @@ ZInstI ZAMCompiler::GenInst(ZOp op, const NameExpr* v1, int i)
return z;
}
ZInstI ZAMCompiler::GenInst(ZOp op, const ConstExpr* c, const NameExpr* v1,
int i)
ZInstI ZAMCompiler::GenInst(ZOp op, const ConstExpr* c, const NameExpr* v1, int i)
{
auto z = ZInstI(op, Frame1Slot(v1, op), i, c);
z.op_type = OP_VVC_I2;
@ -38,16 +37,15 @@ ZInstI ZAMCompiler::GenInst(ZOp op, const NameExpr* v1, const NameExpr* v2)
return ZInstI(op, Frame1Slot(v1, op), nv2);
}
ZInstI ZAMCompiler::GenInst(ZOp op, const NameExpr* v1, const NameExpr* v2,
const NameExpr* v3)
ZInstI ZAMCompiler::GenInst(ZOp op, const NameExpr* v1, const NameExpr* v2, const NameExpr* v3)
{
int nv2 = FrameSlot(v2);
int nv3 = FrameSlot(v3);
return ZInstI(op, Frame1Slot(v1, op), nv2, nv3);
}
ZInstI ZAMCompiler::GenInst(ZOp op, const NameExpr* v1, const NameExpr* v2,
const NameExpr* v3, const NameExpr* v4)
ZInstI ZAMCompiler::GenInst(ZOp op, const NameExpr* v1, const NameExpr* v2, const NameExpr* v3,
const NameExpr* v4)
{
int nv2 = FrameSlot(v2);
int nv3 = FrameSlot(v3);
@ -70,30 +68,28 @@ ZInstI ZAMCompiler::GenInst(ZOp op, const ConstExpr* ce, const NameExpr* v1)
return ZInstI(op, Frame1Slot(v1, op), ce);
}
ZInstI ZAMCompiler::GenInst(ZOp op, const NameExpr* v1, const ConstExpr* ce,
const NameExpr* v2)
ZInstI ZAMCompiler::GenInst(ZOp op, const NameExpr* v1, const ConstExpr* ce, const NameExpr* v2)
{
int nv2 = FrameSlot(v2);
return ZInstI(op, Frame1Slot(v1, op), nv2, ce);
}
ZInstI ZAMCompiler::GenInst(ZOp op, const NameExpr* v1, const NameExpr* v2,
ZInstI ZAMCompiler::GenInst(ZOp op, const NameExpr* v1, const NameExpr* v2, const ConstExpr* ce)
{
int nv2 = FrameSlot(v2);
return ZInstI(op, Frame1Slot(v1, op), nv2, ce);
}
ZInstI ZAMCompiler::GenInst(ZOp op, const NameExpr* v1, const NameExpr* v2, const NameExpr* v3,
const ConstExpr* ce)
{
int nv2 = FrameSlot(v2);
return ZInstI(op, Frame1Slot(v1, op), nv2, ce);
}
ZInstI ZAMCompiler::GenInst(ZOp op, const NameExpr* v1, const NameExpr* v2,
const NameExpr* v3, const ConstExpr* ce)
{
int nv2 = FrameSlot(v2);
int nv3 = FrameSlot(v3);
return ZInstI(op, Frame1Slot(v1, op), nv2, nv3, ce);
}
ZInstI ZAMCompiler::GenInst(ZOp op, const NameExpr* v1, const NameExpr* v2,
const ConstExpr* ce, const NameExpr* v3)
ZInstI ZAMCompiler::GenInst(ZOp op, const NameExpr* v1, const NameExpr* v2, const ConstExpr* ce,
const NameExpr* v3)
{
// Note that here we reverse the order of the arguments; saves
// us from needing to implement a redundant constructor.
@ -102,16 +98,14 @@ ZInstI ZAMCompiler::GenInst(ZOp op, const NameExpr* v1, const NameExpr* v2,
return ZInstI(op, Frame1Slot(v1, op), nv2, nv3, ce);
}
ZInstI ZAMCompiler::GenInst(ZOp op, const NameExpr* v1, const ConstExpr* c,
int i)
ZInstI ZAMCompiler::GenInst(ZOp op, const NameExpr* v1, const ConstExpr* c, int i)
{
auto z = ZInstI(op, Frame1Slot(v1, op), i, c);
z.op_type = OP_VVC_I2;
return z;
}
ZInstI ZAMCompiler::GenInst(ZOp op, const NameExpr* v1, const NameExpr* v2,
int i)
ZInstI ZAMCompiler::GenInst(ZOp op, const NameExpr* v1, const NameExpr* v2, int i)
{
int nv2 = FrameSlot(v2);
auto z = ZInstI(op, Frame1Slot(v1, op), nv2, i);
@ -119,8 +113,7 @@ ZInstI ZAMCompiler::GenInst(ZOp op, const NameExpr* v1, const NameExpr* v2,
return z;
}
ZInstI ZAMCompiler::GenInst(ZOp op, const NameExpr* v1, const NameExpr* v2,
int i1, int i2)
ZInstI ZAMCompiler::GenInst(ZOp op, const NameExpr* v1, const NameExpr* v2, int i1, int i2)
{
int nv2 = FrameSlot(v2);
auto z = ZInstI(op, Frame1Slot(v1, op), nv2, i1, i2);
@ -128,16 +121,15 @@ ZInstI ZAMCompiler::GenInst(ZOp op, const NameExpr* v1, const NameExpr* v2,
return z;
}
ZInstI ZAMCompiler::GenInst(ZOp op, const NameExpr* v, const ConstExpr* c,
int i1, int i2)
ZInstI ZAMCompiler::GenInst(ZOp op, const NameExpr* v, const ConstExpr* c, int i1, int i2)
{
auto z = ZInstI(op, Frame1Slot(v, op), i1, i2, c);
z.op_type = OP_VVVC_I2_I3;
return z;
}
ZInstI ZAMCompiler::GenInst(ZOp op, const NameExpr* v1, const NameExpr* v2,
const NameExpr* v3, int i)
ZInstI ZAMCompiler::GenInst(ZOp op, const NameExpr* v1, const NameExpr* v2, const NameExpr* v3,
int i)
{
int nv2 = FrameSlot(v2);
int nv3 = FrameSlot(v3);
@ -146,8 +138,8 @@ ZInstI ZAMCompiler::GenInst(ZOp op, const NameExpr* v1, const NameExpr* v2,
return z;
}
ZInstI ZAMCompiler::GenInst(ZOp op, const NameExpr* v1, const NameExpr* v2,
const ConstExpr* c, int i)
ZInstI ZAMCompiler::GenInst(ZOp op, const NameExpr* v1, const NameExpr* v2, const ConstExpr* c,
int i)
{
int nv2 = FrameSlot(v2);
auto z = ZInstI(op, Frame1Slot(v1, op), nv2, i, c);
@ -155,8 +147,8 @@ ZInstI ZAMCompiler::GenInst(ZOp op, const NameExpr* v1, const NameExpr* v2,
return z;
}
ZInstI ZAMCompiler::GenInst(ZOp op, const NameExpr* v1, const ConstExpr* c,
const NameExpr* v2, int i)
ZInstI ZAMCompiler::GenInst(ZOp op, const NameExpr* v1, const ConstExpr* c, const NameExpr* v2,
int i)
{
int nv2 = FrameSlot(v2);
auto z = ZInstI(op, Frame1Slot(v1, op), nv2, i, c);
@ -164,4 +156,4 @@ ZInstI ZAMCompiler::GenInst(ZOp op, const NameExpr* v1, const ConstExpr* c,
return z;
}
} // zeek::detail
} // zeek::detail

View file

@ -12,28 +12,22 @@ ZInstI GenInst(ZOp op, const NameExpr* v1);
ZInstI GenInst(ZOp op, const NameExpr* v1, int i);
ZInstI GenInst(ZOp op, const ConstExpr* c, const NameExpr* v1, int i);
ZInstI GenInst(ZOp op, const NameExpr* v1, const NameExpr* v2);
ZInstI GenInst(ZOp op, const NameExpr* v1, const NameExpr* v2,
const NameExpr* v3);
ZInstI GenInst(ZOp op, const NameExpr* v1, const NameExpr* v2,
const NameExpr* v3, const NameExpr* v4);
ZInstI GenInst(ZOp op, const NameExpr* v1, const NameExpr* v2, const NameExpr* v3);
ZInstI GenInst(ZOp op, const NameExpr* v1, const NameExpr* v2, const NameExpr* v3,
const NameExpr* v4);
ZInstI GenInst(ZOp op, const ConstExpr* ce);
ZInstI GenInst(ZOp op, const NameExpr* v1, const ConstExpr* ce);
ZInstI GenInst(ZOp op, const ConstExpr* ce, const NameExpr* v1);
ZInstI GenInst(ZOp op, const NameExpr* v1, const ConstExpr* ce,
const NameExpr* v2);
ZInstI GenInst(ZOp op, const NameExpr* v1, const NameExpr* v2,
ZInstI GenInst(ZOp op, const NameExpr* v1, const ConstExpr* ce, const NameExpr* v2);
ZInstI GenInst(ZOp op, const NameExpr* v1, const NameExpr* v2, const ConstExpr* ce);
ZInstI GenInst(ZOp op, const NameExpr* v1, const NameExpr* v2, const NameExpr* v3,
const ConstExpr* ce);
ZInstI GenInst(ZOp op, const NameExpr* v1, const NameExpr* v2,
const NameExpr* v3, const ConstExpr* ce);
ZInstI GenInst(ZOp op, const NameExpr* v1, const NameExpr* v2,
const ConstExpr* ce, const NameExpr* v3);
ZInstI GenInst(ZOp op, const NameExpr* v1, const NameExpr* v2, const ConstExpr* ce,
const NameExpr* v3);
ZInstI GenInst(ZOp op, const NameExpr* v1, const ConstExpr* c, int i);
ZInstI GenInst(ZOp op, const NameExpr* v1, const NameExpr* v2, int i);
ZInstI GenInst(ZOp op, const NameExpr* v1, const NameExpr* v2, int i1, int i2);
ZInstI GenInst(ZOp op, const NameExpr* v, const ConstExpr* c, int i1, int i2);
ZInstI GenInst(ZOp op, const NameExpr* v1, const NameExpr* v2,
const NameExpr* v3, int i);
ZInstI GenInst(ZOp op, const NameExpr* v1, const NameExpr* v2,
const ConstExpr* c, int i);
ZInstI GenInst(ZOp op, const NameExpr* v1, const ConstExpr* c,
const NameExpr* v2, int i);
ZInstI GenInst(ZOp op, const NameExpr* v1, const NameExpr* v2, const NameExpr* v3, int i);
ZInstI GenInst(ZOp op, const NameExpr* v1, const NameExpr* v2, const ConstExpr* c, int i);
ZInstI GenInst(ZOp op, const NameExpr* v1, const ConstExpr* c, const NameExpr* v2, int i);

View file

@ -8,12 +8,14 @@
#include "zeek/ZeekString.h"
#include "zeek/script_opt/ZAM/ZInst.h"
namespace zeek::detail {
namespace zeek::detail
{
// Class for iterating over the elements of a table. Requires some care
// because the dictionary iterators need to be destructed when done.
class TableIterInfo {
class TableIterInfo
{
public:
// No constructor needed, as all of our member variables are
// instead instantiated via BeginLoop(). This allows us to
@ -22,7 +24,7 @@ public:
// We do, however, want to make sure that when we go out of scope,
// if we have any pending iterators we clear them.
~TableIterInfo() { Clear(); }
~TableIterInfo() { Clear(); }
// Start looping over the elements of the given table. "_aux"
// provides information about the index variables, their types,
@ -37,16 +39,10 @@ public:
}
// True if we're done iterating, false if not.
bool IsDoneIterating() const
{
return *tbl_iter == *tbl_end;
}
bool IsDoneIterating() const { return *tbl_iter == *tbl_end; }
// Indicates that the current iteration is finished.
void IterFinished()
{
++*tbl_iter;
}
void IterFinished() { ++*tbl_iter; }
// Performs the next iteration (assuming IsDoneIterating() returned
// false), assigning to the index variables.
@ -74,7 +70,7 @@ public:
}
// Called upon finishing the iteration.
void EndIter() { Clear(); }
void EndIter() { Clear(); }
// Called to explicitly clear any iteration state.
void Clear()
@ -94,12 +90,13 @@ private:
std::optional<DictIterator> tbl_iter;
std::optional<DictIterator> tbl_end;
};
};
// Class for simple step-wise iteration across an integer range.
// Suitable for iterating over vectors or strings.
class StepIterInfo {
class StepIterInfo
{
public:
// We do some cycle-squeezing by not having a constructor to
// initialize our member variables, since we impose a discipline
@ -123,24 +120,18 @@ public:
}
// True if we're done iterating, false if not.
bool IsDoneIterating() const
{
return iter >= n;
}
bool IsDoneIterating() const { return iter >= n; }
// Indicates that the current iteration is finished.
void IterFinished()
{
++iter;
}
void IterFinished() { ++iter; }
// Counter of where we are in the iteration.
bro_uint_t iter; // initialized to 0 at start of loop
bro_uint_t n; // we loop from 0 ... n-1
bro_uint_t iter; // initialized to 0 at start of loop
bro_uint_t n; // we loop from 0 ... n-1
// The low-level value we're iterating over.
const std::vector<std::optional<ZVal>>* vv;
const String* s;
};
};
} // namespace zeek::detail
} // namespace zeek::detail

View file

@ -2,13 +2,13 @@
// Methods relating to low-level ZAM instruction manipulation.
#include "zeek/Reporter.h"
#include "zeek/Desc.h"
#include "zeek/script_opt/ZAM/Compile.h"
#include "zeek/Reporter.h"
#include "zeek/script_opt/ScriptOpt.h"
#include "zeek/script_opt/ZAM/Compile.h"
namespace zeek::detail {
namespace zeek::detail
{
const ZAMStmt ZAMCompiler::StartingBlock()
{
@ -53,7 +53,7 @@ ZInstAux* ZAMCompiler::InternalBuildVals(const ListExpr* l, int stride)
auto aux = new ZInstAux(n * stride);
int offset = 0; // offset into aux info
int offset = 0; // offset into aux info
for ( int i = 0; i < n; ++i )
{
auto& e = exprs[i];
@ -168,5 +168,4 @@ ZAMStmt ZAMCompiler::PrevStmt(const ZAMStmt s)
return ZAMStmt(s.stmt_num - 1);
}
} // zeek::detail
} // zeek::detail

View file

@ -8,82 +8,84 @@
#include "zeek/script_opt/ProfileFunc.h"
#include "zeek/script_opt/ZAM/Compile.h"
namespace zeek::detail {
namespace zeek::detail
{
const ZAMStmt ZAMCompiler::CompileStmt(const Stmt* s)
{
SetCurrStmt(s);
switch ( s->Tag() ) {
case STMT_PRINT:
return CompilePrint(static_cast<const PrintStmt*>(s));
case STMT_EXPR:
return CompileExpr(static_cast<const ExprStmt*>(s));
case STMT_IF:
return CompileIf(static_cast<const IfStmt*>(s));
case STMT_SWITCH:
return CompileSwitch(static_cast<const SwitchStmt*>(s));
case STMT_ADD:
return CompileAdd(static_cast<const AddStmt*>(s));
case STMT_DELETE:
return CompileDel(static_cast<const DelStmt*>(s));
case STMT_EVENT:
switch ( s->Tag() )
{
auto es = static_cast<const EventStmt*>(s);
auto e = static_cast<const EventExpr*>(es->StmtExpr());
return CompileExpr(e);
case STMT_PRINT:
return CompilePrint(static_cast<const PrintStmt*>(s));
case STMT_EXPR:
return CompileExpr(static_cast<const ExprStmt*>(s));
case STMT_IF:
return CompileIf(static_cast<const IfStmt*>(s));
case STMT_SWITCH:
return CompileSwitch(static_cast<const SwitchStmt*>(s));
case STMT_ADD:
return CompileAdd(static_cast<const AddStmt*>(s));
case STMT_DELETE:
return CompileDel(static_cast<const DelStmt*>(s));
case STMT_EVENT:
{
auto es = static_cast<const EventStmt*>(s);
auto e = static_cast<const EventExpr*>(es->StmtExpr());
return CompileExpr(e);
}
case STMT_WHILE:
return CompileWhile(static_cast<const WhileStmt*>(s));
case STMT_FOR:
return CompileFor(static_cast<const ForStmt*>(s));
case STMT_RETURN:
return CompileReturn(static_cast<const ReturnStmt*>(s));
case STMT_CATCH_RETURN:
return CompileCatchReturn(static_cast<const CatchReturnStmt*>(s));
case STMT_LIST:
return CompileStmts(static_cast<const StmtList*>(s));
case STMT_INIT:
return CompileInit(static_cast<const InitStmt*>(s));
case STMT_NULL:
return EmptyStmt();
case STMT_WHEN:
return CompileWhen(static_cast<const WhenStmt*>(s));
case STMT_CHECK_ANY_LEN:
{
auto cs = static_cast<const CheckAnyLenStmt*>(s);
auto n = cs->StmtExpr()->AsNameExpr();
auto expected_len = cs->ExpectedLen();
return CheckAnyLenVi(n, expected_len);
}
case STMT_NEXT:
return CompileNext();
case STMT_BREAK:
return CompileBreak();
case STMT_FALLTHROUGH:
return CompileFallThrough();
default:
reporter->InternalError("bad statement type in ZAMCompile::CompileStmt");
}
case STMT_WHILE:
return CompileWhile(static_cast<const WhileStmt*>(s));
case STMT_FOR:
return CompileFor(static_cast<const ForStmt*>(s));
case STMT_RETURN:
return CompileReturn(static_cast<const ReturnStmt*>(s));
case STMT_CATCH_RETURN:
return CompileCatchReturn(static_cast<const CatchReturnStmt*>(s));
case STMT_LIST:
return CompileStmts(static_cast<const StmtList*>(s));
case STMT_INIT:
return CompileInit(static_cast<const InitStmt*>(s));
case STMT_NULL:
return EmptyStmt();
case STMT_WHEN:
return CompileWhen(static_cast<const WhenStmt*>(s));
case STMT_CHECK_ANY_LEN:
{
auto cs = static_cast<const CheckAnyLenStmt*>(s);
auto n = cs->StmtExpr()->AsNameExpr();
auto expected_len = cs->ExpectedLen();
return CheckAnyLenVi(n, expected_len);
}
case STMT_NEXT:
return CompileNext();
case STMT_BREAK:
return CompileBreak();
case STMT_FALLTHROUGH:
return CompileFallThrough();
default:
reporter->InternalError("bad statement type in ZAMCompile::CompileStmt");
}
}
const ZAMStmt ZAMCompiler::CompilePrint(const PrintStmt* ps)
@ -159,8 +161,7 @@ const ZAMStmt ZAMCompiler::IfElse(const Expr* e, const Stmt* s1, const Stmt* s2)
{
auto n = e->AsNameExpr();
ZOp op = (s1 && s2) ? OP_IF_ELSE_VV :
(s1 ? OP_IF_VV : OP_IF_NOT_VV);
ZOp op = (s1 && s2) ? OP_IF_ELSE_VV : (s1 ? OP_IF_VV : OP_IF_NOT_VV);
ZInstI cond(op, FrameSlot(n), 0);
cond_stmt = AddInst(cond);
@ -176,8 +177,7 @@ const ZAMStmt ZAMCompiler::IfElse(const Expr* e, const Stmt* s1, const Stmt* s2)
{
auto branch_after_s1 = GoToStub();
auto s2_end = CompileStmt(s2);
SetV(cond_stmt, GoToTargetBeyond(branch_after_s1),
branch_v);
SetV(cond_stmt, GoToTargetBeyond(branch_after_s1), branch_v);
SetGoTo(branch_after_s1, GoToTargetBeyond(s2_end));
return s2_end;
@ -197,59 +197,60 @@ const ZAMStmt ZAMCompiler::IfElse(const Expr* e, const Stmt* s1, const Stmt* s2)
// we're switching to "if ( ! cond ) s2".
auto z = insts1[cond_stmt.stmt_num];
switch ( z->op ) {
case OP_IF_ELSE_VV:
case OP_IF_VV:
case OP_IF_NOT_VV:
// These are generated correctly above, no need
// to fix up.
break;
switch ( z->op )
{
case OP_IF_ELSE_VV:
case OP_IF_VV:
case OP_IF_NOT_VV:
// These are generated correctly above, no need
// to fix up.
break;
case OP_HAS_FIELD_COND_VVV:
z->op = OP_NOT_HAS_FIELD_COND_VVV;
break;
case OP_NOT_HAS_FIELD_COND_VVV:
z->op = OP_HAS_FIELD_COND_VVV;
break;
case OP_HAS_FIELD_COND_VVV:
z->op = OP_NOT_HAS_FIELD_COND_VVV;
break;
case OP_NOT_HAS_FIELD_COND_VVV:
z->op = OP_HAS_FIELD_COND_VVV;
break;
case OP_VAL_IS_IN_TABLE_COND_VVV:
z->op = OP_VAL_IS_NOT_IN_TABLE_COND_VVV;
break;
case OP_VAL_IS_NOT_IN_TABLE_COND_VVV:
z->op = OP_VAL_IS_IN_TABLE_COND_VVV;
break;
case OP_VAL_IS_IN_TABLE_COND_VVV:
z->op = OP_VAL_IS_NOT_IN_TABLE_COND_VVV;
break;
case OP_VAL_IS_NOT_IN_TABLE_COND_VVV:
z->op = OP_VAL_IS_IN_TABLE_COND_VVV;
break;
case OP_CONST_IS_IN_TABLE_COND_VVC:
z->op = OP_CONST_IS_NOT_IN_TABLE_COND_VVC;
break;
case OP_CONST_IS_NOT_IN_TABLE_COND_VVC:
z->op = OP_CONST_IS_IN_TABLE_COND_VVC;
break;
case OP_CONST_IS_IN_TABLE_COND_VVC:
z->op = OP_CONST_IS_NOT_IN_TABLE_COND_VVC;
break;
case OP_CONST_IS_NOT_IN_TABLE_COND_VVC:
z->op = OP_CONST_IS_IN_TABLE_COND_VVC;
break;
case OP_VAL2_IS_IN_TABLE_COND_VVVV:
z->op = OP_VAL2_IS_NOT_IN_TABLE_COND_VVVV;
break;
case OP_VAL2_IS_NOT_IN_TABLE_COND_VVVV:
z->op = OP_VAL2_IS_IN_TABLE_COND_VVVV;
break;
case OP_VAL2_IS_IN_TABLE_COND_VVVV:
z->op = OP_VAL2_IS_NOT_IN_TABLE_COND_VVVV;
break;
case OP_VAL2_IS_NOT_IN_TABLE_COND_VVVV:
z->op = OP_VAL2_IS_IN_TABLE_COND_VVVV;
break;
case OP_VAL2_IS_IN_TABLE_COND_VVVC:
z->op = OP_VAL2_IS_NOT_IN_TABLE_COND_VVVC;
break;
case OP_VAL2_IS_NOT_IN_TABLE_COND_VVVC:
z->op = OP_VAL2_IS_IN_TABLE_COND_VVVC;
break;
case OP_VAL2_IS_IN_TABLE_COND_VVVC:
z->op = OP_VAL2_IS_NOT_IN_TABLE_COND_VVVC;
break;
case OP_VAL2_IS_NOT_IN_TABLE_COND_VVVC:
z->op = OP_VAL2_IS_IN_TABLE_COND_VVVC;
break;
case OP_VAL2_IS_IN_TABLE_COND_VVCV:
z->op = OP_VAL2_IS_NOT_IN_TABLE_COND_VVCV;
break;
case OP_VAL2_IS_NOT_IN_TABLE_COND_VVCV:
z->op = OP_VAL2_IS_IN_TABLE_COND_VVCV;
break;
case OP_VAL2_IS_IN_TABLE_COND_VVCV:
z->op = OP_VAL2_IS_NOT_IN_TABLE_COND_VVCV;
break;
case OP_VAL2_IS_NOT_IN_TABLE_COND_VVCV:
z->op = OP_VAL2_IS_IN_TABLE_COND_VVCV;
break;
default:
reporter->InternalError("inconsistency in ZAMCompiler::IfElse");
}
default:
reporter->InternalError("inconsistency in ZAMCompiler::IfElse");
}
SetV(cond_stmt, GoToTargetBeyond(s2_end), branch_v);
return s2_end;
@ -267,8 +268,7 @@ const ZAMStmt ZAMCompiler::GenCond(const Expr* e, int& branch_v)
if ( e->Tag() == EXPR_HAS_FIELD )
{
auto hf = e->AsHasFieldExpr();
auto z = GenInst(OP_HAS_FIELD_COND_VVV, op1->AsNameExpr(),
hf->Field());
auto z = GenInst(OP_HAS_FIELD_COND_VVV, op1->AsNameExpr(), hf->Field());
z.op_type = OP_VVV_I2_I3;
branch_v = 3;
return AddInst(z);
@ -289,8 +289,7 @@ const ZAMStmt ZAMCompiler::GenCond(const Expr* e, int& branch_v)
if ( op1->Tag() == EXPR_NAME )
{
auto z = GenInst(OP_VAL_IS_IN_TABLE_COND_VVV,
op1->AsNameExpr(), op2, 0);
auto z = GenInst(OP_VAL_IS_IN_TABLE_COND_VVV, op1->AsNameExpr(), op2, 0);
z.t = op1->GetType();
branch_v = 3;
return AddInst(z);
@ -298,8 +297,7 @@ const ZAMStmt ZAMCompiler::GenCond(const Expr* e, int& branch_v)
if ( op1->Tag() == EXPR_CONST )
{
auto z = GenInst(OP_CONST_IS_IN_TABLE_COND_VVC,
op2, op1->AsConstExpr(), 0);
auto z = GenInst(OP_CONST_IS_IN_TABLE_COND_VVC, op2, op1->AsConstExpr(), 0);
z.t = op1->GetType();
branch_v = 2;
return AddInst(z);
@ -328,24 +326,21 @@ const ZAMStmt ZAMCompiler::GenCond(const Expr* e, int& branch_v)
if ( name0 && name1 )
{
z = GenInst(OP_VAL2_IS_IN_TABLE_COND_VVVV,
n0, n1, op2, 0);
z = GenInst(OP_VAL2_IS_IN_TABLE_COND_VVVV, n0, n1, op2, 0);
branch_v = 4;
z.t2 = n0->GetType();
}
else if ( name0 )
{
z = GenInst(OP_VAL2_IS_IN_TABLE_COND_VVVC,
n0, op2, c1, 0);
z = GenInst(OP_VAL2_IS_IN_TABLE_COND_VVVC, n0, op2, c1, 0);
branch_v = 3;
z.t2 = n0->GetType();
}
else if ( name1 )
{
z = GenInst(OP_VAL2_IS_IN_TABLE_COND_VVCV,
n1, op2, c0, 0);
z = GenInst(OP_VAL2_IS_IN_TABLE_COND_VVCV, n1, op2, c0, 0);
branch_v = 3;
z.t2 = n1->GetType();
}
@ -354,8 +349,7 @@ const ZAMStmt ZAMCompiler::GenCond(const Expr* e, int& branch_v)
{ // Both are constants, assign first to temporary.
auto slot = TempForConst(c0);
z = ZInstI(OP_VAL2_IS_IN_TABLE_COND_VVVC,
slot, FrameSlot(op2), 0, c1);
z = ZInstI(OP_VAL2_IS_IN_TABLE_COND_VVVC, slot, FrameSlot(op2), 0, c1);
z.op_type = OP_VVVC_I3;
branch_v = 3;
z.t2 = c0->GetType();
@ -385,12 +379,13 @@ const ZAMStmt ZAMCompiler::GenCond(const Expr* e, int& branch_v)
else
branch_v = 2;
switch ( e->Tag() ) {
switch ( e->Tag() )
{
#include "ZAM-Conds.h"
default:
reporter->InternalError("bad expression type in ZAMCompiler::GenCond");
}
default:
reporter->InternalError("bad expression type in ZAMCompiler::GenCond");
}
// Not reached.
}
@ -415,8 +410,7 @@ const ZAMStmt ZAMCompiler::CompileSwitch(const SwitchStmt* sw)
return ValueSwitch(sw, n, c);
}
const ZAMStmt ZAMCompiler::ValueSwitch(const SwitchStmt* sw, const NameExpr* v,
const ConstExpr* c)
const ZAMStmt ZAMCompiler::ValueSwitch(const SwitchStmt* sw, const NameExpr* v, const ConstExpr* c)
{
int slot = v ? FrameSlot(v) : -1;
@ -432,40 +426,41 @@ const ZAMStmt ZAMCompiler::ValueSwitch(const SwitchStmt* sw, const NameExpr* v,
int tbl = 0;
ZOp op;
switch ( t->InternalType() ) {
case TYPE_INTERNAL_INT:
op = OP_SWITCHI_VVV;
tbl = int_casesI.size();
break;
switch ( t->InternalType() )
{
case TYPE_INTERNAL_INT:
op = OP_SWITCHI_VVV;
tbl = int_casesI.size();
break;
case TYPE_INTERNAL_UNSIGNED:
op = OP_SWITCHU_VVV;
tbl = uint_casesI.size();
break;
case TYPE_INTERNAL_UNSIGNED:
op = OP_SWITCHU_VVV;
tbl = uint_casesI.size();
break;
case TYPE_INTERNAL_DOUBLE:
op = OP_SWITCHD_VVV;
tbl = double_casesI.size();
break;
case TYPE_INTERNAL_DOUBLE:
op = OP_SWITCHD_VVV;
tbl = double_casesI.size();
break;
case TYPE_INTERNAL_STRING:
op = OP_SWITCHS_VVV;
tbl = str_casesI.size();
break;
case TYPE_INTERNAL_STRING:
op = OP_SWITCHS_VVV;
tbl = str_casesI.size();
break;
case TYPE_INTERNAL_ADDR:
op = OP_SWITCHA_VVV;
tbl = str_casesI.size();
break;
case TYPE_INTERNAL_ADDR:
op = OP_SWITCHA_VVV;
tbl = str_casesI.size();
break;
case TYPE_INTERNAL_SUBNET:
op = OP_SWITCHN_VVV;
tbl = str_casesI.size();
break;
case TYPE_INTERNAL_SUBNET:
op = OP_SWITCHN_VVV;
tbl = str_casesI.size();
break;
default:
reporter->InternalError("bad switch type");
}
default:
reporter->InternalError("bad switch type");
}
// Add the "head", i.e., the execution of the jump table.
auto sw_head_op = ZInstI(op, slot, tbl, 0);
@ -510,87 +505,88 @@ const ZAMStmt ZAMCompiler::ValueSwitch(const SwitchStmt* sw, const NameExpr* v,
{
auto case_body_start = case_start[index];
switch ( cv->GetType()->InternalType() ) {
case TYPE_INTERNAL_INT:
new_int_cases[cv->InternalInt()] = case_body_start;
break;
case TYPE_INTERNAL_UNSIGNED:
new_uint_cases[cv->InternalUnsigned()] = case_body_start;
break;
case TYPE_INTERNAL_DOUBLE:
new_double_cases[cv->InternalDouble()] = case_body_start;
break;
case TYPE_INTERNAL_STRING:
switch ( cv->GetType()->InternalType() )
{
// This leaks, but only statically so not worth
// tracking the value for ultimate deletion.
auto sv = cv->AsString()->Render();
std::string s(sv);
new_str_cases[s] = case_body_start;
delete[] sv;
break;
}
case TYPE_INTERNAL_INT:
new_int_cases[cv->InternalInt()] = case_body_start;
break;
case TYPE_INTERNAL_ADDR:
{
auto a = cv->AsAddr().AsString();
new_str_cases[a] = case_body_start;
break;
}
case TYPE_INTERNAL_UNSIGNED:
new_uint_cases[cv->InternalUnsigned()] = case_body_start;
break;
case TYPE_INTERNAL_SUBNET:
{
auto n = cv->AsSubNet().AsString();
new_str_cases[n] = case_body_start;
break;
}
case TYPE_INTERNAL_DOUBLE:
new_double_cases[cv->InternalDouble()] = case_body_start;
break;
default:
reporter->InternalError("bad recovered type when compiling switch");
}
case TYPE_INTERNAL_STRING:
{
// This leaks, but only statically so not worth
// tracking the value for ultimate deletion.
auto sv = cv->AsString()->Render();
std::string s(sv);
new_str_cases[s] = case_body_start;
delete[] sv;
break;
}
case TYPE_INTERNAL_ADDR:
{
auto a = cv->AsAddr().AsString();
new_str_cases[a] = case_body_start;
break;
}
case TYPE_INTERNAL_SUBNET:
{
auto n = cv->AsSubNet().AsString();
new_str_cases[n] = case_body_start;
break;
}
default:
reporter->InternalError("bad recovered type when compiling switch");
}
}
// Now add the jump table to the set we're keeping for the
// corresponding type.
switch ( t->InternalType() ) {
case TYPE_INTERNAL_INT:
int_casesI.push_back(new_int_cases);
break;
switch ( t->InternalType() )
{
case TYPE_INTERNAL_INT:
int_casesI.push_back(new_int_cases);
break;
case TYPE_INTERNAL_UNSIGNED:
uint_casesI.push_back(new_uint_cases);
break;
case TYPE_INTERNAL_UNSIGNED:
uint_casesI.push_back(new_uint_cases);
break;
case TYPE_INTERNAL_DOUBLE:
double_casesI.push_back(new_double_cases);
break;
case TYPE_INTERNAL_DOUBLE:
double_casesI.push_back(new_double_cases);
break;
case TYPE_INTERNAL_STRING:
case TYPE_INTERNAL_ADDR:
case TYPE_INTERNAL_SUBNET:
str_casesI.push_back(new_str_cases);
break;
case TYPE_INTERNAL_STRING:
case TYPE_INTERNAL_ADDR:
case TYPE_INTERNAL_SUBNET:
str_casesI.push_back(new_str_cases);
break;
default:
reporter->InternalError("bad switch type");
}
default:
reporter->InternalError("bad switch type");
}
return body_end;
}
const ZAMStmt ZAMCompiler::TypeSwitch(const SwitchStmt* sw, const NameExpr* v,
const ConstExpr* c)
const ZAMStmt ZAMCompiler::TypeSwitch(const SwitchStmt* sw, const NameExpr* v, const ConstExpr* c)
{
auto cases = sw->Cases();
auto type_map = sw->TypeMap();
auto body_end = EmptyStmt();
auto tmp = NewSlot(true); // true since we know "any" is managed
auto tmp = NewSlot(true); // true since we know "any" is managed
int slot = v ? FrameSlot(v) : 0;
@ -609,8 +605,8 @@ const ZAMStmt ZAMCompiler::TypeSwitch(const SwitchStmt* sw, const NameExpr* v,
}
int def_ind = sw->DefaultCaseIndex();
ZAMStmt def_succ(0); // successor to default, if any
bool saw_def_succ = false; // whether def_succ is meaningful
ZAMStmt def_succ(0); // successor to default, if any
bool saw_def_succ = false; // whether def_succ is meaningful
PushFallThroughs();
for ( auto& i : *type_map )
@ -731,13 +727,12 @@ const ZAMStmt ZAMCompiler::CompileWhile(const WhileStmt* ws)
return While(cond_pred.get(), loop_condition.get(), ws->Body().get());
}
const ZAMStmt ZAMCompiler::While(const Stmt* cond_stmt, const Expr* cond,
const Stmt* body)
const ZAMStmt ZAMCompiler::While(const Stmt* cond_stmt, const Expr* cond, const Stmt* body)
{
auto head = StartingBlock();
if ( cond_stmt )
(void) CompileStmt(cond_stmt);
(void)CompileStmt(cond_stmt);
ZAMStmt cond_IF = EmptyStmt();
int branch_v;
@ -755,7 +750,7 @@ const ZAMStmt ZAMCompiler::While(const Stmt* cond_stmt, const Expr* cond,
PushBreaks();
if ( body && body->Tag() != STMT_NULL )
(void) CompileStmt(body);
(void)CompileStmt(body);
auto tail = GoTo(GoToTarget(head));
@ -842,21 +837,20 @@ const ZAMStmt ZAMCompiler::LoopOverTable(const ForStmt* f, const NameExpr* val)
if ( value_var )
{
ZOp op = no_loop_vars ? OP_NEXT_TABLE_ITER_VAL_VAR_NO_VARS_VVV :
OP_NEXT_TABLE_ITER_VAL_VAR_VVV;
ZOp op =
no_loop_vars ? OP_NEXT_TABLE_ITER_VAL_VAR_NO_VARS_VVV : OP_NEXT_TABLE_ITER_VAL_VAR_VVV;
z = ZInstI(op, FrameSlot(value_var), iter_slot, 0);
z.CheckIfManaged(value_var->GetType());
z.op_type = OP_VVV_I2_I3;
}
else
{
ZOp op = no_loop_vars ? OP_NEXT_TABLE_ITER_NO_VARS_VV :
OP_NEXT_TABLE_ITER_VV;
ZOp op = no_loop_vars ? OP_NEXT_TABLE_ITER_NO_VARS_VV : OP_NEXT_TABLE_ITER_VV;
z = ZInstI(op, iter_slot, 0);
z.op_type = OP_VV_I1_I2;
}
z.aux = aux; // so ZOpt.cc can get to it
z.aux = aux; // so ZOpt.cc can get to it
return FinishLoop(iter_head, z, body, iter_slot, true);
}
@ -919,7 +913,7 @@ const ZAMStmt ZAMCompiler::Loop(const Stmt* body)
PushBreaks();
auto head = StartingBlock();
(void) CompileStmt(body);
(void)CompileStmt(body);
auto tail = GoTo(GoToTarget(head));
ResolveNexts(GoToTarget(head));
@ -928,8 +922,7 @@ const ZAMStmt ZAMCompiler::Loop(const Stmt* body)
return tail;
}
const ZAMStmt ZAMCompiler::FinishLoop(const ZAMStmt iter_head,
ZInstI& iter_stmt, const Stmt* body,
const ZAMStmt ZAMCompiler::FinishLoop(const ZAMStmt iter_head, ZInstI& iter_stmt, const Stmt* body,
int iter_slot, bool is_table)
{
auto loop_iter = AddInst(iter_stmt);
@ -946,7 +939,7 @@ const ZAMStmt ZAMCompiler::FinishLoop(const ZAMStmt iter_head,
auto final_stmt = AddInst(z);
auto ot = iter_stmt.op_type;
if ( ot == OP_VVV_I3 || ot == OP_VVV_I2_I3)
if ( ot == OP_VVV_I3 || ot == OP_VVV_I2_I3 )
SetV3(loop_iter, GoToTarget(final_stmt));
else
SetV2(loop_iter, GoToTarget(final_stmt));
@ -984,9 +977,9 @@ const ZAMStmt ZAMCompiler::CompileReturn(const ReturnStmt* r)
if ( e )
{
if ( e->Tag() == EXPR_NAME )
(void) AssignVV(rv, e->AsNameExpr());
(void)AssignVV(rv, e->AsNameExpr());
else
(void) AssignVC(rv, e->AsConstExpr());
(void)AssignVC(rv, e->AsConstExpr());
}
return CompileCatchReturn();
@ -1035,23 +1028,23 @@ const ZAMStmt ZAMCompiler::CompileInit(const InitStmt* is)
auto& t = aggr->GetType();
switch ( t->Tag() ) {
case TYPE_RECORD:
last = InitRecord(aggr, t->AsRecordType());
break;
switch ( t->Tag() )
{
case TYPE_RECORD:
last = InitRecord(aggr, t->AsRecordType());
break;
case TYPE_VECTOR:
last = InitVector(aggr, t->AsVectorType());
break;
case TYPE_VECTOR:
last = InitVector(aggr, t->AsVectorType());
break;
case TYPE_TABLE:
last = InitTable(aggr, t->AsTableType(),
aggr->GetAttrs().get());
break;
case TYPE_TABLE:
last = InitTable(aggr, t->AsTableType(), aggr->GetAttrs().get());
break;
default:
break;
}
default:
break;
}
}
return last;
@ -1153,4 +1146,4 @@ const ZAMStmt ZAMCompiler::CompileWhen(const WhenStmt* ws)
}
}
} // zeek::detail
} // zeek::detail

View file

@ -2,13 +2,15 @@
// Low-level support utilities/globals for ZAM compilation.
#include "zeek/Reporter.h"
#include "zeek/Desc.h"
#include "zeek/ZeekString.h"
#include "zeek/script_opt/ProfileFunc.h"
#include "zeek/script_opt/ZAM/Support.h"
namespace zeek::detail {
#include "zeek/Desc.h"
#include "zeek/Reporter.h"
#include "zeek/ZeekString.h"
#include "zeek/script_opt/ProfileFunc.h"
namespace zeek::detail
{
const Stmt* curr_stmt;
TypePtr log_ID_enum_type;
@ -39,7 +41,6 @@ bool IsAny(const Type* t)
return t->Tag() == TYPE_ANY;
}
StringVal* ZAM_to_lower(const StringVal* sv)
{
auto bs = sv->AsString();
@ -57,14 +58,14 @@ StringVal* ZAM_to_lower(const StringVal* sv)
}
*ls++ = '\0';
return new StringVal(new String(1, lower_s, n));
}
StringVal* ZAM_sub_bytes(const StringVal* s, bro_uint_t start, bro_int_t n)
{
if ( start > 0 )
--start; // make it 0-based
--start; // make it 0-based
auto ss = s->AsString()->GetSubstring(start, n);
@ -103,4 +104,4 @@ void ZAM_run_time_warning(const Location* loc, const char* msg)
reporter->Warning("%s: %s", d.Description(), msg);
}
} // namespace zeek::detail
} // namespace zeek::detail

View file

@ -7,7 +7,8 @@
#include "zeek/Expr.h"
#include "zeek/Stmt.h"
namespace zeek::detail {
namespace zeek::detail
{
using ValVec = std::vector<ValPtr>;
@ -18,16 +19,20 @@ extern const Stmt* curr_stmt;
// True if a function with the given profile can be compiled to ZAM.
// If not, returns the reason in *reason, if non-nil.
class ProfileFunc;
extern bool is_ZAM_compilable(const ProfileFunc* pf,
const char** reason = nullptr);
extern bool is_ZAM_compilable(const ProfileFunc* pf, const char** reason = nullptr);
// True if a given type is one that we treat internally as an "any" type.
extern bool IsAny(const Type* t);
// Convenience functions for getting to these.
inline bool IsAny(const TypePtr& t) { return IsAny(t.get()); }
inline bool IsAny(const Expr* e) { return IsAny(e->GetType()); }
inline bool IsAny(const TypePtr& t)
{
return IsAny(t.get());
}
inline bool IsAny(const Expr* e)
{
return IsAny(e->GetType());
}
// Needed for the logging built-in. Exported so that ZAM can make sure it's
// defined when compiling.
@ -38,8 +43,7 @@ extern TypePtr any_base_type;
extern void ZAM_run_time_error(const char* msg);
extern void ZAM_run_time_error(const Location* loc, const char* msg);
extern void ZAM_run_time_error(const Location* loc, const char* msg,
const Obj* o);
extern void ZAM_run_time_error(const Location* loc, const char* msg, const Obj* o);
extern void ZAM_run_time_error(const Stmt* stmt, const char* msg);
extern void ZAM_run_time_error(const char* msg, const Obj* o);
@ -50,4 +54,4 @@ extern void ZAM_run_time_warning(const Location* loc, const char* msg);
extern StringVal* ZAM_to_lower(const StringVal* sv);
extern StringVal* ZAM_sub_bytes(const StringVal* s, bro_uint_t start, bro_int_t n);
} // namespace zeek::detail
} // namespace zeek::detail

View file

@ -2,14 +2,14 @@
// Methods for dealing with variables (both ZAM and script-level).
#include "zeek/Reporter.h"
#include "zeek/Desc.h"
#include "zeek/Reporter.h"
#include "zeek/script_opt/ProfileFunc.h"
#include "zeek/script_opt/Reduce.h"
#include "zeek/script_opt/ZAM/Compile.h"
namespace zeek::detail {
namespace zeek::detail
{
bool ZAMCompiler::IsUnused(const IDPtr& id, const Stmt* where) const
{
@ -27,7 +27,8 @@ bool ZAMCompiler::IsUnused(const IDPtr& id, const Stmt* where) const
void ZAMCompiler::LoadParam(ID* id)
{
if ( id->IsType() )
reporter->InternalError("don't know how to compile local variable that's a type not a value");
reporter->InternalError(
"don't know how to compile local variable that's a type not a value");
bool is_any = IsAny(id->GetType());
@ -41,7 +42,7 @@ void ZAMCompiler::LoadParam(ID* id)
z.SetType(id->GetType());
z.op_type = OP_VV_FRAME;
(void) AddInst(z);
(void)AddInst(z);
}
const ZAMStmt ZAMCompiler::LoadGlobal(ID* id)
@ -80,7 +81,7 @@ int ZAMCompiler::FrameSlot(const ID* id)
auto slot = RawSlot(id);
if ( id->IsGlobal() )
(void) LoadGlobal(frame_denizens[slot]);
(void)LoadGlobal(frame_denizens[slot]);
return slot;
}
@ -89,28 +90,29 @@ int ZAMCompiler::Frame1Slot(const ID* id, ZAMOp1Flavor fl)
{
auto slot = RawSlot(id);
switch ( fl ) {
case OP1_READ:
if ( id->IsGlobal() )
(void) LoadGlobal(frame_denizens[slot]);
break;
switch ( fl )
{
case OP1_READ:
if ( id->IsGlobal() )
(void)LoadGlobal(frame_denizens[slot]);
break;
case OP1_WRITE:
if ( id->IsGlobal() )
pending_global_store = global_id_to_info[id];
break;
case OP1_WRITE:
if ( id->IsGlobal() )
pending_global_store = global_id_to_info[id];
break;
case OP1_READ_WRITE:
if ( id->IsGlobal() )
{
(void) LoadGlobal(frame_denizens[slot]);
pending_global_store = global_id_to_info[id];
}
break;
case OP1_READ_WRITE:
if ( id->IsGlobal() )
{
(void)LoadGlobal(frame_denizens[slot]);
pending_global_store = global_id_to_info[id];
}
break;
case OP1_INTERNAL:
break;
}
case OP1_INTERNAL:
break;
}
return slot;
}
@ -152,9 +154,9 @@ int ZAMCompiler::TempForConst(const ConstExpr* c)
auto z = ZInstI(OP_ASSIGN_CONST_VC, slot, c);
z.CheckIfManaged(c->GetType());
(void) AddInst(z);
(void)AddInst(z);
return slot;
}
} // zeek::detail
} // zeek::detail

View file

@ -1,13 +1,13 @@
// See the file "COPYING" in the main distribution directory for copyright.
#include "zeek/Desc.h"
#include "zeek/RE.h"
#include "zeek/Frame.h"
#include "zeek/EventHandler.h"
#include "zeek/Trigger.h"
#include "zeek/Traverse.h"
#include "zeek/Frame.h"
#include "zeek/Overflow.h"
#include "zeek/RE.h"
#include "zeek/Reporter.h"
#include "zeek/Traverse.h"
#include "zeek/Trigger.h"
#include "zeek/script_opt/ScriptOpt.h"
#include "zeek/script_opt/ZAM/Compile.h"
@ -22,8 +22,8 @@
#include "zeek/file_analysis/Manager.h"
#include "zeek/logging/Manager.h"
namespace zeek::detail {
namespace zeek::detail
{
using std::vector;
@ -31,26 +31,22 @@ static bool did_init = false;
// Count of how often each type of ZOP executed, and how much CPU it
// cumulatively took.
int ZOP_count[OP_NOP+1];
double ZOP_CPU[OP_NOP+1];
int ZOP_count[OP_NOP + 1];
double ZOP_CPU[OP_NOP + 1];
void report_ZOP_profile()
{
for ( int i = 1; i <= OP_NOP; ++i )
if ( ZOP_count[i] > 0 )
printf("%s\t%d\t%.06f\n", ZOP_name(ZOp(i)),
ZOP_count[i], ZOP_CPU[i]);
printf("%s\t%d\t%.06f\n", ZOP_name(ZOp(i)), ZOP_count[i], ZOP_CPU[i]);
}
// Sets the given element to a copy of an existing (not newly constructed)
// ZVal, including underlying memory management. Returns false if the
// assigned value was missing (which we can only tell for managed types),
// true otherwise.
static bool copy_vec_elem(VectorVal* vv, bro_uint_t ind, ZVal zv,
const TypePtr& t)
static bool copy_vec_elem(VectorVal* vv, bro_uint_t ind, ZVal zv, const TypePtr& t)
{
if ( vv->Size() <= ind )
vv->Resize(ind + 1);
@ -82,40 +78,39 @@ static bool copy_vec_elem(VectorVal* vv, bro_uint_t ind, ZVal zv,
// Unary and binary element-by-element vector operations, yielding a new
// VectorVal with a yield type of 't'. 'z' is passed in only for localizing
// errors.
static void vec_exec(ZOp op, TypePtr t, VectorVal*& v1, const VectorVal* v2,
static void vec_exec(ZOp op, TypePtr t, VectorVal*& v1, const VectorVal* v2, const ZInst& z);
static void vec_exec(ZOp op, TypePtr t, VectorVal*& v1, const VectorVal* v2, const VectorVal* v3,
const ZInst& z);
static void vec_exec(ZOp op, TypePtr t, VectorVal*& v1, const VectorVal* v2,
const VectorVal* v3, const ZInst& z);
// Vector coercion.
#define VEC_COERCE(tag, lhs_type, cast, rhs_accessor, ov_check, ov_err) \
static VectorVal* vec_coerce_##tag(VectorVal* vec, const ZInst& z) \
{ \
auto& v = *vec->RawVec(); \
auto yt = make_intrusive<VectorType>(base_type(lhs_type)); \
auto res_zv = new VectorVal(yt); \
auto n = v.size(); \
res_zv->Resize(n); \
auto& res = *res_zv->RawVec(); \
for ( auto i = 0U; i < n; ++i ) \
if ( v[i] ) \
{ \
auto vi = (*v[i]).rhs_accessor; \
if ( ov_check(vi) ) \
{ \
std::string err = "overflow promoting from "; \
err += ov_err; \
err += " arithmetic value"; \
ZAM_run_time_error(z.loc, err.c_str()); \
res[i] = std::nullopt; \
} \
else \
res[i] = ZVal(cast(vi)); \
} \
else \
res[i] = std::nullopt; \
return res_zv; \
#define VEC_COERCE(tag, lhs_type, cast, rhs_accessor, ov_check, ov_err) \
static VectorVal* vec_coerce_##tag(VectorVal* vec, const ZInst& z) \
{ \
auto& v = *vec->RawVec(); \
auto yt = make_intrusive<VectorType>(base_type(lhs_type)); \
auto res_zv = new VectorVal(yt); \
auto n = v.size(); \
res_zv->Resize(n); \
auto& res = *res_zv->RawVec(); \
for ( auto i = 0U; i < n; ++i ) \
if ( v[i] ) \
{ \
auto vi = (*v[i]).rhs_accessor; \
if ( ov_check(vi) ) \
{ \
std::string err = "overflow promoting from "; \
err += ov_err; \
err += " arithmetic value"; \
ZAM_run_time_error(z.loc, err.c_str()); \
res[i] = std::nullopt; \
} \
else \
res[i] = ZVal(cast(vi)); \
} \
else \
res[i] = std::nullopt; \
return res_zv; \
}
#define false_func(x) false
@ -124,7 +119,8 @@ VEC_COERCE(DI, TYPE_DOUBLE, double, AsInt(), false_func, "")
VEC_COERCE(DU, TYPE_DOUBLE, double, AsCount(), false_func, "")
VEC_COERCE(ID, TYPE_INT, bro_int_t, AsDouble(), double_to_int_would_overflow, "double to signed")
VEC_COERCE(IU, TYPE_INT, bro_int_t, AsCount(), count_to_int_would_overflow, "unsigned to signed")
VEC_COERCE(UD, TYPE_COUNT, bro_uint_t, AsDouble(), double_to_count_would_overflow, "double to unsigned")
VEC_COERCE(UD, TYPE_COUNT, bro_uint_t, AsDouble(), double_to_count_would_overflow,
"double to unsigned")
VEC_COERCE(UI, TYPE_COUNT, bro_int_t, AsInt(), int_to_count_would_overflow, "signed to unsigned")
double curr_CPU_time()
@ -134,9 +130,7 @@ double curr_CPU_time()
return double(ts.tv_sec) + double(ts.tv_nsec) / 1e9;
}
ZBody::ZBody(const char* _func_name, const ZAMCompiler* zc)
: Stmt(STMT_ZAM)
ZBody::ZBody(const char* _func_name, const ZAMCompiler* zc) : Stmt(STMT_ZAM)
{
func_name = _func_name;
@ -288,14 +282,13 @@ ValPtr ZBody::DoExec(Frame* f, int start_pc, StmtFlowType& flow)
if ( ! table_iters.empty() )
{
local_table_iters =
std::make_unique<TableIterVec>(table_iters.size());
local_table_iters = std::make_unique<TableIterVec>(table_iters.size());
*local_table_iters = table_iters;
tiv_ptr = &(*local_table_iters);
}
}
flow = FLOW_RETURN; // can be over-written by a Hook-Break
flow = FLOW_RETURN; // can be over-written by a Hook-Break
while ( pc < end_pc && ! ZAM_error )
{
@ -315,16 +308,17 @@ ValPtr ZBody::DoExec(Frame* f, int start_pc, StmtFlowType& flow)
}
#endif
switch ( z.op ) {
case OP_NOP:
break;
switch ( z.op )
{
case OP_NOP:
break;
#include "ZAM-EvalMacros.h"
#include "ZAM-EvalDefs.h"
#include "ZAM-EvalMacros.h"
default:
reporter->InternalError("bad ZAM opcode");
}
default:
reporter->InternalError("bad ZAM opcode");
}
#ifdef DEBUG
if ( do_profile )
@ -366,7 +360,7 @@ ValPtr ZBody::DoExec(Frame* f, int start_pc, StmtFlowType& flow)
ZVal::DeleteManagedType(v);
}
delete [] frame;
delete[] frame;
}
// Clear any error state.
@ -393,8 +387,7 @@ void ZBody::ProfileExecution() const
for ( auto i = 0U; i < inst_count->size(); ++i )
{
printf("%s %d %d %.06f ", func_name, i,
(*inst_count)[i], (*inst_CPU)[i]);
printf("%s %d %d %.06f ", func_name, i, (*inst_count)[i], (*inst_CPU)[i]);
insts[i].Dump(i, &frame_denizens);
}
}
@ -420,8 +413,7 @@ bool ZBody::CheckAnyType(const TypePtr& any_type, const TypePtr& expected_type,
}
char buf[8192];
snprintf(buf, sizeof buf, "run-time type clash (%s/%s)",
type_name(at), type_name(et));
snprintf(buf, sizeof buf, "run-time type clash (%s/%s)", type_name(at), type_name(et));
reporter->RuntimeError(loc, "%s", buf);
return false;
@ -474,7 +466,6 @@ TraversalCode ZBody::Traverse(TraversalCallback* cb) const
HANDLE_TC_STMT_POST(tc);
}
ValPtr ZAMResumption::Exec(Frame* f, StmtFlowType& flow)
{
return am->DoExec(f, xfer_pc, flow);
@ -494,10 +485,8 @@ TraversalCode ZAMResumption::Traverse(TraversalCallback* cb) const
HANDLE_TC_STMT_POST(tc);
}
// Unary vector operation of v1 <vec-op> v2.
static void vec_exec(ZOp op, TypePtr t, VectorVal*& v1, const VectorVal* v2,
const ZInst& z)
static void vec_exec(ZOp op, TypePtr t, VectorVal*& v1, const VectorVal* v2, const ZInst& z)
{
// We could speed this up further still by gen'ing up an instance
// of the loop inside each switch case (in which case we might as
@ -512,13 +501,14 @@ static void vec_exec(ZOp op, TypePtr t, VectorVal*& v1, const VectorVal* v2,
for ( auto i = 0U; i < n; ++i )
{
if ( vec2[i] )
switch ( op ) {
switch ( op )
{
#include "ZAM-Vec1EvalDefs.h"
default:
reporter->InternalError("bad invocation of VecExec");
}
default:
reporter->InternalError("bad invocation of VecExec");
}
else
vec1[i] = std::nullopt;
}
@ -530,8 +520,8 @@ static void vec_exec(ZOp op, TypePtr t, VectorVal*& v1, const VectorVal* v2,
}
// Binary vector operation of v1 = v2 <vec-op> v3.
static void vec_exec(ZOp op, TypePtr t, VectorVal*& v1,
const VectorVal* v2, const VectorVal* v3, const ZInst& z)
static void vec_exec(ZOp op, TypePtr t, VectorVal*& v1, const VectorVal* v2, const VectorVal* v3,
const ZInst& z)
{
// See comment above re further speed-up.
@ -544,13 +534,14 @@ static void vec_exec(ZOp op, TypePtr t, VectorVal*& v1,
for ( auto i = 0U; i < vec2.size(); ++i )
{
if ( vec2[i] && vec3[i] )
switch ( op ) {
switch ( op )
{
#include "ZAM-Vec2EvalDefs.h"
default:
reporter->InternalError("bad invocation of VecExec");
}
default:
reporter->InternalError("bad invocation of VecExec");
}
else
vec1[i] = std::nullopt;
}
@ -561,4 +552,4 @@ static void vec_exec(ZOp op, TypePtr t, VectorVal*& v1,
Unref(old_v1);
}
} // zeek::detail
} // zeek::detail

View file

@ -7,25 +7,27 @@
#include "zeek/script_opt/ZAM/IterInfo.h"
#include "zeek/script_opt/ZAM/Support.h"
namespace zeek::detail {
namespace zeek::detail
{
// Static information about globals used in a function.
class GlobalInfo {
class GlobalInfo
{
public:
IDPtr id;
int slot;
};
};
// These are the counterparts to CaseMapI and CaseMapsI in ZAM.h,
// but concretized to use instruction numbers rather than pointers
// to instructions.
template<typename T> using CaseMap = std::map<T, int>;
template<typename T> using CaseMaps = std::vector<CaseMap<T>>;
template <typename T> using CaseMap = std::map<T, int>;
template <typename T> using CaseMaps = std::vector<CaseMap<T>>;
using TableIterVec = std::vector<TableIterInfo>;
class ZBody : public Stmt {
class ZBody : public Stmt
{
public:
ZBody(const char* _func_name, const ZAMCompiler* zc);
@ -62,7 +64,7 @@ protected:
bool CheckAnyType(const TypePtr& any_type, const TypePtr& expected_type,
const Location* loc) const;
StmtPtr Duplicate() override { return {NewRef{}, this}; }
StmtPtr Duplicate() override { return {NewRef{}, this}; }
void StmtDescribe(ODesc* d) const override;
TraversalCode Traverse(TraversalCallback* cb) const override;
@ -105,28 +107,29 @@ private:
//
// These need to be pointers so we can manipulate them in a
// const method.
std::vector<int>* inst_count = nullptr; // for profiling
double* CPU_time = nullptr; // cumulative CPU time for the program
std::vector<double>* inst_CPU; // per-instruction CPU time.
std::vector<int>* inst_count = nullptr; // for profiling
double* CPU_time = nullptr; // cumulative CPU time for the program
std::vector<double>* inst_CPU; // per-instruction CPU time.
CaseMaps<bro_int_t> int_cases;
CaseMaps<bro_uint_t> uint_cases;
CaseMaps<double> double_cases;
CaseMaps<std::string> str_cases;
};
};
// This is a statement that resumes execution into a code block in a
// ZBody. Used for deferred execution for "when" statements.
class ZAMResumption : public Stmt {
class ZAMResumption : public Stmt
{
public:
ZAMResumption(ZBody* _am, int _xfer_pc)
: Stmt(STMT_ZAM_RESUMPTION), am(_am), xfer_pc(_xfer_pc)
{ }
ZAMResumption(ZBody* _am, int _xfer_pc) : Stmt(STMT_ZAM_RESUMPTION), am(_am), xfer_pc(_xfer_pc)
{
}
ValPtr Exec(Frame* f, StmtFlowType& flow) override;
StmtPtr Duplicate() override { return {NewRef{}, this}; }
StmtPtr Duplicate() override { return {NewRef{}, this}; }
void StmtDescribe(ODesc* d) const override;
@ -135,10 +138,9 @@ protected:
ZBody* am;
int xfer_pc = 0;
};
};
// Prints the execution profile.
extern void report_ZOP_profile();
} // namespace zeek::detail
} // namespace zeek::detail

View file

@ -1,13 +1,15 @@
// See the file "COPYING" in the main distribution directory for copyright.
#include "zeek/Desc.h"
#include "zeek/Reporter.h"
#include "zeek/Func.h"
#include "zeek/script_opt/ZAM/ZInst.h"
#include "zeek/Desc.h"
#include "zeek/Func.h"
#include "zeek/Reporter.h"
using std::string;
namespace zeek::detail {
namespace zeek::detail
{
void ZInst::Dump(bro_uint_t inst_num, const FrameReMap* mappings) const
{
@ -21,112 +23,106 @@ void ZInst::Dump(bro_uint_t inst_num, const FrameReMap* mappings) const
Dump(id1, id2, id3, id4);
}
void ZInst::Dump(const string& id1, const string& id2, const string& id3,
const string& id4) const
void ZInst::Dump(const string& id1, const string& id2, const string& id3, const string& id4) const
{
printf("%s ", ZOP_name(op));
// printf("(%s) ", op_type_name(op_type));
if ( t && 0 )
printf("(%s) ", type_name(t->Tag()));
switch ( op_type ) {
case OP_X:
break;
switch ( op_type )
{
case OP_X:
break;
case OP_V:
printf("%s", id1.c_str());
break;
case OP_V:
printf("%s", id1.c_str());
break;
case OP_VV:
printf("%s, %s", id1.c_str(), id2.c_str());
break;
case OP_VV:
printf("%s, %s", id1.c_str(), id2.c_str());
break;
case OP_VVV:
printf("%s, %s, %s", id1.c_str(), id2.c_str(), id3.c_str());
break;
case OP_VVV:
printf("%s, %s, %s", id1.c_str(), id2.c_str(), id3.c_str());
break;
case OP_VVVV:
printf("%s, %s, %s, %s", id1.c_str(), id2.c_str(), id3.c_str(),
id4.c_str());
break;
case OP_VVVV:
printf("%s, %s, %s, %s", id1.c_str(), id2.c_str(), id3.c_str(), id4.c_str());
break;
case OP_VVVC:
printf("%s, %s, %s, %s", id1.c_str(), id2.c_str(), id3.c_str(),
ConstDump().c_str());
break;
case OP_VVVC:
printf("%s, %s, %s, %s", id1.c_str(), id2.c_str(), id3.c_str(), ConstDump().c_str());
break;
case OP_C:
printf("%s", ConstDump().c_str());
break;
case OP_C:
printf("%s", ConstDump().c_str());
break;
case OP_VC:
printf("%s, %s", id1.c_str(), ConstDump().c_str());
break;
case OP_VC:
printf("%s, %s", id1.c_str(), ConstDump().c_str());
break;
case OP_VVC:
printf("%s, %s, %s", id1.c_str(), id2.c_str(),
ConstDump().c_str());
break;
case OP_VVC:
printf("%s, %s, %s", id1.c_str(), id2.c_str(), ConstDump().c_str());
break;
case OP_V_I1:
printf("%d", v1);
break;
case OP_V_I1:
printf("%d", v1);
break;
case OP_VC_I1:
printf("%d %s", v1, ConstDump().c_str());
break;
case OP_VC_I1:
printf("%d %s", v1, ConstDump().c_str());
break;
case OP_VV_FRAME:
printf("%s, interpreter frame[%d]", id1.c_str(), v2);
break;
case OP_VV_FRAME:
printf("%s, interpreter frame[%d]", id1.c_str(), v2);
break;
case OP_VV_I2:
printf("%s, %d", id1.c_str(), v2);
break;
case OP_VV_I2:
printf("%s, %d", id1.c_str(), v2);
break;
case OP_VV_I1_I2:
printf("%d, %d", v1, v2);
break;
case OP_VV_I1_I2:
printf("%d, %d", v1, v2);
break;
case OP_VVC_I2:
printf("%s, %d, %s", id1.c_str(), v2, ConstDump().c_str());
break;
case OP_VVC_I2:
printf("%s, %d, %s", id1.c_str(), v2, ConstDump().c_str());
break;
case OP_VVV_I3:
printf("%s, %s, %d", id1.c_str(), id2.c_str(), v3);
break;
case OP_VVV_I3:
printf("%s, %s, %d", id1.c_str(), id2.c_str(), v3);
break;
case OP_VVV_I2_I3:
printf("%s, %d, %d", id1.c_str(), v2, v3);
break;
case OP_VVV_I2_I3:
printf("%s, %d, %d", id1.c_str(), v2, v3);
break;
case OP_VVVV_I4:
printf("%s, %s, %s, %d", id1.c_str(), id2.c_str(), id3.c_str(),
v4);
break;
case OP_VVVV_I4:
printf("%s, %s, %s, %d", id1.c_str(), id2.c_str(), id3.c_str(), v4);
break;
case OP_VVVV_I3_I4:
printf("%s, %s, %d, %d", id1.c_str(), id2.c_str(), v3, v4);
break;
case OP_VVVV_I3_I4:
printf("%s, %s, %d, %d", id1.c_str(), id2.c_str(), v3, v4);
break;
case OP_VVVV_I2_I3_I4:
printf("%s, %d, %d, %d", id1.c_str(), v2, v3, v4);
break;
case OP_VVVV_I2_I3_I4:
printf("%s, %d, %d, %d", id1.c_str(), v2, v3, v4);
break;
case OP_VVVC_I3:
printf("%s, %s, %d, %s", id1.c_str(), id2.c_str(), v3,
ConstDump().c_str());
break;
case OP_VVVC_I3:
printf("%s, %s, %d, %s", id1.c_str(), id2.c_str(), v3, ConstDump().c_str());
break;
case OP_VVVC_I2_I3:
printf("%s, %d, %d, %s", id1.c_str(), v2, v3,
ConstDump().c_str());
break;
case OP_VVVC_I2_I3:
printf("%s, %d, %d, %s", id1.c_str(), v2, v3, ConstDump().c_str());
break;
case OP_VVVC_I1_I2_I3:
printf("%d, %d, %d, %s", v1, v2, v3, ConstDump().c_str());
break;
}
case OP_VVVC_I1_I2_I3:
printf("%d, %d, %d, %s", v1, v2, v3, ConstDump().c_str());
break;
}
if ( func )
printf(" (func %s)", func->Name());
@ -136,80 +132,82 @@ void ZInst::Dump(const string& id1, const string& id2, const string& id3,
int ZInst::NumFrameSlots() const
{
switch ( op_type ) {
case OP_X:
case OP_C:
case OP_V_I1:
case OP_VC_I1:
case OP_VV_I1_I2:
case OP_VVVC_I1_I2_I3:
return 0;
switch ( op_type )
{
case OP_X:
case OP_C:
case OP_V_I1:
case OP_VC_I1:
case OP_VV_I1_I2:
case OP_VVVC_I1_I2_I3:
return 0;
case OP_V:
case OP_VC:
case OP_VV_FRAME:
case OP_VV_I2:
case OP_VVC_I2:
case OP_VVV_I2_I3:
case OP_VVVC_I2_I3:
case OP_VVVV_I2_I3_I4:
return 1;
case OP_V:
case OP_VC:
case OP_VV_FRAME:
case OP_VV_I2:
case OP_VVC_I2:
case OP_VVV_I2_I3:
case OP_VVVC_I2_I3:
case OP_VVVV_I2_I3_I4:
return 1;
case OP_VV:
case OP_VVC:
case OP_VVV_I3:
case OP_VVVC_I3:
case OP_VVVV_I3_I4:
return 2;
case OP_VV:
case OP_VVC:
case OP_VVV_I3:
case OP_VVVC_I3:
case OP_VVVV_I3_I4:
return 2;
case OP_VVV:
case OP_VVVC:
case OP_VVVV_I4:
return 3;
case OP_VVV:
case OP_VVVC:
case OP_VVVV_I4:
return 3;
case OP_VVVV:
return 4;
}
case OP_VVVV:
return 4;
}
return -1;
}
int ZInst::NumSlots() const
{
switch ( op_type ) {
case OP_C:
case OP_X:
return 0;
switch ( op_type )
{
case OP_C:
case OP_X:
return 0;
case OP_V:
case OP_V_I1:
case OP_VC:
case OP_VC_I1:
return 1;
case OP_V:
case OP_V_I1:
case OP_VC:
case OP_VC_I1:
return 1;
case OP_VV:
case OP_VVC:
case OP_VV_FRAME:
case OP_VV_I2:
case OP_VVC_I2:
case OP_VV_I1_I2:
return 2;
case OP_VV:
case OP_VVC:
case OP_VV_FRAME:
case OP_VV_I2:
case OP_VVC_I2:
case OP_VV_I1_I2:
return 2;
case OP_VVV:
case OP_VVV_I3:
case OP_VVV_I2_I3:
case OP_VVVC:
case OP_VVVC_I3:
case OP_VVVC_I2_I3:
case OP_VVVC_I1_I2_I3:
return 3;
case OP_VVV:
case OP_VVV_I3:
case OP_VVV_I2_I3:
case OP_VVVC:
case OP_VVVC_I3:
case OP_VVVC_I2_I3:
case OP_VVVC_I1_I2_I3:
return 3;
case OP_VVVV:
case OP_VVVV_I4:
case OP_VVVV_I3_I4:
case OP_VVVV_I2_I3_I4:
return 4;
}
case OP_VVVV:
case OP_VVVV_I4:
case OP_VVVV_I3_I4:
case OP_VVVV_I2_I3_I4:
return 4;
}
return -1;
}
@ -236,8 +234,7 @@ string ZInst::VName(int n, bro_uint_t inst_num, const FrameReMap* mappings) cons
// identifiers, then it matters whether this is slot 1
// (starts right here) vs. slot > 1 (ignore change right
// at the boundary and stick with older value).
if ( (n == 1 && map.id_start[i] > inst_num) ||
(n > 1 && map.id_start[i] >= inst_num) )
if ( (n == 1 && map.id_start[i] > inst_num) || (n > 1 && map.id_start[i] >= inst_num) )
// Went too far.
break;
}
@ -247,41 +244,42 @@ string ZInst::VName(int n, bro_uint_t inst_num, const FrameReMap* mappings) cons
ASSERT(i > 0);
}
auto id = map.names.empty() ? map.ids[i-1]->Name() : map.names[i-1];
auto id = map.names.empty() ? map.ids[i - 1]->Name() : map.names[i - 1];
return util::fmt("%d (%s)", slot, id);
}
ValPtr ZInst::ConstVal() const
{
switch ( op_type ) {
case OP_C:
case OP_VC:
case OP_VC_I1:
case OP_VVC:
case OP_VVC_I2:
case OP_VVVC:
case OP_VVVC_I3:
case OP_VVVC_I2_I3:
case OP_VVVC_I1_I2_I3:
return c.ToVal(t);
switch ( op_type )
{
case OP_C:
case OP_VC:
case OP_VC_I1:
case OP_VVC:
case OP_VVC_I2:
case OP_VVVC:
case OP_VVVC_I3:
case OP_VVVC_I2_I3:
case OP_VVVC_I1_I2_I3:
return c.ToVal(t);
case OP_X:
case OP_V:
case OP_VV:
case OP_VVV:
case OP_VVVV:
case OP_V_I1:
case OP_VV_FRAME:
case OP_VV_I2:
case OP_VV_I1_I2:
case OP_VVV_I3:
case OP_VVV_I2_I3:
case OP_VVVV_I4:
case OP_VVVV_I3_I4:
case OP_VVVV_I2_I3_I4:
return nullptr;
}
case OP_X:
case OP_V:
case OP_VV:
case OP_VVV:
case OP_VVVV:
case OP_V_I1:
case OP_VV_FRAME:
case OP_VV_I2:
case OP_VV_I1_I2:
case OP_VVV_I3:
case OP_VVV_I2_I3:
case OP_VVVV_I4:
case OP_VVVV_I3_I4:
case OP_VVVV_I2_I3_I4:
return nullptr;
}
return nullptr;
}
@ -298,7 +296,6 @@ string ZInst::ConstDump() const
return d.Description();
}
void ZInstI::Dump(const FrameMap* frame_ids, const FrameReMap* remappings) const
{
int n = NumFrameSlots();
@ -312,8 +309,7 @@ void ZInstI::Dump(const FrameMap* frame_ids, const FrameReMap* remappings) const
ZInst::Dump(id1, id2, id3, id4);
}
string ZInstI::VName(int n, const FrameMap* frame_ids,
const FrameReMap* remappings) const
string ZInstI::VName(int n, const FrameMap* frame_ids, const FrameReMap* remappings) const
{
if ( n > NumFrameSlots() )
return "";
@ -327,8 +323,7 @@ string ZInstI::VName(int n, const FrameMap* frame_ids,
if ( remappings && live )
{ // Find which identifier manifests at this instruction.
ASSERT(slot >= 0 &&
static_cast<bro_uint_t>(slot) < remappings->size());
ASSERT(slot >= 0 && static_cast<bro_uint_t>(slot) < remappings->size());
auto& map = (*remappings)[slot];
@ -349,7 +344,7 @@ string ZInstI::VName(int n, const FrameMap* frame_ids,
}
// For ZInstI's, map.ids is always populated.
id = map.ids[i-1];
id = map.ids[i - 1];
}
else
@ -360,17 +355,18 @@ string ZInstI::VName(int n, const FrameMap* frame_ids,
bool ZInstI::DoesNotContinue() const
{
switch ( op ) {
case OP_GOTO_V:
case OP_HOOK_BREAK_X:
case OP_RETURN_C:
case OP_RETURN_V:
case OP_RETURN_X:
return true;
switch ( op )
{
case OP_GOTO_V:
case OP_HOOK_BREAK_X:
case OP_RETURN_C:
case OP_RETURN_V:
case OP_RETURN_X:
return true;
default:
return false;
}
default:
return false;
}
}
bool ZInstI::IsDirectAssignment() const
@ -378,25 +374,26 @@ bool ZInstI::IsDirectAssignment() const
if ( op_type != OP_VV )
return false;
switch ( op ) {
case OP_ASSIGN_VV_N:
case OP_ASSIGN_VV_A:
case OP_ASSIGN_VV_O:
case OP_ASSIGN_VV_P:
case OP_ASSIGN_VV_R:
case OP_ASSIGN_VV_S:
case OP_ASSIGN_VV_F:
case OP_ASSIGN_VV_T:
case OP_ASSIGN_VV_V:
case OP_ASSIGN_VV_L:
case OP_ASSIGN_VV_f:
case OP_ASSIGN_VV_t:
case OP_ASSIGN_VV:
return true;
switch ( op )
{
case OP_ASSIGN_VV_N:
case OP_ASSIGN_VV_A:
case OP_ASSIGN_VV_O:
case OP_ASSIGN_VV_P:
case OP_ASSIGN_VV_R:
case OP_ASSIGN_VV_S:
case OP_ASSIGN_VV_F:
case OP_ASSIGN_VV_T:
case OP_ASSIGN_VV_V:
case OP_ASSIGN_VV_L:
case OP_ASSIGN_VV_f:
case OP_ASSIGN_VV_t:
case OP_ASSIGN_VV:
return true;
default:
return false;
}
default:
return false;
}
}
bool ZInstI::HasSideEffects() const
@ -406,39 +403,40 @@ bool ZInstI::HasSideEffects() const
bool ZInstI::AssignsToSlot1() const
{
switch ( op_type ) {
case OP_X:
case OP_C:
case OP_V_I1:
case OP_VC_I1:
case OP_VV_I1_I2:
case OP_VVVC_I1_I2_I3:
return false;
switch ( op_type )
{
case OP_X:
case OP_C:
case OP_V_I1:
case OP_VC_I1:
case OP_VV_I1_I2:
case OP_VVVC_I1_I2_I3:
return false;
// We use this ginormous set of cases rather than "default" so
// that when we add a new operand type, we have to consider
// its behavior here. (Same for many of the other switch's
// used for ZInst/ZinstI.)
case OP_V:
case OP_VC:
case OP_VV_FRAME:
case OP_VV_I2:
case OP_VVC_I2:
case OP_VVV_I2_I3:
case OP_VVVC_I2_I3:
case OP_VVVV_I2_I3_I4:
case OP_VV:
case OP_VVC:
case OP_VVV_I3:
case OP_VVVV_I3_I4:
case OP_VVVC_I3:
case OP_VVV:
case OP_VVVC:
case OP_VVVV_I4:
case OP_VVVV:
auto fl = op1_flavor[op];
return fl == OP1_WRITE || fl == OP1_READ_WRITE;
}
// We use this ginormous set of cases rather than "default" so
// that when we add a new operand type, we have to consider
// its behavior here. (Same for many of the other switch's
// used for ZInst/ZinstI.)
case OP_V:
case OP_VC:
case OP_VV_FRAME:
case OP_VV_I2:
case OP_VVC_I2:
case OP_VVV_I2_I3:
case OP_VVVC_I2_I3:
case OP_VVVV_I2_I3_I4:
case OP_VV:
case OP_VVC:
case OP_VVV_I3:
case OP_VVVV_I3_I4:
case OP_VVVC_I3:
case OP_VVV:
case OP_VVVC:
case OP_VVVV_I4:
case OP_VVVV:
auto fl = op1_flavor[op];
return fl == OP1_WRITE || fl == OP1_READ_WRITE;
}
return false;
}
@ -449,40 +447,41 @@ bool ZInstI::UsesSlot(int slot) const
auto v1_relevant = fl == OP1_READ || fl == OP1_READ_WRITE;
auto v1_match = v1_relevant && v1 == slot;
switch ( op_type ) {
case OP_X:
case OP_C:
case OP_V_I1:
case OP_VC_I1:
case OP_VV_I1_I2:
case OP_VVVC_I1_I2_I3:
return false;
switch ( op_type )
{
case OP_X:
case OP_C:
case OP_V_I1:
case OP_VC_I1:
case OP_VV_I1_I2:
case OP_VVVC_I1_I2_I3:
return false;
case OP_V:
case OP_VC:
case OP_VV_FRAME:
case OP_VV_I2:
case OP_VVC_I2:
case OP_VVV_I2_I3:
case OP_VVVC_I2_I3:
case OP_VVVV_I2_I3_I4:
return v1_match;
case OP_V:
case OP_VC:
case OP_VV_FRAME:
case OP_VV_I2:
case OP_VVC_I2:
case OP_VVV_I2_I3:
case OP_VVVC_I2_I3:
case OP_VVVV_I2_I3_I4:
return v1_match;
case OP_VV:
case OP_VVC:
case OP_VVV_I3:
case OP_VVVV_I3_I4:
case OP_VVVC_I3:
return v1_match || v2 == slot;
case OP_VV:
case OP_VVC:
case OP_VVV_I3:
case OP_VVVV_I3_I4:
case OP_VVVC_I3:
return v1_match || v2 == slot;
case OP_VVV:
case OP_VVVC:
case OP_VVVV_I4:
return v1_match || v2 == slot || v3 == slot;
case OP_VVV:
case OP_VVVC:
case OP_VVVV_I4:
return v1_match || v2 == slot || v3 == slot;
case OP_VVVV:
return v1_match || v2 == slot || v3 == slot || v4 == slot;
}
case OP_VVVV:
return v1_match || v2 == slot || v3 == slot || v4 == slot;
}
return false;
}
@ -494,108 +493,110 @@ bool ZInstI::UsesSlots(int& s1, int& s2, int& s3, int& s4) const
auto fl = op1_flavor[op];
auto v1_relevant = fl == OP1_READ || fl == OP1_READ_WRITE;
switch ( op_type ) {
case OP_X:
case OP_C:
case OP_V_I1:
case OP_VC_I1:
case OP_VV_I1_I2:
case OP_VVVC_I1_I2_I3:
return false;
case OP_V:
case OP_VC:
case OP_VV_FRAME:
case OP_VV_I2:
case OP_VVC_I2:
case OP_VVV_I2_I3:
case OP_VVVC_I2_I3:
case OP_VVVV_I2_I3_I4:
if ( ! v1_relevant )
switch ( op_type )
{
case OP_X:
case OP_C:
case OP_V_I1:
case OP_VC_I1:
case OP_VV_I1_I2:
case OP_VVVC_I1_I2_I3:
return false;
s1 = v1;
return true;
case OP_V:
case OP_VC:
case OP_VV_FRAME:
case OP_VV_I2:
case OP_VVC_I2:
case OP_VVV_I2_I3:
case OP_VVVC_I2_I3:
case OP_VVVV_I2_I3_I4:
if ( ! v1_relevant )
return false;
case OP_VV:
case OP_VVC:
case OP_VVV_I3:
case OP_VVVV_I3_I4:
case OP_VVVC_I3:
s1 = v2;
s1 = v1;
return true;
if ( v1_relevant )
s2 = v1;
case OP_VV:
case OP_VVC:
case OP_VVV_I3:
case OP_VVVV_I3_I4:
case OP_VVVC_I3:
s1 = v2;
return true;
if ( v1_relevant )
s2 = v1;
case OP_VVV:
case OP_VVVC:
case OP_VVVV_I4:
s1 = v2;
s2 = v3;
return true;
if ( v1_relevant )
s3 = v1;
case OP_VVV:
case OP_VVVC:
case OP_VVVV_I4:
s1 = v2;
s2 = v3;
return true;
if ( v1_relevant )
s3 = v1;
case OP_VVVV:
s1 = v2;
s2 = v3;
s3 = v4;
return true;
if ( v1_relevant )
s4 = v1;
case OP_VVVV:
s1 = v2;
s2 = v3;
s3 = v4;
return true;
}
if ( v1_relevant )
s4 = v1;
return true;
}
return false;
}
void ZInstI::UpdateSlots(std::vector<int>& slot_mapping)
{
switch ( op_type ) {
case OP_X:
case OP_C:
case OP_V_I1:
case OP_VC_I1:
case OP_VV_I1_I2:
case OP_VVVC_I1_I2_I3:
return; // so we don't do any v1 remapping.
switch ( op_type )
{
case OP_X:
case OP_C:
case OP_V_I1:
case OP_VC_I1:
case OP_VV_I1_I2:
case OP_VVVC_I1_I2_I3:
return; // so we don't do any v1 remapping.
case OP_V:
case OP_VC:
case OP_VV_FRAME:
case OP_VV_I2:
case OP_VVC_I2:
case OP_VVV_I2_I3:
case OP_VVVC_I2_I3:
case OP_VVVV_I2_I3_I4:
break;
case OP_V:
case OP_VC:
case OP_VV_FRAME:
case OP_VV_I2:
case OP_VVC_I2:
case OP_VVV_I2_I3:
case OP_VVVC_I2_I3:
case OP_VVVV_I2_I3_I4:
break;
case OP_VV:
case OP_VVC:
case OP_VVV_I3:
case OP_VVVV_I3_I4:
case OP_VVVC_I3:
v2 = slot_mapping[v2];
break;
case OP_VV:
case OP_VVC:
case OP_VVV_I3:
case OP_VVVV_I3_I4:
case OP_VVVC_I3:
v2 = slot_mapping[v2];
break;
case OP_VVV:
case OP_VVVC:
case OP_VVVV_I4:
v2 = slot_mapping[v2];
v3 = slot_mapping[v3];
break;
case OP_VVV:
case OP_VVVC:
case OP_VVVV_I4:
v2 = slot_mapping[v2];
v3 = slot_mapping[v3];
break;
case OP_VVVV:
v2 = slot_mapping[v2];
v3 = slot_mapping[v3];
v4 = slot_mapping[v4];
break;
}
case OP_VVVV:
v2 = slot_mapping[v2];
v3 = slot_mapping[v3];
v4 = slot_mapping[v4];
break;
}
// Note, unlike for UsesSlots() we do *not* include OP1_READ_WRITE
// here, because such instructions will already have v1 remapped
@ -617,8 +618,7 @@ bool ZInstI::IsGlobalLoad() const
for ( int t = 0; t < NUM_TYPES; ++t )
{
TypeTag tag = TypeTag(t);
ZOp global_op_flavor =
AssignmentFlavor(OP_LOAD_GLOBAL_VV, tag, false);
ZOp global_op_flavor = AssignmentFlavor(OP_LOAD_GLOBAL_VV, tag, false);
if ( global_op_flavor != OP_NOP )
global_ops.insert(global_op_flavor);
@ -638,4 +638,4 @@ void ZInstI::InitConst(const ConstExpr* ce)
reporter->InternalError("bad value compiling code");
}
} // zeek::detail
} // zeek::detail

View file

@ -7,7 +7,8 @@
#include "zeek/script_opt/ZAM/Support.h"
#include "zeek/script_opt/ZAM/ZOp.h"
namespace zeek::detail {
namespace zeek::detail
{
class Expr;
class ConstExpr;
@ -16,12 +17,13 @@ class Stmt;
using AttributesPtr = IntrusivePtr<Attributes>;
// Maps ZAM frame slots to associated identifiers.
// Maps ZAM frame slots to associated identifiers.
using FrameMap = std::vector<ID*>;
// Maps ZAM frame slots to information for sharing the slot across
// multiple script variables.
class FrameSharingInfo {
class FrameSharingInfo
{
public:
// The variables sharing the slot. ID's need to be non-const so we
// can manipulate them, for example by changing their interpreter
@ -43,7 +45,7 @@ public:
// Whether this is a managed slot.
bool is_managed = false;
};
};
using FrameReMap = std::vector<FrameSharingInfo>;
@ -52,7 +54,8 @@ class ZInstAux;
// A ZAM instruction. This base class has all the information for
// execution, but omits information and methods only necessary for
// compiling.
class ZInst {
class ZInst
{
public:
ZInst(ZOp _op, ZAMOpType _op_type)
{
@ -61,22 +64,21 @@ public:
}
// Create a stub instruction that will be populated later.
ZInst() { }
ZInst() { }
virtual ~ZInst() { }
virtual ~ZInst() { }
// Methods for printing out the instruction for debugging/maintenance.
void Dump(bro_uint_t inst_num, const FrameReMap* mappings) const;
void Dump(const std::string& id1, const std::string& id2,
const std::string& id3, const std::string& id4) const;
void Dump(const std::string& id1, const std::string& id2, const std::string& id3,
const std::string& id4) const;
// Returns the name to use in identifying one of the slots/integer
// values (designated by "n"). "inst_num" identifes the instruction
// by its number within a larger set. "mappings" provides the
// mappings used to translate raw slots to the corresponding
// script variable(s).
std::string VName(int n, bro_uint_t inst_num,
const FrameReMap* mappings) const;
std::string VName(int n, bro_uint_t inst_num, const FrameReMap* mappings) const;
// Number of slots that refer to a frame element. These always
// come first, if we use additional slots.
@ -102,17 +104,17 @@ public:
// Initialized here to keep Coverity happy.
int v1 = -1, v2 = -1, v3 = -1, v4 = -1;
ZVal c; // constant associated with instruction, if any
ZVal c; // constant associated with instruction, if any
// Meta-data associated with the execution.
// Type, usually for interpreting the constant.
TypePtr t = nullptr;
TypePtr t2 = nullptr; // just a few ops need two types
const Expr* e = nullptr; // only needed for "when" expressions
Func* func = nullptr; // used for calls
EventHandler* event_handler = nullptr; // used for referring to events
AttributesPtr attrs = nullptr; // used for things like constructors
TypePtr t2 = nullptr; // just a few ops need two types
const Expr* e = nullptr; // only needed for "when" expressions
Func* func = nullptr; // used for calls
EventHandler* event_handler = nullptr; // used for referring to events
AttributesPtr attrs = nullptr; // used for things like constructors
// Auxiliary information. We could in principle use this to
// consolidate a bunch of the above, though at the cost of
@ -126,13 +128,14 @@ public:
// Whether v1 represents a frame slot type for which we
// explicitly manage the memory.
bool is_managed = false;
};
};
// A intermediary ZAM instruction, one that includes information/methods
// needed for compiling. Intermediate instructions use pointers to other
// such instructions for branches, rather than concrete instruction
// numbers. This allows the AM optimizer to easily prune instructions.
class ZInstI : public ZInst {
class ZInstI : public ZInst
{
public:
// These constructors can be used directly, but often instead
// they'll be generated via the use of Inst-Gen methods.
@ -142,10 +145,7 @@ public:
op_type = OP_X;
}
ZInstI(ZOp _op, int _v1) : ZInst(_op, OP_V)
{
v1 = _v1;
}
ZInstI(ZOp _op, int _v1) : ZInst(_op, OP_V) { v1 = _v1; }
ZInstI(ZOp _op, int _v1, int _v2) : ZInst(_op, OP_VV)
{
@ -160,8 +160,7 @@ public:
v3 = _v3;
}
ZInstI(ZOp _op, int _v1, int _v2, int _v3, int _v4)
: ZInst(_op, OP_VVVV)
ZInstI(ZOp _op, int _v1, int _v2, int _v3, int _v4) : ZInst(_op, OP_VVVV)
{
v1 = _v1;
v2 = _v2;
@ -169,10 +168,7 @@ public:
v4 = _v4;
}
ZInstI(ZOp _op, const ConstExpr* ce) : ZInst(_op, OP_C)
{
InitConst(ce);
}
ZInstI(ZOp _op, const ConstExpr* ce) : ZInst(_op, OP_C) { InitConst(ce); }
ZInstI(ZOp _op, int _v1, const ConstExpr* ce) : ZInst(_op, OP_VC)
{
@ -180,16 +176,14 @@ public:
InitConst(ce);
}
ZInstI(ZOp _op, int _v1, int _v2, const ConstExpr* ce)
: ZInst(_op, OP_VVC)
ZInstI(ZOp _op, int _v1, int _v2, const ConstExpr* ce) : ZInst(_op, OP_VVC)
{
v1 = _v1;
v2 = _v2;
InitConst(ce);
}
ZInstI(ZOp _op, int _v1, int _v2, int _v3, const ConstExpr* ce)
: ZInst(_op, OP_VVVC)
ZInstI(ZOp _op, int _v1, int _v2, int _v3, const ConstExpr* ce) : ZInst(_op, OP_VVVC)
{
v1 = _v1;
v2 = _v2;
@ -206,8 +200,7 @@ public:
// Note that this is *not* an override of the base class's VName
// but instead a method with similar functionality but somewhat
// different behavior (namely, being cognizant of frame_ids).
std::string VName(int n, const FrameMap* frame_ids,
const FrameReMap* remappings) const;
std::string VName(int n, const FrameMap* frame_ids, const FrameReMap* remappings) const;
// True if this instruction definitely won't proceed to the one
// after it.
@ -216,7 +209,7 @@ public:
// True if this instruction always branches elsewhere. Different
// from DoesNotContinue() in that returns & hook breaks do not
// continue, but they are not branches.
bool IsUnconditionalBranch() const { return op == OP_GOTO_V; }
bool IsUnconditionalBranch() const { return op == OP_GOTO_V; }
// True if this instruction is of the form "v1 = v2".
bool IsDirectAssignment() const;
@ -246,19 +239,16 @@ public:
// True if the instruction corresponds to some sort of load,
// either from the interpreter frame or of a global.
bool IsLoad() const
{
return op_type == OP_VV_FRAME || IsGlobalLoad();
}
bool IsLoad() const { return op_type == OP_VV_FRAME || IsGlobalLoad(); }
// True if the instruction corresponds to storing a global.
bool IsGlobalStore() const
{
return op == OP_STORE_GLOBAL_V;
}
bool IsGlobalStore() const { return op == OP_STORE_GLOBAL_V; }
void CheckIfManaged(const TypePtr& t)
{ if ( ZVal::IsManagedType(t) ) is_managed = true; }
{
if ( ZVal::IsManagedType(t) )
is_managed = true;
}
void SetType(TypePtr _t)
{
@ -283,7 +273,7 @@ public:
// Branch target, prior to concretizing into PC target.
ZInstI* target = nullptr;
int target_slot = 0; // which of v1/v2/v3 should hold the target
int target_slot = 0; // which of v1/v2/v3 should hold the target
// The final PC location of the statement. -1 indicates not
// yet assigned.
@ -299,12 +289,13 @@ public:
private:
// Initialize 'c' from the given ConstExpr.
void InitConst(const ConstExpr* ce);
};
};
// Auxiliary information, used when the fixed ZInst layout lacks
// sufficient expressiveness to represent all of the elements that
// an instruction needs.
class ZInstAux {
class ZInstAux
{
public:
// if n is positive then it gives the size of parallel arrays
// tracking slots, constants, and types.
@ -321,9 +312,9 @@ public:
~ZInstAux()
{
delete [] ints;
delete [] constants;
delete [] types;
delete[] ints;
delete[] constants;
delete[] types;
}
// Returns the i'th element of the parallel arrays as a ValPtr.
@ -392,7 +383,6 @@ public:
types[i] = nullptr;
}
// Member variables. We could add accessors for manipulating
// these (and make the variables private), but for convenience we
// make them directly available.
@ -405,8 +395,8 @@ public:
// We track associated types, too, enabling us to use
// ZVal::ToVal to convert frame slots or constants to ValPtr's.
int n; // size of arrays
int* slots = nullptr; // either nil or points to ints
int n; // size of arrays
int* slots = nullptr; // either nil or points to ints
int* ints = nullptr;
ValPtr* constants = nullptr;
TypePtr* types = nullptr;
@ -435,14 +425,13 @@ public:
// iteration.
TypePtr value_var_type;
// This is only used to return values stored elsewhere in this
// object - it's not set directly.
//
// If we cared about memory penny-pinching, we could make this
// a pointer and only instantiate as needed.
ValVec vv;
};
};
// Returns a human-readable version of the given ZAM op-code.
extern const char* ZOP_name(ZOp op);
@ -451,14 +440,13 @@ extern const char* ZOP_name(ZOp op);
// The third argument governs what to do if the given type has no assignment
// flavor. If true, this leads to an assertion failure. If false, and
// if there's no flavor for the type, then OP_NOP is returned.
extern ZOp AssignmentFlavor(ZOp orig, TypeTag tag, bool strict=true);
extern ZOp AssignmentFlavor(ZOp orig, TypeTag tag, bool strict = true);
// The following all use initializations produced by Gen-ZAM.
// Maps first operands, and then type tags, to operands.
extern std::unordered_map<ZOp, std::unordered_map<TypeTag, ZOp>> assignment_flavor;
// Maps flavorful assignments to their non-assignment counterpart.
// Used for optimization when we determine that the assigned-to
// value is superfluous.
@ -468,4 +456,4 @@ extern std::unordered_map<ZOp, ZOp> assignmentless_op;
// counterpart uses.
extern std::unordered_map<ZOp, ZAMOpType> assignmentless_op_type;
} // namespace zeek::detail
} // namespace zeek::detail

View file

@ -1,64 +1,89 @@
// See the file "COPYING" in the main distribution directory for copyright.
#include "zeek/script_opt/ZAM/Support.h"
#include "zeek/script_opt/ZAM/ZOp.h"
#include "zeek/script_opt/ZAM/Support.h"
namespace zeek::detail {
namespace zeek::detail
{
const char* ZOP_name(ZOp op)
{
switch ( op ) {
switch ( op )
{
#include "zeek/ZAM-OpsNamesDefs.h"
case OP_NOP: return "nop";
}
case OP_NOP:
return "nop";
}
return "<error>";
}
static const char* op_type_name(ZAMOpType ot)
{
switch ( ot ) {
case OP_X: return "X";
case OP_C: return "C";
case OP_V: return "V";
case OP_V_I1: return "V_I1";
case OP_VC_I1: return "VC_I1";
case OP_VC: return "VC";
case OP_VV: return "VV";
case OP_VV_I2: return "VV_I2";
case OP_VV_I1_I2: return "VV_I1_I2";
case OP_VV_FRAME: return "VV_FRAME";
case OP_VVC: return "VVC";
case OP_VVC_I2: return "VVC_I2";
case OP_VVV: return "VVV";
case OP_VVV_I3: return "VVV_I3";
case OP_VVV_I2_I3: return "VVV_I2_I3";
case OP_VVVC: return "VVVC";
case OP_VVVC_I3: return "VVVC_I3";
case OP_VVVC_I2_I3: return "VVVC_I2_I3";
case OP_VVVC_I1_I2_I3: return "VVVC_I1_I2_I3";
case OP_VVVV: return "VVVV";
case OP_VVVV_I4: return "VVVV_I4";
case OP_VVVV_I3_I4: return "VVVV_I3_I4";
case OP_VVVV_I2_I3_I4: return "VVVV_I2_I3_I4";
}
switch ( ot )
{
case OP_X:
return "X";
case OP_C:
return "C";
case OP_V:
return "V";
case OP_V_I1:
return "V_I1";
case OP_VC_I1:
return "VC_I1";
case OP_VC:
return "VC";
case OP_VV:
return "VV";
case OP_VV_I2:
return "VV_I2";
case OP_VV_I1_I2:
return "VV_I1_I2";
case OP_VV_FRAME:
return "VV_FRAME";
case OP_VVC:
return "VVC";
case OP_VVC_I2:
return "VVC_I2";
case OP_VVV:
return "VVV";
case OP_VVV_I3:
return "VVV_I3";
case OP_VVV_I2_I3:
return "VVV_I2_I3";
case OP_VVVC:
return "VVVC";
case OP_VVVC_I3:
return "VVVC_I3";
case OP_VVVC_I2_I3:
return "VVVC_I2_I3";
case OP_VVVC_I1_I2_I3:
return "VVVC_I1_I2_I3";
case OP_VVVV:
return "VVVV";
case OP_VVVV_I4:
return "VVVV_I4";
case OP_VVVV_I3_I4:
return "VVVV_I3_I4";
case OP_VVVV_I2_I3_I4:
return "VVVV_I2_I3_I4";
}
return "<error>";
}
ZAMOp1Flavor op1_flavor[] = {
#include "zeek/ZAM-Op1FlavorsDefs.h"
OP1_INTERNAL, // OP_NOP
OP1_INTERNAL, // OP_NOP
};
bool op_side_effects[] = {
#include "zeek/ZAM-OpSideEffects.h"
false, // OP_NOP
false, // OP_NOP
};
std::unordered_map<ZOp, std::unordered_map<TypeTag, ZOp>> assignment_flavor;
std::unordered_map<ZOp, ZOp> assignmentless_op;
std::unordered_map<ZOp, ZAMOpType> assignmentless_op_type;
@ -77,24 +102,25 @@ ZOp AssignmentFlavor(ZOp orig, TypeTag tag, bool strict)
}
// Map type tag to equivalent, as needed.
switch ( tag ) {
case TYPE_BOOL:
case TYPE_ENUM:
tag = TYPE_INT;
break;
switch ( tag )
{
case TYPE_BOOL:
case TYPE_ENUM:
tag = TYPE_INT;
break;
case TYPE_PORT:
tag = TYPE_COUNT;
break;
case TYPE_PORT:
tag = TYPE_COUNT;
break;
case TYPE_TIME:
case TYPE_INTERVAL:
tag = TYPE_DOUBLE;
break;
case TYPE_TIME:
case TYPE_INTERVAL:
tag = TYPE_DOUBLE;
break;
default:
break;
}
default:
break;
}
if ( assignment_flavor.count(orig) == 0 )
{
@ -117,4 +143,4 @@ ZOp AssignmentFlavor(ZOp orig, TypeTag tag, bool strict)
return orig_map[tag];
}
} // zeek::detail
} // zeek::detail

View file

@ -4,14 +4,15 @@
#pragma once
namespace zeek::detail {
namespace zeek::detail
{
// Opcodes associated with ZAM instructions.
enum ZOp {
enum ZOp
{
#include "zeek/ZAM-OpsDefs.h"
OP_NOP,
};
};
// Possible types of instruction operands in terms of which fields they use.
// Used for low-level optimization (so important that they're correct),
@ -22,8 +23,13 @@ enum ZOp {
// I1/I2/I3/I4: the instruction's integer value, used directly (not as a slot)
// FRAME: a slot in the (intrepreter) Frame object
// X: no operands
enum ZAMOpType {
OP_X, OP_C, OP_V, OP_V_I1, OP_VC_I1,
enum ZAMOpType
{
OP_X,
OP_C,
OP_V,
OP_V_I1,
OP_VC_I1,
OP_VC,
OP_VV,
@ -46,15 +52,16 @@ enum ZAMOpType {
OP_VVVV_I3_I4,
OP_VVVV_I2_I3_I4,
};
};
// Possible "flavors" for an operator's first slot.
enum ZAMOp1Flavor {
OP1_READ, // the slot is read, not modified
OP1_WRITE, // the slot is modified, not read - the most common
OP1_READ_WRITE, // the slot is both read and then modified, e.g. "++"
OP1_INTERNAL, // we're doing some internal manipulation of the slot
};
enum ZAMOp1Flavor
{
OP1_READ, // the slot is read, not modified
OP1_WRITE, // the slot is modified, not read - the most common
OP1_READ_WRITE, // the slot is both read and then modified, e.g. "++"
OP1_INTERNAL, // we're doing some internal manipulation of the slot
};
// Maps an operand to its flavor.
extern ZAMOp1Flavor op1_flavor[];
@ -62,4 +69,4 @@ extern ZAMOp1Flavor op1_flavor[];
// Maps an operand to whether it has side effects.
extern bool op_side_effects[];
} // namespace zeek::detail
} // namespace zeek::detail