CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
528 lines
16 KiB
C++
528 lines
16 KiB
C++
//===- 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/Constants.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 "llvm/Support/raw_ostream.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
#include <random>
|
|
|
|
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<int> dist;
|
|
const size_t NBCheck = 10;
|
|
|
|
std::array<int, NBCheck> RandomStreams[2];
|
|
for (auto &RandomStream : RandomStreams) {
|
|
std::unique_ptr<RandomNumberGenerator> 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));
|
|
}
|
|
|
|
TEST(ModuleTest, setModuleFlagInt) {
|
|
LLVMContext Context;
|
|
Module M("M", Context);
|
|
StringRef Key = "Key";
|
|
uint32_t Val1 = 1;
|
|
uint32_t Val2 = 2;
|
|
EXPECT_EQ(nullptr, M.getModuleFlag(Key));
|
|
M.setModuleFlag(Module::ModFlagBehavior::Error, Key, Val1);
|
|
auto A1 = mdconst::extract_or_null<ConstantInt>(M.getModuleFlag(Key));
|
|
EXPECT_EQ(Val1, A1->getZExtValue());
|
|
M.setModuleFlag(Module::ModFlagBehavior::Error, Key, Val2);
|
|
auto A2 = mdconst::extract_or_null<ConstantInt>(M.getModuleFlag(Key));
|
|
EXPECT_EQ(Val2, A2->getZExtValue());
|
|
}
|
|
|
|
TEST(ModuleTest, setModuleFlagTwoMod) {
|
|
LLVMContext Context;
|
|
Module MA("MA", Context);
|
|
Module MB("MB", Context);
|
|
StringRef Key = "Key";
|
|
uint32_t Val1 = 1;
|
|
uint32_t Val2 = 2;
|
|
|
|
// Set a flag to MA
|
|
EXPECT_EQ(nullptr, MA.getModuleFlag(Key));
|
|
MA.setModuleFlag(Module::ModFlagBehavior::Error, Key, Val1);
|
|
auto A1 = mdconst::extract_or_null<ConstantInt>(MA.getModuleFlag(Key));
|
|
EXPECT_EQ(Val1, A1->getZExtValue());
|
|
|
|
// Set a flag to MB
|
|
EXPECT_EQ(nullptr, MB.getModuleFlag(Key));
|
|
MB.setModuleFlag(Module::ModFlagBehavior::Error, Key, Val1);
|
|
auto B1 = mdconst::extract_or_null<ConstantInt>(MB.getModuleFlag(Key));
|
|
EXPECT_EQ(Val1, B1->getZExtValue());
|
|
|
|
// Change the flag of MA
|
|
MA.setModuleFlag(Module::ModFlagBehavior::Error, Key, Val2);
|
|
auto A2 = mdconst::extract_or_null<ConstantInt>(MA.getModuleFlag(Key));
|
|
EXPECT_EQ(Val2, A2->getZExtValue());
|
|
|
|
// MB should keep the original flag value
|
|
auto B2 = mdconst::extract_or_null<ConstantInt>(MB.getModuleFlag(Key));
|
|
EXPECT_EQ(Val1, B2->getZExtValue());
|
|
}
|
|
|
|
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<Module> 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<Module> 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(
|
|
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<Module> 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<Module> 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<Module>("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<Module> M = parseAssemblyString(R"(
|
|
@GV = external global i32
|
|
)",
|
|
Err, Context);
|
|
auto *GV = cast<GlobalVariable>(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);
|
|
}
|
|
|
|
TEST(ModuleTest, MoveAssign) {
|
|
// This tests that we can move-assign modules, we parse two modules and
|
|
// move assign the second one to the first one, and check that the print
|
|
// is equal to what we loaded.
|
|
LLVMContext C;
|
|
SMDiagnostic Err;
|
|
LLVMContext Context;
|
|
std::unique_ptr<Module> M1 = parseAssemblyString(R"(
|
|
; ModuleID = '<string>'
|
|
source_filename = "<string1>"
|
|
|
|
@GV1 = external global i32
|
|
|
|
@GA1 = alias void (), ptr @Foo1
|
|
|
|
define void @Foo1() {
|
|
ret void
|
|
}
|
|
|
|
!llvm.module.flags = !{!0}
|
|
!llvm.dbg.cu = !{!1}
|
|
!foo1 = !{!3}
|
|
!bar1 = !{!4}
|
|
|
|
!0 = !{i32 2, !"Debug Info Version", i32 3}
|
|
!1 = distinct !DICompileUnit(language: DW_LANG_C99, file: !2, producer: "clang1", isOptimized: true, flags: "-O2", runtimeVersion: 0, splitDebugFilename: "abc.debug", emissionKind: LineTablesOnly)
|
|
!2 = !DIFile(filename: "path/to/file1", directory: "/path/to/dir1")
|
|
!3 = !DILocation(line: 12, column: 34, scope: !4)
|
|
!4 = distinct !DISubprogram(name: "foo1", scope: null, type: !5, spFlags: DISPFlagDefinition, unit: !1)
|
|
!5 = !DISubroutineType(types: !6)
|
|
!6 = !{null}
|
|
)",
|
|
Err, Context);
|
|
ASSERT_TRUE(M1.get());
|
|
|
|
StringLiteral M2Str = R"(
|
|
; ModuleID = '<string>'
|
|
source_filename = "<string2>"
|
|
|
|
@GV2 = external global i32
|
|
|
|
@GA2 = alias void (), ptr @Foo2
|
|
|
|
define void @Foo2() {
|
|
ret void
|
|
}
|
|
|
|
!llvm.module.flags = !{!0}
|
|
!llvm.dbg.cu = !{!1}
|
|
!foo2 = !{!3}
|
|
!bar2 = !{!4}
|
|
|
|
!0 = !{i32 2, !"Debug Info Version", i32 3}
|
|
!1 = distinct !DICompileUnit(language: DW_LANG_C99, file: !2, producer: "clang2", isOptimized: true, flags: "-O2", runtimeVersion: 0, splitDebugFilename: "abc.debug", emissionKind: LineTablesOnly)
|
|
!2 = !DIFile(filename: "path/to/file2", directory: "/path/to/dir2")
|
|
!3 = !DILocation(line: 1234, column: 56, scope: !4)
|
|
!4 = distinct !DISubprogram(name: "foo2", scope: null, type: !5, spFlags: DISPFlagDefinition, unit: !1)
|
|
!5 = !DISubroutineType(types: !6)
|
|
!6 = !{null}
|
|
)";
|
|
{
|
|
std::unique_ptr<Module> M2 = parseAssemblyString(M2Str, Err, Context);
|
|
ASSERT_TRUE(M2.get());
|
|
auto *GV1 = M1->getNamedValue("GV1");
|
|
ASSERT_TRUE(GV1);
|
|
auto *GV2 = M2->getNamedValue("GV2");
|
|
ASSERT_TRUE(GV2);
|
|
ASSERT_EQ(GV2->getParent(), &*M2);
|
|
|
|
auto *Foo2MD = M2->getNamedMetadata("foo2");
|
|
auto *Bar2MD = M2->getNamedMetadata("bar2");
|
|
*M1 = std::move(*M2);
|
|
ASSERT_EQ(GV2->getParent(), &*M1);
|
|
ASSERT_EQ(M1->getNamedMetadata("foo2"), Foo2MD);
|
|
ASSERT_EQ(M1->getNamedMetadata("bar2"), Bar2MD);
|
|
ASSERT_EQ(M1->getNamedMetadata("foo1"), nullptr);
|
|
|
|
for (const NamedMDNode &NMD : M1->named_metadata())
|
|
ASSERT_EQ(NMD.getParent(), &*M1);
|
|
}
|
|
|
|
std::string M1Print;
|
|
{
|
|
llvm::raw_string_ostream Os(M1Print);
|
|
Os << "\n" << *M1;
|
|
}
|
|
ASSERT_EQ(M2Str, M1Print);
|
|
}
|
|
|
|
TEST(ModuleTest, FunctionDefinitions) {
|
|
// Test getFunctionDefs() method which returns only functions with bodies
|
|
LLVMContext Context;
|
|
SMDiagnostic Err;
|
|
std::unique_ptr<Module> M = parseAssemblyString(R"(
|
|
declare void @Decl1()
|
|
declare void @Decl2()
|
|
|
|
define void @Def1() {
|
|
ret void
|
|
}
|
|
|
|
define void @Def2() {
|
|
ret void
|
|
}
|
|
|
|
declare void @Decl3()
|
|
|
|
define void @Def3() {
|
|
ret void
|
|
}
|
|
)",
|
|
Err, Context);
|
|
ASSERT_TRUE(M);
|
|
|
|
// Count total functions (should be 6: 3 declarations + 3 definitions)
|
|
size_t TotalFunctions = 0;
|
|
for (Function &F : *M) {
|
|
(void)F;
|
|
++TotalFunctions;
|
|
}
|
|
EXPECT_EQ(TotalFunctions, 6u);
|
|
|
|
// Count function definitions only (should be 3)
|
|
size_t DefinitionCount = 0;
|
|
for (Function &F : M->getFunctionDefs()) {
|
|
EXPECT_FALSE(F.isDeclaration());
|
|
++DefinitionCount;
|
|
}
|
|
EXPECT_EQ(DefinitionCount, 3u);
|
|
|
|
// Verify the names of the definitions
|
|
auto DefRange = M->getFunctionDefs();
|
|
auto It = DefRange.begin();
|
|
EXPECT_EQ(It->getName(), "Def1");
|
|
++It;
|
|
EXPECT_EQ(It->getName(), "Def2");
|
|
++It;
|
|
EXPECT_EQ(It->getName(), "Def3");
|
|
++It;
|
|
EXPECT_EQ(It, DefRange.end());
|
|
}
|
|
|
|
TEST(ModuleTest, FunctionDefinitionsEmpty) {
|
|
// Test getFunctionDefs() with no definitions (only declarations)
|
|
LLVMContext Context;
|
|
SMDiagnostic Err;
|
|
std::unique_ptr<Module> M = parseAssemblyString(R"(
|
|
declare void @Decl1()
|
|
declare void @Decl2()
|
|
declare void @Decl3()
|
|
)",
|
|
Err, Context);
|
|
ASSERT_TRUE(M);
|
|
|
|
// Should have functions
|
|
EXPECT_FALSE(M->empty());
|
|
EXPECT_EQ(M->size(), 3u);
|
|
|
|
// But no definitions
|
|
size_t DefinitionCount = 0;
|
|
for (Function &F : M->getFunctionDefs()) {
|
|
(void)F;
|
|
++DefinitionCount;
|
|
}
|
|
EXPECT_EQ(DefinitionCount, 0u);
|
|
}
|
|
|
|
} // end namespace
|