Skip to content

Commit

Permalink
[InlineFunction] Allow a function to be inlined into another with a d…
Browse files Browse the repository at this point in the history
…ifferent personality function if the callee simply uses the default personality function. This workaround addresses issue #127.
  • Loading branch information
neboat committed Aug 26, 2022
1 parent ac9e020 commit 70f253b
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 1 deletion.
5 changes: 4 additions & 1 deletion llvm/lib/Transforms/Utils/InlineFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}

Expand Down
74 changes: 74 additions & 0 deletions llvm/test/Transforms/Tapir/inlining-personality.ll
Original file line number Diff line number Diff line change
@@ -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<unsigned long, unsigned long, tlx::btree_set<unsigned long, std::less<unsigned long>, tlx::btree_default_traits<unsigned long, unsigned long>, std::allocator<unsigned long>, false>::key_of_value, std::less<unsigned long>, tlx::btree_default_traits<unsigned long, unsigned long>, false, std::allocator<unsigned long>, false>::LeafNode" = type { %"struct.tlx::BTree<unsigned long, unsigned long, tlx::btree_set<unsigned long, std::less<unsigned long>, tlx::btree_default_traits<unsigned long, unsigned long>, std::allocator<unsigned long>, false>::key_of_value, std::less<unsigned long>, tlx::btree_default_traits<unsigned long, unsigned long>, false, std::allocator<unsigned long>, false>::node", %"struct.tlx::BTree<unsigned long, unsigned long, tlx::btree_set<unsigned long, std::less<unsigned long>, tlx::btree_default_traits<unsigned long, unsigned long>, std::allocator<unsigned long>, false>::key_of_value, std::less<unsigned long>, tlx::btree_default_traits<unsigned long, unsigned long>, false, std::allocator<unsigned long>, false>::LeafNode"*, %"struct.tlx::BTree<unsigned long, unsigned long, tlx::btree_set<unsigned long, std::less<unsigned long>, tlx::btree_default_traits<unsigned long, unsigned long>, std::allocator<unsigned long>, false>::key_of_value, std::less<unsigned long>, tlx::btree_default_traits<unsigned long, unsigned long>, false, std::allocator<unsigned long>, false>::LeafNode"*, %class.Lock, [128 x i64] }
%"struct.tlx::BTree<unsigned long, unsigned long, tlx::btree_set<unsigned long, std::less<unsigned long>, tlx::btree_default_traits<unsigned long, unsigned long>, std::allocator<unsigned long>, false>::key_of_value, std::less<unsigned long>, tlx::btree_default_traits<unsigned long, unsigned long>, false, std::allocator<unsigned long>, 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<unsigned long, unsigned long, tlx::btree_set<unsigned long, std::less<unsigned long>, tlx::btree_default_traits<unsigned long, unsigned long>, std::allocator<unsigned long>, false>::key_of_value, std::less<unsigned long>, tlx::btree_default_traits<unsigned long, unsigned long>, false, std::allocator<unsigned long>, 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<unsigned long, unsigned long, tlx::btree_set<unsigned long, std::less<unsigned long>, tlx::btree_default_traits<unsigned long, unsigned long>, std::allocator<unsigned long>, false>::key_of_value, std::less<unsigned long>, tlx::btree_default_traits<unsigned long, unsigned long>, false, std::allocator<unsigned long>, 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<unsigned long, unsigned long, tlx::btree_set<unsigned long, std::less<unsigned long>, tlx::btree_default_traits<unsigned long, unsigned long>, std::allocator<unsigned long>, false>::key_of_value, std::less<unsigned long>, tlx::btree_default_traits<unsigned long, unsigned long>, false, std::allocator<unsigned long>, false>::LeafNode"* null

lpad: ; preds = %entry
%0 = landingpad { i8*, i32 }
cleanup
ret %"struct.tlx::BTree<unsigned long, unsigned long, tlx::btree_set<unsigned long, std::less<unsigned long>, tlx::btree_default_traits<unsigned long, unsigned long>, std::allocator<unsigned long>, false>::key_of_value, std::less<unsigned long>, tlx::btree_default_traits<unsigned long, unsigned long>, false, std::allocator<unsigned long>, false>::LeafNode"* null
}

; Function Attrs: alwaysinline
define linkonce_odr %"struct.tlx::BTree<unsigned long, unsigned long, tlx::btree_set<unsigned long, std::less<unsigned long>, tlx::btree_default_traits<unsigned long, unsigned long>, std::allocator<unsigned long>, false>::key_of_value, std::less<unsigned long>, tlx::btree_default_traits<unsigned long, unsigned long>, false, std::allocator<unsigned long>, 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<unsigned long, unsigned long, tlx::btree_set<unsigned long, std::less<unsigned long>, tlx::btree_default_traits<unsigned long, unsigned long>, std::allocator<unsigned long>, false>::key_of_value, std::less<unsigned long>, tlx::btree_default_traits<unsigned long, unsigned long>, false, std::allocator<unsigned long>, false>::LeafNode"* null
}

; CHECK: define linkonce_odr %"struct.tlx::BTree<unsigned long, unsigned long, tlx::btree_set<unsigned long, std::less<unsigned long>, tlx::btree_default_traits<unsigned long, unsigned long>, std::allocator<unsigned long>, false>::key_of_value, std::less<unsigned long>, tlx::btree_default_traits<unsigned long, unsigned long>, false, std::allocator<unsigned long>, 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<unsigned long, unsigned long, tlx::btree_set<unsigned long, std::less<unsigned long>, tlx::btree_default_traits<unsigned long, unsigned long>, std::allocator<unsigned long>, false>::key_of_value, std::less<unsigned long>, tlx::btree_default_traits<unsigned long, unsigned long>, false, std::allocator<unsigned long>, 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 }

0 comments on commit 70f253b

Please sign in to comment.