From 09ef2fd3cc8f4c89ca82b1a67cab030adccb9146 Mon Sep 17 00:00:00 2001 From: Oskar Wirga <10386631+oskarwirga@users.noreply.github.com> Date: Fri, 22 Sep 2023 10:04:49 -0700 Subject: [PATCH] Fix: Distinguish CFI Metadata Checks in MergeFunctions Pass --- llvm/lib/Transforms/IPO/MergeFunctions.cpp | 25 ++++++++- .../MergeFunc/cfi-function-merging.ll | 53 +++++++++++++++++++ .../MergeFunc/merge-fp-intrinsics.ll | 28 ++++++++++ 3 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 llvm/test/Transforms/MergeFunc/cfi-function-merging.ll create mode 100644 llvm/test/Transforms/MergeFunc/merge-fp-intrinsics.ll diff --git a/llvm/lib/Transforms/IPO/MergeFunctions.cpp b/llvm/lib/Transforms/IPO/MergeFunctions.cpp index 312a8df440bf1..89ddd7b6adebb 100644 --- a/llvm/lib/Transforms/IPO/MergeFunctions.cpp +++ b/llvm/lib/Transforms/IPO/MergeFunctions.cpp @@ -375,9 +375,32 @@ bool MergeFunctions::doFunctionalCheck(std::vector &Worklist) { } #endif +/// Check whether \p F has an intrinsic which references +/// distinct metadata as an operand. The most common +/// instance of this would be CFI checks for function-local types. +static bool hasDistinctMetadataIntrinsic(const Function &F) { + for (const BasicBlock &BB : F) { + for (const Instruction &I : BB.instructionsWithoutDebug()) { + if (!isa(&I)) + continue; + + for (Value *Op : I.operands()) { + auto *MDL = dyn_cast(Op); + if (!MDL) + continue; + if (MDNode *N = dyn_cast(MDL->getMetadata())) + if (N->isDistinct()) + return true; + } + } + } + return false; +} + /// Check whether \p F is eligible for function merging. static bool isEligibleForMerging(Function &F) { - return !F.isDeclaration() && !F.hasAvailableExternallyLinkage(); + return !F.isDeclaration() && !F.hasAvailableExternallyLinkage() && + !hasDistinctMetadataIntrinsic(F); } bool MergeFunctions::runOnModule(Module &M) { diff --git a/llvm/test/Transforms/MergeFunc/cfi-function-merging.ll b/llvm/test/Transforms/MergeFunc/cfi-function-merging.ll new file mode 100644 index 0000000000000..1fe5f71f95c3b --- /dev/null +++ b/llvm/test/Transforms/MergeFunc/cfi-function-merging.ll @@ -0,0 +1,53 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2 +;; 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 + +; 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: define internal void @A__on_zero_sharedEv +; CHECK-SAME: (ptr noundef nonnull align 8 dereferenceable(32) [[THIS:%.*]]) { +; CHECK-NEXT: entry: +; CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8 +; CHECK-NEXT: store ptr [[THIS]], ptr [[THIS_ADDR]], align 8 +; CHECK-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8 +; CHECK-NEXT: [[VTABLE:%.*]] = load ptr, ptr [[THIS1]], align 8 +; CHECK-NEXT: [[TMP0:%.*]] = call i1 @llvm.type.test(ptr [[VTABLE]], metadata [[META0:![0-9]+]]), !nosanitize !1 +; CHECK-NEXT: ret void +; +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: define internal void @B__on_zero_sharedEv +; CHECK-SAME: (ptr noundef nonnull align 8 dereferenceable(32) [[THIS:%.*]]) { +; CHECK-NEXT: entry: +; CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8 +; CHECK-NEXT: store ptr [[THIS]], ptr [[THIS_ADDR]], align 8 +; CHECK-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8 +; CHECK-NEXT: [[VTABLE:%.*]] = load ptr, ptr [[THIS1]], align 8 +; CHECK-NEXT: [[TMP0:%.*]] = call i1 @llvm.type.test(ptr [[VTABLE]], metadata [[META2:![0-9]+]]), !nosanitize !1 +; CHECK-NEXT: ret void +; +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 = !{} diff --git a/llvm/test/Transforms/MergeFunc/merge-fp-intrinsics.ll b/llvm/test/Transforms/MergeFunc/merge-fp-intrinsics.ll new file mode 100644 index 0000000000000..2a19ed8b8cca4 --- /dev/null +++ b/llvm/test/Transforms/MergeFunc/merge-fp-intrinsics.ll @@ -0,0 +1,28 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2 +;; Make sure internal constrained FP intrinsics still merge properly +; RUN: opt -passes=mergefunc -S < %s | FileCheck %s + +declare float @llvm.experimental.constrained.fadd.f32(float, float, metadata, metadata) + +define float @func1(float %a, float %b) { +; CHECK-LABEL: define float @func1 +; CHECK-SAME: (float [[A:%.*]], float [[B:%.*]]) { +; CHECK-NEXT: [[RESULT:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[A]], float [[B]], metadata !"round.dynamic", metadata !"fpexcept.strict") +; CHECK-NEXT: [[RESULT_2:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[A]], float [[B]], metadata !"round.dynamic", metadata !"fpexcept.strict") +; CHECK-NEXT: ret float [[RESULT]] +; + %result = call float @llvm.experimental.constrained.fadd.f32(float %a, float %b, metadata !"round.dynamic", metadata !"fpexcept.strict") + %result_2 = call float @llvm.experimental.constrained.fadd.f32(float %a, float %b, metadata !"round.dynamic", metadata !"fpexcept.strict") + ret float %result +} + +define float @func2(float %a, float %b) { +; CHECK-LABEL: define float @func2 +; CHECK-SAME: (float [[TMP0:%.*]], float [[TMP1:%.*]]) { +; CHECK-NEXT: [[TMP3:%.*]] = tail call float @func1(float [[TMP0]], float [[TMP1]]) +; CHECK-NEXT: ret float [[TMP3]] +; + %result = call float @llvm.experimental.constrained.fadd.f32(float %a, float %b, metadata !"round.dynamic", metadata !"fpexcept.strict") + %result_2 = call float @llvm.experimental.constrained.fadd.f32(float %a, float %b, metadata !"round.dynamic", metadata !"fpexcept.strict") + ret float %result +}