Skip to content

Commit 4bfe03e

Browse files
committed
Add uninitialized multi-versioning trampoline for autoinit support
1 parent cd2dc91 commit 4bfe03e

File tree

1 file changed

+64
-34
lines changed

1 file changed

+64
-34
lines changed

src/llvm-multiversioning.cpp

Lines changed: 64 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
496546
void 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

709739
void CloneCtx::fix_gv_uses()

0 commit comments

Comments
 (0)