@@ -272,13 +272,13 @@ struct CloneCtx {
272
272
Constant *get_ptrdiff32 (Constant *ptr, Constant *base) const ;
273
273
template <typename T>
274
274
Constant *emit_offset_table (const std::vector<T*> &vars, StringRef name) const ;
275
+ void rewrite_alias (GlobalAlias *alias, Function* F);
275
276
276
277
LLVMContext &ctx;
277
278
Type *T_size;
278
279
Type *T_int32;
279
280
Type *T_void;
280
281
PointerType *T_psize;
281
- PointerType *T_pvoidfunc;
282
282
MDNode *tbaa_const;
283
283
MultiVersioning *pass;
284
284
std::vector<jl_target_spec_t > specs;
@@ -295,6 +295,8 @@ struct CloneCtx {
295
295
std::vector<std::pair<Constant*,uint32_t >> gv_relocs{};
296
296
// Mapping from function id (i.e. 0-based index in `fvars`) to GVs to be initialized.
297
297
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;
298
300
bool has_veccall{false };
299
301
bool has_cloneall{false };
300
302
};
@@ -342,7 +344,6 @@ CloneCtx::CloneCtx(MultiVersioning *pass, Module &M)
342
344
T_int32(Type::getInt32Ty(ctx)),
343
345
T_void(Type::getVoidTy(ctx)),
344
346
T_psize(PointerType::get(T_size, 0 )),
345
- T_pvoidfunc(FunctionType::get(T_void, false )->getPointerTo()),
346
347
tbaa_const(tbaa_make_child(" jtbaa_const" , nullptr , true ).first),
347
348
pass(pass),
348
349
specs(jl_get_llvm_clone_targets()),
@@ -702,6 +703,54 @@ Constant *CloneCtx::rewrite_gv_init(const Stack& stack)
702
703
return res;
703
704
}
704
705
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
+
705
754
void CloneCtx::fix_gv_uses ()
706
755
{
707
756
auto single_pass = [&] (Function *orig_f) {
@@ -712,8 +761,14 @@ void CloneCtx::fix_gv_uses()
712
761
auto info = uses.get_info ();
713
762
// We only support absolute pointer relocation.
714
763
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
+ }
717
772
assert (info.use ->getOperandNo () == 0 );
718
773
assert (!val->isConstant ());
719
774
auto fid = get_func_id (orig_f);
@@ -739,8 +794,8 @@ std::pair<uint32_t,GlobalVariable*> CloneCtx::get_reloc_slot(Function *F)
739
794
auto id = get_func_id (F);
740
795
auto &slot = const_relocs[id];
741
796
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 () ),
744
799
F->getName () + " .reloc_slot" );
745
800
return std::make_pair (id, slot);
746
801
}
@@ -820,10 +875,9 @@ void CloneCtx::fix_inst_uses()
820
875
uint32_t id;
821
876
GlobalVariable *slot;
822
877
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);
824
879
ptr->setMetadata (llvm::LLVMContext::MD_tbaa, tbaa_const);
825
880
ptr->setMetadata (llvm::LLVMContext::MD_invariant_load, MDNode::get (ctx, None));
826
- ptr = new BitCastInst (ptr, F->getType (), " " , insert_before);
827
881
use_i->setOperand (info.use ->getOperandNo (),
828
882
rewrite_inst_use (uses.get_stack (), ptr,
829
883
insert_before));
@@ -960,6 +1014,9 @@ void CloneCtx::emit_metadata()
960
1014
values.push_back (id_v);
961
1015
values.push_back (get_ptrdiff32 (it->second , gbase));
962
1016
}
1017
+ if (alias_relocs.find (id) != alias_relocs.end ()) {
1018
+ shared_relocs.insert (id);
1019
+ }
963
1020
}
964
1021
values[0 ] = ConstantInt::get (T_int32, values.size () / 2 );
965
1022
ArrayType *vars_type = ArrayType::get (T_int32, values.size ());
0 commit comments