Index: llvm/lib/Transforms/Utils/FunctionComparator.cpp =================================================================== --- llvm/lib/Transforms/Utils/FunctionComparator.cpp +++ llvm/lib/Transforms/Utils/FunctionComparator.cpp @@ -787,6 +787,14 @@ if (ConstR) return -1; + if (auto LIL = dyn_cast(L), LIR = dyn_cast(R); + LIL && LIR) { + auto NNL = bool(LIL->getMetadata(LLVMContext::MD_nonnull)); + auto NNR = bool(LIR->getMetadata(LLVMContext::MD_nonnull)); + if (NNL != NNR) + return NNL - NNR; + } + const InlineAsm *InlineAsmL = dyn_cast(L); const InlineAsm *InlineAsmR = dyn_cast(R); Index: llvm/test/Transforms/MergeFunc/mergefunc-preserve-nonnull.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/MergeFunc/mergefunc-preserve-nonnull.ll @@ -0,0 +1,48 @@ +; RUN: opt -passes=mergefunc -S < %s | FileCheck %s + +; This test makes sure that the mergefunc pass does not merge functions +; that have different nonnull assertions. + +target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" + +%1 = type { { ptr, i64 }, ptr } + +define hidden void @f1(ptr noalias nocapture noundef sret(%1) dereferenceable(24) %0, ptr noalias nocapture noundef dereferenceable(24) %1) unnamed_addr #0 { + ; CHECK-LABEL: @f1( + ; CHECK: %8 = load ptr, ptr %7, align 8, !nonnull !2, !align !6, !noundef !2 + %3 = getelementptr inbounds { ptr, i64 }, ptr %1, i32 0, i32 0 + %4 = load ptr, ptr %3, align 8, !nonnull !2, !align !3, !noundef !2 + %5 = getelementptr inbounds { ptr, i64 }, ptr %1, i32 0, i32 1 + %6 = load i64, ptr %5, align 8 + %7 = getelementptr inbounds { { ptr, i64 }, ptr }, ptr %1, i32 0, i32 1 + %8 = load ptr, ptr %7, align 8, !nonnull !2, !align !6, !noundef !2 + %9 = getelementptr inbounds { ptr, i64 }, ptr %0, i32 0, i32 0 + store ptr %4, ptr %9, align 8 + %10 = getelementptr inbounds { ptr, i64 }, ptr %0, i32 0, i32 1 + store i64 %6, ptr %10, align 8 + %11 = getelementptr inbounds %1, ptr %0, i32 0, i32 1 + store ptr %8, ptr %11, align 8 + ret void +} + +define hidden void @f2(ptr noalias nocapture noundef sret(%1) dereferenceable(24) %0, ptr noalias nocapture noundef dereferenceable(24) %1) unnamed_addr #0 { + ; CHECK-LABEL: @f2( + ; %8 = load ptr, ptr %7, align 8, !align !6 + %3 = getelementptr inbounds { ptr, i64 }, ptr %1, i32 0, i32 0 + %4 = load ptr, ptr %3, align 8, !nonnull !2, !align !3, !noundef !2 + %5 = getelementptr inbounds { ptr, i64 }, ptr %1, i32 0, i32 1 + %6 = load i64, ptr %5, align 8 + %7 = getelementptr inbounds { { ptr, i64 }, ptr }, ptr %1, i32 0, i32 1 + %8 = load ptr, ptr %7, align 8, !align !6 + %9 = getelementptr inbounds { ptr, i64 }, ptr %0, i32 0, i32 0 + store ptr %4, ptr %9, align 8 + %10 = getelementptr inbounds { ptr, i64 }, ptr %0, i32 0, i32 1 + store i64 %6, ptr %10, align 8 + %11 = getelementptr inbounds %1, ptr %0, i32 0, i32 1 + store ptr %8, ptr %11, align 8 + ret void +} + +!2 = !{} +!3 = !{i64 1} +!6 = !{i64 8}