diff --git a/.gitignore b/.gitignore index f175263c3..1cc71e473 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ bin/* # build directories for cmake build/ build_*/ +build-*/ # LLVM project llvm-project/* diff --git a/lib/PhasarLLVM/Utils/LLVMShorthands.cpp b/lib/PhasarLLVM/Utils/LLVMShorthands.cpp index 772bd9629..62672afab 100644 --- a/lib/PhasarLLVM/Utils/LLVMShorthands.cpp +++ b/lib/PhasarLLVM/Utils/LLVMShorthands.cpp @@ -44,6 +44,7 @@ #include #include #include +#include #include #include @@ -504,32 +505,44 @@ llvm::StringRef getVarAnnotationIntrinsicName(const llvm::CallInst *CallInst) { return Data->getAsCString(); } +struct PhasarModuleSlotTrackerWrapper { + PhasarModuleSlotTrackerWrapper(const llvm::Module *M) : MST(M) {} + + llvm::ModuleSlotTracker MST; + size_t RefCount = 0; +}; + static llvm::SmallDenseMap, 2> + std::unique_ptr, 2> MToST{}; +static std::mutex MSTMx; + llvm::ModuleSlotTracker & ModulesToSlotTracker::getSlotTrackerForModule(const llvm::Module *M) { + std::lock_guard Lck(MSTMx); + auto &Ret = MToST[M]; if (M == nullptr && Ret == nullptr) { - Ret = std::make_unique(M); + Ret = std::make_unique(M); + Ret->RefCount++; } assert(Ret != nullptr && "no ModuleSlotTracker instance for module cached"); - return *Ret; + return Ret->MST; } void ModulesToSlotTracker::setMSTForModule(const llvm::Module *M) { + std::lock_guard Lck(MSTMx); + auto [It, Inserted] = MToST.try_emplace(M, nullptr); - if (!Inserted) { - llvm::report_fatal_error( - "Cannot register the same module twice in the ModulesToSlotTracker! " - "Probably you have managed the same LLVM Module with multiple " - "ProjectIRDB instances at the same time. Don't do that!"); + if (Inserted) { + It->second = std::make_unique(M); } - It->second = std::make_unique(M); + It->second->RefCount++; } void ModulesToSlotTracker::updateMSTForModule(const llvm::Module *Module) { + std::lock_guard Lck(MSTMx); auto It = MToST.find(Module); if (It == MToST.end()) { llvm::report_fatal_error( @@ -541,7 +554,16 @@ void ModulesToSlotTracker::updateMSTForModule(const llvm::Module *Module) { } void ModulesToSlotTracker::deleteMSTForModule(const llvm::Module *M) { - MToST.erase(M); + std::lock_guard Lck(MSTMx); + + auto It = MToST.find(M); + if (It == MToST.end()) { + return; + } + + if (--It->second->RefCount == 0) { + MToST.erase(It); + } } } // namespace psr diff --git a/unittests/Utils/LLVMShorthandsTest.cpp b/unittests/Utils/LLVMShorthandsTest.cpp index d6104664c..2c19ff675 100644 --- a/unittests/Utils/LLVMShorthandsTest.cpp +++ b/unittests/Utils/LLVMShorthandsTest.cpp @@ -4,6 +4,7 @@ #include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h" #include "phasar/Utils/Utilities.h" +#include "llvm/ADT/StringRef.h" #include "llvm/IR/Function.h" #include "llvm/IR/Instructions.h" @@ -43,6 +44,24 @@ TEST(LLVMGetterTest, HandlesLLVMTermInstruction) { ASSERT_EQ(getNthTermInstruction(F, 5), nullptr); } +TEST(SlotTrackerTest, HandleTwoReferences) { + LLVMProjectIRDB IRDB(unittest::PathToLLTestFiles + + "control_flow/global_stmt_cpp.ll"); + + const auto *F = IRDB.getFunctionDefinition("main"); + + ASSERT_NE(F, nullptr); + const auto *Inst = getNthInstruction(F, 6); + llvm::StringRef InstStr = "%0 = load i32, i32* @i, align 4 | ID: 6"; + { + LLVMProjectIRDB IRDB2(IRDB.getModule()); + + EXPECT_EQ(llvmIRToStableString(Inst), InstStr); + } + + EXPECT_EQ(llvmIRToStableString(Inst), InstStr); +} + int main(int Argc, char **Argv) { ::testing::InitGoogleTest(&Argc, Argv); return RUN_ALL_TESTS();