Author: Nikita Popov Date: 2026-07-16T08:59:19+02:00 New Revision: 6f3a1e431f9f8bae9f78244c8ee1a38203dc62b6
URL: https://github.com/llvm/llvm-project/commit/6f3a1e431f9f8bae9f78244c8ee1a38203dc62b6 DIFF: https://github.com/llvm/llvm-project/commit/6f3a1e431f9f8bae9f78244c8ee1a38203dc62b6.diff LOG: Revert "[MergeFunctions] Preserve instruction-level profile metadata during m…" This reverts commit 687fbfae778ac2953c35920fb042446ef967c239. Added: Modified: llvm/include/llvm/Transforms/IPO/MergeFunctions.h llvm/lib/Transforms/IPO/MergeFunctions.cpp llvm/unittests/Transforms/IPO/MergeFunctionsTest.cpp Removed: llvm/test/Transforms/MergeFunc/merge-functions-branch-weights.ll llvm/test/Transforms/MergeFunc/merge-functions-reordered-blocks-branch-weights.ll llvm/test/Transforms/MergeFunc/merge-functions-select-weights.ll llvm/test/Transforms/MergeFunc/merge-functions-value-profile.ll ################################################################################ diff --git a/llvm/include/llvm/Transforms/IPO/MergeFunctions.h b/llvm/include/llvm/Transforms/IPO/MergeFunctions.h index d28d6167e5555..75399d3297a05 100644 --- a/llvm/include/llvm/Transforms/IPO/MergeFunctions.h +++ b/llvm/include/llvm/Transforms/IPO/MergeFunctions.h @@ -28,9 +28,9 @@ class MergeFunctionsPass : public OptionalPassInfoMixin<MergeFunctionsPass> { public: LLVM_ABI PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); - LLVM_ABI static bool runOnModule(Module &M, ModuleAnalysisManager &AM); + LLVM_ABI static bool runOnModule(Module &M); LLVM_ABI static DenseMap<Function *, Function *> - runOnFunctions(ArrayRef<Function *> Funcs, ModuleAnalysisManager &AM); + runOnFunctions(ArrayRef<Function *> F); }; } // end namespace llvm diff --git a/llvm/lib/Transforms/IPO/MergeFunctions.cpp b/llvm/lib/Transforms/IPO/MergeFunctions.cpp index afe80da5843ca..c4e56855ea2fb 100644 --- a/llvm/lib/Transforms/IPO/MergeFunctions.cpp +++ b/llvm/lib/Transforms/IPO/MergeFunctions.cpp @@ -89,15 +89,9 @@ //===----------------------------------------------------------------------===// #include "llvm/Transforms/IPO/MergeFunctions.h" -#include "llvm/ADT/APInt.h" #include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/PostOrderIterator.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" -#include "llvm/Analysis/BlockFrequencyInfo.h" -#include "llvm/Analysis/BranchProbabilityInfo.h" #include "llvm/IR/Argument.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/DebugInfoMetadata.h" @@ -110,21 +104,16 @@ #include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" -#include "llvm/IR/Metadata.h" #include "llvm/IR/Module.h" -#include "llvm/IR/PassManager.h" -#include "llvm/IR/ProfDataUtils.h" #include "llvm/IR/StructuralHash.h" #include "llvm/IR/Type.h" #include "llvm/IR/Use.h" #include "llvm/IR/User.h" #include "llvm/IR/Value.h" #include "llvm/IR/ValueHandle.h" -#include "llvm/ProfileData/InstrProf.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" -#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/IPO.h" @@ -132,10 +121,7 @@ #include "llvm/Transforms/Utils/ModuleUtils.h" #include <algorithm> #include <cassert> -#include <cstddef> -#include <cstdint> #include <iterator> -#include <memory> #include <optional> #include <set> #include <utility> @@ -208,11 +194,11 @@ class FunctionNode { /// bitcast of the other. class MergeFunctions { public: - explicit MergeFunctions(FunctionAnalysisManager &FAM) - : FnTree(FunctionNodeCmp(&GlobalNumbers)), FAM(FAM) {} + MergeFunctions() : FnTree(FunctionNodeCmp(&GlobalNumbers)) { + } template <typename FuncContainer> bool run(FuncContainer &Functions); - DenseMap<Function *, Function *> runOnFunctions(ArrayRef<Function *> Funcs); + DenseMap<Function *, Function *> runOnFunctions(ArrayRef<Function *> F); SmallPtrSet<GlobalValue *, 4> &getUsed(); @@ -271,8 +257,6 @@ class MergeFunctions { /// again. void mergeTwoFunctions(Function *F, Function *G); - void mergeInstrProfMetadataInto(Function *Dst, Function *Src); - /// Fill PDIUnrelatedWL with instructions from the entry block that are /// unrelated to parameter related debug info. /// \param PDVRUnrelatedWL The equivalent non-intrinsic debug records. @@ -303,9 +287,7 @@ class MergeFunctions { // If needed, replace G with an alias to F if possible, or a thunk to F if // profitable. Returns false if neither is the case. If \p G is not needed // (i.e. it is discardable and not used), \p G is removed directly. - // \p MergeProfile must be true when G's profile should be preserved, it is - // merged into F before G is erased or rewritten. - bool writeThunkOrAliasIfNeeded(Function *F, Function *G, bool MergeProfile); + bool writeThunkOrAliasIfNeeded(Function *F, Function *G); /// Replace function F with function G in the function tree. void replaceFunctionInTree(const FunctionNode &FN, Function *G); @@ -323,23 +305,20 @@ class MergeFunctions { /// Deleted-New functions mapping DenseMap<Function *, Function *> DelToNewMap; - - FunctionAnalysisManager &FAM; }; } // end anonymous namespace PreservedAnalyses MergeFunctionsPass::run(Module &M, ModuleAnalysisManager &AM) { - if (!MergeFunctionsPass::runOnModule(M, AM)) + if (!MergeFunctionsPass::runOnModule(M)) return PreservedAnalyses::all(); return PreservedAnalyses::none(); } SmallPtrSet<GlobalValue *, 4> &MergeFunctions::getUsed() { return Used; } -bool MergeFunctionsPass::runOnModule(Module &M, ModuleAnalysisManager &AM) { - auto &FAM = AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager(); - MergeFunctions MF(FAM); +bool MergeFunctionsPass::runOnModule(Module &M) { + MergeFunctions MF; SmallVector<GlobalValue *, 4> UsedV; collectUsedGlobalVariables(M, UsedV, /*CompilerUsed=*/false); collectUsedGlobalVariables(M, UsedV, /*CompilerUsed=*/true); @@ -348,15 +327,9 @@ bool MergeFunctionsPass::runOnModule(Module &M, ModuleAnalysisManager &AM) { } DenseMap<Function *, Function *> -MergeFunctionsPass::runOnFunctions(ArrayRef<Function *> Funcs, - ModuleAnalysisManager &AM) { - if (Funcs.empty()) - return DenseMap<Function *, Function *>(); - - Module &M = *Funcs.front()->getParent(); - auto &FAM = AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager(); - MergeFunctions MF(FAM); - return MF.runOnFunctions(Funcs); +MergeFunctionsPass::runOnFunctions(ArrayRef<Function *> F) { + MergeFunctions MF; + return MF.runOnFunctions(F); } #ifndef NDEBUG @@ -520,8 +493,8 @@ template <typename FuncContainer> bool MergeFunctions::run(FuncContainer &M) { } DenseMap<Function *, Function *> -MergeFunctions::runOnFunctions(ArrayRef<Function *> Funcs) { - [[maybe_unused]] bool MergeResult = this->run(Funcs); +MergeFunctions::runOnFunctions(ArrayRef<Function *> F) { + [[maybe_unused]] bool MergeResult = this->run(F); assert(MergeResult == !DelToNewMap.empty()); return this->DelToNewMap; } @@ -761,7 +734,7 @@ static void copyMetadataIfPresent(Function *From, Function *To, // For better debugability, under MergeFunctionsPDI, we do not modify G's // call sites to point to F even when within the same translation unit. void MergeFunctions::writeThunk(Function *F, Function *G) { - std::optional<uint64_t> GEntryCount = G->getEntryCount(); + std::optional<uint64_t> GEC = G->getEntryCount(); BasicBlock *GEntryBlock = nullptr; std::vector<Instruction *> PDIUnrelatedWL; std::vector<DbgVariableRecord *> PDVRUnrelatedWL; @@ -831,8 +804,8 @@ void MergeFunctions::writeThunk(Function *F, Function *G) { << G->getName() << "()\n"); } else { NewG->copyAttributesFrom(G); - if (GEntryCount) - NewG->setEntryCount(*GEntryCount); + if (GEC) + NewG->setEntryCount(*GEC); NewG->takeName(G); // Ensure CFI type metadata is propagated to the new function. copyMetadataIfPresent(G, NewG, "type"); @@ -885,36 +858,21 @@ void MergeFunctions::writeAlias(Function *F, Function *G) { // If needed, replace G with an alias to F if possible, or a thunk to F if // profitable. Returns false if neither is the case. If \p G is not needed (i.e. -// it is discardable and unused), \p G is removed directly. If \p MergeProfile -// is set, G's profile metadata is merged into F. -bool MergeFunctions::writeThunkOrAliasIfNeeded(Function *F, Function *G, - bool MergeProfile) { - bool ShouldErase = - G->isDiscardableIfUnused() && G->use_empty() && !MergeFunctionsPDI; - bool ShouldAlias = canCreateAliasFor(G); - bool ShouldThunk = canCreateThunkFor(F); - - if (!ShouldErase && !ShouldAlias && !ShouldThunk) - return false; - - if (MergeProfile) - mergeInstrProfMetadataInto(F, G); - - if (ShouldErase) { +// it is discardable and unused), \p G is removed directly. +bool MergeFunctions::writeThunkOrAliasIfNeeded(Function *F, Function *G) { + if (G->isDiscardableIfUnused() && G->use_empty() && !MergeFunctionsPDI) { G->eraseFromParent(); return true; } - - if (ShouldAlias) { + if (canCreateAliasFor(G)) { writeAlias(F, G); return true; } - if (ShouldThunk) { + if (canCreateThunkFor(F)) { writeThunk(F, G); return true; } - - llvm_unreachable("Erase, alias or thunk must apply"); + return false; } /// Returns true if \p F is either weak_odr or linkonce_odr. @@ -922,174 +880,6 @@ static bool isODR(const Function *F) { return F->hasWeakODRLinkage() || F->hasLinkOnceODRLinkage(); } -static uint64_t getBlockCountForMerging(const BlockFrequencyInfo &BFI, - const BasicBlock *BB) { - if (auto Count = BFI.getBlockProfileCount(BB, /*AllowSynthetic=*/true)) - return *Count; - return 1; -} - -// The branch weights are relative within a function. Before merging we -// normalize these to absolute counts. -// (weight * BlockCount / TotalWeight) -static uint64_t scaleToBlockCount(uint64_t Weight, uint64_t TotalWeight, - uint64_t BlockCount) { - if (Weight == 0 || TotalWeight == 0 || BlockCount == 0) - return 0; - APInt Num(128, BlockCount); - Num *= APInt(128, Weight); - APInt Den(128, TotalWeight); - Num = (Num + Den.lshr(1)).udiv(Den); - assert(Num.getActiveBits() <= 64 && - "scaleToBlockCount: result exceeds uint64_t; Weight > TotalWeight?"); - return Num.getLimitedValue(); -} - -// Combine the scaled branch_weights of corresponding instructions of F and G. -static void mergeBranchWeightsOnInstructions(Instruction *DstI, - const Instruction *SrcI, - const BlockFrequencyInfo &DstBFI, - const BlockFrequencyInfo &SrcBFI) { - SmallVector<uint32_t, 8> DstWeights, SrcWeights; - bool HasDst = extractBranchWeights(*DstI, DstWeights); - bool HasSrc = extractBranchWeights(*SrcI, SrcWeights); - if (!HasDst && !HasSrc) - return; - - uint64_t DstBlockCount = getBlockCountForMerging(DstBFI, DstI->getParent()); - uint64_t SrcBlockCount = getBlockCountForMerging(SrcBFI, SrcI->getParent()); - - uint64_t DstTotal = 0, SrcTotal = 0; - if (HasDst) - extractProfTotalWeight(*DstI, DstTotal); - if (HasSrc) - extractProfTotalWeight(*SrcI, SrcTotal); - - assert((!HasDst || !HasSrc || DstWeights.size() == SrcWeights.size()) && - "equivalent branch/select instructions must have matching weight " - "arity"); - size_t NumWeights = HasDst ? DstWeights.size() : SrcWeights.size(); - SmallVector<uint64_t, 8> MergedWeights; - MergedWeights.reserve(NumWeights); - for (size_t I = 0; I < NumWeights; ++I) { - uint64_t DstW = HasDst ? DstWeights[I] : 0; - uint64_t SrcW = HasSrc ? SrcWeights[I] : 0; - uint64_t DstAbs = scaleToBlockCount(DstW, DstTotal, DstBlockCount); - uint64_t SrcAbs = scaleToBlockCount(SrcW, SrcTotal, SrcBlockCount); - MergedWeights.push_back(SaturatingAdd(DstAbs, SrcAbs)); - } - - bool IsExpected = - hasBranchWeightOrigin(*DstI) && hasBranchWeightOrigin(*SrcI); - setFittedBranchWeights(*DstI, MergedWeights, IsExpected); -} - -// Accumulate value profile counts of Instruction I into Merged. Value profile -// counts are absolute, not relative branch-style weights. -static void addValueProfile(const Instruction &I, InstrProfValueKind Kind, - DenseMap<uint64_t, uint64_t> &Merged) { - uint64_t Total = 0; - SmallVector<InstrProfValueData, 4> VDs = - getValueProfDataFromInst(I, Kind, /*MaxNumValueData=*/UINT32_MAX, Total); - if (VDs.empty()) - return; - for (const InstrProfValueData &VD : VDs) - Merged[VD.Value] = SaturatingAdd(Merged[VD.Value], VD.Count); -} - -// Merge (union) value profiles of Dst and Src. -static void mergeValueProfileOnInstructions(Instruction *DstI, - const Instruction *SrcI) { - MDNode *DstProf = DstI->getMetadata(LLVMContext::MD_prof); - MDNode *SrcProf = SrcI->getMetadata(LLVMContext::MD_prof); - bool HasDst = DstProf && isValueProfileMD(DstProf); - bool HasSrc = SrcProf && isValueProfileMD(SrcProf); - if (!HasDst && !HasSrc) - return; - - auto *DstKind = - HasDst ? mdconst::dyn_extract<ConstantInt>(DstProf->getOperand(1)) - : nullptr; - auto *SrcKind = - HasSrc ? mdconst::dyn_extract<ConstantInt>(SrcProf->getOperand(1)) - : nullptr; - if (HasDst && HasSrc && DstKind && SrcKind && - DstKind->getZExtValue() != SrcKind->getZExtValue()) { - DstI->setMetadata(LLVMContext::MD_prof, nullptr); - return; - } - - const ConstantInt *KindCI = DstKind ? DstKind : SrcKind; - if (!KindCI) { - DstI->setMetadata(LLVMContext::MD_prof, nullptr); - return; - } - - InstrProfValueKind Kind = - static_cast<InstrProfValueKind>(KindCI->getZExtValue()); - - DenseMap<uint64_t, uint64_t> Merged; - if (HasDst) - addValueProfile(*DstI, Kind, Merged); - if (HasSrc) - addValueProfile(*SrcI, Kind, Merged); - - if (Merged.empty()) - return; - - SmallVector<InstrProfValueData, 8> VDs; - VDs.reserve(Merged.size()); - uint64_t Sum = 0; - for (auto &[Value, Count] : Merged) { - VDs.push_back({Value, Count}); - Sum = SaturatingAdd(Sum, Count); - } - llvm::sort(VDs, [](const InstrProfValueData &A, const InstrProfValueData &B) { - return A.Count > B.Count; - }); - annotateValueSite(*DstI->getFunction()->getParent(), *DstI, VDs, Sum, Kind, - VDs.size()); -} - -/// Merge \p Src's instruction-level branch weights and value profile -/// metadata into the corresponding instructions of \p Dst. \p Dst is the -/// surviving function; \p Src will be erased or rewritten after this call. -/// Both functions must be structurally identical. -void MergeFunctions::mergeInstrProfMetadataInto(Function *Dst, Function *Src) { - const BlockFrequencyInfo &DstBFI = - FAM.getResult<BlockFrequencyAnalysis>(*Dst); - const BlockFrequencyInfo &SrcBFI = - FAM.getResult<BlockFrequencyAnalysis>(*Src); - - // FunctionComparator guarantees identical CFG topology and instruction - // ordering. Walk the CFGs in RPO rather than function block-list order, as - // equivalent functions need not store their basic blocks in the same order. - ReversePostOrderTraversal<Function *> DstRPOT(Dst); - ReversePostOrderTraversal<Function *> SrcRPOT(Src); - for (auto [DstBB, SrcBB] : llvm::zip_equal(DstRPOT, SrcRPOT)) { - for (auto [DstI, SrcI] : llvm::zip_equal(*DstBB, *SrcBB)) { - MDNode *DstProf = DstI.getMetadata(LLVMContext::MD_prof); - MDNode *SrcProf = SrcI.getMetadata(LLVMContext::MD_prof); - if ((DstProf && isValueProfileMD(DstProf)) || - (SrcProf && isValueProfileMD(SrcProf))) - mergeValueProfileOnInstructions(&DstI, &SrcI); - - // Handle branch weights on SelectInsts here. Terminators are handled - // separately below, outside the instruction loop. - if (isa<SelectInst>(DstI)) - mergeBranchWeightsOnInstructions(&DstI, &SrcI, DstBFI, SrcBFI); - } - Instruction *DstTerm = DstBB->getTerminator(); - const Instruction *SrcTerm = SrcBB->getTerminator(); - mergeBranchWeightsOnInstructions(DstTerm, SrcTerm, DstBFI, SrcBFI); - } - - PreservedAnalyses PA = PreservedAnalyses::all(); - PA.abandon<BranchProbabilityAnalysis>(); - PA.abandon<BlockFrequencyAnalysis>(); - FAM.invalidate(*Dst, PA); -} - static void mergeEntryCountsInto(Function *F, std::optional<uint64_t> FC, std::optional<uint64_t> GC) { if (!FC && !GC) @@ -1101,8 +891,8 @@ static void mergeEntryCountsInto(Function *F, std::optional<uint64_t> FC, // Merge two equivalent functions. Upon completion, Function G is deleted. void MergeFunctions::mergeTwoFunctions(Function *F, Function *G) { - std::optional<uint64_t> FEntryCount = F->getEntryCount(); - std::optional<uint64_t> GEntryCount = G->getEntryCount(); + std::optional<uint64_t> FEC = F->getEntryCount(); + std::optional<uint64_t> GEC = G->getEntryCount(); // Create a new thunk that both F and G can call, if F cannot call G directly. // That is the case if F is either interposable or if G is either weak_odr or @@ -1145,13 +935,10 @@ void MergeFunctions::mergeTwoFunctions(Function *F, Function *G) { const MaybeAlign NewFAlign = NewF->getAlign(); const MaybeAlign GAlign = G->getAlign(); - // Merge !prof, while G still has its body. - writeThunkOrAliasIfNeeded(F, G, /*MergeProfile*/ true); - if (FEntryCount) - NewF->setEntryCount(*FEntryCount); - // NewF becomes thunk/alias to the shared body F, it has no profile to be - // merged. - writeThunkOrAliasIfNeeded(F, NewF, /*MergeProfile*/ false); + writeThunkOrAliasIfNeeded(F, G); + if (FEC) + NewF->setEntryCount(*FEC); + writeThunkOrAliasIfNeeded(F, NewF); if (NewFAlign || GAlign) F->setAlignment(std::max(NewFAlign.valueOrOne(), GAlign.valueOrOne())); @@ -1159,9 +946,8 @@ void MergeFunctions::mergeTwoFunctions(Function *F, Function *G) { F->setAlignment(std::nullopt); F->setLinkage(GlobalValue::PrivateLinkage); // The private shared implementation accumulates both symbols' entries - // (FEntryCount + GEntryCount), while each ODR thunk retains its own - // per-symbol entry count. - mergeEntryCountsInto(F, FEntryCount, GEntryCount); + // (FEC + GEC), while each ODR thunk retains its own per-symbol entry count. + mergeEntryCountsInto(F, FEC, GEC); ++NumDoubleWeak; ++NumFunctionsMerged; } else { @@ -1189,15 +975,14 @@ void MergeFunctions::mergeTwoFunctions(Function *F, Function *G) { // stop here and delete G. There's no need for a thunk. (See note on // MergeFunctionsPDI above). if (G->isDiscardableIfUnused() && G->use_empty() && !MergeFunctionsPDI) { - mergeInstrProfMetadataInto(F, G); - mergeEntryCountsInto(F, FEntryCount, GEntryCount); + mergeEntryCountsInto(F, FEC, GEC); G->eraseFromParent(); ++NumFunctionsMerged; return; } - if (writeThunkOrAliasIfNeeded(F, G, /*MergeProfile*/ true)) { - mergeEntryCountsInto(F, FEntryCount, GEntryCount); + if (writeThunkOrAliasIfNeeded(F, G)) { + mergeEntryCountsInto(F, FEC, GEC); ++NumFunctionsMerged; } } diff --git a/llvm/test/Transforms/MergeFunc/merge-functions-branch-weights.ll b/llvm/test/Transforms/MergeFunc/merge-functions-branch-weights.ll deleted file mode 100644 index 46a80c2916766..0000000000000 --- a/llvm/test/Transforms/MergeFunc/merge-functions-branch-weights.ll +++ /dev/null @@ -1,239 +0,0 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --include-generated-funcs --version 6 -; RUN: opt -S -passes=mergefunc < %s | FileCheck %s - -; Verify that MergeFunctions correctly combines branch_weights on -; conditional branches when merging structurally identical functions. -; Because FunctionComparator only matches functions whose control-flow -; structure and instruction sequence are identical, MergeFunctions can -; process both functions side by side and merge any instruction-level -; metadata, including branch weight information. -; To compute the merged weights, the pass converts each function's -; relative branch weights into absolute execution counts using the -; function's entry count, then adds the corresponding counts together. - -; -------------------------------------------------------------------------- -; Both functions provide branch weight metadata. -; br_both_a: entry count = 100, weights = 10:90 -; absolute counts: true = 10, false = 90 -; br_both_b: entry count = 200, weights = 30:70 -; absolute counts: true = 60, false = 140 -; After merging: -; true = 10 + 60 = 70 -; false = 90 + 140 = 230 -; -------------------------------------------------------------------------- -define internal i32 @br_both_a(i32 %x) !prof !1 { -entry: - %cmp = icmp slt i32 %x, 0 - br i1 %cmp, label %then, label %else, !prof !2 - -then: - ret i32 1 - -else: - ret i32 0 -} - -define internal i32 @br_both_b(i32 %x) !prof !3 { -entry: - %cmp = icmp slt i32 %x, 0 - br i1 %cmp, label %then, label %else, !prof !4 - -then: - ret i32 1 - -else: - ret i32 0 -} - -; -------------------------------------------------------------------------- -; Only one of the functions provides branch weight metadata. -; br_one_a has an entry count of 40 but does not specify any -; branch_weights. -; br_one_b has an entry count of 60 with branch weights of 40:80, -; which correspond to absolute counts of true = 20 and false = 40. -; Since only br_one_b contributes branch weight information, the -; merged branch retains those counts: -; true = 20 -; false = 40 -; -------------------------------------------------------------------------- -define internal i32 @br_one_a(i32 %x) !prof !5 { -entry: - %cmp = icmp sgt i32 %x, 0 - br i1 %cmp, label %then, label %else - -then: - ret i32 7 - -else: - ret i32 8 -} - -define internal i32 @br_one_b(i32 %x) !prof !6 { -entry: - %cmp = icmp sgt i32 %x, 0 - br i1 %cmp, label %then, label %else, !prof !7 - -then: - ret i32 7 - -else: - ret i32 8 -} - -; -------------------------------------------------------------------------- -; Thunk case: two dso_local functions are merged through a thunk, and -; their branch weight metadata is combined as part of the merge. -; thunk_a has an entry count of 10 with branch weights of 1:9, -; resulting in absolute counts of true = 1 and false = 9. -; thunk_b has an entry count of 20 with branch weights of 3:17, -; resulting in absolute counts of true = 3 and false = 17. -; After merging the two functions, the corresponding counts are added: -; true = 1 + 3 = 4 -; false = 9 + 17 = 26 -; -------------------------------------------------------------------------- -define dso_local i32 @thunk_a(i32 %x) unnamed_addr !prof !8 { -entry: - %cmp = icmp ult i32 %x, 3 - br i1 %cmp, label %then, label %else, !prof !9 - -then: - ret i32 9 - -else: - ret i32 10 -} - -define dso_local i32 @thunk_b(i32 %x) unnamed_addr !prof !10 { -entry: - %cmp = icmp ult i32 %x, 3 - br i1 %cmp, label %then, label %else, !prof !11 - -then: - ret i32 9 - -else: - ret i32 10 -} - -; -------------------------------------------------------------------------- -; ODR case: two weak_odr functions are merged into a single shared -; implementation, and their branch weight metadata is merged as well. -; odr_a has an entry count of 100 with branch weights of 1:9, -; corresponding to absolute counts of true = 10 and false = 90. -; odr_b has an entry count of 200 with branch weights of 3:17, -; corresponding to absolute counts of true = 30 and false = 170. -; The merged function combines the counts from both inputs: -; true = 10 + 30 = 40 -; false = 90 + 170 = 260 -; -------------------------------------------------------------------------- -define weak_odr i32 @odr_a(i32 %x) !prof !12 { -entry: - %cmp = icmp ugt i32 %x, 4 - br i1 %cmp, label %then, label %else, !prof !13 - -then: - ret i32 11 - -else: - ret i32 12 -} - -define weak_odr i32 @odr_b(i32 %x) !prof !14 { -entry: - %cmp = icmp ugt i32 %x, 4 - br i1 %cmp, label %then, label %else, !prof !15 - -then: - ret i32 11 - -else: - ret i32 12 -} - -!1 = !{!"function_entry_count", i64 100} -!2 = !{!"branch_weights", i32 10, i32 90} -!3 = !{!"function_entry_count", i64 200} -!4 = !{!"branch_weights", i32 30, i32 70} -!5 = !{!"function_entry_count", i64 40} -!6 = !{!"function_entry_count", i64 60} -!7 = !{!"branch_weights", i32 40, i32 80} -!8 = !{!"function_entry_count", i64 10} -!9 = !{!"branch_weights", i32 1, i32 9} -!10 = !{!"function_entry_count", i64 20} -!11 = !{!"branch_weights", i32 3, i32 17} -!12 = !{!"function_entry_count", i64 100} -!13 = !{!"branch_weights", i32 1, i32 9} -!14 = !{!"function_entry_count", i64 200} -!15 = !{!"branch_weights", i32 3, i32 17} -; CHECK-LABEL: define internal i32 @br_both_a( -; CHECK-SAME: i32 [[X:%.*]]) !prof [[PROF0:![0-9]+]] { -; CHECK-NEXT: [[ENTRY:.*:]] -; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[X]], 0 -; CHECK-NEXT: br i1 [[CMP]], label %[[THEN:.*]], label %[[ELSE:.*]], !prof [[PROF1:![0-9]+]] -; CHECK: [[THEN]]: -; CHECK-NEXT: ret i32 1 -; CHECK: [[ELSE]]: -; CHECK-NEXT: ret i32 0 -; -; -; CHECK-LABEL: define internal i32 @br_one_a( -; CHECK-SAME: i32 [[X:%.*]]) !prof [[PROF2:![0-9]+]] { -; CHECK-NEXT: [[ENTRY:.*:]] -; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[X]], 0 -; CHECK-NEXT: br i1 [[CMP]], label %[[THEN:.*]], label %[[ELSE:.*]], !prof [[PROF3:![0-9]+]] -; CHECK: [[THEN]]: -; CHECK-NEXT: ret i32 7 -; CHECK: [[ELSE]]: -; CHECK-NEXT: ret i32 8 -; -; -; CHECK-LABEL: define dso_local i32 @thunk_a( -; CHECK-SAME: i32 [[X:%.*]]) unnamed_addr !prof [[PROF4:![0-9]+]] { -; CHECK-NEXT: [[ENTRY:.*:]] -; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[X]], 3 -; CHECK-NEXT: br i1 [[CMP]], label %[[THEN:.*]], label %[[ELSE:.*]], !prof [[PROF5:![0-9]+]] -; CHECK: [[THEN]]: -; CHECK-NEXT: ret i32 9 -; CHECK: [[ELSE]]: -; CHECK-NEXT: ret i32 10 -; -; -; CHECK-LABEL: define private i32 @0( -; CHECK-SAME: i32 [[X:%.*]]) !prof [[PROF0]] { -; CHECK-NEXT: [[ENTRY:.*:]] -; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32 [[X]], 4 -; CHECK-NEXT: br i1 [[CMP]], label %[[THEN:.*]], label %[[ELSE:.*]], !prof [[PROF6:![0-9]+]] -; CHECK: [[THEN]]: -; CHECK-NEXT: ret i32 11 -; CHECK: [[ELSE]]: -; CHECK-NEXT: ret i32 12 -; -; -; CHECK-LABEL: define dso_local i32 @thunk_b( -; CHECK-SAME: i32 [[TMP0:%.*]]) unnamed_addr !prof [[PROF7:![0-9]+]] { -; CHECK-NEXT: [[TMP2:%.*]] = tail call i32 @thunk_a(i32 [[TMP0]]) -; CHECK-NEXT: ret i32 [[TMP2]] -; -; -; CHECK-LABEL: define weak_odr i32 @odr_b( -; CHECK-SAME: i32 [[TMP0:%.*]]) !prof [[PROF8:![0-9]+]] { -; CHECK-NEXT: [[TMP2:%.*]] = tail call i32 @[[GLOB0:[0-9]+]](i32 [[TMP0]]) -; CHECK-NEXT: ret i32 [[TMP2]] -; -; -; CHECK-LABEL: define weak_odr i32 @odr_a( -; CHECK-SAME: i32 [[TMP0:%.*]]) !prof [[PROF2]] { -; CHECK-NEXT: [[TMP2:%.*]] = tail call i32 @[[GLOB0]](i32 [[TMP0]]) -; CHECK-NEXT: ret i32 [[TMP2]] -; -;. -; CHECK: [[PROF0]] = !{!"function_entry_count", i64 300} -; CHECK: [[PROF1]] = !{!"branch_weights", i32 70, i32 230} -; CHECK: [[PROF2]] = !{!"function_entry_count", i64 100} -; CHECK: [[PROF3]] = !{!"branch_weights", i32 20, i32 40} -; CHECK: [[PROF4]] = !{!"function_entry_count", i64 30} -; CHECK: [[PROF5]] = !{!"branch_weights", i32 4, i32 26} -; CHECK: [[PROF6]] = !{!"branch_weights", i32 40, i32 260} -; CHECK: [[PROF7]] = !{!"function_entry_count", i64 20} -; CHECK: [[PROF8]] = !{!"function_entry_count", i64 200} -;. diff --git a/llvm/test/Transforms/MergeFunc/merge-functions-reordered-blocks-branch-weights.ll b/llvm/test/Transforms/MergeFunc/merge-functions-reordered-blocks-branch-weights.ll deleted file mode 100644 index 6853813849243..0000000000000 --- a/llvm/test/Transforms/MergeFunc/merge-functions-reordered-blocks-branch-weights.ll +++ /dev/null @@ -1,121 +0,0 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 -; RUN: opt -S -passes=mergefunc < %s | FileCheck %s - -; Verify that MergeFunctions correctly combines branch_weights when equivalent -; functions store corresponding basic blocks in a diff erent textual order. -; mergeInstrProfMetadataInto must match blocks by CFG traversal, not function -; block-list order, so the left and right branch metadata is merged with the -; corresponding block even when @br_reordered_b lists right before left. - -; -------------------------------------------------------------------------- -; Both functions have the same CFG and successor order: -; entry -> left/right -; left -> ret1/ret2 -; right -> ret3/ret4 -; -; br_reordered_a block order: entry, left, right, ret1, ret2, ret3, ret4 -; br_reordered_b block order: entry, right, left, ret1, ret2, ret3, ret4 -; -; entry is reached with counts 100 and 200, and both functions split it evenly: -; true = 50 + 100 = 150 -; false = 50 + 100 = 150 -; -; left is reached with counts 50 and 100. -; br_reordered_a left weights = 1:4, giving counts 10:40. -; br_reordered_b left weights = 3:7, giving counts 30:70. -; After merging left: -; true = 10 + 30 = 40 -; false = 40 + 70 = 110 -; -; right is reached with counts 50 and 100. -; br_reordered_a right weights = 2:3, giving counts 20:30. -; br_reordered_b right weights = 4:6, giving counts 40:60. -; After merging right: -; true = 20 + 40 = 60 -; false = 30 + 60 = 90 -; -------------------------------------------------------------------------- -define internal i32 @br_reordered_a(i32 %x, i32 %y) !prof !0 { -; CHECK-LABEL: define internal i32 @br_reordered_a( -; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) !prof [[PROF0:![0-9]+]] { -; CHECK-NEXT: [[ENTRY:.*:]] -; CHECK-NEXT: [[ENTRY_CMP:%.*]] = icmp slt i32 [[X]], 0 -; CHECK-NEXT: br i1 [[ENTRY_CMP]], label %[[LEFT:.*]], label %[[RIGHT:.*]], !prof [[PROF1:![0-9]+]] -; CHECK: [[LEFT]]: -; CHECK-NEXT: [[LEFT_CMP:%.*]] = icmp slt i32 [[Y]], 10 -; CHECK-NEXT: br i1 [[LEFT_CMP]], label %[[RET1:.*]], label %[[RET2:.*]], !prof [[PROF2:![0-9]+]] -; CHECK: [[RIGHT]]: -; CHECK-NEXT: [[RIGHT_CMP:%.*]] = icmp slt i32 [[Y]], 20 -; CHECK-NEXT: br i1 [[RIGHT_CMP]], label %[[RET3:.*]], label %[[RET4:.*]], !prof [[PROF3:![0-9]+]] -; CHECK: [[RET1]]: -; CHECK-NEXT: ret i32 1 -; CHECK: [[RET2]]: -; CHECK-NEXT: ret i32 2 -; CHECK: [[RET3]]: -; CHECK-NEXT: ret i32 3 -; CHECK: [[RET4]]: -; CHECK-NEXT: ret i32 4 -; -entry: - %entry.cmp = icmp slt i32 %x, 0 - br i1 %entry.cmp, label %left, label %right, !prof !1 - -left: ; preds = %entry - %left.cmp = icmp slt i32 %y, 10 - br i1 %left.cmp, label %ret1, label %ret2, !prof !2 - -right: ; preds = %entry - %right.cmp = icmp slt i32 %y, 20 - br i1 %right.cmp, label %ret3, label %ret4, !prof !3 - -ret1: ; preds = %left - ret i32 1 - -ret2: ; preds = %left - ret i32 2 - -ret3: ; preds = %right - ret i32 3 - -ret4: ; preds = %right - ret i32 4 -} - -define internal i32 @br_reordered_b(i32 %x, i32 %y) !prof !4 { -entry: - %entry.cmp = icmp slt i32 %x, 0 - br i1 %entry.cmp, label %left, label %right, !prof !1 - -right: ; preds = %entry - %right.cmp = icmp slt i32 %y, 20 - br i1 %right.cmp, label %ret3, label %ret4, !prof !5 - -left: ; preds = %entry - %left.cmp = icmp slt i32 %y, 10 - br i1 %left.cmp, label %ret1, label %ret2, !prof !6 - -ret1: ; preds = %left - ret i32 1 - -ret2: ; preds = %left - ret i32 2 - -ret3: ; preds = %right - ret i32 3 - -ret4: ; preds = %right - ret i32 4 -} - -!0 = !{!"function_entry_count", i64 100} -!1 = !{!"branch_weights", i32 1, i32 1} -!2 = !{!"branch_weights", i32 1, i32 4} -!3 = !{!"branch_weights", i32 2, i32 3} -!4 = !{!"function_entry_count", i64 200} -!5 = !{!"branch_weights", i32 4, i32 6} -!6 = !{!"branch_weights", i32 3, i32 7} -;. -; CHECK: [[PROF0]] = !{!"function_entry_count", i64 300} -; CHECK: [[PROF1]] = !{!"branch_weights", i32 150, i32 150} -; CHECK: [[PROF2]] = !{!"branch_weights", i32 40, i32 110} -; CHECK: [[PROF3]] = !{!"branch_weights", i32 60, i32 90} -;. diff --git a/llvm/test/Transforms/MergeFunc/merge-functions-select-weights.ll b/llvm/test/Transforms/MergeFunc/merge-functions-select-weights.ll deleted file mode 100644 index c052cabba6288..0000000000000 --- a/llvm/test/Transforms/MergeFunc/merge-functions-select-weights.ll +++ /dev/null @@ -1,50 +0,0 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 -; RUN: opt -S -passes=mergefunc < %s | FileCheck %s -; - -; Verify that MergeFunctions correctly combines select-instruction -; branch_weights when merging two structurally identical functions. -; Since FunctionComparator only considers functions equal when their -; control-flow graphs and instruction order match exactly, MergeFunctions -; can safely walk both functions in parallel and merge any instruction-level -; metadata it encounters. -; -; The functions sel_a and sel_b diff er only in their entry counts and -; select branch_weights. When merged, the pass first converts each -; function's relative branch weights into absolute execution counts using -; its entry count, and then adds the counts together to produce the -; final merged weights. -; -; sel_a: entry 50, weights 10:90 -> true=5, false=45 -; sel_b: entry 150, weights 30:70 -> true=45, false=105 -; Merged: true=5+45=50, false=45+105=150 - -define internal i32 @sel_a(i32 %x) !prof !1 { -; CHECK-LABEL: define internal i32 @sel_a( -; CHECK-SAME: i32 [[X:%.*]]) !prof [[PROF0:![0-9]+]] { -; CHECK-NEXT: [[ENTRY:.*:]] -; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[X]], 0 -; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 1, i32 0, !prof [[PROF1:![0-9]+]] -; CHECK-NEXT: ret i32 [[SEL]] -; -entry: - %cmp = icmp slt i32 %x, 0 - %sel = select i1 %cmp, i32 1, i32 0, !prof !2 - ret i32 %sel -} - -define internal i32 @sel_b(i32 %x) !prof !3 { -entry: - %cmp = icmp slt i32 %x, 0 - %sel = select i1 %cmp, i32 1, i32 0, !prof !4 - ret i32 %sel -} - -!1 = !{!"function_entry_count", i64 50} -!2 = !{!"branch_weights", i32 10, i32 90} -!3 = !{!"function_entry_count", i64 150} -!4 = !{!"branch_weights", i32 30, i32 70} -;. -; CHECK: [[PROF0]] = !{!"function_entry_count", i64 200} -; CHECK: [[PROF1]] = !{!"branch_weights", i32 50, i32 150} -;. diff --git a/llvm/test/Transforms/MergeFunc/merge-functions-value-profile.ll b/llvm/test/Transforms/MergeFunc/merge-functions-value-profile.ll deleted file mode 100644 index c5e9488b90480..0000000000000 --- a/llvm/test/Transforms/MergeFunc/merge-functions-value-profile.ll +++ /dev/null @@ -1,142 +0,0 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 -; RUN: opt -S -passes=mergefunc < %s | FileCheck %s -; - -; Verify that MergeFunctions correctly merges value profile (VP) metadata -; on indirect calls when combining structurally identical functions. -; Because FunctionComparator only considers functions equivalent when -; their control-flow structure and instruction ordering match exactly, -; MergeFunctions can walk the two functions in parallel and safely merge -; instruction-level metadata. -; -; Value profile counts are already absolute. The pass combines profiles by -; adding counts for targets that appear in both functions and preserving -; targets that appear in only one. - -; -------------------------------------------------------------------------- -; Both functions provide value profile metadata for the indirect call. -; -; vp_both_a has an entry count of 100 and a profile of: -; {111:60, 222:40} -; -; vp_both_b has an entry count of 200 and a profile of: -; {111:120, 333:80} -; -; After merging, counts for shared targets are summed while unique -; targets are carried over: -; -; entry count = 300 -; VP {111:180, 333:80, 222:40} -; -------------------------------------------------------------------------- -define internal i32 @vp_both_a(ptr %fn) !prof !1 { -; CHECK-LABEL: define internal i32 @vp_both_a( -; CHECK-SAME: ptr [[FN:%.*]]) !prof [[PROF0:![0-9]+]] { -; CHECK-NEXT: [[ENTRY:.*:]] -; CHECK-NEXT: [[FN_VAL:%.*]] = load ptr, ptr [[FN]], align 8 -; CHECK-NEXT: [[R:%.*]] = call i32 [[FN_VAL]](), !prof [[PROF1:![0-9]+]] -; CHECK-NEXT: ret i32 [[R]] -; -entry: - %fn_val = load ptr, ptr %fn - %r = call i32 %fn_val(), !prof !2 - ret i32 %r -} - -define internal i32 @vp_both_b(ptr %fn) !prof !3 { -entry: - %fn_val = load ptr, ptr %fn - %r = call i32 %fn_val(), !prof !4 - ret i32 %r -} - -; -------------------------------------------------------------------------- -; Only one of the functions provides value profile metadata for the -; indirect call. -; -; vp_one_a has an entry count of 30 but does not contain any VP data -; on the call site. -; -; vp_one_b has an entry count of 70 and records the target profile: -; {888:50} -; -; Since only vp_one_b contributes value profile information, the merged -; function carries that profile forward unchanged while combining the -; overall entry counts. -; -; entry count = 100 -; VP {888:50} -; -------------------------------------------------------------------------- -define internal i32 @vp_one_a(ptr %fn) !prof !5 { -; CHECK-LABEL: define internal i32 @vp_one_a( -; CHECK-SAME: ptr [[FN:%.*]]) !prof [[PROF2:![0-9]+]] { -; CHECK-NEXT: [[ENTRY:.*:]] -; CHECK-NEXT: [[FN_VAL:%.*]] = load ptr, ptr [[FN]], align 8 -; CHECK-NEXT: [[R:%.*]] = call i32 [[FN_VAL]](), !prof [[PROF3:![0-9]+]] -; CHECK-NEXT: [[ADJ:%.*]] = add i32 [[R]], 3 -; CHECK-NEXT: ret i32 [[ADJ]] -; -entry: - %fn_val = load ptr, ptr %fn - %r = call i32 %fn_val() - %adj = add i32 %r, 3 - ret i32 %adj -} - -define internal i32 @vp_one_b(ptr %fn) !prof !6 { -entry: - %fn_val = load ptr, ptr %fn - %r = call i32 %fn_val(), !prof !7 - %adj = add i32 %r, 3 - ret i32 %adj -} - -; -------------------------------------------------------------------------- -; Both functions attach value profile metadata to the indirect call, but -; they use diff erent VP kinds. -; -; Because the profiles are not compatible, MergeFunctions cannot safely -; merge them into a single representation. Rather than producing -; potentially misleading profile data, the pass drops the call-site -; !prof metadata during the merge. -; -------------------------------------------------------------------------- -define internal i32 @vp_kind_a(ptr %fn) !prof !8 { -; CHECK-LABEL: define internal i32 @vp_kind_a( -; CHECK-SAME: ptr [[FN:%.*]]) !prof [[PROF2]] { -; CHECK-NEXT: [[ENTRY:.*:]] -; CHECK-NEXT: [[FN_VAL:%.*]] = load ptr, ptr [[FN]], align 8 -; CHECK-NEXT: [[R:%.*]] = call i32 [[FN_VAL]]() -; CHECK-NEXT: [[ADJ:%.*]] = add i32 [[R]], 2 -; CHECK-NEXT: ret i32 [[ADJ]] -; -entry: - %fn_val = load ptr, ptr %fn - %r = call i32 %fn_val(), !prof !9 - %adj = add i32 %r, 2 - ret i32 %adj -} - -define internal i32 @vp_kind_b(ptr %fn) !prof !10 { -entry: - %fn_val = load ptr, ptr %fn - %r = call i32 %fn_val(), !prof !11 - %adj = add i32 %r, 2 - ret i32 %adj -} - -!1 = !{!"function_entry_count", i64 100} -!2 = !{!"VP", i32 0, i64 100, i64 111, i64 60, i64 222, i64 40} -!3 = !{!"function_entry_count", i64 200} -!4 = !{!"VP", i32 0, i64 200, i64 111, i64 120, i64 333, i64 80} -!5 = !{!"function_entry_count", i64 30} -!6 = !{!"function_entry_count", i64 70} -!7 = !{!"VP", i32 0, i64 70, i64 888, i64 50} -!8 = !{!"function_entry_count", i64 30} -!9 = !{!"VP", i32 0, i64 30, i64 666, i64 20} -!10 = !{!"function_entry_count", i64 70} -!11 = !{!"VP", i32 1, i64 70, i64 777, i64 50} -;. -; CHECK: [[PROF0]] = !{!"function_entry_count", i64 300} -; CHECK: [[PROF1]] = !{!"VP", i32 0, i64 300, i64 111, i64 180, i64 333, i64 80, i64 222, i64 40} -; CHECK: [[PROF2]] = !{!"function_entry_count", i64 100} -; CHECK: [[PROF3]] = !{!"VP", i32 0, i64 50, i64 888, i64 50} -;. diff --git a/llvm/unittests/Transforms/IPO/MergeFunctionsTest.cpp b/llvm/unittests/Transforms/IPO/MergeFunctionsTest.cpp index 879b48e6457a3..5be92b5ae3188 100644 --- a/llvm/unittests/Transforms/IPO/MergeFunctionsTest.cpp +++ b/llvm/unittests/Transforms/IPO/MergeFunctionsTest.cpp @@ -9,15 +9,9 @@ #include "llvm/Transforms/IPO/MergeFunctions.h" #include "llvm/ADT/SetVector.h" -#include "llvm/Analysis/BlockFrequencyInfo.h" -#include "llvm/Analysis/BranchProbabilityInfo.h" -#include "llvm/Analysis/LoopInfo.h" -#include "llvm/Analysis/PostDominators.h" -#include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/AsmParser/Parser.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" -#include "llvm/IR/PassInstrumentation.h" #include "llvm/Support/SourceMgr.h" #include "gtest/gtest.h" #include <memory> @@ -26,35 +20,10 @@ using namespace llvm; namespace { -class MergeFunctionsTest : public testing::Test { -protected: +TEST(MergeFunctions, TrueOutputModuleTest) { LLVMContext Ctx; - ModuleAnalysisManager MAM; - FunctionAnalysisManager FAM; - - MergeFunctionsTest() { - FAM.registerPass([&] { return TargetLibraryAnalysis(); }); - FAM.registerPass([&] { return DominatorTreeAnalysis(); }); - FAM.registerPass([&] { return PostDominatorTreeAnalysis(); }); - FAM.registerPass([&] { return LoopAnalysis(); }); - FAM.registerPass([&] { return BranchProbabilityAnalysis(); }); - FAM.registerPass([&] { return BlockFrequencyAnalysis(); }); - FAM.registerPass([&] { return PassInstrumentationAnalysis(); }); - FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM); }); - MAM.registerPass([&] { return PassInstrumentationAnalysis(); }); - MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); }); - } - - std::unique_ptr<Module> parseModule(StringRef IR) { - SMDiagnostic Err; - std::unique_ptr<Module> M = parseAssemblyString(IR, Err, Ctx); - EXPECT_TRUE(M); - return M; - } -}; - -TEST_F(MergeFunctionsTest, TrueOutputModuleTest) { - std::unique_ptr<Module> M = parseModule(R"invalid( + SMDiagnostic Err; + std::unique_ptr<Module> M(parseAssemblyString(R"invalid( @.str = private unnamed_addr constant [10 x i8] c"On f: %d\0A\00", align 1 @.str.1 = private unnamed_addr constant [13 x i8] c"On main: %d\0A\00", align 1 @@ -95,14 +64,17 @@ TEST_F(MergeFunctionsTest, TrueOutputModuleTest) { %4 = add nsw i32 %3, 2 ret i32 %4 } - )invalid"); + )invalid", + Err, Ctx)); // Expects true after merging _slice_add10 and _slice_add10_alt - EXPECT_TRUE(MergeFunctionsPass::runOnModule(*M, MAM)); + EXPECT_TRUE(MergeFunctionsPass::runOnModule(*M)); } -TEST_F(MergeFunctionsTest, TrueOutputFunctionsTest) { - std::unique_ptr<Module> M = parseModule(R"invalid( +TEST(MergeFunctions, TrueOutputFunctionsTest) { + LLVMContext Ctx; + SMDiagnostic Err; + std::unique_ptr<Module> M(parseAssemblyString(R"invalid( @.str = private unnamed_addr constant [10 x i8] c"On f: %d\0A\00", align 1 @.str.1 = private unnamed_addr constant [13 x i8] c"On main: %d\0A\00", align 1 @@ -143,14 +115,15 @@ TEST_F(MergeFunctionsTest, TrueOutputFunctionsTest) { %4 = add nsw i32 %3, 2 ret i32 %4 } - )invalid"); + )invalid", + Err, Ctx)); SetVector<Function *> FunctionsSet; for (Function &F : *M) FunctionsSet.insert(&F); DenseMap<Function *, Function *> MergeResult = - MergeFunctionsPass::runOnFunctions(FunctionsSet.getArrayRef(), MAM); + MergeFunctionsPass::runOnFunctions(FunctionsSet.getArrayRef()); // Expects that both functions (_slice_add10 and _slice_add10_alt) // be mapped to the same new function @@ -161,8 +134,10 @@ TEST_F(MergeFunctionsTest, TrueOutputFunctionsTest) { EXPECT_EQ(P.second, NewFunction); } -TEST_F(MergeFunctionsTest, FalseOutputModuleTest) { - std::unique_ptr<Module> M = parseModule(R"invalid( +TEST(MergeFunctions, FalseOutputModuleTest) { + LLVMContext Ctx; + SMDiagnostic Err; + std::unique_ptr<Module> M(parseAssemblyString(R"invalid( @.str = private unnamed_addr constant [10 x i8] c"On f: %d\0A\00", align 1 @.str.1 = private unnamed_addr constant [13 x i8] c"On main: %d\0A\00", align 1 @@ -203,14 +178,17 @@ TEST_F(MergeFunctionsTest, FalseOutputModuleTest) { %4 = add nsw i32 %3, 2 ret i32 %0 } - )invalid"); + )invalid", + Err, Ctx)); // Expects false after trying to merge _slice_add10 and _slice_add10_alt - EXPECT_FALSE(MergeFunctionsPass::runOnModule(*M, MAM)); + EXPECT_FALSE(MergeFunctionsPass::runOnModule(*M)); } -TEST_F(MergeFunctionsTest, FalseOutputFunctionsTest) { - std::unique_ptr<Module> M = parseModule(R"invalid( +TEST(MergeFunctions, FalseOutputFunctionsTest) { + LLVMContext Ctx; + SMDiagnostic Err; + std::unique_ptr<Module> M(parseAssemblyString(R"invalid( @.str = private unnamed_addr constant [10 x i8] c"On f: %d\0A\00", align 1 @.str.1 = private unnamed_addr constant [13 x i8] c"On main: %d\0A\00", align 1 @@ -251,14 +229,15 @@ TEST_F(MergeFunctionsTest, FalseOutputFunctionsTest) { %4 = add nsw i32 %3, 2 ret i32 %0 } - )invalid"); + )invalid", + Err, Ctx)); SetVector<Function *> FunctionsSet; for (Function &F : *M) FunctionsSet.insert(&F); DenseMap<Function *, Function *> MergeResult = - MergeFunctionsPass::runOnFunctions(FunctionsSet.getArrayRef(), MAM); + MergeFunctionsPass::runOnFunctions(FunctionsSet.getArrayRef()); // Expects empty map EXPECT_EQ(MergeResult.size(), 0u); _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
