streamline generated -O C++ code by relying on per-function profiles rather than aggregate profile

This commit is contained in:
Vern Paxson 2024-12-06 16:23:32 -08:00
parent 79c5790bbf
commit 612d99e751
3 changed files with 43 additions and 12 deletions

View file

@ -29,6 +29,7 @@ CPPCompile::CPPCompile(vector<FuncInfo>& _funcs, std::shared_ptr<ProfileFuncs> _
CPPCompile::~CPPCompile() { fclose(write_file); }
void CPPCompile::Compile(bool report_uncompilable) {
unordered_set<const Type*> rep_types;
unordered_set<string> filenames_reported_as_skipped;
bool had_to_skip = false;
@ -63,6 +64,24 @@ void CPPCompile::Compile(bool report_uncompilable) {
continue;
}
auto pf = func.Profile();
total_hash = merge_p_hashes(total_hash, pf->HashVal());
for ( auto t : pf->UnorderedTypes() )
rep_types.insert(pfs->TypeRep(t));
auto& pf_all_gl = pf->AllGlobals();
all_accessed_globals.insert(pf_all_gl.begin(), pf_all_gl.end());
auto& pf_gl = pf->Globals();
accessed_globals.insert(pf_gl.begin(), pf_gl.end());
auto& pf_events = pf->Events();
accessed_events.insert(pf_events.begin(), pf_events.end());
auto& pf_lambdas = pf->Lambdas();
accessed_lambdas.insert(pf_lambdas.begin(), pf_lambdas.end());
if ( is_lambda(f) || is_when_lambda(f) ) {
// We deal with these separately.
func.SetSkip(true);
@ -85,35 +104,35 @@ void CPPCompile::Compile(bool report_uncompilable) {
}
}
if ( standalone && had_to_skip )
reporter->FatalError("aborting standalone compilation to C++ due to having to skip some functions");
// Generate a hash unique for this compilation.
for ( const auto& func : funcs )
if ( ! func.ShouldSkip() )
total_hash = merge_p_hashes(total_hash, func.Profile()->HashVal());
if ( standalone && had_to_skip )
reporter->FatalError("aborting standalone compilation to C++ due to having to skip some functions");
auto t = util::current_time();
total_hash = merge_p_hashes(total_hash, hash<double>{}(t));
GenProlog();
// Track all of the types we'll be using.
for ( const auto& t : pfs->RepTypes() ) {
for ( const auto& t : rep_types ) {
TypePtr tp{NewRef{}, (Type*)(t)};
types.AddKey(tp, pfs->HashType(t));
}
NL();
for ( auto& g : pfs->AllGlobals() )
for ( auto& g : all_accessed_globals )
CreateGlobal(g);
for ( const auto& e : pfs->Events() )
for ( const auto& e : accessed_events )
if ( AddGlobal(e, "gl") )
Emit("EventHandlerPtr %s_ev;", globals[string(e)]);
for ( const auto& t : pfs->RepTypes() ) {
for ( const auto& t : rep_types ) {
ASSERT(types.HasKey(t));
TypePtr tp{NewRef{}, (Type*)(t)};
RegisterType(tp);
@ -131,7 +150,7 @@ void CPPCompile::Compile(bool report_uncompilable) {
// be identical. In that case, we don't want to generate the lambda
// twice, but we do want to map the second one to the same body name.
unordered_map<string, const Stmt*> lambda_ASTs;
for ( const auto& l : pfs->Lambdas() ) {
for ( const auto& l : accessed_lambdas ) {
const auto& n = l->Name();
const auto body = l->Ingredients()->Body().get();
if ( lambda_ASTs.count(n) > 0 )
@ -151,7 +170,7 @@ void CPPCompile::Compile(bool report_uncompilable) {
CompileFunc(func);
lambda_ASTs.clear();
for ( const auto& l : pfs->Lambdas() ) {
for ( const auto& l : accessed_lambdas ) {
const auto& n = l->Name();
if ( lambda_ASTs.count(n) > 0 )
continue;

View file

@ -308,9 +308,8 @@ string CPPCompile::GenCallExpr(const CallExpr* c, GenType gt, bool top_level) {
if ( pfs->BiFGlobals().count(f_id) == 0 )
gen += +"->AsFunc()";
else if ( pfs->Globals().count(f_id) > 0 )
// The BiF version has an extra "_", per
// AddBiF(..., true).
else if ( accessed_globals.count(f_id) > 0 )
// The BiF version has an extra "_", per AddBiF(..., true).
gen = globals[string(id_name) + "_"];
}

View file

@ -53,6 +53,19 @@ std::string Canonicalize(const std::string& name) const;
// be a EXPR_NAME).
std::string GlobalName(const ExprPtr& e) { return globals[e->AsNameExpr()->Id()->Name()]; }
// Globals that are used (appear in the profiles) of the bodies we're
// compiling. Includes globals just used as functions to call.
std::unordered_set<const ID*> all_accessed_globals;
// Same, but just the globals used in contexts beyond function calls.
std::unordered_set<const ID*> accessed_globals;
// Lambdas that are accessed.
std::unordered_set<const LambdaExpr*> accessed_lambdas;
// Events that are accessed.
std::unordered_set<std::string> accessed_events;
// Maps global names (not identifiers) to the names we use for them.
std::unordered_map<std::string, std::string> globals;