Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions include/phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ class LLVMBasedICFG : public LLVMBasedCFG, public ICFGBase<LLVMBasedICFG> {
Soundness S = Soundness::Soundy,
bool IncludeGlobals = true);

explicit LLVMBasedICFG(LLVMProjectIRDB *IRDB,
const nlohmann::json &SerializedCG);

~LLVMBasedICFG();

LLVMBasedICFG(const LLVMBasedICFG &) = delete;
Expand Down
2 changes: 2 additions & 0 deletions include/phasar/PhasarLLVM/HelperAnalyses.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class HelperAnalyses { // NOLINT(cppcoreguidelines-special-member-functions)
std::optional<nlohmann::json> PrecomputedPTS,
AliasAnalysisType PTATy, bool AllowLazyPTS,
std::vector<std::string> EntryPoints,
std::optional<nlohmann::json> PrecomputedCG,
CallGraphAnalysisType CGTy, Soundness SoundnessLevel,
bool AutoGlobalSupport) noexcept;

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

// ICF
std::optional<nlohmann::json> PrecomputedCG;
std::vector<std::string> EntryPoints;
CallGraphAnalysisType CGTy{};
Soundness SoundnessLevel{};
Expand Down
1 change: 1 addition & 0 deletions include/phasar/PhasarLLVM/HelperAnalysisConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
namespace psr {
struct HelperAnalysisConfig {
std::optional<nlohmann::json> PrecomputedPTS = std::nullopt;
std::optional<nlohmann::json> PrecomputedCG = std::nullopt;
AliasAnalysisType PTATy = AliasAnalysisType::CFLAnders;
CallGraphAnalysisType CGTy = CallGraphAnalysisType::OTF;
Soundness SoundnessLevel = Soundness::Soundy;
Expand Down
5 changes: 5 additions & 0 deletions lib/Controller/AnalysisController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include "phasar/Controller/AnalysisController.h"

#include "phasar//Utils/NlohmannLogging.h"
#include "phasar/AnalysisStrategy/Strategies.h"
#include "phasar/Controller/AnalysisControllerEmitterOptions.h"
#include "phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h"
Expand Down Expand Up @@ -184,6 +185,10 @@ void AnalysisController::emitRequestedHelperAnalysisResults() {
WithResultFileOrStdout("/psr-cg.txt",
[this](auto &OS) { HA.getICFG().print(OS); });
}
if (EmitterOptions & AnalysisControllerEmitterOptions::EmitCGAsJson) {
WithResultFileOrStdout(
"/psr-cg.json", [this](auto &OS) { OS << HA.getICFG().getAsJson(); });
}

if (EmitterOptions &
(AnalysisControllerEmitterOptions::EmitStatisticsAsJson |
Expand Down
69 changes: 52 additions & 17 deletions lib/PhasarLLVM/ControlFlow/LLVMBasedICFG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -366,9 +366,8 @@ LLVMBasedICFG::LLVMBasedICFG(LLVMProjectIRDB *IRDB,
llvm::ArrayRef<std::string> EntryPoints,
LLVMTypeHierarchy *TH, LLVMAliasInfoRef PT,
Soundness S, bool IncludeGlobals)
: TH(TH) {
: IRDB(IRDB), TH(TH) {
assert(IRDB != nullptr);
this->IRDB = IRDB;

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

LLVMBasedICFG::LLVMBasedICFG(LLVMProjectIRDB *IRDB,
const nlohmann::json &SerializedCG)
: IRDB(IRDB) {
assert(IRDB != nullptr);

PHASAR_LOG_LEVEL_CAT(DEBUG, "LLVMBasedICFG",
"Load precomputed call-graph from JSON");

auto It = SerializedCG.find(PhasarConfig::JsonCallGraphID().str());

if (It == SerializedCG.end()) {
PHASAR_LOG_LEVEL_CAT(ERROR, "LLVMBasedICFG",
"Cannot deserialize call-graph from JSON: No key '"
<< PhasarConfig::JsonCallGraphID() << "' present");
return;
}

const auto &Edges = It.value();

CallersOf.reserve(Edges.size());
CalleesAt.reserve(Edges.size());
VertexFunctions.reserve(Edges.size());

for (const auto &[FunName, CallerIDs] : Edges.items()) {
const auto *Fun = IRDB->getFunction(FunName);
if (!Fun) {
PHASAR_LOG_LEVEL_CAT(WARNING, "LLVMBasedICFG",
"Invalid function name: " << FunName);
continue;
}
auto *CEdges = addFunctionVertex(Fun);
CEdges->reserve(CallerIDs.size());

for (const auto &JId : CallerIDs) {
auto Id = JId.get<size_t>();
const auto *CS = IRDB->getInstruction(Id);
if (!CS) {
PHASAR_LOG_LEVEL_CAT(WARNING, "LLVMBasedICFG",
"Invalid CAll-Instruction Id: " << Id);
}

addCallEdge(CS, Fun);
}
}
}

LLVMBasedICFG::~LLVMBasedICFG() = default;

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

for (size_t Vtx = 0, VtxEnd = VertexFunctions.size(); Vtx != VtxEnd; ++Vtx) {
auto VtxFunName = VertexFunctions[Vtx]->getName().str();
J[PhasarConfig::JsonCallGraphID().str()][VtxFunName] =
nlohmann::json::array();

for (const auto &Inst : llvm::instructions(VertexFunctions[Vtx])) {
if (!llvm::isa<llvm::CallBase>(Inst)) {
continue;
}
auto &Edges = J[PhasarConfig::JsonCallGraphID().str()];
for (const auto &[Fun, Callers] : CallersOf) {
auto &JCallers = Edges[Fun->getName().str()];

if (auto It = CalleesAt.find(&Inst); It != CalleesAt.end()) {
for (const auto *Succ : *It->second) {
J[PhasarConfig::JsonCallGraphID().str()][VtxFunName].push_back(
Succ->getName().str());
}
}
for (const auto *CS : *Callers) {
JCallers.push_back(IRDB->getInstructionId(CS));
}
}

Expand Down
2 changes: 1 addition & 1 deletion lib/PhasarLLVM/DB/LLVMProjectIRDB.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -260,5 +260,5 @@ const llvm::Value *psr::fromMetaDataId(const LLVMProjectIRDB &IRDB,
}

auto IdNr = ParseInt(Id);
return IdNr ? IRDB.getInstruction(*IdNr) : nullptr;
return IdNr ? IRDB.getValueFromId(*IdNr) : nullptr;
}
20 changes: 14 additions & 6 deletions lib/PhasarLLVM/HelperAnalyses.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@ HelperAnalyses::HelperAnalyses(std::string IRFile,
std::optional<nlohmann::json> PrecomputedPTS,
AliasAnalysisType PTATy, bool AllowLazyPTS,
std::vector<std::string> EntryPoints,
std::optional<nlohmann::json> PrecomputedCG,
CallGraphAnalysisType CGTy,
Soundness SoundnessLevel,
bool AutoGlobalSupport) noexcept
: IRFile(std::move(IRFile)), PrecomputedPTS(std::move(PrecomputedPTS)),
PTATy(PTATy), AllowLazyPTS(AllowLazyPTS),
PrecomputedCG(std::move(PrecomputedCG)),
EntryPoints(std::move(EntryPoints)), CGTy(CGTy),
SoundnessLevel(SoundnessLevel), AutoGlobalSupport(AutoGlobalSupport) {}

Expand All @@ -26,8 +28,10 @@ HelperAnalyses::HelperAnalyses(std::string IRFile,
HelperAnalysisConfig Config) noexcept
: IRFile(std::move(IRFile)),
PrecomputedPTS(std::move(Config.PrecomputedPTS)), PTATy(Config.PTATy),
AllowLazyPTS(Config.AllowLazyPTS), EntryPoints(std::move(EntryPoints)),
CGTy(Config.CGTy), SoundnessLevel(Config.SoundnessLevel),
AllowLazyPTS(Config.AllowLazyPTS),
PrecomputedCG(std::move(Config.PrecomputedCG)),
EntryPoints(std::move(EntryPoints)), CGTy(Config.CGTy),
SoundnessLevel(Config.SoundnessLevel),
AutoGlobalSupport(Config.AutoGlobalSupport) {}

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

LLVMBasedICFG &HelperAnalyses::getICFG() {
if (!ICF) {
ICF = std::make_unique<LLVMBasedICFG>(
&getProjectIRDB(), CGTy, std::move(EntryPoints), &getTypeHierarchy(),
CGTy == CallGraphAnalysisType::OTF ? &getAliasInfo() : nullptr,
SoundnessLevel, AutoGlobalSupport);
if (PrecomputedCG.has_value()) {
ICF = std::make_unique<LLVMBasedICFG>(&getProjectIRDB(), *PrecomputedCG);
} else {
ICF = std::make_unique<LLVMBasedICFG>(
&getProjectIRDB(), CGTy, std::move(EntryPoints), &getTypeHierarchy(),
CGTy == CallGraphAnalysisType::OTF ? &getAliasInfo() : nullptr,
SoundnessLevel, AutoGlobalSupport);
}
}

return *ICF;
Expand Down
3 changes: 2 additions & 1 deletion lib/PhasarLLVM/Pointer/LLVMAliasSet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@ LLVMAliasSet::LLVMAliasSet(LLVMProjectIRDB *IRDB,
assert(IRDB != nullptr);
// Assume, we already have validated the json schema

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

const auto &Sets = SerializedPTS.at("AliasSets");
assert(Sets.is_array());
Expand Down
35 changes: 33 additions & 2 deletions tools/phasar-cli/phasar-cli.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,6 @@ cl::opt<std::string>

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

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

cl::opt<std::string> LoadCGFromJsonOpt(
"load-cg-from-json",
cl::desc("Load the persisted call-graph previously exported via "
"emit-cg-as-json from the given file"),
cl::cat(PsrCat));

PSR_SHORTLONG_OPTION(PammOutOpt, std::string, "A", "pamm-out",
"Filename for PAMM's gathered data",
cl::init("PAMM_data.json"), cl::cat(PsrCat), cl::Hidden);
Expand Down Expand Up @@ -344,6 +349,15 @@ int main(int Argc, const char **Argv) {
return 1;
}

if (ProjectIdOpt.empty()) {
ProjectIdOpt = std::filesystem::path(ModuleOpt.getValue())
.filename()
.replace_extension();
if (ProjectIdOpt.empty()) {
ProjectIdOpt = "default-phasar-project";
}
}

validateParamModule();
validateParamOutput();
validateParamPointerAnalysis();
Expand Down Expand Up @@ -385,6 +399,15 @@ int main(int Argc, const char **Argv) {
if (EmitCGAsDotOpt) {
EmitterOptions |= AnalysisControllerEmitterOptions::EmitCGAsDot;
}
if (EmitCGAsJsonOpt) {
EmitterOptions |= AnalysisControllerEmitterOptions::EmitCGAsJson;
}
if (EmitCGAsTextOpt) {
llvm::errs()
<< "ERROR: emit-cg-as-text is currently not supported. Did you mean "
"emit-cg-as-dot? For reversible serialization use emit-cg-as-json\n";
return 1;
}
if (EmitPTAAsTextOpt) {
EmitterOptions |= AnalysisControllerEmitterOptions::EmitPTAAsText;
}
Expand All @@ -410,9 +433,16 @@ int main(int Argc, const char **Argv) {

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

std::optional<nlohmann::json> PrecomputedCallGraph;
if (!LoadCGFromJsonOpt.empty()) {
PHASAR_LOG_LEVEL(INFO, "Load CallGraph from file: " << LoadCGFromJsonOpt);
PrecomputedCallGraph = readJsonFile(LoadCGFromJsonOpt);
}

if (EntryOpt.empty()) {
EntryOpt.push_back("main");
}
Expand All @@ -421,7 +451,8 @@ int main(int Argc, const char **Argv) {
HelperAnalyses HA(std::move(ModuleOpt.getValue()),
std::move(PrecomputedAliasSet), AliasTypeOpt,
!AnalysisController::needsToEmitPTA(EmitterOptions),
EntryOpt, CGTypeOpt, SoundnessOpt, AutoGlobalsOpt);
EntryOpt, std::move(PrecomputedCallGraph), CGTypeOpt,
SoundnessOpt, AutoGlobalsOpt);

AnalysisController Controller(
HA, DataFlowAnalysisOpt, {AnalysisConfigOpt.getValue()}, EntryOpt,
Expand Down
1 change: 1 addition & 0 deletions unittests/PhasarLLVM/ControlFlow/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ set(ControlFlowSources
LLVMBasedBackwardICFGTest.cpp
LLVMBasedICFGExportTest.cpp
LLVMBasedICFGGlobCtorDtorTest.cpp
LLVMBasedICFGSerializationTest.cpp
)

foreach(TEST_SRC ${ControlFlowSources})
Expand Down
Loading