@@ -246,17 +246,51 @@ static Value *runtime_sym_lookup(PointerType *funcptype, char *f_lib, char *f_na
246
246
# include " abi_llvm.cpp"
247
247
#endif
248
248
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 )
250
250
{
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) {
252
279
return v;
280
+ }
253
281
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
+ }
255
288
289
+ // Vector or non-Aggregate types
256
290
// LLVM doesn't allow us to cast values directly, so
257
291
// 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 ()));
260
294
return builder.CreateLoad (mem);
261
295
}
262
296
@@ -265,27 +299,36 @@ Value *llvm_type_rewrite(Value *v, Type *target_type, jl_value_t *ty, bool isret
265
299
static Value *julia_to_native (Type *ty, jl_value_t *jt, Value *jv,
266
300
jl_value_t *aty, bool addressOf,
267
301
bool byRef, bool inReg,
268
- bool needCopy,
302
+ bool needCopy, bool tojulia,
269
303
int argn, jl_codectx_t *ctx,
270
304
bool *needStackRestore)
271
305
{
272
306
Type *vt = jv->getType ();
273
307
274
- // We're passing any
308
+ // We're passing Any
275
309
if (ty == jl_pvalue_llvmt) {
276
310
return boxed (jv,ctx);
277
311
}
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
+
278
319
if (ty == vt && !addressOf && !byRef) {
279
320
return jv;
280
321
}
322
+
281
323
if (vt != jl_pvalue_llvmt) {
282
324
// argument value is unboxed
325
+ if (vt != jv->getType ())
326
+ jv = builder.CreateLoad (jv);
283
327
if (addressOf || (byRef && inReg)) {
284
- if (ty->isPointerTy () && ty->getContainedType (0 )== vt) {
328
+ if (ty->isPointerTy () && ty->getContainedType (0 ) == vt) {
285
329
// pass the address of an alloca'd thing, not a box
286
330
// since those are immutable.
287
- *needStackRestore = true ;
288
- Value *slot = builder.CreateAlloca (vt);
331
+ Value *slot = emit_static_alloca (vt, ctx);
289
332
builder.CreateStore (jv, slot);
290
333
return builder.CreateBitCast (slot, ty);
291
334
}
@@ -299,29 +342,30 @@ static Value *julia_to_native(Type *ty, jl_value_t *jt, Value *jv,
299
342
return builder.CreateBitCast (jv, ty);
300
343
}
301
344
else {
302
- *needStackRestore = true ;
303
- Value *mem = builder.CreateAlloca (ty);
345
+ Value *mem = emit_static_alloca (ty, ctx);
304
346
builder.CreateStore (jv,builder.CreateBitCast (mem,vt->getPointerTo ()));
305
347
return mem;
306
348
}
307
349
}
308
350
}
309
351
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;
312
356
}
313
357
else {
314
- *needStackRestore = true ;
315
- Value *mem = builder.CreateAlloca (vt);
316
- builder.CreateStore (jv,mem);
317
- return mem;
358
+ return jv;
318
359
}
319
360
}
320
361
321
362
emit_error (" ccall: argument type did not match declaration" , ctx);
322
363
}
364
+
365
+ // argument value is boxed
323
366
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
325
369
}
326
370
if (jl_is_cpointer_type (jt) && addressOf) {
327
371
assert (ty->isPointerTy ());
@@ -349,7 +393,7 @@ static Value *julia_to_native(Type *ty, jl_value_t *jt, Value *jv,
349
393
*needStackRestore = true ;
350
394
AllocaInst *ai = builder.CreateAlloca (T_int8, nbytes);
351
395
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 );
353
397
return builder.CreateBitCast (ai, ty);
354
398
}
355
399
// emit maybe copy
@@ -375,7 +419,7 @@ static Value *julia_to_native(Type *ty, jl_value_t *jt, Value *jv,
375
419
false ));
376
420
AllocaInst *ai = builder.CreateAlloca (T_int8, nbytes);
377
421
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 );
379
423
Value *p2 = builder.CreatePointerCast (ai, ty);
380
424
builder.CreateBr (afterBB);
381
425
builder.SetInsertPoint (afterBB);
@@ -393,21 +437,19 @@ static Value *julia_to_native(Type *ty, jl_value_t *jt, Value *jv,
393
437
msg << argn;
394
438
emit_typecheck (jv, jt, msg.str (), ctx);
395
439
}
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 ));
398
441
if (byRef) {
399
442
if (!needCopy) {
400
443
return pjv;
401
444
}
402
445
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 );
406
448
return mem;
407
449
}
408
450
}
409
451
else {
410
- return builder. CreateLoad ( pjv, false );
452
+ return pjv; // lazy load by llvm_type_rewrite
411
453
}
412
454
}
413
455
@@ -661,7 +703,8 @@ static Value *emit_llvmcall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx)
661
703
make_gcroot (arg, ctx);
662
704
}
663
705
#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 );
665
708
}
666
709
667
710
Function *f;
@@ -786,6 +829,7 @@ typedef AttributeSet attr_type;
786
829
787
830
static std::string generate_func_sig (Type **lrt, Type **prt, int &sret,
788
831
std::vector<Type *> &fargt, std::vector<Type *> &fargt_sig,
832
+ Type *&fargt_vasig,
789
833
std::vector<bool > &inRegList,
790
834
std::vector<bool > &byRefList, attr_type &attributes,
791
835
jl_value_t *rt, jl_svec_t *tt)
@@ -805,7 +849,7 @@ static std::string generate_func_sig(Type **lrt, Type **prt, int &sret,
805
849
*prt = *lrt = T_void;
806
850
}
807
851
else {
808
- *prt = preferred_llvm_type (rt,true );
852
+ *prt = preferred_llvm_type (rt, true );
809
853
if (*prt == NULL )
810
854
*prt = *lrt;
811
855
@@ -892,7 +936,7 @@ static std::string generate_func_sig(Type **lrt, Type **prt, int &sret,
892
936
893
937
fargt.push_back (t);
894
938
895
- Type *pat = preferred_llvm_type (tti,false );
939
+ Type *pat = preferred_llvm_type (tti, false );
896
940
if (pat != NULL )
897
941
t = pat;
898
942
else if (byRef)
@@ -901,6 +945,9 @@ static std::string generate_func_sig(Type **lrt, Type **prt, int &sret,
901
945
if (!current_isVa) {
902
946
fargt_sig.push_back (t);
903
947
}
948
+ else {
949
+ fargt_vasig = t;
950
+ }
904
951
}
905
952
906
953
if (retattrs.hasAttributes ())
@@ -1128,12 +1175,13 @@ static Value *emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx)
1128
1175
1129
1176
std::vector<Type*> fargt (0 );
1130
1177
std::vector<Type*> fargt_sig (0 );
1178
+ Type *fargt_vasig = NULL ;
1131
1179
std::vector<bool > inRegList (0 );
1132
1180
std::vector<bool > byRefList (0 );
1133
1181
attr_type attrs;
1134
1182
Type *prt = NULL ;
1135
1183
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);
1137
1185
if (!err_msg.empty ()) {
1138
1186
JL_GC_POP ();
1139
1187
emit_error (err_msg,ctx);
@@ -1143,19 +1191,21 @@ static Value *emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx)
1143
1191
// emit arguments
1144
1192
Value **argvals = (Value**) alloca (((nargs-3 )/2 + sret)*sizeof (Value*));
1145
1193
Value *result = NULL ;
1194
+ bool needStackRestore = false ;
1146
1195
1147
1196
// First, if the ABI requires us to provide the space for the return
1148
1197
// argument, allocate the box and store that as the first argument type
1149
1198
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?
1151
1200
assert (result != NULL && " Type was not concrete" );
1152
1201
if (!result->getType ()->isPointerTy ()) {
1153
- Value *mem = builder. CreateAlloca (lrt);
1202
+ Value *mem = emit_static_alloca (lrt, ctx );
1154
1203
builder.CreateStore (result, mem);
1155
1204
result = mem;
1156
1205
argvals[0 ] = result;
1157
1206
}
1158
1207
else {
1208
+ // XXX: result needs a GC root here if result->getType() == jl_pvalue_llvmt
1159
1209
argvals[0 ] = builder.CreateBitCast (result, fargt_sig[0 ]);
1160
1210
}
1161
1211
}
@@ -1164,7 +1214,6 @@ static Value *emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx)
1164
1214
int last_depth = ctx->argDepth ;
1165
1215
1166
1216
// number of parameters to the c function
1167
- bool needStackRestore = false ;
1168
1217
for (i=4 ; i < nargs+1 ; i+=2 ) {
1169
1218
// Current C function parameter
1170
1219
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)
1240
1289
bool nSR=false ;
1241
1290
argvals[ai + sret] = llvm_type_rewrite (
1242
1291
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] );
1246
1295
needStackRestore |= nSR;
1247
1296
}
1248
1297
@@ -1330,40 +1379,38 @@ static Value *emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx)
1330
1379
JL_GC_POP ();
1331
1380
// Finally we need to box the result into julia type
1332
1381
// 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),
1334
1383
// then we do not need to do this.
1335
1384
if (!sret) {
1336
1385
if (lrt == T_void)
1337
1386
result = literal_pointer_val ((jl_value_t *)jl_nothing);
1338
1387
else if (lrt->isStructTy ()) {
1339
1388
// fprintf(stderr, "ccall rt: %s -> %s\n", f_name, ((jl_tag_type_t*)rt)->name->name->name);
1340
1389
assert (jl_is_structtype (rt));
1341
-
1342
1390
Value *newst = emit_new_struct (rt,1 ,NULL ,ctx);
1343
1391
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;
1353
1395
}
1354
1396
else {
1355
1397
if (prt->getPrimitiveSizeInBits () == lrt->getPrimitiveSizeInBits ()) {
1356
1398
result = builder.CreateBitCast (result,lrt);
1357
1399
}
1358
1400
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
+ }
1362
1409
}
1363
1410
}
1364
1411
}
1365
1412
else {
1366
- if (result->getType () != jl_pvalue_llvmt)
1413
+ if (result->getType () != jl_pvalue_llvmt && !lrt-> isAggregateType () )
1367
1414
result = builder.CreateLoad (result);
1368
1415
}
1369
1416
0 commit comments