Skip to content

Commit 39a8d02

Browse files
author
Your Name
committed
Use a function to cache
1 parent 4d6070c commit 39a8d02

2 files changed

Lines changed: 48 additions & 45 deletions

File tree

lib/programmemory.cpp

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

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)
347+
// findChanged: optional cached findExpressionChanged (see ProgramMemoryState::FindChangedFn).
348+
static void programMemoryParseCondition(ProgramMemory& pm, const Token* tok, const Token* endTok, const Settings& settings, bool then, const ProgramMemoryState::FindChangedFn& findChanged = {})
361349
{
362350
auto eval = [&](const Token* t) -> std::vector<MathLib::bigint> {
363351
if (!t)
@@ -371,6 +359,10 @@ static void programMemoryParseCondition(ProgramMemory& pm, const Token* tok, con
371359
return {result};
372360
return std::vector<MathLib::bigint>{};
373361
};
362+
// Use the cached closure if given, else compute directly.
363+
auto changed = [&](const Token* e, const Token* s, const Token* en) -> const Token* {
364+
return findChanged ? findChanged(e, s, en) : findExpressionChanged(e, s, en, settings);
365+
};
374366
if (Token::Match(tok, "==|>=|<=|<|>|!=")) {
375367
ValueFlow::Value truevalue;
376368
ValueFlow::Value falsevalue;
@@ -381,7 +373,7 @@ static void programMemoryParseCondition(ProgramMemory& pm, const Token* tok, con
381373
return;
382374
if (!truevalue.isIntValue())
383375
return;
384-
if (endTok && cachedFindExpressionChanged(cache, vartok, tok->next(), endTok, settings))
376+
if (endTok && changed(vartok, tok->next(), endTok))
385377
return;
386378
const bool impossible = (tok->str() == "==" && !then) || (tok->str() == "!=" && then);
387379
const ValueFlow::Value& v = then ? truevalue : falsevalue;
@@ -390,26 +382,26 @@ static void programMemoryParseCondition(ProgramMemory& pm, const Token* tok, con
390382
if (containerTok)
391383
pm.setContainerSizeValue(containerTok, v.intvalue, !impossible);
392384
} else if (Token::simpleMatch(tok, "!")) {
393-
programMemoryParseCondition(pm, tok->astOperand1(), endTok, settings, !then, cache);
385+
programMemoryParseCondition(pm, tok->astOperand1(), endTok, settings, !then, findChanged);
394386
} else if (then && Token::simpleMatch(tok, "&&")) {
395-
programMemoryParseCondition(pm, tok->astOperand1(), endTok, settings, then, cache);
396-
programMemoryParseCondition(pm, tok->astOperand2(), endTok, settings, then, cache);
387+
programMemoryParseCondition(pm, tok->astOperand1(), endTok, settings, then, findChanged);
388+
programMemoryParseCondition(pm, tok->astOperand2(), endTok, settings, then, findChanged);
397389
} else if (!then && Token::simpleMatch(tok, "||")) {
398-
programMemoryParseCondition(pm, tok->astOperand1(), endTok, settings, then, cache);
399-
programMemoryParseCondition(pm, tok->astOperand2(), endTok, settings, then, cache);
390+
programMemoryParseCondition(pm, tok->astOperand1(), endTok, settings, then, findChanged);
391+
programMemoryParseCondition(pm, tok->astOperand2(), endTok, settings, then, findChanged);
400392
} else if (Token::Match(tok, "&&|%oror%")) {
401393
std::vector<MathLib::bigint> lhs = eval(tok->astOperand1());
402394
std::vector<MathLib::bigint> rhs = eval(tok->astOperand2());
403395
if (lhs.empty() || rhs.empty()) {
404396
if (frontIs(lhs, !then))
405-
programMemoryParseCondition(pm, tok->astOperand2(), endTok, settings, then, cache);
397+
programMemoryParseCondition(pm, tok->astOperand2(), endTok, settings, then, findChanged);
406398
else if (frontIs(rhs, !then))
407-
programMemoryParseCondition(pm, tok->astOperand1(), endTok, settings, then, cache);
399+
programMemoryParseCondition(pm, tok->astOperand1(), endTok, settings, then, findChanged);
408400
else
409401
pm.setIntValue(tok, 0, then);
410402
}
411403
} else if (tok && tok->exprId() > 0) {
412-
if (endTok && cachedFindExpressionChanged(cache, tok, tok->next(), endTok, settings))
404+
if (endTok && changed(tok, tok->next(), endTok))
413405
return;
414406
pm.setIntValue(tok, 0, then);
415407
const Token* containerTok = settings.library.getContainerFromYield(tok, Library::Container::Yield::EMPTY);
@@ -418,14 +410,14 @@ static void programMemoryParseCondition(ProgramMemory& pm, const Token* tok, con
418410
}
419411
}
420412

421-
static void fillProgramMemoryFromConditions(ProgramMemory& pm, const Scope* scope, const Token* endTok, const Settings& settings, ProgramMemoryState::ChangedCache* cache)
413+
static void fillProgramMemoryFromConditions(ProgramMemory& pm, const Scope* scope, const Token* endTok, const Settings& settings, const ProgramMemoryState::FindChangedFn& findChanged)
422414
{
423415
if (!scope)
424416
return;
425417
if (!scope->isLocal())
426418
return;
427419
assert(scope != scope->nestedIn);
428-
fillProgramMemoryFromConditions(pm, scope->nestedIn, endTok, settings, cache);
420+
fillProgramMemoryFromConditions(pm, scope->nestedIn, endTok, settings, findChanged);
429421
if (scope->type == ScopeType::eIf || scope->type == ScopeType::eWhile || scope->type == ScopeType::eElse || scope->type == ScopeType::eFor) {
430422
const Token* condTok = getCondTokFromEnd(scope->bodyEnd);
431423
if (!condTok)
@@ -434,13 +426,13 @@ static void fillProgramMemoryFromConditions(ProgramMemory& pm, const Scope* scop
434426
bool error = false;
435427
execute(condTok, pm, &result, &error, settings);
436428
if (error)
437-
programMemoryParseCondition(pm, condTok, endTok, settings, scope->type != ScopeType::eElse, cache);
429+
programMemoryParseCondition(pm, condTok, endTok, settings, scope->type != ScopeType::eElse, findChanged);
438430
}
439431
}
440432

441-
static void fillProgramMemoryFromConditions(ProgramMemory& pm, const Token* tok, const Settings& settings, ProgramMemoryState::ChangedCache* cache = nullptr)
433+
static void fillProgramMemoryFromConditions(ProgramMemory& pm, const Token* tok, const Settings& settings, const ProgramMemoryState::FindChangedFn& findChanged = {})
442434
{
443-
fillProgramMemoryFromConditions(pm, tok->scope(), tok, settings, cache);
435+
fillProgramMemoryFromConditions(pm, tok->scope(), tok, settings, findChanged);
444436
}
445437

446438
static void fillProgramMemoryFromAssignments(ProgramMemory& pm, const Token* tok, const Settings& settings, const ProgramMemory& state, const ProgramMemory::Map& vars)
@@ -549,7 +541,7 @@ void ProgramMemoryState::addState(const Token* tok, const ProgramMemory::Map& va
549541
{
550542
ProgramMemory local = state;
551543
addVars(local, vars);
552-
fillProgramMemoryFromConditions(local, tok, settings, changedCache.get());
544+
fillProgramMemoryFromConditions(local, tok, settings, getCachedFindExpressionChanged(/*skipDeadCode*/ false));
553545
ProgramMemory pm;
554546
fillProgramMemoryFromAssignments(pm, tok, settings, local, vars);
555547
local.replace(std::move(pm));
@@ -577,29 +569,38 @@ void ProgramMemoryState::assume(const Token* tok, bool b, bool isEmpty, const To
577569
replace(std::move(pm), origin);
578570
}
579571

580-
const Token* ProgramMemoryState::findExpressionChanged(const Token* expr, const Token* start, const Token* tok) const
572+
ProgramMemoryState::FindChangedFn ProgramMemoryState::getCachedFindExpressionChanged(bool skipDeadCode) const
581573
{
582-
// Memoized structural pre-filter (a superset) gates the expensive dead-code-aware walk.
583-
if (!cachedFindExpressionChanged(changedCache.get(), expr, start, tok, settings))
584-
return nullptr;
585-
auto eval = [&](const Token* cond) -> std::vector<MathLib::bigint> {
586-
ProgramMemory pm2 = state;
587-
const auto result = execute(cond, pm2, settings);
588-
if (isTrue(result))
589-
return {1};
590-
if (isFalse(result))
591-
return {0};
592-
return {};
574+
// The structural findExpressionChanged() is pure, so memoize it in changedCache (never
575+
// invalidated). skipDeadCode gates it as a pre-filter for the dead-code walk, which needs state.
576+
return [cache = changedCache, sp = &settings, statePtr = &state, skipDeadCode](const Token* expr, const Token* start, const Token* end) -> const Token* {
577+
const auto key = std::make_tuple(expr, start, end);
578+
const auto it = cache->find(key);
579+
const Token* modified = (it != cache->end())
580+
? it->second
581+
: cache->emplace(key, findExpressionChanged(expr, start, end, *sp)).first->second;
582+
if (!skipDeadCode || !modified)
583+
return modified;
584+
auto eval = [&](const Token* cond) -> std::vector<MathLib::bigint> {
585+
ProgramMemory pm2 = *statePtr;
586+
const auto result = execute(cond, pm2, *sp);
587+
if (isTrue(result))
588+
return {1};
589+
if (isFalse(result))
590+
return {0};
591+
return {};
592+
};
593+
return findExpressionChangedSkipDeadCode(expr, start, end, *sp, eval);
593594
};
594-
return ::findExpressionChangedSkipDeadCode(expr, start, tok, settings, eval);
595595
}
596596

597597
void ProgramMemoryState::removeModifiedVars(const Token* tok)
598598
{
599+
const auto findChanged = getCachedFindExpressionChanged(/*skipDeadCode*/ true);
599600
state.erase_if([&](const ExprIdToken& e) {
600601
const Token* start = origins[e.getExpressionId()];
601602
const Token* expr = e.tok;
602-
const bool changed = !expr || findExpressionChanged(expr, start, tok);
603+
const bool changed = !expr || findChanged(expr, start, tok);
603604
if (changed)
604605
origins.erase(e.getExpressionId());
605606
return changed;

lib/programmemory.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,8 @@ struct CPPCHECKLIB ProgramMemory {
163163

164164
struct ProgramMemoryState {
165165
using ChangedCache = std::map<std::tuple<const Token*, const Token*, const Token*>, const Token*>;
166+
// The token modifying expr between start and end, or nullptr.
167+
using FindChangedFn = std::function<const Token*(const Token* expr, const Token* start, const Token* end)>;
166168

167169
ProgramMemory state;
168170
std::map<nonneg int, const Token*> origins;
@@ -180,8 +182,8 @@ struct ProgramMemoryState {
180182

181183
void removeModifiedVars(const Token* tok);
182184

183-
// Token modifying expr between start and tok, or nullptr.
184-
const Token* findExpressionChanged(const Token* expr, const Token* start, const Token* tok) const;
185+
// A findExpressionChanged() closure memoized in changedCache
186+
FindChangedFn getCachedFindExpressionChanged(bool skipDeadCode) const;
185187

186188
ProgramMemory get(const Token* tok, const Token* ctx, const ProgramMemory::Map& vars) const;
187189
};

0 commit comments

Comments
 (0)