factoring + record constructors

This commit is contained in:
Vern Paxson 2023-11-30 10:23:55 -08:00
parent ed70fefd34
commit ba9781d83e
2 changed files with 27 additions and 37 deletions

View file

@ -988,15 +988,15 @@ TraversalCode CSE_ValidityChecker::PreExpr(const Expr* e) {
// so we don't want to traverse them. // so we don't want to traverse them.
return TC_ABORTSTMT; return TC_ABORTSTMT;
case EXPR_RECORD_COERCE:
case EXPR_RECORD_CONSTRUCTOR: case EXPR_RECORD_CONSTRUCTOR:
// If these have initializations done at construction // Note, record coercion behaves like constructors in terms of
// time, those can include function calls. // potentially executing &default functions. In either case,
if ( have_sensitive_IDs ) { // the type of the expression reflects the type we want to analyze
auto& et = e->GetType(); // for side effects.
if ( et->Tag() == TYPE_RECORD && ! et->AsRecordType()->IdempotentCreation() ) { if ( CheckRecordConstructor(e->GetType()) ) {
is_valid = false; is_valid = false;
return TC_ABORTALL; return TC_ABORTALL;
}
} }
break; break;
@ -1078,6 +1078,13 @@ bool CSE_ValidityChecker::CheckAggrMod(const TypePtr& t) const {
return false; return false;
} }
bool CSE_ValidityChecker::CheckRecordConstructor(const TypePtr& t) const {
if ( t->Tag() != TYPE_RECORD )
return false;
return CheckSideEffects(SideEffectsOp::CONSTRUCTION, t);
}
bool CSE_ValidityChecker::CheckTableMod(const TypePtr& t) const { bool CSE_ValidityChecker::CheckTableMod(const TypePtr& t) const {
if ( ! CheckAggrMod(t) ) if ( ! CheckAggrMod(t) )
return false; return false;
@ -1085,54 +1092,35 @@ bool CSE_ValidityChecker::CheckTableMod(const TypePtr& t) const {
if ( t->Tag() != TYPE_TABLE ) if ( t->Tag() != TYPE_TABLE )
return false; return false;
// Note, the following will almost always remain empty. return CheckSideEffects(SideEffectsOp::WRITE, t);
}
bool CSE_ValidityChecker::CheckTableRef(const TypePtr& t) const {
return CheckSideEffects(SideEffectsOp::READ, t);
}
bool CSE_ValidityChecker::CheckSideEffects(SideEffectsOp::AccessType access, const TypePtr& t) const {
IDSet non_local_ids; IDSet non_local_ids;
std::unordered_set<const Type*> aggrs; std::unordered_set<const Type*> aggrs;
if ( pfs.GetSideEffects(SideEffectsOp::WRITE, t.get(), non_local_ids, aggrs) ) if ( pfs.GetSideEffects(access, t.get(), non_local_ids, aggrs) )
return true; return true;
if ( non_local_ids.empty() && aggrs.empty() ) if ( non_local_ids.empty() && aggrs.empty() )
// This is far and away the most common case.
return false; return false;
for ( auto i : ids ) { for ( auto i : ids ) {
for ( auto nli : non_local_ids ) for ( auto nli : non_local_ids )
if ( nli == i ) { if ( nli == i ) {
// printf("non-local ID on WRITE: %s\n", i->Name()); // printf("non-local ID on %d: %s\n", access, i->Name());
return true; return true;
} }
auto i_t = i->GetType(); auto i_t = i->GetType();
for ( auto a : aggrs ) for ( auto a : aggrs )
if ( same_type(a, i_t.get()) ) { if ( same_type(a, i_t.get()) ) {
// printf("aggr type on WRITE: %s\n", i->Name()); // printf("aggr type on %d: %s\n", access, i->Name());
return true;
}
}
return false;
}
bool CSE_ValidityChecker::CheckTableRef(const TypePtr& t) const {
// Note, the following will almost always remain empty, so spinning
// through them in the loop below will be very quick.
IDSet non_local_ids;
std::unordered_set<const Type*> aggrs;
if ( pfs.GetSideEffects(SideEffectsOp::READ, t.get(), non_local_ids, aggrs) )
return true;
for ( auto i : ids ) {
for ( auto nli : non_local_ids )
if ( nli == i ) {
// printf("non-local ID on READ: %s\n", i->Name());
return true;
}
auto i_t = i->GetType();
for ( auto a : aggrs )
if ( same_type(a, i_t.get()) ) {
// printf("aggr type on READ: %p %s\n", e, obj_desc(e).c_str());
return true; return true;
} }
} }

View file

@ -352,8 +352,10 @@ protected:
// About elements ... // About elements ...
// ### // ###
bool CheckRecordConstructor(const TypePtr& t) const;
bool CheckTableMod(const TypePtr& t) const; bool CheckTableMod(const TypePtr& t) const;
bool CheckTableRef(const TypePtr& t) const; bool CheckTableRef(const TypePtr& t) const;
bool CheckSideEffects(SideEffectsOp::AccessType access, const TypePtr& t) const;
// Profile across all script functions. // Profile across all script functions.
ProfileFuncs& pfs; ProfileFuncs& pfs;