ZAM support for two-valued "for" loops over vectors

This commit is contained in:
Vern Paxson 2022-09-16 09:40:39 -07:00
parent 02cd773c51
commit 5fe4eb27a8
6 changed files with 83 additions and 8 deletions

View file

@ -400,6 +400,16 @@ void ZAMCompiler::ComputeFrameLifetimes()
} }
break; break;
case OP_NEXT_VECTOR_ITER_VAL_VAR_VVVV:
{
CheckSlotAssignment(inst->v2, inst);
auto depth = inst->loop_depth;
ExtendLifetime(inst->v1, EndOfLoop(inst, depth));
ExtendLifetime(inst->v2, EndOfLoop(inst, depth));
}
break;
case OP_NEXT_VECTOR_ITER_VVV: case OP_NEXT_VECTOR_ITER_VVV:
case OP_NEXT_STRING_ITER_VVV: case OP_NEXT_STRING_ITER_VVV:
// Sometimes loops are written that don't actually // Sometimes loops are written that don't actually
@ -916,6 +926,9 @@ bool ZAMCompiler::VarIsAssigned(int slot, const ZInstI* i) const
// *does* also assign to slot 1. // *does* also assign to slot 1.
} }
if ( i->op == OP_NEXT_VECTOR_ITER_VAL_VAR_VVVV && i->v2 == slot )
return true;
if ( i->op_type == OP_VV_FRAME ) if ( i->op_type == OP_VV_FRAME )
// We don't want to consider these as assigning to the // We don't want to consider these as assigning to the
// variable, since the point of this method is to figure // variable, since the point of this method is to figure

View file

@ -171,8 +171,8 @@ void ZAMCompiler::SetV4(ZAMStmt s, const InstLabel l)
auto ot = inst->op_type; auto ot = inst->op_type;
ASSERT(ot == OP_VVVV || ot == OP_VVVV_I4); ASSERT(ot == OP_VVVV || ot == OP_VVVV_I4 || ot == OP_VVVV_I3_I4);
if ( ot != OP_VVVV_I4 ) if ( ot == OP_VVVV )
inst->op_type = OP_VVVV_I4; inst->op_type = OP_VVVV_I4;
} }

View file

@ -1761,6 +1761,30 @@ eval auto& si = step_iters[z.v2];
frame[z.v1].uint_val = si.iter; frame[z.v1].uint_val = si.iter;
si.IterFinished(); si.IterFinished();
internal-op Next-Vector-Iter-Val-Var
# v1 = iteration variable
# v2 = value variable
# v3 = iteration info
# v4 = branch target if loop done
op1-read-write
type VVVV
eval auto& si = step_iters[z.v3];
if ( si.IsDoneIterating() )
BRANCH(v4)
const auto& vv = *si.vv;
if ( ! vv[si.iter] )
{ // Account for vector hole. Re-execute for next position.
si.IterFinished();
--pc; // so we then increment to here again
break;
}
frame[z.v1].uint_val = si.iter;
if ( z.is_managed )
frame[z.v2] = BuildVal(vv[si.iter]->ToVal(z.t), z.t);
else
frame[z.v2] = *vv[si.iter];
si.IterFinished();
internal-op Init-String-Loop internal-op Init-String-Loop
type VV type VV

View file

@ -864,6 +864,7 @@ const ZAMStmt ZAMCompiler::LoopOverVector(const ForStmt* f, const NameExpr* val)
{ {
auto loop_vars = f->LoopVars(); auto loop_vars = f->LoopVars();
auto loop_var = (*loop_vars)[0]; auto loop_var = (*loop_vars)[0];
auto value_var = f->ValueVar();
int iter_slot = num_step_iters++; int iter_slot = num_step_iters++;
@ -873,8 +874,20 @@ const ZAMStmt ZAMCompiler::LoopOverVector(const ForStmt* f, const NameExpr* val)
auto init_end = AddInst(z); auto init_end = AddInst(z);
auto iter_head = StartingBlock(); auto iter_head = StartingBlock();
if ( value_var )
{
z = ZInstI(OP_NEXT_VECTOR_ITER_VAL_VAR_VVVV, FrameSlot(loop_var), FrameSlot(value_var),
iter_slot, 0);
z.t = value_var->GetType();
z.is_managed = ZVal::IsManagedType(z.t);
z.op_type = OP_VVVV_I3_I4;
}
else
{
z = ZInstI(OP_NEXT_VECTOR_ITER_VVV, FrameSlot(loop_var), iter_slot, 0); z = ZInstI(OP_NEXT_VECTOR_ITER_VVV, FrameSlot(loop_var), iter_slot, 0);
z.op_type = OP_VVV_I2_I3; z.op_type = OP_VVV_I2_I3;
}
return FinishLoop(iter_head, z, f->LoopBody(), iter_slot, false); return FinishLoop(iter_head, z, f->LoopBody(), iter_slot, false);
} }
@ -944,7 +957,9 @@ const ZAMStmt ZAMCompiler::FinishLoop(const ZAMStmt iter_head, ZInstI& iter_stmt
auto final_stmt = AddInst(z); auto final_stmt = AddInst(z);
auto ot = iter_stmt.op_type; auto ot = iter_stmt.op_type;
if ( ot == OP_VVV_I3 || ot == OP_VVV_I2_I3 ) if ( ot == OP_VVVV_I3_I4 )
SetV4(loop_iter, GoToTarget(final_stmt));
else if ( ot == OP_VVV_I3 || ot == OP_VVV_I2_I3 )
SetV3(loop_iter, GoToTarget(final_stmt)); SetV3(loop_iter, GoToTarget(final_stmt));
else else
SetV2(loop_iter, GoToTarget(final_stmt)); SetV2(loop_iter, GoToTarget(final_stmt));

View file

@ -331,9 +331,16 @@ string ZInstI::VName(int n, const FrameMap* frame_ids, const FrameReMap* remappi
auto inst_num_u = static_cast<zeek_uint_t>(inst_num); auto inst_num_u = static_cast<zeek_uint_t>(inst_num);
for ( i = 0; i < map.id_start.size(); ++i ) for ( i = 0; i < map.id_start.size(); ++i )
{ {
// See discussion for ZInst::VName. // See discussion for ZInst::VName, though this is
if ( (n == 1 && map.id_start[i] > inst_num_u) || // a tad different since we have the general notion
(n > 1 && map.id_start[i] >= inst_num_u) ) // of AssignsToSlot().
if ( AssignsToSlot(n) )
{
if ( map.id_start[i] > inst_num_u )
break;
}
else if ( map.id_start[i] >= inst_num_u )
// Went too far. // Went too far.
break; break;
} }
@ -441,6 +448,18 @@ bool ZInstI::AssignsToSlot1() const
return false; return false;
} }
bool ZInstI::AssignsToSlot(int slot) const
{
switch ( op )
{
case OP_NEXT_VECTOR_ITER_VAL_VAR_VVVV:
return slot == 1 || slot == 2;
default:
return slot == 1 && AssignsToSlot1();
}
}
bool ZInstI::UsesSlot(int slot) const bool ZInstI::UsesSlot(int slot) const
{ {
auto fl = op1_flavor[op]; auto fl = op1_flavor[op];

View file

@ -222,6 +222,10 @@ public:
// given by slot 1 (v1). // given by slot 1 (v1).
bool AssignsToSlot1() const; bool AssignsToSlot1() const;
// True if the given instruction assigns to the frame location
// corresponding to the given slot.
bool AssignsToSlot(int slot) const;
// True if the given instruction uses the value in the given frame // True if the given instruction uses the value in the given frame
// slot. (Assigning to the slot does not constitute using the value.) // slot. (Assigning to the slot does not constitute using the value.)
bool UsesSlot(int slot) const; bool UsesSlot(int slot) const;