@@ -1542,7 +1542,7 @@ class jl_codectx_t {
1542
1542
jl_codegen_params_t &emission_context;
1543
1543
llvm::MapVector<jl_code_instance_t *, jl_codegen_call_target_t > call_targets;
1544
1544
std::map<void *, GlobalVariable*> &global_targets;
1545
- std::map<std::tuple<jl_code_instance_t *, bool >, Function *> &external_calls;
1545
+ std::map<std::tuple<jl_code_instance_t *, bool >, GlobalVariable *> &external_calls;
1546
1546
Function *f = NULL ;
1547
1547
// local var info. globals are not in here.
1548
1548
std::vector<jl_varinfo_t > slots;
@@ -1704,7 +1704,7 @@ static Value *get_current_task(jl_codectx_t &ctx);
1704
1704
static Value *get_current_ptls (jl_codectx_t &ctx);
1705
1705
static Value *get_last_age_field (jl_codectx_t &ctx);
1706
1706
static void CreateTrap (IRBuilder<> &irbuilder, bool create_new_block = true );
1707
- static CallInst *emit_jlcall (jl_codectx_t &ctx, Function * theFptr, Value *theF,
1707
+ static CallInst *emit_jlcall (jl_codectx_t &ctx, FunctionCallee theFptr, Value *theF,
1708
1708
const jl_cgval_t *args, size_t nargs, JuliaFunction *trampoline);
1709
1709
static CallInst *emit_jlcall (jl_codectx_t &ctx, JuliaFunction *theFptr, Value *theF,
1710
1710
const jl_cgval_t *args, size_t nargs, JuliaFunction *trampoline);
@@ -4039,14 +4039,14 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f,
4039
4039
}
4040
4040
4041
4041
// Returns ctx.types().T_prjlvalue
4042
- static CallInst *emit_jlcall (jl_codectx_t &ctx, Function * theFptr, Value *theF,
4042
+ static CallInst *emit_jlcall (jl_codectx_t &ctx, FunctionCallee theFptr, Value *theF,
4043
4043
const jl_cgval_t *argv, size_t nargs, JuliaFunction *trampoline)
4044
4044
{
4045
4045
++EmittedJLCalls;
4046
4046
Function *TheTrampoline = prepare_call (trampoline);
4047
4047
// emit arguments
4048
4048
SmallVector<Value*, 4 > theArgs;
4049
- theArgs.push_back (theFptr);
4049
+ theArgs.push_back (theFptr. getCallee () );
4050
4050
if (theF)
4051
4051
theArgs.push_back (theF);
4052
4052
for (size_t i = 0 ; i < nargs; i++) {
@@ -4067,7 +4067,7 @@ static CallInst *emit_jlcall(jl_codectx_t &ctx, JuliaFunction *theFptr, Value *t
4067
4067
}
4068
4068
4069
4069
4070
- static jl_cgval_t emit_call_specfun_other (jl_codectx_t &ctx, jl_method_instance_t *mi, jl_value_t *jlretty, StringRef specFunctionObject,
4070
+ static jl_cgval_t emit_call_specfun_other (jl_codectx_t &ctx, jl_method_instance_t *mi, jl_value_t *jlretty, StringRef specFunctionObject, jl_code_instance_t *fromexternal,
4071
4071
const jl_cgval_t *argv, size_t nargs, jl_returninfo_t ::CallingConv *cc, unsigned *return_roots, jl_value_t *inferred_retty)
4072
4072
{
4073
4073
++EmittedSpecfunCalls;
@@ -4143,7 +4143,22 @@ static jl_cgval_t emit_call_specfun_other(jl_codectx_t &ctx, jl_method_instance_
4143
4143
idx++;
4144
4144
}
4145
4145
assert (idx == nfargs);
4146
- CallInst *call = ctx.builder .CreateCall (returninfo.decl , ArrayRef<Value*>(&argvals[0 ], nfargs));
4146
+ Value *callee = returninfo.decl ;
4147
+ if (fromexternal) {
4148
+ std::string namep (" p" );
4149
+ namep += returninfo.decl ->getName ();
4150
+ GlobalVariable *GV = cast_or_null<GlobalVariable>(jl_Module->getNamedValue (namep));
4151
+ if (GV == nullptr ) {
4152
+ GV = new GlobalVariable (*jl_Module, callee->getType (), false ,
4153
+ GlobalVariable::ExternalLinkage,
4154
+ Constant::getNullValue (callee->getType ()),
4155
+ namep);
4156
+ ctx.external_calls [std::make_tuple (fromexternal, true )] = GV;
4157
+ }
4158
+ jl_aliasinfo_t ai = jl_aliasinfo_t::fromTBAA (ctx, ctx.tbaa ().tbaa_const );
4159
+ callee = ai.decorateInst (ctx.builder .CreateAlignedLoad (callee->getType (), GV, Align (sizeof (void *))));
4160
+ }
4161
+ CallInst *call = ctx.builder .CreateCall (cft, callee, ArrayRef<Value*>(&argvals[0 ], nfargs));
4147
4162
call->setAttributes (returninfo.decl ->getAttributes ());
4148
4163
4149
4164
jl_cgval_t retval;
@@ -4182,13 +4197,30 @@ static jl_cgval_t emit_call_specfun_other(jl_codectx_t &ctx, jl_method_instance_
4182
4197
return update_julia_type (ctx, retval, inferred_retty);
4183
4198
}
4184
4199
4185
- static jl_cgval_t emit_call_specfun_boxed (jl_codectx_t &ctx, jl_value_t *jlretty, StringRef specFunctionObject,
4200
+ static jl_cgval_t emit_call_specfun_boxed (jl_codectx_t &ctx, jl_value_t *jlretty, StringRef specFunctionObject, jl_code_instance_t *fromexternal,
4186
4201
const jl_cgval_t *argv, size_t nargs, jl_value_t *inferred_retty)
4187
4202
{
4188
- auto theFptr = cast<Function>(
4189
- jl_Module->getOrInsertFunction (specFunctionObject, ctx.types ().T_jlfunc ).getCallee ());
4190
- addRetAttr (theFptr, Attribute::NonNull);
4191
- Value *ret = emit_jlcall (ctx, theFptr, nullptr , argv, nargs, julia_call);
4203
+ Value *theFptr;
4204
+ if (fromexternal) {
4205
+ std::string namep (" p" );
4206
+ namep += specFunctionObject;
4207
+ GlobalVariable *GV = cast_or_null<GlobalVariable>(jl_Module->getNamedValue (namep));
4208
+ Type *pfunc = ctx.types ().T_jlfunc ->getPointerTo ();
4209
+ if (GV == nullptr ) {
4210
+ GV = new GlobalVariable (*jl_Module, pfunc, false ,
4211
+ GlobalVariable::ExternalLinkage,
4212
+ Constant::getNullValue (pfunc),
4213
+ namep);
4214
+ ctx.external_calls [std::make_tuple (fromexternal, false )] = GV;
4215
+ }
4216
+ jl_aliasinfo_t ai = jl_aliasinfo_t::fromTBAA (ctx, ctx.tbaa ().tbaa_const );
4217
+ theFptr = ai.decorateInst (ctx.builder .CreateAlignedLoad (pfunc, GV, Align (sizeof (void *))));
4218
+ }
4219
+ else {
4220
+ theFptr = jl_Module->getOrInsertFunction (specFunctionObject, ctx.types ().T_jlfunc ).getCallee ();
4221
+ addRetAttr (cast<Function>(theFptr), Attribute::NonNull);
4222
+ }
4223
+ Value *ret = emit_jlcall (ctx, FunctionCallee (ctx.types ().T_jlfunc , theFptr), nullptr , argv, nargs, julia_call);
4192
4224
return update_julia_type (ctx, mark_julia_type (ctx, ret, true , jlretty), inferred_retty);
4193
4225
}
4194
4226
@@ -4223,12 +4255,12 @@ static jl_cgval_t emit_invoke(jl_codectx_t &ctx, const jl_cgval_t &lival, const
4223
4255
FunctionType *ft = ctx.f ->getFunctionType ();
4224
4256
StringRef protoname = ctx.f ->getName ();
4225
4257
if (ft == ctx.types ().T_jlfunc ) {
4226
- result = emit_call_specfun_boxed (ctx, ctx.rettype , protoname, argv, nargs, rt);
4258
+ result = emit_call_specfun_boxed (ctx, ctx.rettype , protoname, nullptr , argv, nargs, rt);
4227
4259
handled = true ;
4228
4260
}
4229
4261
else if (ft != ctx.types ().T_jlfuncparams ) {
4230
4262
unsigned return_roots = 0 ;
4231
- result = emit_call_specfun_other (ctx, mi, ctx.rettype , protoname, argv, nargs, &cc, &return_roots, rt);
4263
+ result = emit_call_specfun_other (ctx, mi, ctx.rettype , protoname, nullptr , argv, nargs, &cc, &return_roots, rt);
4232
4264
handled = true ;
4233
4265
}
4234
4266
}
@@ -4248,16 +4280,17 @@ static jl_cgval_t emit_invoke(jl_codectx_t &ctx, const jl_cgval_t &lival, const
4248
4280
std::string name;
4249
4281
StringRef protoname;
4250
4282
bool need_to_emit = true ;
4251
- bool cache_valid = ctx.use_cache ;
4283
+ bool cache_valid = ctx.use_cache || ctx. external_linkage ;
4252
4284
bool external = false ;
4253
- if (ctx. external_linkage ) {
4254
- if ( 0 && jl_object_in_image (( jl_value_t *)codeinst)) {
4255
- // Target is present in another pkgimage
4256
- cache_valid = true ;
4257
- external = true ;
4258
- }
4285
+
4286
+ // Check if we already queued this up
4287
+ auto it = ctx. call_targets . find (codeinst);
4288
+ if (need_to_emit && it != ctx. call_targets . end ()) {
4289
+ protoname = std::get< 2 >(it-> second )-> getName () ;
4290
+ need_to_emit = cache_valid = false ;
4259
4291
}
4260
4292
4293
+ // Check if it is already compiled (either JIT or externally)
4261
4294
if (cache_valid) {
4262
4295
// optimization: emit the correct name immediately, if we know it
4263
4296
// TODO: use `emitted` map here too to try to consolidate names?
@@ -4270,32 +4303,30 @@ static jl_cgval_t emit_invoke(jl_codectx_t &ctx, const jl_cgval_t &lival, const
4270
4303
invoke = jl_atomic_load_relaxed (&codeinst->invoke );
4271
4304
if (specsig ? jl_atomic_load_relaxed (&codeinst->specsigflags ) & 0b1 : invoke == jl_fptr_args_addr) {
4272
4305
protoname = jl_ExecutionEngine->getFunctionAtAddress ((uintptr_t )fptr, codeinst);
4273
- need_to_emit = false ;
4306
+ if (ctx.external_linkage ) {
4307
+ // TODO: Add !specsig support to aotcompile.cpp
4308
+ // Check that the codeinst is containing native code
4309
+ if (specsig && jl_atomic_load_relaxed (&codeinst->specsigflags ) & 0b100 ) {
4310
+ external = true ;
4311
+ need_to_emit = false ;
4312
+ }
4313
+ }
4314
+ else { // ctx.use_cache
4315
+ need_to_emit = false ;
4316
+ }
4274
4317
}
4275
4318
}
4276
4319
}
4277
- auto it = ctx.call_targets .find (codeinst);
4278
- if (need_to_emit && it != ctx.call_targets .end ()) {
4279
- protoname = std::get<2 >(it->second )->getName ();
4280
- need_to_emit = false ;
4281
- }
4282
4320
if (need_to_emit) {
4283
4321
raw_string_ostream (name) << (specsig ? " j_" : " j1_" ) << name_from_method_instance (mi) << " _" << jl_atomic_fetch_add (&globalUniqueGeneratedNames, 1 );
4284
4322
protoname = StringRef (name);
4285
4323
}
4286
4324
jl_returninfo_t ::CallingConv cc = jl_returninfo_t ::CallingConv::Boxed;
4287
4325
unsigned return_roots = 0 ;
4288
4326
if (specsig)
4289
- result = emit_call_specfun_other (ctx, mi, codeinst->rettype , protoname, argv, nargs, &cc, &return_roots, rt);
4327
+ result = emit_call_specfun_other (ctx, mi, codeinst->rettype , protoname, external ? codeinst : nullptr , argv, nargs, &cc, &return_roots, rt);
4290
4328
else
4291
- result = emit_call_specfun_boxed (ctx, codeinst->rettype , protoname, argv, nargs, rt);
4292
- if (external) {
4293
- assert (!need_to_emit);
4294
- auto calledF = jl_Module->getFunction (protoname);
4295
- assert (calledF);
4296
- // TODO: Check if already present?
4297
- ctx.external_calls [std::make_tuple (codeinst, specsig)] = calledF;
4298
- }
4329
+ result = emit_call_specfun_boxed (ctx, codeinst->rettype , protoname, external ? codeinst : nullptr , argv, nargs, rt);
4299
4330
handled = true ;
4300
4331
if (need_to_emit) {
4301
4332
Function *trampoline_decl = cast<Function>(jl_Module->getNamedValue (protoname));
@@ -5617,14 +5648,7 @@ static Function *emit_tojlinvoke(jl_code_instance_t *codeinst, Module *M, jl_cod
5617
5648
Function *theFunc;
5618
5649
Value *theFarg;
5619
5650
auto invoke = jl_atomic_load_relaxed (&codeinst->invoke );
5620
-
5621
5651
bool cache_valid = params.cache ;
5622
- if (params.external_linkage ) {
5623
- if (0 && jl_object_in_image ((jl_value_t *)codeinst)) {
5624
- // Target is present in another pkgimage
5625
- cache_valid = true ;
5626
- }
5627
- }
5628
5652
5629
5653
if (cache_valid && invoke != NULL ) {
5630
5654
StringRef theFptrName = jl_ExecutionEngine->getFunctionAtAddress ((uintptr_t )invoke, codeinst);
@@ -8537,9 +8561,6 @@ void jl_compile_workqueue(
8537
8561
bool preal_specsig = false ;
8538
8562
auto invoke = jl_atomic_load_acquire (&codeinst->invoke );
8539
8563
bool cache_valid = params.cache ;
8540
- if (params.external_linkage ) {
8541
- cache_valid = 0 && jl_object_in_image ((jl_value_t *)codeinst);
8542
- }
8543
8564
// WARNING: isspecsig is protected by the codegen-lock. If that lock is removed, then the isspecsig load needs to be properly atomically sequenced with this.
8544
8565
if (cache_valid && invoke != NULL ) {
8545
8566
auto fptr = jl_atomic_load_relaxed (&codeinst->specptr .fptr );
0 commit comments