implementation for Reduce class - code now links

This commit is contained in:
Vern Paxson 2021-01-10 14:14:09 -08:00
parent 7a9694a2a4
commit 607e9950bf
2 changed files with 283 additions and 0 deletions

282
src/script_opt/Reduce.cc Normal file
View file

@ -0,0 +1,282 @@
// See the file "COPYING" in the main distribution directory for copyright.
#include "ID.h"
#include "Var.h"
#include "Scope.h"
#include "Expr.h"
#include "Stmt.h"
#include "Desc.h"
#include "ProfileFunc.h"
#include "Reporter.h"
#include "zeek/script_opt/Reduce.h"
#include "zeek/script_opt/TempVar.h"
namespace zeek::detail {
Reducer::Reducer(Scope* s)
{
scope = s;
}
Reducer::~Reducer()
{
for ( int i = 0; i < temps.length(); ++i )
delete temps[i];
}
ExprPtr Reducer::GenTemporaryExpr(const TypePtr& t, ExprPtr rhs)
{
auto e = make_intrusive<NameExpr>(GenTemporary(t, rhs));
e->SetLocationInfo(rhs->GetLocationInfo());
return e;
}
NameExpr* Reducer::UpdateName(NameExpr* n)
{
if ( NameIsReduced(n) )
{
Ref(n);
return n;
}
return new NameExpr(FindNewLocal(n));
}
bool Reducer::NameIsReduced(const NameExpr* n) const
{
auto id = n->Id();
return inline_block_level == 0 || id->IsGlobal() || IsTemporary(id) ||
IsNewLocal(n);
}
void Reducer::UpdateIDs(IDPList* ids)
{
loop_over_list(*ids, i)
{
IDPtr id = {NewRef{}, (*ids)[i]};
if ( ! ID_IsReduced(id) )
(*ids)[i] = UpdateID(id).release();
}
}
void Reducer::UpdateIDs(std::vector<IDPtr>& ids)
{
for ( auto& id : ids )
if ( ! ID_IsReduced(id) )
id = UpdateID(id);
}
bool Reducer::IDsAreReduced(const IDPList* ids) const
{
for ( auto& id : *ids )
if ( ! ID_IsReduced(id) )
return false;
return true;
}
bool Reducer::IDsAreReduced(const std::vector<IDPtr>& ids) const
{
for ( auto& id : ids )
if ( ! ID_IsReduced(id) )
return false;
return true;
}
IDPtr Reducer::UpdateID(IDPtr id)
{
if ( ID_IsReduced(id) )
return id;
return FindNewLocal(id.get());
}
bool Reducer::ID_IsReduced(const ID* id) const
{
return inline_block_level == 0 || id->IsGlobal() || IsTemporary(id) ||
IsNewLocal(id);
}
NameExprPtr Reducer::GenInlineBlockName(IDPtr id)
{
return make_intrusive<NameExpr>(GenLocal(id.get()));
}
NameExprPtr Reducer::PushInlineBlock(TypePtr type)
{
++inline_block_level;
if ( ! type || type->Tag() == TYPE_VOID )
return nullptr;
char buf[8192];
int n = new_locals.size();
snprintf(buf, sizeof buf, "@retvar");
IDPtr ret_id = install_ID(buf, "<internal>", false, false);
ret_id->SetType(type);
// Track this as a new local *if* we're in the outermost inlining
// block. If we're recursively deeper into inlining, then this
// variable will get mapped to a local anyway, so no need.
if ( inline_block_level == 1 )
new_locals.insert(ret_id.get());
return GenInlineBlockName(ret_id);
}
void Reducer::PopInlineBlock()
{
--inline_block_level;
}
bool Reducer::SameVal(const Val* v1, const Val* v2) const
{
if ( is_atomic_val(v1) )
return same_atomic_val(v1, v2);
else
return v1 == v2;
}
IDPtr Reducer::GenTemporary(const TypePtr& t, ExprPtr rhs)
{
if ( Optimizing() )
reporter->InternalError("Generating a new temporary while optimizing");
auto temp = new TempVar(temps.length(), t, rhs);
IDPtr temp_id = install_ID(temp->Name(), "<internal>", false, false);
temp->SetID(temp_id);
temp_id->SetType(t);
temps.append(temp);
ids_to_temps[temp_id.get()] = temp;
return temp_id;
}
IDPtr Reducer::FindNewLocal(ID* id)
{
auto mapping = orig_to_new_locals.find(id);
if ( mapping != orig_to_new_locals.end() )
return mapping->second;
return GenLocal(id);
}
IDPtr Reducer::GenLocal(ID* orig)
{
if ( Optimizing() )
reporter->InternalError("Generating a new local while optimizing");
char buf[8192];
int n = new_locals.size();
snprintf(buf, sizeof buf, "%s.%d", orig->Name(), n);
IDPtr local_id = install_ID(buf, "<internal>", false, false);
local_id->SetType(orig->GetType());
new_locals.insert(local_id.get());
orig_to_new_locals[orig] = local_id;
return local_id;
}
bool Reducer::IsNewLocal(const ID* id) const
{
ID* non_const_ID = (ID*) id; // I don't get why C++ requires this
return new_locals.count(non_const_ID) != 0;
}
TempVar* Reducer::FindTemporary(const ID* id) const
{
auto tmp = ids_to_temps.find(id);
if ( tmp == ids_to_temps.end() )
return nullptr;
else
return tmp->second;
}
Stmt* Reducer::MergeStmts(const NameExpr* lhs, ExprPtr rhs, Stmt* succ_stmt)
{
// First check for tmp=rhs.
auto lhs_id = lhs->Id();
auto lhs_tmp = FindTemporary(lhs_id);
if ( ! lhs_tmp )
return nullptr;
// We have tmp=rhs. Now look for var=tmp.
if ( succ_stmt->Tag() != STMT_EXPR )
return nullptr;
auto s_e = succ_stmt->AsExprStmt()->StmtExpr();
if ( s_e->Tag() != EXPR_ASSIGN )
return nullptr;
auto a = s_e->AsAssignExpr();
auto a_lhs = a->GetOp1();
auto a_rhs = a->GetOp2();
if ( a_lhs->Tag() != EXPR_REF || a_rhs->Tag() != EXPR_NAME )
// Complex 2nd-statement assignment, or RHS not a candidate.
return nullptr;
auto a_lhs_deref = a_lhs->AsRefExprPtr()->GetOp1();
if ( a_lhs_deref->Tag() != EXPR_NAME )
// Complex 2nd-statement assignment.
return nullptr;
auto a_lhs_var = a_lhs_deref->AsNameExpr()->Id();
auto a_rhs_var = a_rhs->AsNameExpr()->Id();
if ( a_rhs_var != lhs_id )
// 2nd statement is var=something else.
return nullptr;
if ( a_lhs_var->GetType()->Tag() != a_rhs_var->GetType()->Tag() )
// This can happen when we generate an assignment
// specifically to convert to/from an "any" type.
return nullptr;
if ( FindTemporary(a_lhs_var) )
{
// "var" is itself a temporary. Don't complain, as
// complex reductions can generate these. We'll wind
// up folding the chain once it hits a regular variable.
return nullptr;
}
// Got it. Mark the original temporary as no longer relevant.
lhs_tmp->Deactivate();
auto merge_e = make_intrusive<AssignExpr>(a_lhs_deref, rhs, false,
nullptr, nullptr, false);
TrackExprReplacement(rhs.get(), merge_e.get());
return new ExprStmt(merge_e);
}
void Reducer::TrackExprReplacement(const Expr* orig, const Expr* e)
{
new_expr_to_orig[e] = orig;
}
const Expr* non_reduced_perp;
bool checking_reduction;
bool NonReduced(const Expr* perp)
{
if ( checking_reduction )
non_reduced_perp = perp;
return false;
}
} // zeek::detail