@@ -288,6 +288,7 @@ static Function *jlthrow_line_func;
288288static Function *jlerror_func;
289289static Function *jltypeerror_func;
290290static Function *jlundefvarerror_func;
291+ static Function *jlboundserrorint_func;
291292static Function *jlboundserror_func;
292293static Function *jluboundserror_func;
293294static Function *jlvboundserror_func;
@@ -2488,6 +2489,123 @@ static Value *emit_known_call(jl_value_t *ff, jl_value_t **args, size_t nargs,
24882489 }
24892490 // TODO: faster code for integer index
24902491 }
2492+ else if (f->fptr == &jl_f_modifyelement && nargs == 3 ) {
2493+ jl_datatype_t *sty = (jl_datatype_t *)expr_type (args[1 ], ctx);
2494+ // First check if this is a constant index
2495+ bool isconstidx = jl_is_long (args[2 ]);
2496+ if (!isconstidx && jl_is_tuple (args[2 ])) {
2497+ isconstidx = true ;
2498+ jl_datatype_t *tt = (jl_datatype_t *)jl_typeof (args[2 ]);
2499+ for (size_t i = 0 ; i < jl_nfields (args[2 ]); ++i) {
2500+ if ((jl_datatype_t *)jl_field_type (tt, i) != jl_long_type) {
2501+ isconstidx = false ;
2502+ break ;
2503+ }
2504+ }
2505+ }
2506+
2507+ rt1 = (jl_value_t *)sty;
2508+ if (jl_is_ref_type ((jl_value_t *)sty)) {
2509+ jl_datatype_t *tt = (jl_datatype_t *)jl_tparam0 (sty);
2510+ if (jl_is_tuple_type (tt)){
2511+ Value *addr = NULL ;
2512+ Value *strct = NULL ;
2513+ jl_datatype_t *fieldty;
2514+ if (isconstidx) {
2515+ if (jl_is_long (args[2 ])) {
2516+ size_t idx = jl_unbox_long (args[2 ]) - 1 ;
2517+ if (idx < jl_datatype_nfields (sty)) {
2518+ Value *strct = emit_expr (args[1 ], ctx);
2519+ addr = emit_gep_knownidx (strct, idx, sty);
2520+ fieldty = (jl_datatype_t *)jl_field_type (tt, idx);
2521+ }
2522+ }
2523+ else {
2524+ // First check bounds, then emit code
2525+ bool boundsok = true ;
2526+ fieldty = tt;
2527+ for (size_t i = 0 ; i < jl_nfields (args[2 ]); ++i) {
2528+ unsigned idx = jl_unbox_long (jl_get_nth_field (args[2 ],i))-1 ;
2529+ if (idx >= jl_datatype_nfields (fieldty)) {
2530+ boundsok = false ;
2531+ break ;
2532+ }
2533+ fieldty = (jl_datatype_t *)jl_field_type (fieldty, idx);
2534+ }
2535+ if (boundsok) {
2536+ Value *strct = emit_expr (args[1 ], ctx);
2537+ std::vector<Value *> idxs;
2538+ idxs.push_back (ConstantInt::get (T_int32, 0 ));
2539+ idxs.push_back (ConstantInt::get (T_int32, 0 ));
2540+ for (size_t i = 0 ; i < jl_nfields (args[2 ]); ++i)
2541+ idxs.push_back (ConstantInt::get (T_int32, jl_unbox_long (jl_get_nth_field (args[2 ],i))-1 ));
2542+ addr = emit_gep_knownidx (strct, idxs, sty);
2543+ }
2544+ }
2545+ } else {
2546+ // Not const index, first check if the tuple is homogeneous to the required depth
2547+ jl_datatype_t *idxty = (jl_datatype_t *)expr_type (args[2 ], ctx);
2548+ int depth = idxty == jl_long_type ? 1 : jl_is_tuple_type (idxty) ?
2549+ jl_svec_len (idxty->types ) : 0 ;
2550+ if (depth != 0 ) {
2551+ fieldty = tt;
2552+ bool ishomogeneous = true ;
2553+ for (size_t i = 0 ; i < depth; ++i) {
2554+ if (!is_tupletype_homogeneous (fieldty->types )) {
2555+ ishomogeneous = false ;
2556+ break ;
2557+ }
2558+ fieldty = (jl_datatype_t *)jl_field_type (fieldty,0 );
2559+ }
2560+ if (ishomogeneous) {
2561+ // Now we know we can emit this efficiently
2562+ strct = emit_expr (args[1 ], ctx);
2563+ Value *idxval = emit_expr (args[2 ], ctx);
2564+ // Emit boundscheck
2565+ std::vector<Value *> idxs;
2566+ idxs.push_back (ConstantInt::get (T_int32, 0 ));
2567+ idxs.push_back (ConstantInt::get (T_int32, 0 ));
2568+ fieldty = tt;
2569+ Value *bndacc = ConstantInt::get (T_int1, 1 );
2570+ for (size_t i = 0 ; i < depth; ++i) {
2571+ Value *idx = builder.CreateSub (
2572+ emit_getfield_knownidx (idxval, i, idxty, ctx),
2573+ ConstantInt::get (T_size, 1 ));
2574+ // For bounds check
2575+ Value *ok = builder.CreateICmpULT (idx,
2576+ ConstantInt::get (T_size, jl_datatype_nfields (fieldty)));
2577+ bndacc = builder.CreateAnd (ok,bndacc);
2578+ idxs.push_back (idx);
2579+ fieldty = (jl_datatype_t *)jl_field_type (fieldty,0 );
2580+ }
2581+ if (((ctx->boundsCheck .empty () || ctx->boundsCheck .back ()==true ) &&
2582+ jl_options.check_bounds != JL_OPTIONS_CHECK_BOUNDS_OFF) ||
2583+ jl_options.check_bounds == JL_OPTIONS_CHECK_BOUNDS_ON) {
2584+ BasicBlock *failBB = BasicBlock::Create (getGlobalContext ()," fail" ,ctx->f );
2585+ BasicBlock *passBB = BasicBlock::Create (getGlobalContext ()," pass" ,ctx->f );
2586+ builder.CreateCondBr (bndacc, passBB, failBB);
2587+ builder.SetInsertPoint (failBB);
2588+ builder.CreateCall (prepare_call (jlboundserror_func), {
2589+ boxed (strct, ctx), boxed (idxval, ctx, (jl_value_t *)idxty)
2590+ });
2591+ builder.CreateUnreachable ();
2592+ builder.SetInsertPoint (passBB);
2593+ }
2594+ addr = emit_gep_knownidx (strct, idxs, sty);
2595+ }
2596+ }
2597+ }
2598+
2599+ if (addr != NULL ) {
2600+ int align = jl_datatype_size (fieldty);
2601+ typed_store (addr, ConstantInt::get (T_int32, 0 ), emit_expr (args[3 ], ctx),
2602+ (jl_value_t *)fieldty, ctx, tbaa_user, strct, align);
2603+ JL_GC_POP ();
2604+ return ghostValue (jl_typeof (jl_nothing));
2605+ }
2606+ }
2607+ }
2608+ }
24912609 else if (f->fptr == &jl_f_nfields && nargs==1 ) {
24922610 if (ctx->vaStack && symbol_eq (args[1 ], ctx->vaName ) && !ctx->vars [ctx->vaName ].isAssigned ) {
24932611 JL_GC_POP ();
@@ -5059,6 +5177,16 @@ static void init_julia_llvm_env(Module *m)
50595177 jlundefvarerror_func->setDoesNotReturn ();
50605178 add_named_global (jlundefvarerror_func, (void *)&jl_undefined_var_error);
50615179
5180+ std::vector<Type*> args2_boundserror (0 );
5181+ args2_boundserror.push_back (jl_pvalue_llvmt);
5182+ args2_boundserror.push_back (jl_pvalue_llvmt);
5183+ jlboundserror_func =
5184+ Function::Create (FunctionType::get (T_void, args2_boundserror, false ),
5185+ Function::ExternalLinkage,
5186+ " jl_bounds_error" , m);
5187+ jlboundserror_func->setDoesNotReturn ();
5188+ add_named_global (jlboundserror_func, (void *)&jl_bounds_error);
5189+
50625190 std::vector<Type*> args2_boundserrorv (0 );
50635191 args2_boundserrorv.push_back (jl_pvalue_llvmt);
50645192 args2_boundserrorv.push_back (T_psize);
@@ -5070,15 +5198,15 @@ static void init_julia_llvm_env(Module *m)
50705198 jlboundserrorv_func->setDoesNotReturn ();
50715199 add_named_global (jlboundserrorv_func, (void *)&jl_bounds_error_ints);
50725200
5073- std::vector<Type*> args2_boundserror (0 );
5074- args2_boundserror .push_back (jl_pvalue_llvmt);
5075- args2_boundserror .push_back (T_size);
5076- jlboundserror_func =
5077- Function::Create (FunctionType::get (T_void, args2_boundserror , false ),
5201+ std::vector<Type*> args2_boundserrorint (0 );
5202+ args2_boundserrorint .push_back (jl_pvalue_llvmt);
5203+ args2_boundserrorint .push_back (T_size);
5204+ jlboundserrorint_func =
5205+ Function::Create (FunctionType::get (T_void, args2_boundserrorint , false ),
50785206 Function::ExternalLinkage,
50795207 " jl_bounds_error_int" , m);
5080- jlboundserror_func ->setDoesNotReturn ();
5081- add_named_global (jlboundserror_func , (void *)&jl_bounds_error_int);
5208+ jlboundserrorint_func ->setDoesNotReturn ();
5209+ add_named_global (jlboundserrorint_func , (void *)&jl_bounds_error_int);
50825210
50835211 std::vector<Type*> args3_vboundserror (0 );
50845212 args3_vboundserror.push_back (jl_ppvalue_llvmt);
@@ -5190,6 +5318,7 @@ static void init_julia_llvm_env(Module *m)
51905318 builtin_func_map[jl_f_isdefined] = jlcall_func_to_llvm (" jl_f_isdefined" , (void *)&jl_f_isdefined, m);
51915319 builtin_func_map[jl_f_get_field] = jlcall_func_to_llvm (" jl_f_get_field" , (void *)&jl_f_get_field, m);
51925320 builtin_func_map[jl_f_set_field] = jlcall_func_to_llvm (" jl_f_set_field" , (void *)&jl_f_set_field, m);
5321+ builtin_func_map[jl_f_modifyelement] = jlcall_func_to_llvm (" jl_f_modifyelement" , (void *)&jl_f_modifyelement, m);
51935322 builtin_func_map[jl_f_field_type] = jlcall_func_to_llvm (" jl_f_field_type" , (void *)&jl_f_field_type, m);
51945323 builtin_func_map[jl_f_nfields] = jlcall_func_to_llvm (" jl_f_nfields" , (void *)&jl_f_nfields, m);
51955324 builtin_func_map[jl_f_new_expr] = jlcall_func_to_llvm (" jl_f_new_expr" , (void *)&jl_f_new_expr, m);
0 commit comments