ZAM optimizations for record creation

This commit is contained in:
Vern Paxson 2023-12-18 17:12:30 -08:00
parent 6fc8397cbf
commit 94efeda228
3 changed files with 82 additions and 20 deletions

View file

@ -1100,16 +1100,34 @@ const ZAMStmt ZAMCompiler::ConstructSet(const NameExpr* n, const Expr* e) {
const ZAMStmt ZAMCompiler::ConstructRecord(const NameExpr* n, const Expr* e) {
auto rc = e->AsRecordConstructorExpr();
auto rt = e->GetType()->AsRecordType();
auto map = rc->Map();
ZInstI z;
if ( rc->Map() ) {
z = GenInst(OP_CONSTRUCT_KNOWN_RECORD_V, n);
if ( map ) {
// Compute whether we need at least one of the default field
// initializations. We don't need so if every one of the fields
// with such an initializer is already covered in the map (meaning
// it has an explicit initialization value).
auto& ci = rt->CreationInits();
zeek_uint_t common = 0;
for ( auto& c : ci )
for ( auto r : *map )
if ( c.first == r )
++common;
auto need_init = common != ci.size();
z = GenInst(OP_CONSTRUCT_KNOWN_RECORD_Vi, n, need_init);
z.aux = InternalBuildVals(rc->Op().get());
z.aux->map = *rc->Map();
z.aux->map = *map;
}
else {
z = GenInst(OP_CONSTRUCT_RECORD_V, n);
// Constructors that don't need maps are explicitly initializing
// every field, so they don't need default initializations, hence
// "false" in the following.
z = GenInst(OP_CONSTRUCT_DIRECT_RECORD_Vi, n, false);
z.aux = InternalBuildVals(rc->Op().get());
}
@ -1118,6 +1136,33 @@ const ZAMStmt ZAMCompiler::ConstructRecord(const NameExpr* n, const Expr* e) {
if ( pfs->HasSideEffects(SideEffectsOp::CONSTRUCTION, z.t) )
z.aux->can_change_non_locals = true;
// If one of the initialization values is an unspecified vector (which
// in general we can't know until run-time) then we'll need to
// "concretize" it. We first see whether this is a possibility, since
// it usually isn't, by counting up how many of the record fields are
// vectors.
std::vector<int> vector_fields; // holds indices of the vector fields
for ( int i = 0; i < z.aux->n; ++i ) {
auto field_ind = map ? (*map)[i] : i;
if ( rt->GetFieldType(field_ind)->Tag() == TYPE_VECTOR )
vector_fields.push_back(field_ind);
}
auto inst = AddInst(z);
if ( vector_fields.empty() )
// Common case of no vector fields, we're done.
return inst;
// Need to add a separate instruction for concretizing the fields.
z = GenInst(OP_CONCRETIZE_VECTOR_FIELDS_V, n);
z.t = e->GetType();
int nf = static_cast<int>(vector_fields.size());
z.aux = new ZInstAux(nf);
z.aux->elems_has_slots = false; // we're storing field offsets, not slots
for ( int i = 0; i < nf; ++i )
z.aux->Add(i, vector_fields[i]);
return AddInst(z);
}

View file

@ -1199,35 +1199,49 @@ eval ConstructTableOrSetPre()
direct-unary-op Record-Constructor ConstructRecord
internal-op Construct-Record
type V
# v2 is boolean of whether to initialize fields. For this instruction,
# it's always false.
op Construct-Direct-Record
type Vi
eval EvalConstructRecord(, i)
# v2 is boolean of whether to initialize fields.
op Construct-Known-Record
type Vi
eval EvalConstructRecord(auto& map = aux->map;, map[i])
macro EvalConstructRecord(map_init, map_accessor)
auto rt = cast_intrusive<RecordType>(z.t);
auto new_r = new RecordVal(rt);
auto new_r = new RecordVal(rt, z.v2 ? RecordVal::RV_FULL_INIT : RecordVal::RV_SLOTS_INIT);
auto aux = z.aux;
auto n = aux->n;
map_init
for ( auto i = 0; i < n; ++i )
{
auto v_i = aux->ToVal(frame, i);
auto ind = map_accessor;
if ( v_i && v_i->GetType()->Tag() == TYPE_VECTOR &&
v_i->GetType<VectorType>()->IsUnspecifiedVector() )
{
const auto& t_ind = rt->GetFieldType(ind);
v_i->AsVectorVal()->Concretize(t_ind->Yield());
}
new_r->Assign(ind, v_i);
}
new_r->InitField(map_accessor, aux->ToZVal(frame, i));
auto& r = frame[z.v1].record_val;
Unref(r);
r = new_r;
internal-op Construct-Known-Record
# Special instruction for concretizing vectors that are fields in a
# newly-constructed record. "aux" holds which fields in the record to
# inspect.
op Concretize-Vector-Fields
op1-read
type V
eval EvalConstructRecord(auto& map = aux->map;, map[i])
eval auto rt = cast_intrusive<RecordType>(z.t);
auto r = frame[z.v1].record_val;
auto aux = z.aux;
auto n = aux->n;
for ( auto i = 0; i < n; ++i )
{
auto v_i = r->GetField(aux->elems[i].IntVal());
ASSERT(v_i);
if ( v_i->GetType<VectorType>()->IsUnspecifiedVector() )
{
const auto& t_i = rt->GetFieldType(i);
v_i->AsVectorVal()->Concretize(t_i->Yield());
}
}
direct-unary-op Vector-Constructor ConstructVector

View file

@ -418,6 +418,9 @@ public:
// and type.
void Add(int i, int slot, TypePtr t) { elems[i].SetInt(slot, t); }
// Same, but for non-slot integers.
void Add(int i, int v_i) { elems[i].SetInt(v_i); }
// Same but for constants.
void Add(int i, ValPtr c) { elems[i].SetConstant(c); }