Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Get LLVMContext instance directly from llvm::Module when building SVFModule #1292

Merged
merged 1 commit into from
Dec 20, 2023
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
12 changes: 7 additions & 5 deletions svf-llvm/include/SVF-LLVM/LLVMModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ class LLVMModuleSet
static bool preProcessed;
SymbolTableInfo* symInfo;
SVFModule* svfModule; ///< Borrowed from singleton SVFModule::svfModule
std::unique_ptr<LLVMContext> cxts;
std::unique_ptr<LLVMContext> owned_ctx;
std::vector<std::unique_ptr<Module>> owned_modules;
std::vector<std::reference_wrapper<Module>> modules;

Expand Down Expand Up @@ -111,8 +111,10 @@ class LLVMModuleSet
llvmModuleSet = nullptr;
}

// The parameter of context should be the llvm context of the mod, the llvm context of mod and extapi module should be the same
static SVFModule* buildSVFModule(Module& mod, std::unique_ptr<LLVMContext> context);
// Build an SVF module from a given LLVM Module instance (for use e.g. in a LLVM pass)
static SVFModule* buildSVFModule(Module& mod);

// Build an SVF module from the bitcode files provided in `moduleNameVec`
static SVFModule* buildSVFModule(const std::vector<std::string>& moduleNameVec);

inline SVFModule* getSVFModule()
Expand Down Expand Up @@ -357,8 +359,8 @@ class LLVMModuleSet
std::vector<const Function*> getLLVMGlobalFunctions(const GlobalVariable* global);

void loadModules(const std::vector<std::string>& moduleNameVec);
// The llvm context of app module and extapi module should be the same
void loadExtAPIModules(std::unique_ptr<LLVMContext> context = nullptr);
// Loads ExtAPI bitcode file; uses LLVMContext made while loading module bitcode files or from Module
void loadExtAPIModules();
void addSVFMain();

void createSVFDataStructure();
Expand Down
54 changes: 37 additions & 17 deletions svf-llvm/lib/LLVMModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,19 +73,18 @@

LLVMModuleSet::LLVMModuleSet()
: symInfo(SymbolTableInfo::SymbolInfo()),
svfModule(SVFModule::getSVFModule()), cxts(nullptr)
svfModule(SVFModule::getSVFModule())
{
}

SVFModule* LLVMModuleSet::buildSVFModule(Module &mod, std::unique_ptr<LLVMContext> context)
SVFModule* LLVMModuleSet::buildSVFModule(Module &mod)

Check warning on line 80 in svf-llvm/lib/LLVMModule.cpp

View check run for this annotation

Codecov / codecov/patch

svf-llvm/lib/LLVMModule.cpp#L80

Added line #L80 was not covered by tests
{
LLVMModuleSet* mset = getLLVMModuleSet();

double startSVFModuleTime = SVFStat::getClk(true);
SVFModule::getSVFModule()->setModuleIdentifier(mod.getModuleIdentifier());
mset->modules.emplace_back(mod);
mset->loadExtAPIModules(std::move(context));

mset->modules.emplace_back(mod); // Populates `modules`; can get context via `this->getContext()`
mset->loadExtAPIModules(); // Uses context from module through `this->getContext()`

Check warning on line 87 in svf-llvm/lib/LLVMModule.cpp

View check run for this annotation

Codecov / codecov/patch

svf-llvm/lib/LLVMModule.cpp#L86-L87

Added lines #L86 - L87 were not covered by tests
mset->build();
double endSVFModuleTime = SVFStat::getClk(true);
SVFStat::timeOfBuildingLLVMModule = (endSVFModuleTime - startSVFModuleTime)/TIMEINTERVAL;
Expand All @@ -101,8 +100,8 @@

LLVMModuleSet* mset = getLLVMModuleSet();

mset->loadModules(moduleNameVec);
mset->loadExtAPIModules();
mset->loadModules(moduleNameVec); // Populates `modules`; can get context via `this->getContext()`
mset->loadExtAPIModules(); // Uses context from first module through `this->getContext()`

if (!moduleNameVec.empty())
{
Expand Down Expand Up @@ -507,9 +506,11 @@
SVFModule::setPagFromTXT(Options::Graphtxt());

//
// To avoid the following type bugs (t1 != t3) when parsing multiple modules,
// We should use only one LLVMContext object for multiple modules in the same thread.
// No such problem if only one module is processed by SVF.
// LLVMContext objects separate global LLVM settings (from which e.g. types are
// derived); multiple LLVMContext objects can coexist and each context can "own"
// multiple modules (modules can only have one context). Mixing contexts can lead
// to unintended inequalities, such as the following:
//
// ------------------------------------------------------------------
// LLVMContext ctxa,ctxb;
// IntegerType * t1 = IntegerType::get(ctxa,32);
Expand All @@ -521,7 +522,16 @@
// assert(t1 != t3);
// ------------------------------------------------------------------
//
cxts = std::make_unique<LLVMContext>();
// When loading bytecode files, SVF will use the same LLVMContext object for all
// modules (i.e. the context owns all loaded modules). This applies to ExtAPI as
// well, which *must* be loaded using the same LLVMContext object. Hence, when
// loading modules from bitcode files, a new LLVMContext is created (using a
// `std::unique_ptr<LLVMContext>` type to ensure automatic garbage collection).
//
// This garbage collection should be avoided when building an SVF module from an LLVM
// module instance; see the comment(s) in `buildSVFModule` and `loadExtAPIModules()`

owned_ctx = std::make_unique<LLVMContext>();

for (const std::string& moduleName : moduleNameVec)
{
Expand All @@ -532,7 +542,7 @@
}

SMDiagnostic Err;
std::unique_ptr<Module> mod = parseIRFile(moduleName, Err, *cxts);
std::unique_ptr<Module> mod = parseIRFile(moduleName, Err, *owned_ctx);
if (mod == nullptr)
{
SVFUtil::errs() << "load module: " << moduleName << "failed!!\n\n";
Expand All @@ -544,8 +554,21 @@
}
}

void LLVMModuleSet::loadExtAPIModules(std::unique_ptr<LLVMContext> context)
void LLVMModuleSet::loadExtAPIModules()
{
// This function loads the ExtAPI bitcode file as an LLVM module. Note that it is important that
// the same LLVMContext object is used to load this bitcode file as is used by the other modules
// being analysed.
// When the modules are loaded from bitcode files (i.e. passing filenames to files containing
// LLVM IR to `buildSVFModule({file1.bc, file2.bc, ...})) the context is created while loading
// the modules in `loadModules()`, which populates this->modules and this->owned_modules.
// If, however, an LLVM Module object is passed to `buildSVFModule` (e.g. from an LLVM pass),
// the context should be retrieved from the module itself (note that the garbage collection from
// `std::unique_ptr<LLVMContext> LLVMModuleSet::owned_ctx` should be avoided in this case). This
// function populates only this->modules.
// In both cases, fetching the context from the main LLVM module (through `getContext`) works
assert(!empty() && "LLVMModuleSet contains no modules; cannot load ExtAPI module without LLVMContext!");

// Load external API module (extapi.bc)
if (!ExtAPI::getExtAPI()->getExtBcPath().empty())
{
Expand All @@ -556,10 +579,7 @@
abort();
}
SMDiagnostic Err;
assert(!(cxts == nullptr && context == nullptr) && "Before loading extapi module, at least one LLVMContext should be initialized !!!");
if (context != nullptr)
cxts = std::move(context);
std::unique_ptr<Module> mod = parseIRFile(extModuleName, Err, *cxts);
std::unique_ptr<Module> mod = parseIRFile(extModuleName, Err, getContext());
if (mod == nullptr)
{
SVFUtil::errs() << "load external module: " << extModuleName << "failed!!\n\n";
Expand Down
Loading