class ProgramUsageVisitor : public ProgramVisitor { public:
ProgramUsageVisitor(ProgramUsage* usage, int delta) : fUsage(usage), fDelta(delta) {}
bool visitProgramElement(const ProgramElement& pe) override { if (pe.is<FunctionDefinition>()) { for (const Variable* param : pe.as<FunctionDefinition>().declaration().parameters()) { // Ensure function-parameter variables exist in the variable usage map. They aren't // otherwise declared, but ProgramUsage::get() should be able to find them, even if // they are unread and unwritten.
ProgramUsage::VariableCounts& counts = fUsage->fVariableCounts[param];
counts.fVarExists += fDelta;
this->visitType(param->type());
}
} elseif (pe.is<InterfaceBlock>()) { // Ensure interface-block variables exist in the variable usage map. const Variable* var = pe.as<InterfaceBlock>().var();
fUsage->fVariableCounts[var];
this->visitType(var->type());
} elseif (pe.is<StructDefinition>()) { // Ensure that structs referenced as nested types in other structs are counted as used.
this->visitStructFields(pe.as<StructDefinition>().type());
} return INHERITED::visitProgramElement(pe);
}
bool visitStatement(const Statement& s) override { if (s.is<VarDeclaration>()) { // Add all declared variables to the usage map (even if never otherwise accessed). const VarDeclaration& vd = s.as<VarDeclaration>(); const Variable* var = vd.var();
ProgramUsage::VariableCounts& counts = fUsage->fVariableCounts[var];
counts.fVarExists += fDelta;
SkASSERT(counts.fVarExists >= 0 && counts.fVarExists <= 1); if (vd.value()) { // The initial-value expression, when present, counts as a write.
counts.fWrite += fDelta;
}
this->visitType(var->type());
} return INHERITED::visitStatement(s);
}
for (const Module* m = &module; m != nullptr; m = m->fParent) { for (const std::unique_ptr<ProgramElement>& element : m->fElements) {
addRefs.visitProgramElement(*element);
}
} return usage;
}
staticbool contains_matching_data(const ProgramUsage& a, const ProgramUsage& b) {
constexpr bool kReportMismatch = false;
for (constauto& [varA, varCountA] : a.fVariableCounts) { // Skip variable entries with zero reported usage. if (!varCountA.fVarExists && !varCountA.fRead && !varCountA.fWrite) { continue;
} // Find the matching variable in the other map and ensure that its counts match. const ProgramUsage::VariableCounts* varCountB = b.fVariableCounts.find(varA); if (!varCountB || 0 != memcmp(&varCountA, varCountB, sizeof(varCountA))) { if constexpr (kReportMismatch) {
SkDebugf("VariableCounts mismatch: '%.*s' (E%d R%d W%d != E%d R%d W%d)\n",
(int)varA->name().size(), varA->name().data(),
varCountA.fVarExists,
varCountA.fRead,
varCountA.fWrite,
varCountB ? varCountB->fVarExists : 0,
varCountB ? varCountB->fRead : 0,
varCountB ? varCountB->fWrite : 0);
} returnfalse;
}
}
for (constauto& [callA, callCountA] : a.fCallCounts) { // Skip function-call entries with zero reported usage. if (!callCountA) { continue;
} // Find the matching function in the other map and ensure that its call-count matches. constint* callCountB = b.fCallCounts.find(callA); if (!callCountB || callCountA != *callCountB) { if constexpr (kReportMismatch) {
SkDebugf("CallCounts mismatch: '%.*s' (%d != %d)\n",
(int)callA->name().size(), callA->name().data(),
callCountA,
callCountB ? *callCountB : 0);
} returnfalse;
}
}
for (constauto& [structA, structCountA] : a.fStructCounts) { // Skip struct entries with zero reported usage. if (!structCountA) { continue;
} // Find the matching struct in the other map and ensure that its usage-count matches. constint* structCountB = b.fStructCounts.find(structA); if (!structCountB || structCountA != *structCountB) { if constexpr (kReportMismatch) {
SkDebugf("StructCounts mismatch: '%.*s' (%d != %d)\n",
(int)structA->name().size(), structA->name().data(),
structCountA,
structCountB ? *structCountB : 0);
} returnfalse;
}
}
// Every non-zero entry in A has a matching non-zero entry in B. returntrue;
}
bool ProgramUsage::operator==(const ProgramUsage& that) const { // ProgramUsage can be "equal" while the underlying hash maps look slightly different, because a // dead-stripped variable or function will have a usage count of zero, but will still exist in // the maps. If the program usage is re-analyzed from scratch, the maps will not contain an // entry for these variables or functions at all. This means our maps can be "equal" while // having different element counts. // // In order to check these maps, we compare map entries bi-directionally, skipping zero-usage // entries. If all the non-zero elements in `this` match the elements in `that`, and all the // non-zero elements in `that` match the elements in `this`, all the non-zero elements must be // identical, and all the zero elements must be either zero or non-existent on both sides. return contains_matching_data(*this, that) &&
contains_matching_data(that, *this);
}
} // namespace SkSL
Messung V0.5
¤ Dauer der Verarbeitung: 0.41 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.