Skip to content

Commit 4d6070c

Browse files
author
Your Name
committed
Use the cache in fillProgramMemoryFromConditions
1 parent d86eea6 commit 4d6070c

1 file changed

Lines changed: 30 additions & 21 deletions

File tree

lib/programmemory.cpp

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,20 @@ static bool isBasicForLoop(const Token* tok)
344344
return true;
345345
}
346346

347-
static void programMemoryParseCondition(ProgramMemory& pm, const Token* tok, const Token* endTok, const Settings& settings, bool then)
347+
// findExpressionChanged() is a pure structural query, so memoize it via the program-state cache,
348+
// keyed by (expr, start, end). This dominates the cost of building program memory from conditions.
349+
static const Token* cachedFindExpressionChanged(ProgramMemoryState::ChangedCache* cache, const Token* expr, const Token* start, const Token* end, const Settings& settings)
350+
{
351+
if (!cache)
352+
return findExpressionChanged(expr, start, end, settings);
353+
const auto key = std::make_tuple(expr, start, end);
354+
const auto it = cache->find(key);
355+
if (it != cache->end())
356+
return it->second;
357+
return cache->emplace(key, findExpressionChanged(expr, start, end, settings)).first->second;
358+
}
359+
360+
static void programMemoryParseCondition(ProgramMemory& pm, const Token* tok, const Token* endTok, const Settings& settings, bool then, ProgramMemoryState::ChangedCache* cache = nullptr)
348361
{
349362
auto eval = [&](const Token* t) -> std::vector<MathLib::bigint> {
350363
if (!t)
@@ -368,7 +381,7 @@ static void programMemoryParseCondition(ProgramMemory& pm, const Token* tok, con
368381
return;
369382
if (!truevalue.isIntValue())
370383
return;
371-
if (endTok && findExpressionChanged(vartok, tok->next(), endTok, settings))
384+
if (endTok && cachedFindExpressionChanged(cache, vartok, tok->next(), endTok, settings))
372385
return;
373386
const bool impossible = (tok->str() == "==" && !then) || (tok->str() == "!=" && then);
374387
const ValueFlow::Value& v = then ? truevalue : falsevalue;
@@ -377,26 +390,26 @@ static void programMemoryParseCondition(ProgramMemory& pm, const Token* tok, con
377390
if (containerTok)
378391
pm.setContainerSizeValue(containerTok, v.intvalue, !impossible);
379392
} else if (Token::simpleMatch(tok, "!")) {
380-
programMemoryParseCondition(pm, tok->astOperand1(), endTok, settings, !then);
393+
programMemoryParseCondition(pm, tok->astOperand1(), endTok, settings, !then, cache);
381394
} else if (then && Token::simpleMatch(tok, "&&")) {
382-
programMemoryParseCondition(pm, tok->astOperand1(), endTok, settings, then);
383-
programMemoryParseCondition(pm, tok->astOperand2(), endTok, settings, then);
395+
programMemoryParseCondition(pm, tok->astOperand1(), endTok, settings, then, cache);
396+
programMemoryParseCondition(pm, tok->astOperand2(), endTok, settings, then, cache);
384397
} else if (!then && Token::simpleMatch(tok, "||")) {
385-
programMemoryParseCondition(pm, tok->astOperand1(), endTok, settings, then);
386-
programMemoryParseCondition(pm, tok->astOperand2(), endTok, settings, then);
398+
programMemoryParseCondition(pm, tok->astOperand1(), endTok, settings, then, cache);
399+
programMemoryParseCondition(pm, tok->astOperand2(), endTok, settings, then, cache);
387400
} else if (Token::Match(tok, "&&|%oror%")) {
388401
std::vector<MathLib::bigint> lhs = eval(tok->astOperand1());
389402
std::vector<MathLib::bigint> rhs = eval(tok->astOperand2());
390403
if (lhs.empty() || rhs.empty()) {
391404
if (frontIs(lhs, !then))
392-
programMemoryParseCondition(pm, tok->astOperand2(), endTok, settings, then);
405+
programMemoryParseCondition(pm, tok->astOperand2(), endTok, settings, then, cache);
393406
else if (frontIs(rhs, !then))
394-
programMemoryParseCondition(pm, tok->astOperand1(), endTok, settings, then);
407+
programMemoryParseCondition(pm, tok->astOperand1(), endTok, settings, then, cache);
395408
else
396409
pm.setIntValue(tok, 0, then);
397410
}
398411
} else if (tok && tok->exprId() > 0) {
399-
if (endTok && findExpressionChanged(tok, tok->next(), endTok, settings))
412+
if (endTok && cachedFindExpressionChanged(cache, tok, tok->next(), endTok, settings))
400413
return;
401414
pm.setIntValue(tok, 0, then);
402415
const Token* containerTok = settings.library.getContainerFromYield(tok, Library::Container::Yield::EMPTY);
@@ -405,14 +418,14 @@ static void programMemoryParseCondition(ProgramMemory& pm, const Token* tok, con
405418
}
406419
}
407420

408-
static void fillProgramMemoryFromConditions(ProgramMemory& pm, const Scope* scope, const Token* endTok, const Settings& settings)
421+
static void fillProgramMemoryFromConditions(ProgramMemory& pm, const Scope* scope, const Token* endTok, const Settings& settings, ProgramMemoryState::ChangedCache* cache)
409422
{
410423
if (!scope)
411424
return;
412425
if (!scope->isLocal())
413426
return;
414427
assert(scope != scope->nestedIn);
415-
fillProgramMemoryFromConditions(pm, scope->nestedIn, endTok, settings);
428+
fillProgramMemoryFromConditions(pm, scope->nestedIn, endTok, settings, cache);
416429
if (scope->type == ScopeType::eIf || scope->type == ScopeType::eWhile || scope->type == ScopeType::eElse || scope->type == ScopeType::eFor) {
417430
const Token* condTok = getCondTokFromEnd(scope->bodyEnd);
418431
if (!condTok)
@@ -421,13 +434,13 @@ static void fillProgramMemoryFromConditions(ProgramMemory& pm, const Scope* scop
421434
bool error = false;
422435
execute(condTok, pm, &result, &error, settings);
423436
if (error)
424-
programMemoryParseCondition(pm, condTok, endTok, settings, scope->type != ScopeType::eElse);
437+
programMemoryParseCondition(pm, condTok, endTok, settings, scope->type != ScopeType::eElse, cache);
425438
}
426439
}
427440

428-
static void fillProgramMemoryFromConditions(ProgramMemory& pm, const Token* tok, const Settings& settings)
441+
static void fillProgramMemoryFromConditions(ProgramMemory& pm, const Token* tok, const Settings& settings, ProgramMemoryState::ChangedCache* cache = nullptr)
429442
{
430-
fillProgramMemoryFromConditions(pm, tok->scope(), tok, settings);
443+
fillProgramMemoryFromConditions(pm, tok->scope(), tok, settings, cache);
431444
}
432445

433446
static void fillProgramMemoryFromAssignments(ProgramMemory& pm, const Token* tok, const Settings& settings, const ProgramMemory& state, const ProgramMemory::Map& vars)
@@ -536,7 +549,7 @@ void ProgramMemoryState::addState(const Token* tok, const ProgramMemory::Map& va
536549
{
537550
ProgramMemory local = state;
538551
addVars(local, vars);
539-
fillProgramMemoryFromConditions(local, tok, settings);
552+
fillProgramMemoryFromConditions(local, tok, settings, changedCache.get());
540553
ProgramMemory pm;
541554
fillProgramMemoryFromAssignments(pm, tok, settings, local, vars);
542555
local.replace(std::move(pm));
@@ -567,11 +580,7 @@ void ProgramMemoryState::assume(const Token* tok, bool b, bool isEmpty, const To
567580
const Token* ProgramMemoryState::findExpressionChanged(const Token* expr, const Token* start, const Token* tok) const
568581
{
569582
// Memoized structural pre-filter (a superset) gates the expensive dead-code-aware walk.
570-
const auto key = std::make_tuple(expr, start, tok);
571-
auto it = changedCache->find(key);
572-
if (it == changedCache->end())
573-
it = changedCache->emplace(key, ::findExpressionChanged(expr, start, tok, settings)).first;
574-
if (!it->second)
583+
if (!cachedFindExpressionChanged(changedCache.get(), expr, start, tok, settings))
575584
return nullptr;
576585
auto eval = [&](const Token* cond) -> std::vector<MathLib::bigint> {
577586
ProgramMemory pm2 = state;

0 commit comments

Comments
 (0)