@@ -272,13 +272,13 @@ struct CloneCtx {
272272 Constant *get_ptrdiff32 (Constant *ptr, Constant *base) const ;
273273 template <typename T>
274274 Constant *emit_offset_table (const std::vector<T*> &vars, StringRef name) const ;
275+ void rewrite_alias (GlobalAlias *alias, Function* F);
275276
276277 LLVMContext &ctx;
277278 Type *T_size;
278279 Type *T_int32;
279280 Type *T_void;
280281 PointerType *T_psize;
281- PointerType *T_pvoidfunc;
282282 MDNode *tbaa_const;
283283 MultiVersioning *pass;
284284 std::vector<jl_target_spec_t > specs;
@@ -295,6 +295,8 @@ struct CloneCtx {
295295 std::vector<std::pair<Constant*,uint32_t >> gv_relocs{};
296296 // Mapping from function id (i.e. 0-based index in `fvars`) to GVs to be initialized.
297297 std::map<uint32_t ,GlobalVariable*> const_relocs;
298+ // Functions that were referred to by a global alias, and might not have other uses.
299+ std::set<uint32_t > alias_relocs;
298300 bool has_veccall{false };
299301 bool has_cloneall{false };
300302};
@@ -342,7 +344,6 @@ CloneCtx::CloneCtx(MultiVersioning *pass, Module &M)
342344 T_int32(Type::getInt32Ty(ctx)),
343345 T_void(Type::getVoidTy(ctx)),
344346 T_psize(PointerType::get(T_size, 0 )),
345- T_pvoidfunc(FunctionType::get(T_void, false )->getPointerTo()),
346347 tbaa_const(tbaa_make_child(" jtbaa_const" , nullptr , true ).first),
347348 pass(pass),
348349 specs(jl_get_llvm_clone_targets()),
@@ -702,6 +703,54 @@ Constant *CloneCtx::rewrite_gv_init(const Stack& stack)
702703 return res;
703704}
704705
706+ // replace an alias to a function with a trampoline and (uninitialized) global variable slot
707+ void CloneCtx::rewrite_alias (GlobalAlias *alias, Function *F)
708+ {
709+ assert (!is_vector (F->getFunctionType ()));
710+
711+ Function *trampoline =
712+ Function::Create (F->getFunctionType (), alias->getLinkage (), " " , &M);
713+ trampoline->copyAttributesFrom (F);
714+ trampoline->takeName (alias);
715+ alias->eraseFromParent ();
716+
717+ uint32_t id;
718+ GlobalVariable *slot;
719+ std::tie (id, slot) = get_reloc_slot (F);
720+ for (auto &grp: groups) {
721+ grp.relocs .insert (id);
722+ for (auto &tgt: grp.clones ) {
723+ tgt.relocs .insert (id);
724+ }
725+ }
726+ alias_relocs.insert (id);
727+
728+ auto BB = BasicBlock::Create (ctx, " top" , trampoline);
729+ IRBuilder<> irbuilder (BB);
730+
731+ auto ptr = irbuilder.CreateLoad (F->getType (), slot);
732+ ptr->setMetadata (llvm::LLVMContext::MD_tbaa, tbaa_const);
733+ ptr->setMetadata (llvm::LLVMContext::MD_invariant_load, MDNode::get (ctx, None));
734+
735+ std::vector<Value *> Args;
736+ for (auto &arg : trampoline->args ())
737+ Args.push_back (&arg);
738+ auto call = irbuilder.CreateCall (F->getFunctionType (), ptr, makeArrayRef (Args));
739+ if (F->isVarArg ())
740+ #if (defined(_CPU_ARM_) || defined(_CPU_PPC_) || defined(_CPU_PPC64_))
741+ abort (); // musttail support is very bad on ARM, PPC, PPC64 (as of LLVM 3.9)
742+ #else
743+ call->setTailCallKind (CallInst::TCK_MustTail);
744+ #endif
745+ else
746+ call->setTailCallKind (CallInst::TCK_Tail);
747+
748+ if (F->getReturnType () == T_void)
749+ irbuilder.CreateRetVoid ();
750+ else
751+ irbuilder.CreateRet (call);
752+ }
753+
705754void CloneCtx::fix_gv_uses ()
706755{
707756 auto single_pass = [&] (Function *orig_f) {
@@ -712,8 +761,14 @@ void CloneCtx::fix_gv_uses()
712761 auto info = uses.get_info ();
713762 // We only support absolute pointer relocation.
714763 assert (info.samebits );
715- // And only for non-constant global variable initializers
716- auto val = cast<GlobalVariable>(info.val );
764+ GlobalVariable *val;
765+ if (auto alias = dyn_cast<GlobalAlias>(info.val )) {
766+ rewrite_alias (alias, orig_f);
767+ continue ;
768+ }
769+ else {
770+ val = cast<GlobalVariable>(info.val );
771+ }
717772 assert (info.use ->getOperandNo () == 0 );
718773 assert (!val->isConstant ());
719774 auto fid = get_func_id (orig_f);
@@ -739,8 +794,8 @@ std::pair<uint32_t,GlobalVariable*> CloneCtx::get_reloc_slot(Function *F)
739794 auto id = get_func_id (F);
740795 auto &slot = const_relocs[id];
741796 if (!slot)
742- slot = new GlobalVariable (M, T_pvoidfunc , false , GlobalVariable::InternalLinkage,
743- ConstantPointerNull::get (T_pvoidfunc ),
797+ slot = new GlobalVariable (M, F-> getType () , false , GlobalVariable::InternalLinkage,
798+ ConstantPointerNull::get (F-> getType () ),
744799 F->getName () + " .reloc_slot" );
745800 return std::make_pair (id, slot);
746801}
@@ -820,10 +875,9 @@ void CloneCtx::fix_inst_uses()
820875 uint32_t id;
821876 GlobalVariable *slot;
822877 std::tie (id, slot) = get_reloc_slot (orig_f);
823- Instruction *ptr = new LoadInst (T_pvoidfunc , slot, " " , false , insert_before);
878+ Instruction *ptr = new LoadInst (orig_f-> getType () , slot, " " , false , insert_before);
824879 ptr->setMetadata (llvm::LLVMContext::MD_tbaa, tbaa_const);
825880 ptr->setMetadata (llvm::LLVMContext::MD_invariant_load, MDNode::get (ctx, None));
826- ptr = new BitCastInst (ptr, F->getType (), " " , insert_before);
827881 use_i->setOperand (info.use ->getOperandNo (),
828882 rewrite_inst_use (uses.get_stack (), ptr,
829883 insert_before));
@@ -960,6 +1014,9 @@ void CloneCtx::emit_metadata()
9601014 values.push_back (id_v);
9611015 values.push_back (get_ptrdiff32 (it->second , gbase));
9621016 }
1017+ if (alias_relocs.find (id) != alias_relocs.end ()) {
1018+ shared_relocs.insert (id);
1019+ }
9631020 }
9641021 values[0 ] = ConstantInt::get (T_int32, values.size () / 2 );
9651022 ArrayType *vars_type = ArrayType::get (T_int32, values.size ());
0 commit comments