Index: llvm/lib/Transforms/IPO/MergeFunctions.cpp =================================================================== --- llvm/lib/Transforms/IPO/MergeFunctions.cpp +++ llvm/lib/Transforms/IPO/MergeFunctions.cpp @@ -403,19 +403,42 @@ #endif /// Check whether \p F is eligible for function merging. -static bool isEligibleForMerging(Function &F) { - return !F.isDeclaration() && !F.hasAvailableExternallyLinkage(); +static bool +isEligibleForMerging(Function &F, + std::set TypeCheckedLoadUsingFuncs) { + if (F.isDeclaration() || F.hasAvailableExternallyLinkage()) + return false; + + if (TypeCheckedLoadUsingFuncs.count(&F)) + return false; + + return true; } bool MergeFunctions::runOnModule(Module &M) { bool Changed = false; + // Functions that use @llvm.type.checked.load intrinsic calls are not eligible + // for merging because the type metadata is not considered meaningful when + // comparing functions for equality. Let's find such functions. + Function *TypeCheckedLoadFunc = + M.getFunction(Intrinsic::getName(Intrinsic::type_checked_load)); + std::set TypeCheckedLoadUsingFuncs; + if (TypeCheckedLoadFunc) { + for (auto U : TypeCheckedLoadFunc->users()) { + auto CI = dyn_cast(U); + if (!CI) + continue; + TypeCheckedLoadUsingFuncs.insert(CI->getFunction()); + } + } + // All functions in the module, ordered by hash. Functions with a unique // hash value are easily eliminated. std::vector> HashedFuncs; for (Function &Func : M) { - if (isEligibleForMerging(Func)) { + if (isEligibleForMerging(Func, TypeCheckedLoadUsingFuncs)) { HashedFuncs.push_back({FunctionComparator::functionHash(Func), &Func}); } } Index: llvm/test/Transforms/MergeFunc/merge-type-metadata.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/MergeFunc/merge-type-metadata.ll @@ -0,0 +1,23 @@ +; RUN: opt -S -mergefunc < %s | FileCheck %s + +; CHECK: @call_vfunc1 +define internal i32 @call_vfunc1(i8* %vtable) unnamed_addr { + %a = tail call { i8*, i1 } @llvm.type.checked.load(i8* %vtable, i32 0, metadata !"vtype1") + ret i32 0 +} + +; CHECK: @call_vfunc2 +define internal i32 @call_vfunc2(i8* %vtable) unnamed_addr { + %a = tail call { i8*, i1 } @llvm.type.checked.load(i8* %vtable, i32 0, metadata !"vtype2") + ret i32 0 +} + +declare { i8*, i1 } @llvm.type.checked.load(i8*, i32, metadata) + +define void @main() { + %a = call i32 @call_vfunc1(i8* null) + ; CHECK: call i32 @call_vfunc1 + %b = call i32 @call_vfunc2(i8* null) + ; CHECK: call i32 @call_vfunc2 + ret void +}