| //===- MachineModuleInfoTest.cpp ------------------------------------------===// |
| // |
| // 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/CodeGen/MachineModuleInfo.h" |
| #include "llvm/CodeGen/MachineFunction.h" |
| #include "llvm/IR/DerivedTypes.h" |
| #include "llvm/IR/Function.h" |
| #include "llvm/IR/Module.h" |
| #include "llvm/MC/TargetRegistry.h" |
| #include "llvm/Support/TargetSelect.h" |
| #include "llvm/Target/TargetMachine.h" |
| #include "llvm/Target/TargetOptions.h" |
| #include "gtest/gtest.h" |
| |
| #include <memory> |
| |
| using namespace llvm; |
| |
| namespace { |
| |
| class MachineModuleInfoTest : public testing::Test { |
| protected: |
| LLVMContext Ctx; |
| std::unique_ptr<Module> M; |
| std::unique_ptr<TargetMachine> TM; |
| |
| void SetUp() override { |
| InitializeAllTargets(); |
| InitializeAllTargetMCs(); |
| |
| M = std::make_unique<Module>("test", Ctx); |
| |
| Triple TargetTriple("x86_64--"); |
| std::string Error; |
| const Target *T = TargetRegistry::lookupTarget("", TargetTriple, Error); |
| if (!T) |
| GTEST_SKIP(); |
| |
| TargetOptions Options; |
| TM.reset(T->createTargetMachine(TargetTriple, "", "", Options, std::nullopt, |
| std::nullopt, CodeGenOptLevel::None)); |
| M->setDataLayout(TM->createDataLayout()); |
| } |
| |
| Function *createEmptyFunction(StringRef Name) { |
| auto *Ty = FunctionType::get(Type::getVoidTy(Ctx), false); |
| return Function::Create(Ty, GlobalValue::ExternalLinkage, Name, M.get()); |
| } |
| }; |
| |
| // Deleting an ungrouped function erases its MachineFunction immediately. |
| TEST_F(MachineModuleInfoTest, DeleteUngroupedMachineFunction) { |
| MachineModuleInfo MMI(TM.get()); |
| |
| Function *F = createEmptyFunction("f"); |
| MMI.getOrCreateMachineFunction(*F); |
| ASSERT_NE(MMI.getMachineFunction(*F), nullptr); |
| |
| MMI.deleteMachineFunctionFor(*F); |
| EXPECT_EQ(MMI.getMachineFunction(*F), nullptr); |
| } |
| |
| // When two functions are grouped for deletion, their MachineFunctions must not |
| // be erased until every function in the group has been finalized. |
| TEST_F(MachineModuleInfoTest, DeleteGroupedMachineFunctions) { |
| MachineModuleInfo MMI(TM.get()); |
| |
| Function *F1 = createEmptyFunction("f1"); |
| Function *F2 = createEmptyFunction("f2"); |
| MMI.getOrCreateMachineFunction(*F1); |
| MMI.getOrCreateMachineFunction(*F2); |
| ASSERT_NE(MMI.getMachineFunction(*F1), nullptr); |
| ASSERT_NE(MMI.getMachineFunction(*F2), nullptr); |
| |
| MMI.groupMachineFunctionsForDeletion(*F1, *F2); |
| |
| // Finalizing only the first grouped function must defer erasure of both |
| // MachineFunctions. |
| MMI.deleteMachineFunctionFor(*F1); |
| EXPECT_NE(MMI.getMachineFunction(*F1), nullptr); |
| EXPECT_NE(MMI.getMachineFunction(*F2), nullptr); |
| |
| // Once the last grouped function is finalized, all grouped MachineFunctions |
| // are erased together. |
| MMI.deleteMachineFunctionFor(*F2); |
| EXPECT_EQ(MMI.getMachineFunction(*F1), nullptr); |
| EXPECT_EQ(MMI.getMachineFunction(*F2), nullptr); |
| } |
| |
| // A group of three functions is only erased once all three are finalized, |
| // regardless of the order in which they are deleted. |
| TEST_F(MachineModuleInfoTest, DeleteGroupedMachineFunctionsThreeMembers) { |
| MachineModuleInfo MMI(TM.get()); |
| |
| Function *F1 = createEmptyFunction("f1"); |
| Function *F2 = createEmptyFunction("f2"); |
| Function *F3 = createEmptyFunction("f3"); |
| Function *F4 = createEmptyFunction("f4"); |
| MMI.getOrCreateMachineFunction(*F1); |
| MMI.getOrCreateMachineFunction(*F2); |
| MMI.getOrCreateMachineFunction(*F3); |
| MMI.getOrCreateMachineFunction(*F4); |
| |
| // Build a single group {F1, F2, F3} out of two pairwise groupings. |
| MMI.groupMachineFunctionsForDeletion(*F1, *F2); |
| MMI.groupMachineFunctionsForDeletion(*F2, *F3); |
| |
| MMI.deleteMachineFunctionFor(*F3); |
| EXPECT_NE(MMI.getMachineFunction(*F1), nullptr); |
| EXPECT_NE(MMI.getMachineFunction(*F2), nullptr); |
| EXPECT_NE(MMI.getMachineFunction(*F3), nullptr); |
| |
| MMI.deleteMachineFunctionFor(*F4); |
| EXPECT_EQ(MMI.getMachineFunction(*F4), nullptr); |
| |
| MMI.deleteMachineFunctionFor(*F1); |
| EXPECT_NE(MMI.getMachineFunction(*F1), nullptr); |
| EXPECT_NE(MMI.getMachineFunction(*F2), nullptr); |
| EXPECT_NE(MMI.getMachineFunction(*F3), nullptr); |
| |
| MMI.deleteMachineFunctionFor(*F2); |
| EXPECT_EQ(MMI.getMachineFunction(*F1), nullptr); |
| EXPECT_EQ(MMI.getMachineFunction(*F2), nullptr); |
| EXPECT_EQ(MMI.getMachineFunction(*F3), nullptr); |
| } |
| |
| } // namespace |