@@ -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,54 @@ 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::InternalLinkage, " " , &M);
502+
503+ trampoline->copyAttributesFrom (F);
504+ trampoline->setVisibility (GlobalValue::HiddenVisibility);
505+ trampoline->setDSOLocal (true );
506+
507+ // drop multiversioning attributes, add alias attribute for testing purposes
508+ trampoline->removeFnAttr (" julia.mv.reloc" );
509+ trampoline->removeFnAttr (" julia.mv.clones" );
510+ trampoline->addFnAttr (" julia.mv.alias" );
511+
512+ auto BB = BasicBlock::Create (F->getContext (), " top" , trampoline);
513+ IRBuilder<> irbuilder (BB);
514+
515+ if (autoinit) {
516+ irbuilder.CreateCall (F->getParent ()->getOrInsertFunction (
517+ XSTR (jl_autoinit_and_adopt_thread),
518+ PointerType::get (F->getContext (), 0 )
519+ ));
520+ }
521+
522+ auto ptr = irbuilder.CreateLoad (F->getType (), slot);
523+ ptr->setMetadata (llvm::LLVMContext::MD_tbaa, tbaa_const);
524+ ptr->setMetadata (llvm::LLVMContext::MD_invariant_load, MDNode::get (F->getContext (), None));
525+
526+ SmallVector<Value *, 0 > Args;
527+ for (auto &arg : trampoline->args ())
528+ Args.push_back (&arg);
529+ auto call = irbuilder.CreateCall (F->getFunctionType (), ptr, ArrayRef<Value *>(Args));
530+ if (F->isVarArg ()) {
531+ assert (!TT.isARM () && !TT.isPPC () && " musttail not supported on ARM/PPC!" );
532+ call->setTailCallKind (CallInst::TCK_MustTail);
533+ } else {
534+ call->setTailCallKind (CallInst::TCK_Tail);
535+
536+ }
537+
538+ if (F->getReturnType () == Type::getVoidTy (F->getContext ()))
539+ irbuilder.CreateRetVoid ();
540+ else
541+ irbuilder.CreateRet (call);
542+
543+ return trampoline;
544+ }
545+
496546void CloneCtx::prepare_slots ()
497547{
498548 for (auto &F : orig_funcs) {
@@ -507,7 +557,12 @@ void CloneCtx::prepare_slots()
507557 else {
508558 auto id = get_func_id (F);
509559 const_relocs[id] = GV;
510- GV->setInitializer (Constant::getNullValue (F->getType ()));
560+
561+ // Initialize with a single-use trampoline that calls `jl_autoinit_and_adopt_thread`,
562+ // so that auto-initialization works with multi-versioned entrypoints.
563+ Function *trampoline = create_trampoline (F, GV, /* autoinit */ true );
564+ trampoline->setName (F->getName () + " .autoinit_trampoline" );
565+ GV->setInitializer (trampoline);
511566 }
512567 }
513568 }
@@ -665,45 +720,20 @@ void CloneCtx::rewrite_alias(GlobalAlias *alias, Function *F)
665720{
666721 assert (!is_vector (F->getFunctionType ()));
667722
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-
681723 uint32_t id;
682724 GlobalVariable *slot;
683725 std::tie (id, slot) = get_reloc_slot (F);
726+ assert (slot);
684727
685- auto BB = BasicBlock::Create (F->getContext (), " top" , trampoline);
686- IRBuilder<> irbuilder (BB);
687-
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));
728+ Function *trampoline = create_trampoline (F, slot, /* autoinit */ false );
691729
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