Skip to content

Commit 06da95b

Browse files
authored
HelperAnalyses with existing Module (#667)
* Allow creating a HelperAnalyses object from an already existing LLVM Module * minor API extension of ProjectIRDB
1 parent 1fafc44 commit 06da95b

5 files changed

Lines changed: 95 additions & 45 deletions

File tree

include/phasar/PhasarLLVM/DB/LLVMProjectIRDB.h

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,19 +41,23 @@ class LLVMProjectIRDB : public ProjectIRDBBase<LLVMProjectIRDB> {
4141
friend ProjectIRDBBase;
4242

4343
public:
44-
/// Reads and parses the given LLVM IR file and owns the resulting IR Module
44+
/// Reads and parses the given LLVM IR file and owns the resulting IR Module.
45+
/// If an error occurs, an error message is written to stderr and subsequent
46+
/// calls to isValid() return false.
4547
explicit LLVMProjectIRDB(const llvm::Twine &IRFileName);
4648
/// Initializes the new ProjectIRDB with the given IR Module _without_ taking
47-
/// ownership. The module is not being preprocessed.
49+
/// ownership. The module is optionally being preprocessed.
4850
///
4951
/// CAUTION: Do not manage the same LLVM Module with multiple LLVMProjectIRDB
5052
/// instances at the same time! This will confuse the ModulesToSlotTracker
51-
explicit LLVMProjectIRDB(llvm::Module *Mod);
53+
explicit LLVMProjectIRDB(llvm::Module *Mod, bool DoPreprocessing = true);
5254
/// Initializes the new ProjectIRDB with the given IR Module and takes
53-
/// ownership of it
55+
/// ownership of it. The module is optionally being preprocessed.
5456
explicit LLVMProjectIRDB(std::unique_ptr<llvm::Module> Mod,
5557
bool DoPreprocessing = true);
56-
/// Parses the given LLVM IR file and owns the resulting IR Module
58+
/// Parses the given LLVM IR file and owns the resulting IR Module.
59+
/// If an error occurs, an error message is written to stderr and subsequent
60+
/// calls to isValid() return false.
5761
explicit LLVMProjectIRDB(llvm::MemoryBufferRef Buf);
5862

5963
LLVMProjectIRDB(const LLVMProjectIRDB &) = delete;
@@ -64,6 +68,9 @@ class LLVMProjectIRDB : public ProjectIRDBBase<LLVMProjectIRDB> {
6468
[[nodiscard]] static std::unique_ptr<llvm::Module>
6569
getParsedIRModuleOrNull(const llvm::Twine &IRFileName,
6670
llvm::LLVMContext &Ctx) noexcept;
71+
[[nodiscard]] static std::unique_ptr<llvm::Module>
72+
getParsedIRModuleOrNull(llvm::MemoryBufferRef IRFileContent,
73+
llvm::LLVMContext &Ctx) noexcept;
6774

6875
/// Also use the const overload
6976
using ProjectIRDBBase::getFunction;
@@ -81,7 +88,7 @@ class LLVMProjectIRDB : public ProjectIRDBBase<LLVMProjectIRDB> {
8188
/// Also use the const overload
8289
using ProjectIRDBBase::getModule;
8390
/// Non-const overload
84-
[[nodiscard]] llvm::Module *getModule() { return Mod.get(); }
91+
[[nodiscard]] llvm::Module *getModule() noexcept { return Mod.get(); }
8592

8693
/// Similar to getInstruction(size_t), but is also able to return global
8794
/// variables by id
@@ -96,6 +103,8 @@ class LLVMProjectIRDB : public ProjectIRDBBase<LLVMProjectIRDB> {
96103
/// called twice for the same function. Use with care!
97104
void insertFunction(llvm::Function *F, bool DoPreprocessing = true);
98105

106+
explicit operator bool() const noexcept { return isValid(); }
107+
99108
private:
100109
[[nodiscard]] m_t getModuleImpl() const noexcept { return Mod.get(); }
101110
[[nodiscard]] bool debugInfoAvailableImpl() const;

include/phasar/PhasarLLVM/HelperAnalyses.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@
2020
#include <set>
2121
#include <vector>
2222

23+
namespace llvm {
24+
class Module;
25+
} // namespace llvm
26+
2327
namespace psr {
2428
class LLVMProjectIRDB;
2529
class LLVMTypeHierarchy;
@@ -46,6 +50,12 @@ class HelperAnalyses { // NOLINT(cppcoreguidelines-special-member-functions)
4650
explicit HelperAnalyses(const char *IRFile,
4751
std::vector<std::string> EntryPoints,
4852
HelperAnalysisConfig Config = {});
53+
explicit HelperAnalyses(llvm::Module *IRModule,
54+
std::vector<std::string> EntryPoints,
55+
HelperAnalysisConfig Config = {});
56+
explicit HelperAnalyses(std::unique_ptr<llvm::Module> IRModule,
57+
std::vector<std::string> EntryPoints,
58+
HelperAnalysisConfig Config = {});
4959
~HelperAnalyses() noexcept;
5060

5161
[[nodiscard]] LLVMProjectIRDB &getProjectIRDB();

include/phasar/PhasarLLVM/HelperAnalysisConfig.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ struct HelperAnalysisConfig {
2727
Soundness SoundnessLevel = Soundness::Soundy;
2828
bool AutoGlobalSupport = true;
2929
bool AllowLazyPTS = true;
30+
/// Preprocess a ProjectIRDB even if it gets constructed by an already
31+
/// existing llvm::Module
32+
bool PreprocessExistingModule = true;
3033

3134
HelperAnalysisConfig &&withCGType(CallGraphAnalysisType CGTy) &&noexcept {
3235
this->CGTy = CGTy;

lib/PhasarLLVM/DB/LLVMProjectIRDB.cpp

Lines changed: 53 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,57 @@
1313
#include "llvm/IRReader/IRReader.h"
1414
#include "llvm/Support/Debug.h"
1515
#include "llvm/Support/FormattedStream.h"
16+
#include "llvm/Support/MemoryBufferRef.h"
1617
#include "llvm/Support/SourceMgr.h"
1718

1819
#include <charconv>
1920

2021
namespace psr {
2122

23+
std::unique_ptr<llvm::Module>
24+
LLVMProjectIRDB::getParsedIRModuleOrNull(llvm::MemoryBufferRef IRFileContent,
25+
llvm::LLVMContext &Ctx) noexcept {
26+
27+
llvm::SMDiagnostic Diag;
28+
std::unique_ptr<llvm::Module> M = llvm::parseIR(IRFileContent, Diag, Ctx);
29+
bool BrokenDebugInfo = false;
30+
if (M == nullptr) {
31+
Diag.print(nullptr, llvm::errs());
32+
return nullptr;
33+
}
34+
/* Crash in presence of llvm-3.9.1 module (segfault) */
35+
if (M == nullptr || llvm::verifyModule(*M, &llvm::errs(), &BrokenDebugInfo)) {
36+
PHASAR_LOG_LEVEL(ERROR, IRFileContent.getBufferIdentifier()
37+
<< " could not be parsed correctly!");
38+
return nullptr;
39+
}
40+
if (BrokenDebugInfo) {
41+
PHASAR_LOG_LEVEL(WARNING, "Debug info is broken!");
42+
}
43+
return M;
44+
}
45+
46+
std::unique_ptr<llvm::Module>
47+
LLVMProjectIRDB::getParsedIRModuleOrNull(const llvm::Twine &IRFileName,
48+
llvm::LLVMContext &Ctx) noexcept {
49+
// Look at LLVM's IRReader.cpp for reference
50+
51+
auto FileOrErr =
52+
llvm::MemoryBuffer::getFileOrSTDIN(IRFileName, /*IsText=*/true);
53+
if (std::error_code EC = FileOrErr.getError()) {
54+
llvm::SmallString<128> Buf;
55+
auto Err = llvm::SMDiagnostic(IRFileName.toStringRef(Buf),
56+
llvm::SourceMgr::DK_Error,
57+
"Could not open input file: " + EC.message());
58+
Err.print(nullptr, llvm::errs());
59+
return nullptr;
60+
}
61+
return getParsedIRModuleOrNull(*FileOrErr.get(), Ctx);
62+
}
63+
2264
LLVMProjectIRDB::LLVMProjectIRDB(const llvm::Twine &IRFileName) {
2365

24-
std::unique_ptr<llvm::Module> M = getParsedIRModuleOrNull(IRFileName, Ctx);
66+
auto M = getParsedIRModuleOrNull(IRFileName, Ctx);
2567

2668
if (!M) {
2769
return;
@@ -87,10 +129,16 @@ void LLVMProjectIRDB::preprocessModule(llvm::Module *NonConstMod) {
87129
assert(InstToId.size() == IdToInst.size());
88130
}
89131

90-
LLVMProjectIRDB::LLVMProjectIRDB(llvm::Module *Mod) : Mod(Mod) {
132+
LLVMProjectIRDB::LLVMProjectIRDB(llvm::Module *Mod, bool DoPreprocessing)
133+
: Mod(Mod) {
91134
assert(Mod != nullptr);
92135
ModulesToSlotTracker::setMSTForModule(Mod);
93-
initInstructionIds();
136+
137+
if (DoPreprocessing) {
138+
preprocessModule(Mod);
139+
} else {
140+
initInstructionIds();
141+
}
94142
}
95143

96144
LLVMProjectIRDB::LLVMProjectIRDB(std::unique_ptr<llvm::Module> Mod,
@@ -109,21 +157,10 @@ LLVMProjectIRDB::LLVMProjectIRDB(std::unique_ptr<llvm::Module> Mod,
109157

110158
LLVMProjectIRDB::LLVMProjectIRDB(llvm::MemoryBufferRef Buf) {
111159
llvm::SMDiagnostic Diag;
112-
std::unique_ptr<llvm::Module> M = llvm::parseIR(Buf, Diag, Ctx);
113-
bool BrokenDebugInfo = false;
114-
if (M == nullptr) {
115-
Diag.print(nullptr, llvm::errs());
116-
return;
117-
}
118-
119-
if (llvm::verifyModule(*M, &llvm::errs(), &BrokenDebugInfo)) {
120-
PHASAR_LOG_LEVEL(ERROR, Buf.getBufferIdentifier()
121-
<< " could not be parsed correctly!");
160+
auto M = getParsedIRModuleOrNull(Buf, Ctx);
161+
if (!M) {
122162
return;
123163
}
124-
if (BrokenDebugInfo) {
125-
PHASAR_LOG_LEVEL(WARNING, "Debug info is broken!");
126-
}
127164

128165
auto *NonConst = M.get();
129166
Mod = std::move(M);
@@ -137,29 +174,6 @@ LLVMProjectIRDB::~LLVMProjectIRDB() {
137174
}
138175
}
139176

140-
std::unique_ptr<llvm::Module>
141-
LLVMProjectIRDB::getParsedIRModuleOrNull(const llvm::Twine &IRFileName,
142-
llvm::LLVMContext &Ctx) noexcept {
143-
llvm::SMDiagnostic Diag;
144-
llvm::SmallString<256> Buf;
145-
std::unique_ptr<llvm::Module> M =
146-
llvm::parseIRFile(IRFileName.toStringRef(Buf), Diag, Ctx);
147-
bool BrokenDebugInfo = false;
148-
if (M == nullptr) {
149-
Diag.print(nullptr, llvm::errs());
150-
return nullptr;
151-
}
152-
/* Crash in presence of llvm-3.9.1 module (segfault) */
153-
if (M == nullptr || llvm::verifyModule(*M, &llvm::errs(), &BrokenDebugInfo)) {
154-
PHASAR_LOG_LEVEL(ERROR, IRFileName << " could not be parsed correctly!");
155-
return nullptr;
156-
}
157-
if (BrokenDebugInfo) {
158-
PHASAR_LOG_LEVEL(WARNING, "Debug info is broken!");
159-
}
160-
return M;
161-
}
162-
163177
static llvm::Function *
164178
internalGetFunctionDefinition(const llvm::Module &M,
165179
llvm::StringRef FunctionName) {

lib/PhasarLLVM/HelperAnalyses.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,20 @@ HelperAnalyses::HelperAnalyses(const char *IRFile,
4343
HelperAnalysisConfig Config)
4444
: HelperAnalyses(std::string(IRFile), std::move(EntryPoints),
4545
std::move(Config)) {}
46+
HelperAnalyses::HelperAnalyses(llvm::Module *IRModule,
47+
std::vector<std::string> EntryPoints,
48+
HelperAnalysisConfig Config)
49+
: HelperAnalyses(std::string(), std::move(EntryPoints), std::move(Config)) {
50+
this->IRDB = std::make_unique<LLVMProjectIRDB>(
51+
IRModule, Config.PreprocessExistingModule);
52+
}
53+
HelperAnalyses::HelperAnalyses(std::unique_ptr<llvm::Module> IRModule,
54+
std::vector<std::string> EntryPoints,
55+
HelperAnalysisConfig Config)
56+
: HelperAnalyses(std::string(), std::move(EntryPoints), std::move(Config)) {
57+
this->IRDB = std::make_unique<LLVMProjectIRDB>(
58+
std::move(IRModule), Config.PreprocessExistingModule);
59+
}
4660

4761
HelperAnalyses::~HelperAnalyses() noexcept = default;
4862

0 commit comments

Comments
 (0)