@@ -378,6 +378,8 @@ struct CloneCtx {
378378 void clone_partial (Group &grp, Target &tgt);
379379 uint32_t get_func_id (Function *F) const ;
380380 std::pair<uint32_t ,GlobalVariable*> get_reloc_slot (Function *F) const ;
381+
382+ Function *create_trampoline (Function *F, GlobalVariable *slot, bool autoinit=false );
381383 void rewrite_alias (GlobalAlias *alias, Function* F);
382384
383385 MDNode *tbaa_const;
@@ -493,6 +495,53 @@ void CloneCtx::prepare_vmap(ValueToValueMapTy &vmap)
493495 }
494496}
495497
498+ Function *CloneCtx::create_trampoline (Function *F, GlobalVariable *slot, bool autoinit)
499+ {
500+ Function *trampoline =
501+ Function::Create (F->getFunctionType (), GlobalValue::ExternalLinkage, " " , &M);
502+
503+ trampoline->copyAttributesFrom (F);
504+ trampoline->setVisibility (GlobalValue::HiddenVisibility);
505+ trampoline->setDSOLocal (true );
506+
507+ // drop multiversioning attributes
508+ trampoline->removeFnAttr (" julia.mv.reloc" );
509+ trampoline->removeFnAttr (" julia.mv.clones" );
510+
511+ auto BB = BasicBlock::Create (F->getContext (), " top" , trampoline);
512+ IRBuilder<> irbuilder (BB);
513+
514+ if (autoinit) {
515+ irbuilder.CreateCall (F->getParent ()->getOrInsertFunction (
516+ XSTR (jl_autoinit_and_adopt_thread),
517+ PointerType::get (F->getContext (), 0 )
518+ ));
519+ }
520+
521+ auto ptr = irbuilder.CreateLoad (F->getType (), slot);
522+ ptr->setMetadata (llvm::LLVMContext::MD_tbaa, tbaa_const);
523+ ptr->setMetadata (llvm::LLVMContext::MD_invariant_load, MDNode::get (F->getContext (), None));
524+
525+ SmallVector<Value *, 0 > Args;
526+ for (auto &arg : trampoline->args ())
527+ Args.push_back (&arg);
528+ auto call = irbuilder.CreateCall (F->getFunctionType (), ptr, ArrayRef<Value *>(Args));
529+ if (F->isVarArg ()) {
530+ assert (!TT.isARM () && !TT.isPPC () && " musttail not supported on ARM/PPC!" );
531+ call->setTailCallKind (CallInst::TCK_MustTail);
532+ } else {
533+ call->setTailCallKind (CallInst::TCK_Tail);
534+
535+ }
536+
537+ if (F->getReturnType () == Type::getVoidTy (F->getContext ()))
538+ irbuilder.CreateRetVoid ();
539+ else
540+ irbuilder.CreateRet (call);
541+
542+ return trampoline;
543+ }
544+
496545void CloneCtx::prepare_slots ()
497546{
498547 for (auto &F : orig_funcs) {
@@ -507,7 +556,12 @@ void CloneCtx::prepare_slots()
507556 else {
508557 auto id = get_func_id (F);
509558 const_relocs[id] = GV;
510- GV->setInitializer (Constant::getNullValue (F->getType ()));
559+
560+ // Initialize with a single-use trampoline that calls `jl_autoinit_and_adopt_thread`,
561+ // so that auto-initialization works with multi-versioned entrypoints.
562+ Function *trampoline = create_trampoline (F, GV, /* autoinit */ true );
563+ trampoline->setName (F->getName () + " .autoinit_trampoline" );
564+ GV->setInitializer (trampoline);
511565 }
512566 }
513567 }
@@ -665,45 +719,21 @@ void CloneCtx::rewrite_alias(GlobalAlias *alias, Function *F)
665719{
666720 assert (!is_vector (F->getFunctionType ()));
667721
668- Function *trampoline =
669- Function::Create (F->getFunctionType (), alias->getLinkage (), " " , &M);
670- trampoline->copyAttributesFrom (F);
671- trampoline->takeName (alias);
672- trampoline->setVisibility (alias->getVisibility ());
673- trampoline->setDSOLocal (alias->isDSOLocal ());
674- // drop multiversioning attributes, add alias attribute for testing purposes
675- trampoline->removeFnAttr (" julia.mv.reloc" );
676- trampoline->removeFnAttr (" julia.mv.clones" );
677- trampoline->addFnAttr (" julia.mv.alias" );
678- trampoline->setDLLStorageClass (alias->getDLLStorageClass ());
679- alias->eraseFromParent ();
680-
681722 uint32_t id;
682723 GlobalVariable *slot;
683724 std::tie (id, slot) = get_reloc_slot (F);
725+ assert (slot);
684726
685- auto BB = BasicBlock::Create (F-> getContext (), " top " , trampoline );
686- IRBuilder<> irbuilder (BB);
727+ Function *trampoline = create_trampoline (F, slot, /* autoinit */ false );
728+ trampoline-> addFnAttr ( " julia.mv.alias " ); // add alias attribute for testing purposes
687729
688- auto ptr = irbuilder.CreateLoad (F->getType (), slot);
689- ptr->setMetadata (llvm::LLVMContext::MD_tbaa, tbaa_const);
690- ptr->setMetadata (llvm::LLVMContext::MD_invariant_load, MDNode::get (F->getContext (), None));
691-
692- SmallVector<Value *, 0 > Args;
693- for (auto &arg : trampoline->args ())
694- Args.push_back (&arg);
695- auto call = irbuilder.CreateCall (F->getFunctionType (), ptr, ArrayRef<Value *>(Args));
696- if (F->isVarArg ()) {
697- assert (!TT.isARM () && !TT.isPPC () && " musttail not supported on ARM/PPC!" );
698- call->setTailCallKind (CallInst::TCK_MustTail);
699- } else {
700- call->setTailCallKind (CallInst::TCK_Tail);
701- }
730+ trampoline->takeName (alias);
731+ trampoline->setLinkage (alias->getLinkage ());
732+ trampoline->setVisibility (alias->getVisibility ());
733+ trampoline->setDSOLocal (alias->isDSOLocal ());
734+ trampoline->setDLLStorageClass (alias->getDLLStorageClass ());
702735
703- if (F->getReturnType () == Type::getVoidTy (F->getContext ()))
704- irbuilder.CreateRetVoid ();
705- else
706- irbuilder.CreateRet (call);
736+ alias->eraseFromParent ();
707737}
708738
709739void CloneCtx::fix_gv_uses ()
0 commit comments