Skip to content

Commit 3ec5dc0

Browse files
committed
inform gen_cfun_wrapper that the jlcall api changed
1 parent 1f216da commit 3ec5dc0

File tree

1 file changed

+98
-144
lines changed

1 file changed

+98
-144
lines changed

src/codegen.cpp

+98-144
Original file line numberDiff line numberDiff line change
@@ -4160,10 +4160,10 @@ static void emit_cfunc_invalidate(
41604160
#if JL_LLVM_VERSION >= 50000
41614161
0,
41624162
#endif
4163-
ConstantInt::get(T_int32, nargs + 1), "jlcall", ctx.ptlsStates);
4163+
ConstantInt::get(T_int32, nargs), "jlcall", ctx.ptlsStates);
41644164
if (cc == jl_returninfo_t::SRet || cc == jl_returninfo_t::Union)
41654165
++AI;
4166-
for (size_t i = 0; i < nargs + 1; i++) {
4166+
for (size_t i = 0; i < nargs; i++) {
41674167
jl_value_t *jt = jl_nth_slot_type(lam->specTypes, i);
41684168
bool isboxed;
41694169
Type *et = julia_type_to_llvm(jt, &isboxed);
@@ -4193,7 +4193,7 @@ static void emit_cfunc_invalidate(
41934193
ctx.builder.CreateStore(maybe_decay_untracked(arg_box), argn);
41944194
}
41954195
assert(AI == gf_thunk->arg_end());
4196-
Value *nargs_v = ConstantInt::get(T_int32, nargs + 1);
4196+
Value *nargs_v = ConstantInt::get(T_int32, nargs);
41974197
Value *gf_ret = ctx.builder.CreateCall(prepare_call(jlapplygeneric_func), { myargs, nargs_v });
41984198
jl_cgval_t gf_retbox = mark_julia_type(ctx, gf_ret, true, jl_any_type, /*needsroot*/false);
41994199
jl_value_t *astrt = lam->rettype;
@@ -4343,73 +4343,16 @@ static Function *gen_cfun_wrapper(jl_function_t *ff, jl_value_t *jlrettype, jl_t
43434343
sf->func.value = jl_box_voidpointer((void*)cw_proto);
43444344
jl_gc_wb(sf, sf->func.value);
43454345

4346-
// See whether this function is specsig or jlcall or generic (unknown)
4347-
bool specsig, jlfunc_sret;
4348-
jl_returninfo_t::CallingConv cc = jl_returninfo_t::Boxed;
4349-
Function *theFptr;
4350-
Value *result;
4351-
Value *myargs;
4352-
size_t FParamIndex = 0;
4353-
std::vector<Value*> args;
4346+
// first emit code to record the arguments
43544347
Function::arg_iterator AI = cw->arg_begin();
43554348
Value *sretPtr = sig.sret ? &*AI++ : NULL;
4356-
if (lam && lam->jlcall_api == 2) {
4357-
nargs = 0; // arguments not needed
4358-
specsig = true;
4359-
jlfunc_sret = false;
4360-
myargs = NULL;
4361-
theFptr = NULL;
4362-
}
4363-
else if (lam && lam->functionObjectsDecls.specFunctionObject != NULL) {
4364-
const char *protoname = lam->functionObjectsDecls.specFunctionObject;
4365-
jl_returninfo_t returninfo = get_specsig_function(M, protoname, lam->specTypes, lam->rettype);
4366-
FunctionType *cft = returninfo.decl->getFunctionType();
4367-
theFptr = returninfo.decl;
4368-
specsig = true;
4369-
cc = returninfo.cc;
4370-
jlfunc_sret = cc == jl_returninfo_t::SRet;
4371-
if (jlfunc_sret || cc == jl_returninfo_t::Union) {
4372-
// fuse the two sret together, or emit an alloca to hold it
4373-
if (sig.sret && jlfunc_sret)
4374-
result = emit_bitcast(ctx, sretPtr, cft->getParamType(0));
4375-
else
4376-
result = decay_derived(ctx.builder.CreateAlloca(cft->getParamType(0)->getContainedType(0)));
4377-
args.push_back(result);
4378-
FParamIndex++;
4379-
}
4380-
myargs = NULL;
4381-
}
4382-
else {
4383-
theFptr = NULL;
4384-
if (lam) {
4385-
const char *fname = lam->functionObjectsDecls.functionObject;
4386-
if (fname) {
4387-
theFptr = cast_or_null<Function>(jl_Module->getNamedValue(fname));
4388-
if (!theFptr) {
4389-
theFptr = Function::Create(jl_func_sig, GlobalVariable::ExternalLinkage,
4390-
fname, jl_Module);
4391-
}
4392-
else {
4393-
assert(theFptr->getFunctionType() == jl_func_sig);
4394-
}
4395-
}
4396-
}
4397-
specsig = false;
4398-
jlfunc_sret = false;
4399-
myargs = new AllocaInst(T_prjlvalue,
4400-
#if JL_LLVM_VERSION >= 50000
4401-
0,
4402-
#endif
4403-
ConstantInt::get(T_int32, nargs + 1), "jlcall", /*InsertBefore*/ctx.ptlsStates);
4404-
FParamIndex++; // leave room for writing the ff object at the beginning
4405-
}
4406-
4407-
// first emit the arguments
4408-
for (size_t i = 0; i < nargs; i++) {
4409-
Value *val = &*AI++;
4349+
jl_cgval_t *inputargs = (jl_cgval_t*)alloca(sizeof(jl_cgval_t) * (nargs + 1));
4350+
inputargs[0] = mark_julia_const(ff); // we need to pass the function object even if (even though) it is a ghost
4351+
for (size_t i = 0; i < nargs; ++i, ++AI) {
4352+
Value *val = &*AI;
44104353
jl_value_t *jargty = jl_nth_slot_type((jl_value_t*)argt, i);
44114354
// figure out how to unpack this type
4412-
jl_cgval_t inputarg;
4355+
jl_cgval_t &inputarg = inputargs[i + 1];
44134356
if (jl_is_abstract_ref_type(jargty)) {
44144357
// a pointer to a value
44154358
jargty = jl_tparam0(jargty);
@@ -4473,18 +4416,39 @@ static Function *gen_cfun_wrapper(jl_function_t *ff, jl_value_t *jlrettype, jl_t
44734416
}
44744417
}
44754418
}
4419+
}
4420+
assert(AI == cw->arg_end());
44764421

4477-
// figure out how to repack this type
4478-
if (!specsig) {
4479-
Value *arg = boxed(ctx, inputarg, false); // don't want a gcroot, since it's about to be put into the jlcall frame anyways
4480-
GetElementPtrInst *slot = GetElementPtrInst::Create(T_prjlvalue, myargs,
4481-
ArrayRef<Value*>(ConstantInt::get(T_int32, FParamIndex)));
4482-
slot->insertAfter(ctx.ptlsStates);
4483-
ctx.builder.CreateStore(arg, slot);
4422+
// Create the call
4423+
bool jlfunc_sret;
4424+
jl_cgval_t retval;
4425+
if (lam && lam->jlcall_api == 2) {
4426+
nargs = 0; // arguments not needed -- TODO: not really true, should emit an age_ok test and jlcall
4427+
jlfunc_sret = false;
4428+
retval = mark_julia_const(lam->inferred_const);
4429+
}
4430+
else if (lam && lam->functionObjectsDecls.specFunctionObject != NULL) {
4431+
// emit a specsig call
4432+
const char *protoname = lam->functionObjectsDecls.specFunctionObject;
4433+
jl_returninfo_t returninfo = get_specsig_function(M, protoname, lam->specTypes, lam->rettype);
4434+
FunctionType *cft = returninfo.decl->getFunctionType();
4435+
jlfunc_sret = (returninfo.cc == jl_returninfo_t::SRet);
4436+
4437+
std::vector<Value*> args;
4438+
Value *result;
4439+
if (jlfunc_sret || returninfo.cc == jl_returninfo_t::Union) {
4440+
// fuse the two sret together, or emit an alloca to hold it
4441+
if (sig.sret && jlfunc_sret)
4442+
result = emit_bitcast(ctx, sretPtr, cft->getParamType(0));
4443+
else
4444+
result = decay_derived(emit_static_alloca(ctx, cft->getParamType(0)->getContainedType(0)));
4445+
args.push_back(result);
44844446
}
4485-
else {
4447+
for (size_t i = 0; i < nargs + 1; i++) {
4448+
// figure out how to repack the arguments
4449+
const jl_cgval_t &inputarg = inputargs[i];
44864450
Value *arg;
4487-
jl_value_t *spect = jl_nth_slot_type(lam->specTypes, i + 1); // +1 because argt excludes function
4451+
jl_value_t *spect = jl_nth_slot_type(lam->specTypes, i);
44884452
bool isboxed;
44894453
Type *T = julia_type_to_llvm(spect, &isboxed);
44904454
if (isboxed) {
@@ -4505,63 +4469,62 @@ static Function *gen_cfun_wrapper(jl_function_t *ff, jl_value_t *jlrettype, jl_t
45054469
// add to argument list
45064470
args.push_back(arg);
45074471
}
4508-
FParamIndex++;
4509-
}
4510-
4511-
// Create the call
4512-
jl_cgval_t retval;
4513-
Function *gf_thunk = NULL;
4514-
if (specsig) {
4515-
if (lam->jlcall_api == 2) {
4516-
retval = mark_julia_const(lam->inferred_const);
4517-
}
4518-
else {
4519-
assert(theFptr);
4520-
Value *call_v = prepare_call(theFptr);
4521-
if (age_ok) {
4522-
funcName << "_gfthunk";
4523-
gf_thunk = Function::Create(theFptr->getFunctionType(),
4524-
GlobalVariable::InternalLinkage,
4525-
funcName.str(), M);
4526-
jl_init_function(gf_thunk);
4527-
gf_thunk->setAttributes(theFptr->getAttributes());
4528-
gf_thunk->addFnAttr("no-frame-pointer-elim", "true");
4529-
call_v = ctx.builder.CreateSelect(age_ok, call_v, gf_thunk);
4530-
}
4531-
CallInst *call = ctx.builder.CreateCall(call_v, ArrayRef<Value*>(args));
4532-
call->setAttributes(theFptr->getAttributes());
4533-
switch (cc) {
4534-
case jl_returninfo_t::Boxed:
4535-
retval = mark_julia_type(ctx, call, true, astrt);
4536-
break;
4537-
case jl_returninfo_t::Register:
4538-
retval = mark_julia_type(ctx, call, false, astrt);
4539-
break;
4540-
case jl_returninfo_t::SRet:
4541-
retval = mark_julia_slot(result, astrt, NULL, tbaa_stack);
4542-
break;
4543-
case jl_returninfo_t::Union:
4544-
retval = mark_julia_slot(ctx.builder.CreateExtractValue(call, 0),
4545-
astrt,
4546-
ctx.builder.CreateExtractValue(call, 1),
4547-
tbaa_stack);
4548-
// note that the value may not be rooted here (on the return path)
4549-
break;
4550-
case jl_returninfo_t::Ghosts:
4551-
retval = mark_julia_slot(NULL, astrt, call, tbaa_stack);
4552-
break;
4553-
}
4472+
Value *theFptr = returninfo.decl;
4473+
assert(theFptr);
4474+
if (age_ok) {
4475+
funcName << "_gfthunk";
4476+
Function *gf_thunk = Function::Create(returninfo.decl->getFunctionType(),
4477+
GlobalVariable::InternalLinkage, funcName.str(), M);
4478+
jl_init_function(gf_thunk);
4479+
gf_thunk->setAttributes(returninfo.decl->getAttributes());
4480+
gf_thunk->addFnAttr("no-frame-pointer-elim", "true");
4481+
// build a specsig -> jl_apply_generic converter thunk
4482+
// this builds a method that calls jl_apply_generic (as a closure over a singleton function pointer),
4483+
// but which has the signature of a specsig
4484+
emit_cfunc_invalidate(gf_thunk, returninfo.cc, lam, nargs + 1, world);
4485+
theFptr = ctx.builder.CreateSelect(age_ok, theFptr, gf_thunk);
4486+
}
4487+
CallInst *call = ctx.builder.CreateCall(theFptr, ArrayRef<Value*>(args));
4488+
call->setAttributes(returninfo.decl->getAttributes());
4489+
switch (returninfo.cc) {
4490+
case jl_returninfo_t::Boxed:
4491+
retval = mark_julia_type(ctx, call, true, astrt);
4492+
break;
4493+
case jl_returninfo_t::Register:
4494+
retval = mark_julia_type(ctx, call, false, astrt);
4495+
break;
4496+
case jl_returninfo_t::SRet:
4497+
retval = mark_julia_slot(result, astrt, NULL, tbaa_stack);
4498+
break;
4499+
case jl_returninfo_t::Union:
4500+
retval = mark_julia_slot(ctx.builder.CreateExtractValue(call, 0),
4501+
astrt,
4502+
ctx.builder.CreateExtractValue(call, 1),
4503+
tbaa_stack);
4504+
// note that the value may not be rooted here (on the return path)
4505+
break;
4506+
case jl_returninfo_t::Ghosts:
4507+
retval = mark_julia_slot(NULL, astrt, call, tbaa_stack);
4508+
break;
45544509
}
45554510
}
45564511
else {
4557-
// for jlcall, we need to pass the function object even if it is a ghost.
4558-
// here we reconstruct the function instance from its type (first elt of argt)
4559-
Value *theF = literal_pointer_val(ctx, (jl_value_t*)ff);
4560-
GetElementPtrInst *slot = GetElementPtrInst::Create(T_prjlvalue, myargs,
4561-
ArrayRef<Value*>(ConstantInt::get(T_int32, 0)));
4562-
slot->insertAfter(ctx.ptlsStates);
4563-
ctx.builder.CreateStore(theF, slot);
4564-
4512+
// emit a jlcall
4513+
jlfunc_sret = false;
4514+
Function *theFptr = NULL;
4515+
if (lam) {
4516+
const char *fname = lam->functionObjectsDecls.functionObject;
4517+
if (fname) {
4518+
theFptr = cast_or_null<Function>(jl_Module->getNamedValue(fname));
4519+
if (!theFptr) {
4520+
theFptr = Function::Create(jl_func_sig, GlobalVariable::ExternalLinkage,
4521+
fname, jl_Module);
4522+
}
4523+
else {
4524+
assert(theFptr->getFunctionType() == jl_func_sig);
4525+
}
4526+
}
4527+
}
45654528
BasicBlock *b_generic, *b_jlcall, *b_after;
45664529
Value *ret_jlcall;
45674530
if (age_ok) {
@@ -4571,19 +4534,18 @@ static Function *gen_cfun_wrapper(jl_function_t *ff, jl_value_t *jlrettype, jl_t
45714534
b_after = BasicBlock::Create(jl_LLVMContext, "after", cw);
45724535
ctx.builder.CreateCondBr(age_ok, b_jlcall, b_generic);
45734536
ctx.builder.SetInsertPoint(b_jlcall);
4574-
Value *nargs_v = ConstantInt::get(T_int32, nargs);
4575-
Value *myargs1 = ctx.builder.CreateConstInBoundsGEP1_32(T_prjlvalue, myargs, 1);
4576-
ret_jlcall = ctx.builder.CreateCall(prepare_call(theFptr), {theF, myargs1, nargs_v});
4537+
// for jlcall, we need to pass the function object even if it is a ghost.
4538+
Value *theF = boxed(ctx, inputargs[0]);
4539+
assert(theF);
4540+
ret_jlcall = emit_jlcall(ctx, theFptr, theF, &inputargs[1], nargs);
45774541
ctx.builder.CreateBr(b_after);
45784542
ctx.builder.SetInsertPoint(b_generic);
45794543
}
4580-
4581-
Value *nargs_v = ConstantInt::get(T_int32, nargs + 1);
4582-
Value *ret = ctx.builder.CreateCall(prepare_call(jlapplygeneric_func), {myargs, nargs_v});
4544+
Value *ret = emit_jlcall(ctx, prepare_call(jlapplygeneric_func), NULL, inputargs, nargs + 1);
45834545
if (age_ok) {
45844546
ctx.builder.CreateBr(b_after);
45854547
ctx.builder.SetInsertPoint(b_after);
4586-
PHINode *retphi = ctx.builder.CreatePHI(T_pjlvalue, 2);
4548+
PHINode *retphi = ctx.builder.CreatePHI(T_prjlvalue, 2);
45874549
retphi->addIncoming(ret_jlcall, b_jlcall);
45884550
retphi->addIncoming(ret, b_generic);
45894551
ret = retphi;
@@ -4627,14 +4589,6 @@ static Function *gen_cfun_wrapper(jl_function_t *ff, jl_value_t *jlrettype, jl_t
46274589
ctx.builder.CreateStore(last_age, ctx.world_age_field);
46284590
ctx.builder.CreateRet(r);
46294591

4630-
// also need to finish emission of our specsig -> jl_apply_generic converter thunk
4631-
// this builds a method that calls jl_apply_generic (as a closure over a singleton function pointer),
4632-
// but which has the signature of a specsig
4633-
if (gf_thunk) {
4634-
assert(lam && specsig);
4635-
emit_cfunc_invalidate(gf_thunk, cc, lam, nargs, world);
4636-
}
4637-
46384592
ctx.builder.SetCurrentDebugLocation(noDbg);
46394593
ctx.builder.ClearInsertionPoint();
46404594

0 commit comments

Comments
 (0)