Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit a34fae4

Browse files
committedJun 9, 2015
store tuple and vector types to the stack eagerly [ci skip]
fix #11187, fix #11450, fix #11026, ref #10525, fix #11003 TODO: confirm all of those numbers were fixed TODO: ensure the lazy-loaded objects have gc-roots TODO: re-enable VectorType objects, so small objects still end up in registers in the calling convention TODO: allow moving pointers sometimes rather than copying TODO: teach the GC how it can re-use an existing pointer as a box this also changes the julia specSig calling convention to pass non-primitive types by pointer instead of by-value this additionally fixes a bug in gen_cfunction that could be exposed by turning off specSig this additionally moves the alloca calls in ccall (and other places) to the entry BasicBlock in the function, ensuring that llvm detects them as static allocations and moves them into the function prologue
1 parent 9ea69be commit a34fae4

File tree

7 files changed

+328
-192
lines changed

7 files changed

+328
-192
lines changed
 

‎base/inference.jl

+3-2
Original file line numberDiff line numberDiff line change
@@ -3038,6 +3038,7 @@ end
30383038
function remove_redundant_temp_vars(ast, sa)
30393039
varinfo = ast.args[2][2]
30403040
gensym_types = ast.args[2][4]
3041+
body = ast.args[3]
30413042
for (v,init) in sa
30423043
if ((isa(init,Symbol) || isa(init,SymbolNode)) &&
30433044
any(vi->symequal(vi[1],init), varinfo) &&
@@ -3046,7 +3047,7 @@ function remove_redundant_temp_vars(ast, sa)
30463047
# this transformation is not valid for vars used before def.
30473048
# we need to preserve the point of assignment to know where to
30483049
# throw errors (issue #4645).
3049-
if !occurs_undef(v, ast.args[3], varinfo)
3050+
if !occurs_undef(v, body, varinfo)
30503051

30513052
# the transformation is not ideal if the assignment
30523053
# is present for the auto-unbox functionality
@@ -3055,7 +3056,7 @@ function remove_redundant_temp_vars(ast, sa)
30553056
# everywhere later in the function
30563057
if (isa(init,SymbolNode) ? (init.typ <: (isa(v,GenSym)?gensym_types[(v::GenSym).id+1]:local_typeof(v, varinfo))) : true)
30573058
delete_var!(ast, v)
3058-
sym_replace(ast.args[3], [v], [], [init], [])
3059+
sym_replace(body, Any[v], Void[], Any[init], Void[])
30593060
end
30603061
end
30613062
end

‎src/builtins.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@ static int NOINLINE compare_fields(jl_value_t *a, jl_value_t *b,
273273
return 1;
274274
}
275275

276-
int jl_egal(jl_value_t *a, jl_value_t *b)
276+
int jl_egal(jl_value_t *a, jl_value_t *b) // warning: a,b may NOT have been gc-rooted by the caller
277277
{
278278
if (a == b)
279279
return 1;

‎src/ccall.cpp

+99-52
Original file line numberDiff line numberDiff line change
@@ -246,17 +246,51 @@ static Value *runtime_sym_lookup(PointerType *funcptype, char *f_lib, char *f_na
246246
# include "abi_llvm.cpp"
247247
#endif
248248

249-
Value *llvm_type_rewrite(Value *v, Type *target_type, jl_value_t *ty, bool isret)
249+
Value *llvm_type_rewrite(Value *v, Type *from_type, Type *target_type, bool tojulia, bool byref)
250250
{
251-
if (preferred_llvm_type(ty,isret) == NULL || target_type == NULL || target_type == v->getType())
251+
Type *ptarget_type = PointerType::get(target_type, 0);
252+
253+
if (tojulia) {
254+
if (byref) {
255+
if (v->getType() != ptarget_type) {
256+
v = builder.CreatePointerCast(v, ptarget_type);
257+
}
258+
return builder.CreateLoad(v);
259+
}
260+
}
261+
else {
262+
if (byref) { // client is supposed to have already done the alloca and store
263+
if (v->getType() != target_type) {
264+
v = builder.CreatePointerCast(v, target_type);
265+
}
266+
return v;
267+
}
268+
269+
if (v->getType() != from_type) { // this is already be a pointer in the codegen
270+
if (v->getType() != ptarget_type) {
271+
v = builder.CreatePointerCast(v, ptarget_type);
272+
}
273+
return builder.CreateLoad(v);
274+
}
275+
}
276+
assert(v->getType() == from_type);
277+
278+
if (target_type == from_type) {
252279
return v;
280+
}
253281

254-
assert(!v->getType()->isPointerTy());
282+
if ((target_type->isIntegerTy() && from_type->isIntegerTy()) ||
283+
(target_type->isFloatingPointTy() && from_type->isFloatingPointTy()) ||
284+
(target_type->isPointerTy() && from_type->isPointerTy())) {
285+
assert(target_type->getPrimitiveSizeInBits() == from_type->getPrimitiveSizeInBits());
286+
return builder.CreateBitCast(v, target_type);
287+
}
255288

289+
// Vector or non-Aggregate types
256290
// LLVM doesn't allow us to cast values directly, so
257291
// we need to use this alloca trick
258-
Value *mem = builder.CreateAlloca(target_type);
259-
builder.CreateStore(v,builder.CreatePointerCast(mem,v->getType()->getPointerTo()));
292+
Value *mem = builder.CreateAlloca(target_type); // XXX: don't frob the stack
293+
builder.CreateStore(v, builder.CreatePointerCast(mem, from_type->getPointerTo()));
260294
return builder.CreateLoad(mem);
261295
}
262296

@@ -265,27 +299,36 @@ Value *llvm_type_rewrite(Value *v, Type *target_type, jl_value_t *ty, bool isret
265299
static Value *julia_to_native(Type *ty, jl_value_t *jt, Value *jv,
266300
jl_value_t *aty, bool addressOf,
267301
bool byRef, bool inReg,
268-
bool needCopy,
302+
bool needCopy, bool tojulia,
269303
int argn, jl_codectx_t *ctx,
270304
bool *needStackRestore)
271305
{
272306
Type *vt = jv->getType();
273307

274-
// We're passing any
308+
// We're passing Any
275309
if (ty == jl_pvalue_llvmt) {
276310
return boxed(jv,ctx);
277311
}
312+
313+
if (!tojulia && julia_type_to_llvm(aty)->isAggregateType()) {
314+
// this value is expected to be a pointer in the julia codegen,
315+
// so it needs to be extracted first if not tojulia
316+
vt = vt->getContainedType(0);
317+
}
318+
278319
if (ty == vt && !addressOf && !byRef) {
279320
return jv;
280321
}
322+
281323
if (vt != jl_pvalue_llvmt) {
282324
// argument value is unboxed
325+
if (vt != jv->getType())
326+
jv = builder.CreateLoad(jv);
283327
if (addressOf || (byRef && inReg)) {
284-
if (ty->isPointerTy() && ty->getContainedType(0)==vt) {
328+
if (ty->isPointerTy() && ty->getContainedType(0) == vt) {
285329
// pass the address of an alloca'd thing, not a box
286330
// since those are immutable.
287-
*needStackRestore = true;
288-
Value *slot = builder.CreateAlloca(vt);
331+
Value *slot = emit_static_alloca(vt, ctx);
289332
builder.CreateStore(jv, slot);
290333
return builder.CreateBitCast(slot, ty);
291334
}
@@ -299,29 +342,30 @@ static Value *julia_to_native(Type *ty, jl_value_t *jt, Value *jv,
299342
return builder.CreateBitCast(jv, ty);
300343
}
301344
else {
302-
*needStackRestore = true;
303-
Value *mem = builder.CreateAlloca(ty);
345+
Value *mem = emit_static_alloca(ty, ctx);
304346
builder.CreateStore(jv,builder.CreateBitCast(mem,vt->getPointerTo()));
305347
return mem;
306348
}
307349
}
308350
}
309351
else if (vt->isStructTy()) {
310-
if (!byRef) {
311-
return jv;
352+
if (byRef) {
353+
Value *mem = emit_static_alloca(vt, ctx);
354+
builder.CreateStore(jv, mem);
355+
return mem;
312356
}
313357
else {
314-
*needStackRestore = true;
315-
Value *mem = builder.CreateAlloca(vt);
316-
builder.CreateStore(jv,mem);
317-
return mem;
358+
return jv;
318359
}
319360
}
320361

321362
emit_error("ccall: argument type did not match declaration", ctx);
322363
}
364+
365+
// argument value is boxed
323366
if (jl_is_tuple(jt)) {
324-
return emit_unbox(ty,jv,jt);
367+
emit_error("ccall: unimplemented: boxed tuple argument type", ctx);
368+
return jv; // TODO: this is wrong
325369
}
326370
if (jl_is_cpointer_type(jt) && addressOf) {
327371
assert(ty->isPointerTy());
@@ -349,7 +393,7 @@ static Value *julia_to_native(Type *ty, jl_value_t *jt, Value *jv,
349393
*needStackRestore = true;
350394
AllocaInst *ai = builder.CreateAlloca(T_int8, nbytes);
351395
ai->setAlignment(16);
352-
builder.CreateMemCpy(ai, builder.CreateBitCast(jv, T_pint8), nbytes, 1);
396+
builder.CreateMemCpy(ai, builder.CreateBitCast(jv, T_pint8), nbytes, 0);
353397
return builder.CreateBitCast(ai, ty);
354398
}
355399
// emit maybe copy
@@ -375,7 +419,7 @@ static Value *julia_to_native(Type *ty, jl_value_t *jt, Value *jv,
375419
false));
376420
AllocaInst *ai = builder.CreateAlloca(T_int8, nbytes);
377421
ai->setAlignment(16);
378-
builder.CreateMemCpy(ai, builder.CreatePointerCast(jv, T_pint8), nbytes, 1);
422+
builder.CreateMemCpy(ai, builder.CreatePointerCast(jv, T_pint8), nbytes, 0);
379423
Value *p2 = builder.CreatePointerCast(ai, ty);
380424
builder.CreateBr(afterBB);
381425
builder.SetInsertPoint(afterBB);
@@ -393,21 +437,19 @@ static Value *julia_to_native(Type *ty, jl_value_t *jt, Value *jv,
393437
msg << argn;
394438
emit_typecheck(jv, jt, msg.str(), ctx);
395439
}
396-
Value *p = data_pointer(jv);
397-
Value *pjv = builder.CreatePointerCast(p, PointerType::get(ty,0));
440+
Value *pjv = builder.CreatePointerCast(jv, PointerType::get(ty,0));
398441
if (byRef) {
399442
if (!needCopy) {
400443
return pjv;
401444
}
402445
else {
403-
*needStackRestore = true;
404-
Value *mem = builder.CreateAlloca(ty);
405-
builder.CreateMemCpy(mem,pjv,(uint64_t)jl_datatype_size(jt),(uint64_t)((jl_datatype_t*)jt)->alignment);
446+
Value *mem = emit_static_alloca(ty, ctx);
447+
builder.CreateMemCpy(mem, pjv, (uint64_t)jl_datatype_size(jt), (uint64_t)((jl_datatype_t*)jt)->alignment);
406448
return mem;
407449
}
408450
}
409451
else {
410-
return builder.CreateLoad(pjv,false);
452+
return pjv; // lazy load by llvm_type_rewrite
411453
}
412454
}
413455

@@ -661,7 +703,8 @@ static Value *emit_llvmcall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx)
661703
make_gcroot(arg, ctx);
662704
}
663705
#endif
664-
argvals[i] = julia_to_native(t, tti, arg, expr_type(argi, ctx), false, false, false, false, i, ctx, NULL);
706+
Value *v = julia_to_native(t, tti, arg, expr_type(argi, ctx), false, false, false, false, false, i, ctx, NULL);
707+
argvals[i] = llvm_type_rewrite(v, t, t, false, false);
665708
}
666709

667710
Function *f;
@@ -786,6 +829,7 @@ typedef AttributeSet attr_type;
786829

787830
static std::string generate_func_sig(Type **lrt, Type **prt, int &sret,
788831
std::vector<Type *> &fargt, std::vector<Type *> &fargt_sig,
832+
Type *&fargt_vasig,
789833
std::vector<bool> &inRegList,
790834
std::vector<bool> &byRefList, attr_type &attributes,
791835
jl_value_t *rt, jl_svec_t *tt)
@@ -805,7 +849,7 @@ static std::string generate_func_sig(Type **lrt, Type **prt, int &sret,
805849
*prt = *lrt = T_void;
806850
}
807851
else {
808-
*prt = preferred_llvm_type(rt,true);
852+
*prt = preferred_llvm_type(rt, true);
809853
if (*prt == NULL)
810854
*prt = *lrt;
811855

@@ -892,7 +936,7 @@ static std::string generate_func_sig(Type **lrt, Type **prt, int &sret,
892936

893937
fargt.push_back(t);
894938

895-
Type *pat = preferred_llvm_type(tti,false);
939+
Type *pat = preferred_llvm_type(tti, false);
896940
if (pat != NULL)
897941
t = pat;
898942
else if (byRef)
@@ -901,6 +945,9 @@ static std::string generate_func_sig(Type **lrt, Type **prt, int &sret,
901945
if (!current_isVa) {
902946
fargt_sig.push_back(t);
903947
}
948+
else {
949+
fargt_vasig = t;
950+
}
904951
}
905952

906953
if (retattrs.hasAttributes())
@@ -1128,12 +1175,13 @@ static Value *emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx)
11281175

11291176
std::vector<Type*> fargt(0);
11301177
std::vector<Type*> fargt_sig(0);
1178+
Type *fargt_vasig = NULL;
11311179
std::vector<bool> inRegList(0);
11321180
std::vector<bool> byRefList(0);
11331181
attr_type attrs;
11341182
Type *prt = NULL;
11351183
int sret = 0;
1136-
std::string err_msg = generate_func_sig(&lrt, &prt, sret, fargt, fargt_sig, inRegList, byRefList, attrs, rt, tt);
1184+
std::string err_msg = generate_func_sig(&lrt, &prt, sret, fargt, fargt_sig, fargt_vasig, inRegList, byRefList, attrs, rt, tt);
11371185
if (!err_msg.empty()) {
11381186
JL_GC_POP();
11391187
emit_error(err_msg,ctx);
@@ -1143,19 +1191,21 @@ static Value *emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx)
11431191
// emit arguments
11441192
Value **argvals = (Value**) alloca(((nargs-3)/2 + sret)*sizeof(Value*));
11451193
Value *result = NULL;
1194+
bool needStackRestore = false;
11461195

11471196
// First, if the ABI requires us to provide the space for the return
11481197
// argument, allocate the box and store that as the first argument type
11491198
if (sret) {
1150-
result = emit_new_struct(rt,1,NULL,ctx);
1199+
result = emit_new_struct(rt,1,NULL,ctx); // TODO: is it valid to be creating an incomplete type this way?
11511200
assert(result != NULL && "Type was not concrete");
11521201
if (!result->getType()->isPointerTy()) {
1153-
Value *mem = builder.CreateAlloca(lrt);
1202+
Value *mem = emit_static_alloca(lrt, ctx);
11541203
builder.CreateStore(result, mem);
11551204
result = mem;
11561205
argvals[0] = result;
11571206
}
11581207
else {
1208+
// XXX: result needs a GC root here if result->getType() == jl_pvalue_llvmt
11591209
argvals[0] = builder.CreateBitCast(result, fargt_sig[0]);
11601210
}
11611211
}
@@ -1164,7 +1214,6 @@ static Value *emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx)
11641214
int last_depth = ctx->argDepth;
11651215

11661216
// number of parameters to the c function
1167-
bool needStackRestore = false;
11681217
for(i=4; i < nargs+1; i+=2) {
11691218
// Current C function parameter
11701219
size_t ai = (i-4)/2;
@@ -1240,9 +1289,9 @@ static Value *emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx)
12401289
bool nSR=false;
12411290
argvals[ai + sret] = llvm_type_rewrite(
12421291
julia_to_native(largty, jargty, arg, expr_type(argi, ctx), addressOf, byRefList[ai], inRegList[ai],
1243-
need_private_copy(jargty, byRefList[ai]), ai + 1, ctx, &nSR),
1244-
fargt_sig.size() > ai + sret ? fargt_sig[ai + sret] : preferred_llvm_type(jargty, false),
1245-
jargty, false);
1292+
need_private_copy(jargty, byRefList[ai]), false, ai + 1, ctx, &nSR),
1293+
largty, ai + sret < fargt_sig.size() ? fargt_sig[ai + sret] : fargt_vasig,
1294+
false, byRefList[ai]);
12461295
needStackRestore |= nSR;
12471296
}
12481297

@@ -1330,40 +1379,38 @@ static Value *emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx)
13301379
JL_GC_POP();
13311380
// Finally we need to box the result into julia type
13321381
// However, if we have already created a box for the return
1333-
// type because we the ABI required us to pass a pointer (sret),
1382+
// type because the ABI required us to pass a pointer (sret),
13341383
// then we do not need to do this.
13351384
if (!sret) {
13361385
if (lrt == T_void)
13371386
result = literal_pointer_val((jl_value_t*)jl_nothing);
13381387
else if (lrt->isStructTy()) {
13391388
//fprintf(stderr, "ccall rt: %s -> %s\n", f_name, ((jl_tag_type_t*)rt)->name->name->name);
13401389
assert(jl_is_structtype(rt));
1341-
13421390
Value *newst = emit_new_struct(rt,1,NULL,ctx);
13431391
assert(newst != NULL && "Type was not concrete");
1344-
if (newst->getType()->isPointerTy()) {
1345-
builder.CreateStore(result,builder.CreateBitCast(newst, prt->getPointerTo()));
1346-
result = newst;
1347-
}
1348-
else if (lrt != prt) {
1349-
result = llvm_type_rewrite(result,lrt,rt,true);
1350-
}
1351-
// otherwise it's fine to pass this by value. Technically we could do alloca/store/load,
1352-
// but why should we?
1392+
assert(newst->getType()->isPointerTy());
1393+
builder.CreateStore(result, builder.CreateBitCast(newst, prt->getPointerTo()));
1394+
result = newst;
13531395
}
13541396
else {
13551397
if (prt->getPrimitiveSizeInBits() == lrt->getPrimitiveSizeInBits()) {
13561398
result = builder.CreateBitCast(result,lrt);
13571399
}
13581400
else {
1359-
Value *rloc = builder.CreateAlloca(prt);
1360-
builder.CreateStore(result, rloc);
1361-
result = builder.CreateLoad(builder.CreatePointerCast(rloc, PointerType::get(lrt,0)));
1401+
Value *rloc = emit_static_alloca(lrt, ctx);
1402+
builder.CreateStore(result, builder.CreatePointerCast(rloc, PointerType::get(prt,0)));
1403+
if (lrt->isAggregateType()) {
1404+
result = rloc;
1405+
}
1406+
else {
1407+
result = builder.CreateLoad(rloc);
1408+
}
13621409
}
13631410
}
13641411
}
13651412
else {
1366-
if (result->getType() != jl_pvalue_llvmt)
1413+
if (result->getType() != jl_pvalue_llvmt && !lrt->isAggregateType())
13671414
result = builder.CreateLoad(result);
13681415
}
13691416

0 commit comments

Comments
 (0)
Please sign in to comment.