From 70f253bd464e94584efd774c7d5615176cdc2590 Mon Sep 17 00:00:00 2001 From: TB Schardl Date: Thu, 25 Aug 2022 11:21:18 +0000 Subject: [PATCH] [InlineFunction] Allow a function to be inlined into another with a different personality function if the callee simply uses the default personality function. This workaround addresses issue #127. --- llvm/lib/Transforms/Utils/InlineFunction.cpp | 5 +- .../Transforms/Tapir/inlining-personality.ll | 74 +++++++++++++++++++ 2 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 llvm/test/Transforms/Tapir/inlining-personality.ll diff --git a/llvm/lib/Transforms/Utils/InlineFunction.cpp b/llvm/lib/Transforms/Utils/InlineFunction.cpp index e31252c012de..afa8bc9207a8 100644 --- a/llvm/lib/Transforms/Utils/InlineFunction.cpp +++ b/llvm/lib/Transforms/Utils/InlineFunction.cpp @@ -2240,13 +2240,16 @@ llvm::InlineResult llvm::InlineFunction(CallBase &CB, InlineFunctionInfo &IFI, ? Caller->getPersonalityFn()->stripPointerCasts() : nullptr; if (CalledPersonality) { + Triple T(Caller->getParent()->getTargetTriple()); if (!CallerPersonality) Caller->setPersonalityFn(CalledPersonality); // If the personality functions match, then we can perform the // inlining. Otherwise, we can't inline. // TODO: This isn't 100% true. Some personality functions are proper // supersets of others and can be used in place of the other. - else if (CalledPersonality != CallerPersonality) + else if (CalledPersonality != CallerPersonality && + classifyEHPersonality(CalledPersonality) != + getDefaultEHPersonality(T)) return InlineResult::failure("incompatible personality"); } diff --git a/llvm/test/Transforms/Tapir/inlining-personality.ll b/llvm/test/Transforms/Tapir/inlining-personality.ll new file mode 100644 index 000000000000..e9c15af40fec --- /dev/null +++ b/llvm/test/Transforms/Tapir/inlining-personality.ll @@ -0,0 +1,74 @@ +; Check the compiler's ability to inline one function into another +; when their personality functions do not match. +; +; TODO: We have a workaround to allow inlining one function into +; another when the callee's personality function is simply the +; default. Revisit this test if the workaround is replaced. +; +; RUN: opt < %s -passes="always-inline" -S | FileCheck %s + +source_filename = "inlining-personality.ll" + +%"struct.tlx::BTree, tlx::btree_default_traits, std::allocator, false>::key_of_value, std::less, tlx::btree_default_traits, false, std::allocator, false>::LeafNode" = type { %"struct.tlx::BTree, tlx::btree_default_traits, std::allocator, false>::key_of_value, std::less, tlx::btree_default_traits, false, std::allocator, false>::node", %"struct.tlx::BTree, tlx::btree_default_traits, std::allocator, false>::key_of_value, std::less, tlx::btree_default_traits, false, std::allocator, false>::LeafNode"*, %"struct.tlx::BTree, tlx::btree_default_traits, std::allocator, false>::key_of_value, std::less, tlx::btree_default_traits, false, std::allocator, false>::LeafNode"*, %class.Lock, [128 x i64] } +%"struct.tlx::BTree, tlx::btree_default_traits, std::allocator, false>::key_of_value, std::less, tlx::btree_default_traits, false, std::allocator, false>::node" = type { i16, i16 } +%class.Lock = type { %"struct.std::atomic.10" } +%"struct.std::atomic.10" = type { %"struct.std::__atomic_base.11" } +%"struct.std::__atomic_base.11" = type { i8 } +%"class.std::allocator.36" = type { i8 } + +$_ZNSaIN3tlx5BTreeImmNS_9btree_setImSt4lessImENS_20btree_default_traitsImmEESaImELb0EE12key_of_valueES3_S5_Lb0ES6_Lb0EE8LeafNodeEE8allocateEm = comdat any + +; Function Attrs: nofree nosync nounwind readnone speculatable willreturn +declare void @llvm.dbg.declare(metadata, metadata, metadata) #0 + +; Function Attrs: argmemonly nofree nosync nounwind willreturn +declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1 + +; Function Attrs: argmemonly nofree nosync nounwind willreturn +declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #1 + +declare i32 @__gxx_personality_v0(...) + +declare i32 @__gcc_personality_v0(...) + +define linkonce_odr %"struct.tlx::BTree, tlx::btree_default_traits, std::allocator, false>::key_of_value, std::less, tlx::btree_default_traits, false, std::allocator, false>::LeafNode"* @_ZN3tlx5BTreeImmNS_9btree_setImSt4lessImENS_20btree_default_traitsImmEESaImELb0EE12key_of_valueES3_S5_Lb0ES6_Lb0EE13allocate_leafEv() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { +entry: + %call = invoke %"struct.tlx::BTree, tlx::btree_default_traits, std::allocator, false>::key_of_value, std::less, tlx::btree_default_traits, false, std::allocator, false>::LeafNode"* @_ZNSaIN3tlx5BTreeImmNS_9btree_setImSt4lessImENS_20btree_default_traitsImmEESaImELb0EE12key_of_valueES3_S5_Lb0ES6_Lb0EE8LeafNodeEE8allocateEm(%"class.std::allocator.36"* null, i64 0) + to label %invoke.cont unwind label %lpad + +invoke.cont: ; preds = %entry + ret %"struct.tlx::BTree, tlx::btree_default_traits, std::allocator, false>::key_of_value, std::less, tlx::btree_default_traits, false, std::allocator, false>::LeafNode"* null + +lpad: ; preds = %entry + %0 = landingpad { i8*, i32 } + cleanup + ret %"struct.tlx::BTree, tlx::btree_default_traits, std::allocator, false>::key_of_value, std::less, tlx::btree_default_traits, false, std::allocator, false>::LeafNode"* null +} + +; Function Attrs: alwaysinline +define linkonce_odr %"struct.tlx::BTree, tlx::btree_default_traits, std::allocator, false>::key_of_value, std::less, tlx::btree_default_traits, false, std::allocator, false>::LeafNode"* @_ZNSaIN3tlx5BTreeImmNS_9btree_setImSt4lessImENS_20btree_default_traitsImmEESaImELb0EE12key_of_valueES3_S5_Lb0ES6_Lb0EE8LeafNodeEE8allocateEm(%"class.std::allocator.36"* %this, i64 %__n) #2 comdat personality i32 (...)* @__gcc_personality_v0 { +entry: + ret %"struct.tlx::BTree, tlx::btree_default_traits, std::allocator, false>::key_of_value, std::less, tlx::btree_default_traits, false, std::allocator, false>::LeafNode"* null +} + +; CHECK: define linkonce_odr %"struct.tlx::BTree, tlx::btree_default_traits, std::allocator, false>::key_of_value, std::less, tlx::btree_default_traits, false, std::allocator, false>::LeafNode"* @_ZN3tlx5BTreeImmNS_9btree_setImSt4lessImENS_20btree_default_traitsImmEESaImELb0EE12key_of_valueES3_S5_Lb0ES6_Lb0EE13allocate_leafEv() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { +; CHECK: entry: +; CHECK-NEXT: br label %invoke.cont +; CHECK: invoke.cont: +; CHECK-NEXT: ret %"struct.tlx::BTree, tlx::btree_default_traits, std::allocator, false>::key_of_value, std::less, tlx::btree_default_traits, false, std::allocator, false>::LeafNode"* null + +; Function Attrs: argmemonly nofree nounwind willreturn writeonly +declare void @llvm.memset.p0i8.i64(i8* nocapture writeonly, i8, i64, i1 immarg) #3 + +; Function Attrs: nofree nosync nounwind readnone willreturn +declare i8* @llvm.frameaddress.p0i8(i32 immarg) #4 + +; Function Attrs: nofree nosync nounwind willreturn +declare i8* @llvm.stacksave() #5 + +attributes #0 = { nofree nosync nounwind readnone speculatable willreturn } +attributes #1 = { argmemonly nofree nosync nounwind willreturn } +attributes #2 = { alwaysinline } +attributes #3 = { argmemonly nofree nounwind willreturn writeonly } +attributes #4 = { nofree nosync nounwind readnone willreturn } +attributes #5 = { nofree nosync nounwind willreturn }