//===- unittests/IR/ModuleTest.cpp - Module unit tests --------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "llvm/IR/Module.h" #include "llvm/AsmParser/Parser.h" #include "llvm/IR/GlobalVariable.h" #include "llvm/IR/ModuleSummaryIndex.h" #include "llvm/Pass.h" #include "llvm/Support/RandomNumberGenerator.h" #include "llvm/Support/SourceMgr.h" #include "gtest/gtest.h" #include using namespace llvm; namespace { bool sortByName(const GlobalVariable &L, const GlobalVariable &R) { return L.getName() < R.getName(); } bool sortByNameReverse(const GlobalVariable &L, const GlobalVariable &R) { return sortByName(R, L); } TEST(ModuleTest, sortGlobalsByName) { LLVMContext Context; for (auto compare : {&sortByName, &sortByNameReverse}) { Module M("M", Context); Type *T = Type::getInt8Ty(Context); GlobalValue::LinkageTypes L = GlobalValue::ExternalLinkage; (void)new GlobalVariable(M, T, false, L, nullptr, "A"); (void)new GlobalVariable(M, T, false, L, nullptr, "F"); (void)new GlobalVariable(M, T, false, L, nullptr, "G"); (void)new GlobalVariable(M, T, false, L, nullptr, "E"); (void)new GlobalVariable(M, T, false, L, nullptr, "B"); (void)new GlobalVariable(M, T, false, L, nullptr, "H"); (void)new GlobalVariable(M, T, false, L, nullptr, "C"); (void)new GlobalVariable(M, T, false, L, nullptr, "D"); // Sort the globals by name. EXPECT_FALSE(std::is_sorted(M.global_begin(), M.global_end(), compare)); } } TEST(ModuleTest, randomNumberGenerator) { LLVMContext Context; static char ID; struct DummyPass : ModulePass { DummyPass() : ModulePass(ID) {} bool runOnModule(Module &) override { return true; } } DP; Module M("R", Context); std::uniform_int_distribution dist; const size_t NBCheck = 10; std::array RandomStreams[2]; for (auto &RandomStream : RandomStreams) { std::unique_ptr RNG = M.createRNG(DP.getPassName()); std::generate(RandomStream.begin(), RandomStream.end(), [&]() { return dist(*RNG); }); } EXPECT_TRUE(std::equal(RandomStreams[0].begin(), RandomStreams[0].end(), RandomStreams[1].begin())); } TEST(ModuleTest, setModuleFlag) { LLVMContext Context; Module M("M", Context); StringRef Key = "Key"; Metadata *Val1 = MDString::get(Context, "Val1"); Metadata *Val2 = MDString::get(Context, "Val2"); EXPECT_EQ(nullptr, M.getModuleFlag(Key)); M.setModuleFlag(Module::ModFlagBehavior::Error, Key, Val1); EXPECT_EQ(Val1, M.getModuleFlag(Key)); M.setModuleFlag(Module::ModFlagBehavior::Error, Key, Val2); EXPECT_EQ(Val2, M.getModuleFlag(Key)); } const char *IRString = R"IR( !llvm.module.flags = !{!0} !0 = !{i32 1, !"ProfileSummary", !1} !1 = !{!2, !3, !4, !5, !6, !7, !8, !9} !2 = !{!"ProfileFormat", !"SampleProfile"} !3 = !{!"TotalCount", i64 10000} !4 = !{!"MaxCount", i64 10} !5 = !{!"MaxInternalCount", i64 1} !6 = !{!"MaxFunctionCount", i64 1000} !7 = !{!"NumCounts", i64 200} !8 = !{!"NumFunctions", i64 3} !9 = !{!"DetailedSummary", !10} !10 = !{!11, !12, !13} !11 = !{i32 10000, i64 1000, i32 1} !12 = !{i32 990000, i64 300, i32 10} !13 = !{i32 999999, i64 5, i32 100} )IR"; TEST(ModuleTest, setProfileSummary) { SMDiagnostic Err; LLVMContext Context; std::unique_ptr M = parseAssemblyString(IRString, Err, Context); auto *PS = ProfileSummary::getFromMD(M->getProfileSummary(/*IsCS*/ false)); EXPECT_NE(nullptr, PS); EXPECT_FALSE(PS->isPartialProfile()); PS->setPartialProfile(true); M->setProfileSummary(PS->getMD(Context), ProfileSummary::PSK_Sample); delete PS; PS = ProfileSummary::getFromMD(M->getProfileSummary(/*IsCS*/ false)); EXPECT_NE(nullptr, PS); EXPECT_EQ(true, PS->isPartialProfile()); delete PS; } TEST(ModuleTest, setPartialSampleProfileRatio) { const char *IRString = R"IR( !llvm.module.flags = !{!0} !0 = !{i32 1, !"ProfileSummary", !1} !1 = !{!2, !3, !4, !5, !6, !7, !8, !9, !10, !11} !2 = !{!"ProfileFormat", !"SampleProfile"} !3 = !{!"TotalCount", i64 10000} !4 = !{!"MaxCount", i64 10} !5 = !{!"MaxInternalCount", i64 1} !6 = !{!"MaxFunctionCount", i64 1000} !7 = !{!"NumCounts", i64 200} !8 = !{!"NumFunctions", i64 3} !9 = !{!"IsPartialProfile", i64 1} !10 = !{!"PartialProfileRatio", double 0.0} !11 = !{!"DetailedSummary", !12} !12 = !{!13, !14, !15} !13 = !{i32 10000, i64 1000, i32 1} !14 = !{i32 990000, i64 300, i32 10} !15 = !{i32 999999, i64 5, i32 100} )IR"; SMDiagnostic Err; LLVMContext Context; std::unique_ptr M = parseAssemblyString(IRString, Err, Context); ModuleSummaryIndex Index(/*HaveGVs*/ false); const unsigned BlockCount = 100; const unsigned NumCounts = 200; Index.setBlockCount(BlockCount); M->setPartialSampleProfileRatio(Index); double Ratio = (double)BlockCount / NumCounts; std::unique_ptr ProfileSummary( ProfileSummary::getFromMD(M->getProfileSummary(/*IsCS*/ false))); EXPECT_EQ(Ratio, ProfileSummary->getPartialProfileRatio()); } TEST(ModuleTest, AliasList) { // This tests all Module's functions that interact with Module::AliasList. LLVMContext C; SMDiagnostic Err; LLVMContext Context; std::unique_ptr M = parseAssemblyString(R"( declare void @Foo() @GA = alias void (), ptr @Foo )", Err, Context); Function *Foo = M->getFunction("Foo"); auto *GA = M->getNamedAlias("GA"); EXPECT_EQ(M->alias_size(), 1u); auto *NewGA = GlobalAlias::create(Foo->getType(), 0, GlobalValue::ExternalLinkage, "NewGA", Foo, /*Parent=*/nullptr); EXPECT_EQ(M->alias_size(), 1u); M->insertAlias(NewGA); EXPECT_EQ(&*std::prev(M->aliases().end()), NewGA); M->removeAlias(NewGA); EXPECT_EQ(M->alias_size(), 1u); M->insertAlias(NewGA); EXPECT_EQ(M->alias_size(), 2u); EXPECT_EQ(&*std::prev(M->aliases().end()), NewGA); auto Range = M->aliases(); EXPECT_EQ(&*Range.begin(), GA); EXPECT_EQ(&*std::next(Range.begin()), NewGA); EXPECT_EQ(std::next(Range.begin(), 2), Range.end()); M->removeAlias(NewGA); EXPECT_EQ(M->alias_size(), 1u); M->insertAlias(NewGA); M->eraseAlias(NewGA); EXPECT_EQ(M->alias_size(), 1u); } TEST(ModuleTest, IFuncList) { // This tests all Module's functions that interact with Module::IFuncList. LLVMContext C; SMDiagnostic Err; LLVMContext Context; std::unique_ptr M = parseAssemblyString(R"( declare void @Foo() @GIF = ifunc void (), ptr @Foo )", Err, Context); Function *Foo = M->getFunction("Foo"); auto *GIF = M->getNamedIFunc("GIF"); EXPECT_EQ(M->ifunc_size(), 1u); auto *NewGIF = GlobalIFunc::create(Foo->getType(), 0, GlobalValue::ExternalLinkage, "NewGIF", Foo, /*Parent=*/nullptr); EXPECT_EQ(M->ifunc_size(), 1u); M->insertIFunc(NewGIF); EXPECT_EQ(&*std::prev(M->ifuncs().end()), NewGIF); M->removeIFunc(NewGIF); EXPECT_EQ(M->ifunc_size(), 1u); M->insertIFunc(NewGIF); EXPECT_EQ(M->ifunc_size(), 2u); EXPECT_EQ(&*std::prev(M->ifuncs().end()), NewGIF); auto Range = M->ifuncs(); EXPECT_EQ(&*Range.begin(), GIF); EXPECT_EQ(&*std::next(Range.begin()), NewGIF); EXPECT_EQ(std::next(Range.begin(), 2), Range.end()); M->removeIFunc(NewGIF); EXPECT_EQ(M->ifunc_size(), 1u); M->insertIFunc(NewGIF); M->eraseIFunc(NewGIF); EXPECT_EQ(M->ifunc_size(), 1u); } TEST(ModuleTest, NamedMDList) { // This tests all Module's functions that interact with Module::NamedMDList. LLVMContext C; SMDiagnostic Err; LLVMContext Context; auto M = std::make_unique("M", C); NamedMDNode *MDN1 = M->getOrInsertNamedMetadata("MDN1"); EXPECT_EQ(M->named_metadata_size(), 1u); NamedMDNode *MDN2 = M->getOrInsertNamedMetadata("MDN2"); EXPECT_EQ(M->named_metadata_size(), 2u); auto *NewMDN = M->getOrInsertNamedMetadata("NewMDN"); EXPECT_EQ(M->named_metadata_size(), 3u); M->removeNamedMDNode(NewMDN); EXPECT_EQ(M->named_metadata_size(), 2u); M->insertNamedMDNode(NewMDN); EXPECT_EQ(&*std::prev(M->named_metadata().end()), NewMDN); M->removeNamedMDNode(NewMDN); M->insertNamedMDNode(NewMDN); EXPECT_EQ(M->named_metadata_size(), 3u); EXPECT_EQ(&*std::prev(M->named_metadata().end()), NewMDN); auto Range = M->named_metadata(); EXPECT_EQ(&*Range.begin(), MDN1); EXPECT_EQ(&*std::next(Range.begin(), 1), MDN2); EXPECT_EQ(&*std::next(Range.begin(), 2), NewMDN); EXPECT_EQ(std::next(Range.begin(), 3), Range.end()); M->eraseNamedMDNode(NewMDN); EXPECT_EQ(M->named_metadata_size(), 2u); } TEST(ModuleTest, GlobalList) { // This tests all Module's functions that interact with Module::GlobalList. LLVMContext C; SMDiagnostic Err; LLVMContext Context; std::unique_ptr M = parseAssemblyString(R"( @GV = external global i32 )", Err, Context); auto *GV = cast(M->getNamedValue("GV")); EXPECT_EQ(M->global_size(), 1u); GlobalVariable *NewGV = new GlobalVariable( Type::getInt32Ty(C), /*isConstant=*/true, GlobalValue::InternalLinkage, /*Initializer=*/nullptr, "NewGV"); EXPECT_EQ(M->global_size(), 1u); // Insert before M->insertGlobalVariable(M->globals().begin(), NewGV); EXPECT_EQ(M->global_size(), 2u); EXPECT_EQ(&*M->globals().begin(), NewGV); // Insert at end() M->removeGlobalVariable(NewGV); EXPECT_EQ(M->global_size(), 1u); M->insertGlobalVariable(NewGV); EXPECT_EQ(M->global_size(), 2u); EXPECT_EQ(&*std::prev(M->globals().end()), NewGV); // Check globals() auto Range = M->globals(); EXPECT_EQ(&*Range.begin(), GV); EXPECT_EQ(&*std::next(Range.begin()), NewGV); EXPECT_EQ(std::next(Range.begin(), 2), Range.end()); // Check remove M->removeGlobalVariable(NewGV); EXPECT_EQ(M->global_size(), 1u); // Check erase M->insertGlobalVariable(NewGV); M->eraseGlobalVariable(NewGV); EXPECT_EQ(M->global_size(), 1u); } } // end namespace