Skip to content

Commit a586558

Browse files
authored
Deserialization for LLVMBasedICFG (#617)
* Fix fromMetaDataId + add deserialization support for LLVMBasedICFG * pre-commit * Remove out-commented code
1 parent d7cb8ea commit a586558

File tree

11 files changed

+269
-27
lines changed

11 files changed

+269
-27
lines changed

include/phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,9 @@ class LLVMBasedICFG : public LLVMBasedCFG, public ICFGBase<LLVMBasedICFG> {
8989
Soundness S = Soundness::Soundy,
9090
bool IncludeGlobals = true);
9191

92+
explicit LLVMBasedICFG(LLVMProjectIRDB *IRDB,
93+
const nlohmann::json &SerializedCG);
94+
9295
~LLVMBasedICFG();
9396

9497
LLVMBasedICFG(const LLVMBasedICFG &) = delete;

include/phasar/PhasarLLVM/HelperAnalyses.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ class HelperAnalyses { // NOLINT(cppcoreguidelines-special-member-functions)
3333
std::optional<nlohmann::json> PrecomputedPTS,
3434
AliasAnalysisType PTATy, bool AllowLazyPTS,
3535
std::vector<std::string> EntryPoints,
36+
std::optional<nlohmann::json> PrecomputedCG,
3637
CallGraphAnalysisType CGTy, Soundness SoundnessLevel,
3738
bool AutoGlobalSupport) noexcept;
3839

@@ -69,6 +70,7 @@ class HelperAnalyses { // NOLINT(cppcoreguidelines-special-member-functions)
6970
bool AllowLazyPTS{};
7071

7172
// ICF
73+
std::optional<nlohmann::json> PrecomputedCG;
7274
std::vector<std::string> EntryPoints;
7375
CallGraphAnalysisType CGTy{};
7476
Soundness SoundnessLevel{};

include/phasar/PhasarLLVM/HelperAnalysisConfig.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
namespace psr {
2222
struct HelperAnalysisConfig {
2323
std::optional<nlohmann::json> PrecomputedPTS = std::nullopt;
24+
std::optional<nlohmann::json> PrecomputedCG = std::nullopt;
2425
AliasAnalysisType PTATy = AliasAnalysisType::CFLAnders;
2526
CallGraphAnalysisType CGTy = CallGraphAnalysisType::OTF;
2627
Soundness SoundnessLevel = Soundness::Soundy;

lib/Controller/AnalysisController.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#include "phasar/Controller/AnalysisController.h"
1111

12+
#include "phasar//Utils/NlohmannLogging.h"
1213
#include "phasar/AnalysisStrategy/Strategies.h"
1314
#include "phasar/Controller/AnalysisControllerEmitterOptions.h"
1415
#include "phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h"
@@ -184,6 +185,10 @@ void AnalysisController::emitRequestedHelperAnalysisResults() {
184185
WithResultFileOrStdout("/psr-cg.txt",
185186
[this](auto &OS) { HA.getICFG().print(OS); });
186187
}
188+
if (EmitterOptions & AnalysisControllerEmitterOptions::EmitCGAsJson) {
189+
WithResultFileOrStdout(
190+
"/psr-cg.json", [this](auto &OS) { OS << HA.getICFG().getAsJson(); });
191+
}
187192

188193
if (EmitterOptions &
189194
(AnalysisControllerEmitterOptions::EmitStatisticsAsJson |

lib/PhasarLLVM/ControlFlow/LLVMBasedICFG.cpp

Lines changed: 52 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -366,9 +366,8 @@ LLVMBasedICFG::LLVMBasedICFG(LLVMProjectIRDB *IRDB,
366366
llvm::ArrayRef<std::string> EntryPoints,
367367
LLVMTypeHierarchy *TH, LLVMAliasInfoRef PT,
368368
Soundness S, bool IncludeGlobals)
369-
: TH(TH) {
369+
: IRDB(IRDB), TH(TH) {
370370
assert(IRDB != nullptr);
371-
this->IRDB = IRDB;
372371

373372
Builder B{IRDB, this, PT};
374373
LLVMAliasInfo PTOwn;
@@ -398,6 +397,52 @@ LLVMBasedICFG::LLVMBasedICFG(LLVMProjectIRDB *IRDB,
398397
<< std::chrono::steady_clock::now().time_since_epoch().count());
399398
}
400399

400+
LLVMBasedICFG::LLVMBasedICFG(LLVMProjectIRDB *IRDB,
401+
const nlohmann::json &SerializedCG)
402+
: IRDB(IRDB) {
403+
assert(IRDB != nullptr);
404+
405+
PHASAR_LOG_LEVEL_CAT(DEBUG, "LLVMBasedICFG",
406+
"Load precomputed call-graph from JSON");
407+
408+
auto It = SerializedCG.find(PhasarConfig::JsonCallGraphID().str());
409+
410+
if (It == SerializedCG.end()) {
411+
PHASAR_LOG_LEVEL_CAT(ERROR, "LLVMBasedICFG",
412+
"Cannot deserialize call-graph from JSON: No key '"
413+
<< PhasarConfig::JsonCallGraphID() << "' present");
414+
return;
415+
}
416+
417+
const auto &Edges = It.value();
418+
419+
CallersOf.reserve(Edges.size());
420+
CalleesAt.reserve(Edges.size());
421+
VertexFunctions.reserve(Edges.size());
422+
423+
for (const auto &[FunName, CallerIDs] : Edges.items()) {
424+
const auto *Fun = IRDB->getFunction(FunName);
425+
if (!Fun) {
426+
PHASAR_LOG_LEVEL_CAT(WARNING, "LLVMBasedICFG",
427+
"Invalid function name: " << FunName);
428+
continue;
429+
}
430+
auto *CEdges = addFunctionVertex(Fun);
431+
CEdges->reserve(CallerIDs.size());
432+
433+
for (const auto &JId : CallerIDs) {
434+
auto Id = JId.get<size_t>();
435+
const auto *CS = IRDB->getInstruction(Id);
436+
if (!CS) {
437+
PHASAR_LOG_LEVEL_CAT(WARNING, "LLVMBasedICFG",
438+
"Invalid CAll-Instruction Id: " << Id);
439+
}
440+
441+
addCallEdge(CS, Fun);
442+
}
443+
}
444+
}
445+
401446
LLVMBasedICFG::~LLVMBasedICFG() = default;
402447

403448
[[nodiscard]] FunctionRange LLVMBasedICFG::getAllFunctionsImpl() const {
@@ -504,22 +549,12 @@ void LLVMBasedICFG::printImpl(llvm::raw_ostream &OS) const {
504549
[[nodiscard]] nlohmann::json LLVMBasedICFG::getAsJsonImpl() const {
505550
nlohmann::json J;
506551

507-
for (size_t Vtx = 0, VtxEnd = VertexFunctions.size(); Vtx != VtxEnd; ++Vtx) {
508-
auto VtxFunName = VertexFunctions[Vtx]->getName().str();
509-
J[PhasarConfig::JsonCallGraphID().str()][VtxFunName] =
510-
nlohmann::json::array();
511-
512-
for (const auto &Inst : llvm::instructions(VertexFunctions[Vtx])) {
513-
if (!llvm::isa<llvm::CallBase>(Inst)) {
514-
continue;
515-
}
552+
auto &Edges = J[PhasarConfig::JsonCallGraphID().str()];
553+
for (const auto &[Fun, Callers] : CallersOf) {
554+
auto &JCallers = Edges[Fun->getName().str()];
516555

517-
if (auto It = CalleesAt.find(&Inst); It != CalleesAt.end()) {
518-
for (const auto *Succ : *It->second) {
519-
J[PhasarConfig::JsonCallGraphID().str()][VtxFunName].push_back(
520-
Succ->getName().str());
521-
}
522-
}
556+
for (const auto *CS : *Callers) {
557+
JCallers.push_back(IRDB->getInstructionId(CS));
523558
}
524559
}
525560

lib/PhasarLLVM/DB/LLVMProjectIRDB.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,5 +260,5 @@ const llvm::Value *psr::fromMetaDataId(const LLVMProjectIRDB &IRDB,
260260
}
261261

262262
auto IdNr = ParseInt(Id);
263-
return IdNr ? IRDB.getInstruction(*IdNr) : nullptr;
263+
return IdNr ? IRDB.getValueFromId(*IdNr) : nullptr;
264264
}

lib/PhasarLLVM/HelperAnalyses.cpp

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,13 @@ HelperAnalyses::HelperAnalyses(std::string IRFile,
1313
std::optional<nlohmann::json> PrecomputedPTS,
1414
AliasAnalysisType PTATy, bool AllowLazyPTS,
1515
std::vector<std::string> EntryPoints,
16+
std::optional<nlohmann::json> PrecomputedCG,
1617
CallGraphAnalysisType CGTy,
1718
Soundness SoundnessLevel,
1819
bool AutoGlobalSupport) noexcept
1920
: IRFile(std::move(IRFile)), PrecomputedPTS(std::move(PrecomputedPTS)),
2021
PTATy(PTATy), AllowLazyPTS(AllowLazyPTS),
22+
PrecomputedCG(std::move(PrecomputedCG)),
2123
EntryPoints(std::move(EntryPoints)), CGTy(CGTy),
2224
SoundnessLevel(SoundnessLevel), AutoGlobalSupport(AutoGlobalSupport) {}
2325

@@ -26,8 +28,10 @@ HelperAnalyses::HelperAnalyses(std::string IRFile,
2628
HelperAnalysisConfig Config) noexcept
2729
: IRFile(std::move(IRFile)),
2830
PrecomputedPTS(std::move(Config.PrecomputedPTS)), PTATy(Config.PTATy),
29-
AllowLazyPTS(Config.AllowLazyPTS), EntryPoints(std::move(EntryPoints)),
30-
CGTy(Config.CGTy), SoundnessLevel(Config.SoundnessLevel),
31+
AllowLazyPTS(Config.AllowLazyPTS),
32+
PrecomputedCG(std::move(Config.PrecomputedCG)),
33+
EntryPoints(std::move(EntryPoints)), CGTy(Config.CGTy),
34+
SoundnessLevel(Config.SoundnessLevel),
3135
AutoGlobalSupport(Config.AutoGlobalSupport) {}
3236

3337
HelperAnalyses::HelperAnalyses(const llvm::Twine &IRFile,
@@ -70,10 +74,14 @@ LLVMTypeHierarchy &HelperAnalyses::getTypeHierarchy() {
7074

7175
LLVMBasedICFG &HelperAnalyses::getICFG() {
7276
if (!ICF) {
73-
ICF = std::make_unique<LLVMBasedICFG>(
74-
&getProjectIRDB(), CGTy, std::move(EntryPoints), &getTypeHierarchy(),
75-
CGTy == CallGraphAnalysisType::OTF ? &getAliasInfo() : nullptr,
76-
SoundnessLevel, AutoGlobalSupport);
77+
if (PrecomputedCG.has_value()) {
78+
ICF = std::make_unique<LLVMBasedICFG>(&getProjectIRDB(), *PrecomputedCG);
79+
} else {
80+
ICF = std::make_unique<LLVMBasedICFG>(
81+
&getProjectIRDB(), CGTy, std::move(EntryPoints), &getTypeHierarchy(),
82+
CGTy == CallGraphAnalysisType::OTF ? &getAliasInfo() : nullptr,
83+
SoundnessLevel, AutoGlobalSupport);
84+
}
7785
}
7886

7987
return *ICF;

lib/PhasarLLVM/Pointer/LLVMAliasSet.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,8 @@ LLVMAliasSet::LLVMAliasSet(LLVMProjectIRDB *IRDB,
100100
assert(IRDB != nullptr);
101101
// Assume, we already have validated the json schema
102102

103-
llvm::outs() << "Load precomputed points-to info from JSON\n";
103+
PHASAR_LOG_LEVEL_CAT(DEBUG, "LLVMAliasSet",
104+
"Load precomputed points-to info from JSON");
104105

105106
const auto &Sets = SerializedPTS.at("AliasSets");
106107
assert(Sets.is_array());

tools/phasar-cli/phasar-cli.cpp

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,6 @@ cl::opt<std::string>
169169

170170
cl::opt<std::string> ProjectIdOpt("project-id",
171171
cl::desc("Project id used for output"),
172-
cl::init("default-phasar-project"),
173172
cl::cat(PsrCat), cl::Hidden);
174173

175174
PSR_SHORTLONG_OPTION(OutDirOpt, std::string, "O", "out",
@@ -233,6 +232,12 @@ cl::opt<std::string>
233232
"via emit-pta-as-json from the given file"),
234233
cl::cat(PsrCat));
235234

235+
cl::opt<std::string> LoadCGFromJsonOpt(
236+
"load-cg-from-json",
237+
cl::desc("Load the persisted call-graph previously exported via "
238+
"emit-cg-as-json from the given file"),
239+
cl::cat(PsrCat));
240+
236241
PSR_SHORTLONG_OPTION(PammOutOpt, std::string, "A", "pamm-out",
237242
"Filename for PAMM's gathered data",
238243
cl::init("PAMM_data.json"), cl::cat(PsrCat), cl::Hidden);
@@ -344,6 +349,15 @@ int main(int Argc, const char **Argv) {
344349
return 1;
345350
}
346351

352+
if (ProjectIdOpt.empty()) {
353+
ProjectIdOpt = std::filesystem::path(ModuleOpt.getValue())
354+
.filename()
355+
.replace_extension();
356+
if (ProjectIdOpt.empty()) {
357+
ProjectIdOpt = "default-phasar-project";
358+
}
359+
}
360+
347361
validateParamModule();
348362
validateParamOutput();
349363
validateParamPointerAnalysis();
@@ -385,6 +399,15 @@ int main(int Argc, const char **Argv) {
385399
if (EmitCGAsDotOpt) {
386400
EmitterOptions |= AnalysisControllerEmitterOptions::EmitCGAsDot;
387401
}
402+
if (EmitCGAsJsonOpt) {
403+
EmitterOptions |= AnalysisControllerEmitterOptions::EmitCGAsJson;
404+
}
405+
if (EmitCGAsTextOpt) {
406+
llvm::errs()
407+
<< "ERROR: emit-cg-as-text is currently not supported. Did you mean "
408+
"emit-cg-as-dot? For reversible serialization use emit-cg-as-json\n";
409+
return 1;
410+
}
388411
if (EmitPTAAsTextOpt) {
389412
EmitterOptions |= AnalysisControllerEmitterOptions::EmitPTAAsText;
390413
}
@@ -410,9 +433,16 @@ int main(int Argc, const char **Argv) {
410433

411434
std::optional<nlohmann::json> PrecomputedAliasSet;
412435
if (!LoadPTAFromJsonOpt.empty()) {
436+
PHASAR_LOG_LEVEL(INFO, "Load AliasInfo from file: " << LoadCGFromJsonOpt);
413437
PrecomputedAliasSet = readJsonFile(LoadPTAFromJsonOpt);
414438
}
415439

440+
std::optional<nlohmann::json> PrecomputedCallGraph;
441+
if (!LoadCGFromJsonOpt.empty()) {
442+
PHASAR_LOG_LEVEL(INFO, "Load CallGraph from file: " << LoadCGFromJsonOpt);
443+
PrecomputedCallGraph = readJsonFile(LoadCGFromJsonOpt);
444+
}
445+
416446
if (EntryOpt.empty()) {
417447
EntryOpt.push_back("main");
418448
}
@@ -421,7 +451,8 @@ int main(int Argc, const char **Argv) {
421451
HelperAnalyses HA(std::move(ModuleOpt.getValue()),
422452
std::move(PrecomputedAliasSet), AliasTypeOpt,
423453
!AnalysisController::needsToEmitPTA(EmitterOptions),
424-
EntryOpt, CGTypeOpt, SoundnessOpt, AutoGlobalsOpt);
454+
EntryOpt, std::move(PrecomputedCallGraph), CGTypeOpt,
455+
SoundnessOpt, AutoGlobalsOpt);
425456

426457
AnalysisController Controller(
427458
HA, DataFlowAnalysisOpt, {AnalysisConfigOpt.getValue()}, EntryOpt,

unittests/PhasarLLVM/ControlFlow/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ set(ControlFlowSources
99
LLVMBasedBackwardICFGTest.cpp
1010
LLVMBasedICFGExportTest.cpp
1111
LLVMBasedICFGGlobCtorDtorTest.cpp
12+
LLVMBasedICFGSerializationTest.cpp
1213
)
1314

1415
foreach(TEST_SRC ${ControlFlowSources})

0 commit comments

Comments
 (0)