diff --git a/llvm/lib/Transforms/Utils/FunctionComparator.cpp b/llvm/lib/Transforms/Utils/FunctionComparator.cpp --- a/llvm/lib/Transforms/Utils/FunctionComparator.cpp +++ b/llvm/lib/Transforms/Utils/FunctionComparator.cpp @@ -23,6 +23,7 @@ #include "llvm/IR/Constant.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" +#include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Function.h" #include "llvm/IR/GlobalValue.h" @@ -795,6 +796,28 @@ /// that we will detect mismatches on next use. /// See comments in declaration for more details. int FunctionComparator::cmpValues(const Value *L, const Value *R) const { + // Distinct metadata is different and shouldn't be merged unless it's + // just debug info + auto *MDL = dyn_cast(L); + auto *MDR = dyn_cast(R); + if (MDL && MDR) { + const MDNode *MDNodeL = dyn_cast(MDL->getMetadata()); + const MDNode *MDNodeR = dyn_cast(MDR->getMetadata()); + if (MDNodeL && MDNodeR) { + if (MDNodeL->isDistinct() && MDNodeR->isDistinct()) { + if (isa(MDNodeL) && isa(MDNodeR)) + return 0; + return -1; + } + if (MDNodeL->isDistinct()) { + return 1; + } + if (MDNodeR->isDistinct()) { + return -1; + } + } + } + // Catch self-reference case. if (L == FnL) { if (R == FnR) diff --git a/llvm/test/Transforms/MergeFunc/cfi-function-merging.ll b/llvm/test/Transforms/MergeFunc/cfi-function-merging.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/MergeFunc/cfi-function-merging.ll @@ -0,0 +1,38 @@ +;; Check the cases involving internal CFI instrumented functions where we do not expect functions to be merged. +; RUN: opt -S -passes=mergefunc < %s | FileCheck %s + + +target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" +target triple = "aarch64-none-linux-android28" + +; Function Attrs: nocallback nofree nosync nounwind readnone speculatable willreturn +declare i1 @llvm.type.test(ptr, metadata) #6 + +define internal void @A__on_zero_sharedEv(ptr noundef nonnull align 8 dereferenceable(32) %this) { +; CHECK-LABEL: @A__on_zero_sharedEv +entry: + %this.addr = alloca ptr, align 8 + store ptr %this, ptr %this.addr, align 8 + %this1 = load ptr, ptr %this.addr, align 8 + %vtable = load ptr, ptr %this1, align 8 + %0 = call i1 @llvm.type.test(ptr %vtable, metadata !11), !nosanitize !47 + ret void +} + +; Function Attrs: mustprogress noinline nounwind optnone uwtable +define internal void @B__on_zero_sharedEv(ptr noundef nonnull align 8 dereferenceable(32) %this) { +; CHECK-LABEL: @B__on_zero_sharedEv +entry: + %this.addr = alloca ptr, align 8 + store ptr %this, ptr %this.addr, align 8 + %this1 = load ptr, ptr %this.addr, align 8 + %vtable = load ptr, ptr %this1, align 8 + %0 = call i1 @llvm.type.test(ptr %vtable, metadata !22), !nosanitize !47 + ret void +} + +!10 = !{i64 16, !11} +!11 = distinct !{} +!21 = !{i64 16, !22} +!22 = distinct !{} +!47 = !{}