@@ -879,6 +879,8 @@ static const std::map<jl_fptr_args_t, JuliaFunction*> builtin_func_map = {
879
879
{ &jl_f_isdefined, new JuliaFunction{" jl_f_isdefined" , get_func_sig, get_func_attrs} },
880
880
{ &jl_f_getfield, new JuliaFunction{" jl_f_getfield" , get_func_sig, get_func_attrs} },
881
881
{ &jl_f_setfield, new JuliaFunction{" jl_f_setfield" , get_func_sig, get_func_attrs} },
882
+ { &jl_f_swapfield, new JuliaFunction{" jl_f_swapfield" , get_func_sig, get_func_attrs} },
883
+ { &jl_f_modifyfield, new JuliaFunction{" jl_f_modifyfield" , get_func_sig, get_func_attrs} },
882
884
{ &jl_f_fieldtype, new JuliaFunction{" jl_f_fieldtype" , get_func_sig, get_func_attrs} },
883
885
{ &jl_f_nfields, new JuliaFunction{" jl_f_nfields" , get_func_sig, get_func_attrs} },
884
886
{ &jl_f__expr, new JuliaFunction{" jl_f__expr" , get_func_sig, get_func_attrs} },
@@ -1160,6 +1162,8 @@ static CallInst *emit_jlcall(jl_codectx_t &ctx, Function *theFptr, Value *theF,
1160
1162
jl_cgval_t *args, size_t nargs, CallingConv::ID cc);
1161
1163
static CallInst *emit_jlcall (jl_codectx_t &ctx, JuliaFunction *theFptr, Value *theF,
1162
1164
jl_cgval_t *args, size_t nargs, CallingConv::ID cc);
1165
+ static Value *emit_f_is (jl_codectx_t &ctx, const jl_cgval_t &arg1, const jl_cgval_t &arg2,
1166
+ Value *nullcheck1 = nullptr , Value *nullcheck2 = nullptr );
1163
1167
1164
1168
static Value *literal_pointer_val (jl_codectx_t &ctx, jl_value_t *p);
1165
1169
static GlobalVariable *prepare_global_in (Module *M, GlobalVariable *G);
@@ -1441,6 +1445,17 @@ static void alloc_def_flag(jl_codectx_t &ctx, jl_varinfo_t& vi)
1441
1445
1442
1446
// --- utilities ---
1443
1447
1448
+ static Constant *undef_value_for_type (Type *T) {
1449
+ auto tracked = CountTrackedPointers (T);
1450
+ Constant *undef;
1451
+ if (tracked.count )
1452
+ // make sure gc pointers (including ptr_phi of union-split) are initialized to NULL
1453
+ undef = Constant::getNullValue (T);
1454
+ else
1455
+ undef = UndefValue::get (T);
1456
+ return undef;
1457
+ }
1458
+
1444
1459
static void CreateTrap (IRBuilder<> &irbuilder)
1445
1460
{
1446
1461
Function *f = irbuilder.GetInsertBlock ()->getParent ();
@@ -1472,6 +1487,7 @@ static void CreateConditionalAbort(IRBuilder<> &irbuilder, Value *test)
1472
1487
#endif
1473
1488
#endif
1474
1489
1490
+
1475
1491
#include " cgutils.cpp"
1476
1492
1477
1493
static jl_cgval_t convert_julia_type_union (jl_codectx_t &ctx, const jl_cgval_t &v, jl_value_t *typ, Value **skip)
@@ -2351,62 +2367,6 @@ static jl_cgval_t emit_globalref(jl_codectx_t &ctx, jl_module_t *mod, jl_sym_t *
2351
2367
return emit_checked_var (ctx, bp, name, false , tbaa_binding);
2352
2368
}
2353
2369
2354
- template <typename Func>
2355
- static Value *emit_guarded_test (jl_codectx_t &ctx, Value *ifnot, Constant *defval, Func &&func)
2356
- {
2357
- if (auto Cond = dyn_cast<ConstantInt>(ifnot)) {
2358
- if (Cond->isZero ())
2359
- return defval;
2360
- return func ();
2361
- }
2362
- BasicBlock *currBB = ctx.builder .GetInsertBlock ();
2363
- BasicBlock *passBB = BasicBlock::Create (jl_LLVMContext, " guard_pass" , ctx.f );
2364
- BasicBlock *exitBB = BasicBlock::Create (jl_LLVMContext, " guard_exit" , ctx.f );
2365
- ctx.builder .CreateCondBr (ifnot, passBB, exitBB);
2366
- ctx.builder .SetInsertPoint (passBB);
2367
- auto res = func ();
2368
- passBB = ctx.builder .GetInsertBlock ();
2369
- ctx.builder .CreateBr (exitBB);
2370
- ctx.builder .SetInsertPoint (exitBB);
2371
- if (defval == nullptr )
2372
- return nullptr ;
2373
- PHINode *phi = ctx.builder .CreatePHI (defval->getType (), 2 );
2374
- phi->addIncoming (defval, currBB);
2375
- phi->addIncoming (res, passBB);
2376
- return phi;
2377
- }
2378
-
2379
- template <typename Func>
2380
- static Value *emit_guarded_test (jl_codectx_t &ctx, Value *ifnot, bool defval, Func &&func)
2381
- {
2382
- return emit_guarded_test (ctx, ifnot, ConstantInt::get (T_int1, defval), func);
2383
- }
2384
-
2385
- template <typename Func>
2386
- static Value *emit_nullcheck_guard (jl_codectx_t &ctx, Value *nullcheck, Func &&func)
2387
- {
2388
- if (!nullcheck)
2389
- return func ();
2390
- return emit_guarded_test (ctx, null_pointer_cmp (ctx, nullcheck), false , func);
2391
- }
2392
-
2393
- template <typename Func>
2394
- static Value *emit_nullcheck_guard2 (jl_codectx_t &ctx, Value *nullcheck1,
2395
- Value *nullcheck2, Func &&func)
2396
- {
2397
- if (!nullcheck1)
2398
- return emit_nullcheck_guard (ctx, nullcheck2, func);
2399
- if (!nullcheck2)
2400
- return emit_nullcheck_guard (ctx, nullcheck1, func);
2401
- nullcheck1 = null_pointer_cmp (ctx, nullcheck1);
2402
- nullcheck2 = null_pointer_cmp (ctx, nullcheck2);
2403
- // If both are NULL, return true.
2404
- return emit_guarded_test (ctx, ctx.builder .CreateOr (nullcheck1, nullcheck2), true , [&] {
2405
- return emit_guarded_test (ctx, ctx.builder .CreateAnd (nullcheck1, nullcheck2),
2406
- false , func);
2407
- });
2408
- }
2409
-
2410
2370
static Value *emit_box_compare (jl_codectx_t &ctx, const jl_cgval_t &arg1, const jl_cgval_t &arg2,
2411
2371
Value *nullcheck1, Value *nullcheck2)
2412
2372
{
@@ -2443,8 +2403,6 @@ static Value *emit_box_compare(jl_codectx_t &ctx, const jl_cgval_t &arg1, const
2443
2403
}
2444
2404
2445
2405
static Value *emit_bits_compare (jl_codectx_t &ctx, jl_cgval_t arg1, jl_cgval_t arg2);
2446
- static Value *emit_f_is (jl_codectx_t &ctx, const jl_cgval_t &arg1, const jl_cgval_t &arg2,
2447
- Value *nullcheck1 = nullptr , Value *nullcheck2 = nullptr );
2448
2406
2449
2407
static Value *emit_bitsunion_compare (jl_codectx_t &ctx, const jl_cgval_t &arg1, const jl_cgval_t &arg2)
2450
2408
{
@@ -3011,13 +2969,18 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f,
3011
2969
else {
3012
2970
typed_store (ctx,
3013
2971
emit_arrayptr (ctx, ary, ary_ex, isboxed),
3014
- idx, val, ety,
2972
+ idx, val, jl_cgval_t (), ety,
3015
2973
isboxed ? tbaa_ptrarraybuf : tbaa_arraybuf,
3016
2974
ctx.aliasscope ,
3017
2975
data_owner,
3018
2976
isboxed,
3019
2977
isboxed ? AtomicOrdering::Unordered : AtomicOrdering::NotAtomic, // TODO: we should do this for anything with CountTrackedPointers(elty).count > 0
3020
- 0 );
2978
+ isboxed ? AtomicOrdering::Unordered : AtomicOrdering::NotAtomic, // TODO: we should do this for anything with CountTrackedPointers(elty).count > 0
2979
+ 0 ,
2980
+ false ,
2981
+ true ,
2982
+ false ,
2983
+ false );
3021
2984
}
3022
2985
}
3023
2986
*ret = ary;
@@ -3158,19 +3121,34 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f,
3158
3121
return false ;
3159
3122
}
3160
3123
3161
- else if (f == jl_builtin_setfield && (nargs == 3 || nargs == 4 )) {
3124
+ else if ((f == jl_builtin_setfield && (nargs == 3 || nargs == 4 )) ||
3125
+ (f == jl_builtin_swapfield && (nargs == 3 || nargs == 4 )) ||
3126
+ (f == jl_builtin_replacefield && (nargs == 4 || nargs == 5 || nargs == 6 ))) {
3127
+ bool issetfield = f == jl_builtin_setfield;
3128
+ bool isreplacefield = f == jl_builtin_replacefield;
3129
+ const jl_cgval_t undefval;
3162
3130
const jl_cgval_t &obj = argv[1 ];
3163
3131
const jl_cgval_t &fld = argv[2 ];
3164
- const jl_cgval_t &val = argv[3 ];
3132
+ const jl_cgval_t &val = argv[isreplacefield ? 4 : 3 ];
3133
+ const jl_cgval_t &cmp = isreplacefield ? argv[3 ] : undefval;
3165
3134
enum jl_memory_order order = jl_memory_order_notatomic;
3166
- if (nargs == 4 ) {
3167
- const jl_cgval_t &ord = argv[4 ];
3168
- emit_typecheck (ctx, ord, (jl_value_t *)jl_symbol_type, " setfield!" );
3135
+ if (nargs >= (isreplacefield ? 5 : 4 )) {
3136
+ const jl_cgval_t &ord = argv[isreplacefield ? 5 : 4 ];
3137
+ emit_typecheck (ctx, ord, (jl_value_t *)jl_symbol_type,
3138
+ issetfield ? " setfield!" : isreplacefield ? " replacefield!" : " swapfield!" );
3169
3139
if (!ord.constant )
3170
3140
return false ;
3171
- order = jl_get_atomic_order ((jl_sym_t *)ord.constant , false , true );
3141
+ order = jl_get_atomic_order ((jl_sym_t *)ord.constant , !issetfield , true );
3172
3142
}
3173
- if (order == jl_memory_order_invalid) {
3143
+ enum jl_memory_order fail_order = order;
3144
+ if (isreplacefield && nargs == 6 ) {
3145
+ const jl_cgval_t &ord = argv[6 ];
3146
+ emit_typecheck (ctx, ord, (jl_value_t *)jl_symbol_type, " replacefield!" );
3147
+ if (!ord.constant )
3148
+ return false ;
3149
+ fail_order = jl_get_atomic_order ((jl_sym_t *)ord.constant , true , false );
3150
+ }
3151
+ if (order == jl_memory_order_invalid || fail_order == jl_memory_order_invalid || fail_order > order) {
3174
3152
emit_atomic_error (ctx, " invalid atomic ordering" );
3175
3153
*ret = jl_cgval_t (); // unreachable
3176
3154
return true ;
@@ -3189,27 +3167,39 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f,
3189
3167
}
3190
3168
if (idx != -1 ) {
3191
3169
jl_value_t *ft = jl_svecref (uty->types , idx);
3192
- if (jl_subtype (val.typ , ft)) {
3170
+ if (! jl_has_free_typevars (ft) && jl_subtype (val.typ , ft)) {
3193
3171
// TODO: attempt better codegen for approximate types
3194
3172
bool isboxed = jl_field_isptr (uty, idx);
3195
3173
bool isatomic = jl_field_isatomic (uty, idx);
3196
3174
bool needlock = isatomic && !isboxed && jl_datatype_size (jl_field_type (uty, idx)) > MAX_ATOMIC_SIZE;
3197
3175
if (isatomic == (order == jl_memory_order_notatomic)) {
3198
3176
emit_atomic_error (ctx,
3199
- isatomic ? " setfield!: atomic field cannot be written non-atomically"
3200
- : " setfield!: non-atomic field cannot be written atomically" );
3177
+ issetfield ?
3178
+ (isatomic ? " setfield!: atomic field cannot be written non-atomically"
3179
+ : " setfield!: non-atomic field cannot be written atomically" ) :
3180
+ isreplacefield ?
3181
+ (isatomic ? " replacefield!: atomic field cannot be written non-atomically"
3182
+ : " replacefield!: non-atomic field cannot be written atomically" ) :
3183
+ (isatomic ? " swapfield!: atomic field cannot be written non-atomically"
3184
+ : " swapfield!: non-atomic field cannot be written atomically" ));
3185
+ *ret = jl_cgval_t ();
3186
+ return true ;
3187
+ }
3188
+ if (isatomic == (fail_order == jl_memory_order_notatomic)) {
3189
+ emit_atomic_error (ctx,
3190
+ (isatomic ? " replacefield!: atomic field cannot be accessed non-atomically"
3191
+ : " replacefield!: non-atomic field cannot be accessed atomically" ));
3201
3192
*ret = jl_cgval_t ();
3202
3193
return true ;
3203
3194
}
3204
- if (needlock)
3205
- emit_lockstate_value (ctx, obj, true );
3206
- emit_setfield (ctx, uty, obj, idx, val, true , true ,
3195
+ *ret = emit_setfield (ctx, uty, obj, idx, val, cmp, true , true ,
3207
3196
(needlock || order <= jl_memory_order_notatomic)
3208
3197
? (isboxed ? AtomicOrdering::Unordered : AtomicOrdering::NotAtomic) // TODO: we should do this for anything with CountTrackedPointers(elty).count > 0
3209
- : get_llvm_atomic_order (order));
3210
- if (needlock)
3211
- emit_lockstate_value (ctx, obj, false );
3212
- *ret = val;
3198
+ : get_llvm_atomic_order (order),
3199
+ (needlock || fail_order <= jl_memory_order_notatomic)
3200
+ ? (isboxed ? AtomicOrdering::Unordered : AtomicOrdering::NotAtomic) // TODO: we should do this for anything with CountTrackedPointers(elty).count > 0
3201
+ : get_llvm_atomic_order (fail_order),
3202
+ needlock, issetfield, isreplacefield);
3213
3203
return true ;
3214
3204
}
3215
3205
}
@@ -7233,17 +7223,6 @@ static std::pair<std::unique_ptr<Module>, jl_llvm_functions_t>
7233
7223
ctx.builder .SetCurrentDebugLocation (noDbg);
7234
7224
ctx.builder .ClearInsertionPoint ();
7235
7225
7236
- auto undef_value_for_type = [&](Type *T) {
7237
- auto tracked = CountTrackedPointers (T);
7238
- Constant *undef;
7239
- if (tracked.count )
7240
- // make sure gc pointers (including ptr_phi of union-split) are initialized to NULL
7241
- undef = Constant::getNullValue (T);
7242
- else
7243
- undef = UndefValue::get (T);
7244
- return undef;
7245
- };
7246
-
7247
7226
// Codegen Phi nodes
7248
7227
std::map<std::pair<BasicBlock*, BasicBlock*>, BasicBlock*> BB_rewrite_map;
7249
7228
std::vector<llvm::PHINode*> ToDelete;
0 commit comments