From 61ee70d533905318814220f0442d047a28817772 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Sat, 2 Sep 2017 21:00:10 -0400 Subject: [PATCH] Remove some leagcy gcroot codegen code The LLVM pass now figures this out automatically, so we no longer need to put it explicitly into the code. There's more cleanup to be done here, but I want to take this one step at a time, since this legacy code may have been hiding issues in the GC root placement pass. --- Makefile | 4 +-- src/ccall.cpp | 2 +- src/cgutils.cpp | 31 ++++++++------------ src/codegen.cpp | 72 +++++++++++++++++++--------------------------- src/intrinsics.cpp | 2 +- 5 files changed, 45 insertions(+), 66 deletions(-) diff --git a/Makefile b/Makefile index d34d715fcc2cf..fd04142297f50 100644 --- a/Makefile +++ b/Makefile @@ -551,9 +551,9 @@ test: check-whitespace $(JULIA_BUILD_MODE) @$(MAKE) $(QUIET_MAKE) -C $(BUILDROOT)/test default JULIA_BUILD_MODE=$(JULIA_BUILD_MODE) ifeq ($(JULIA_BUILD_MODE),release) -JULIA_SYSIMG=$(build_private_libdir)/sys$(JULIA_LIBSUFFIX).$(SHLIB_EXT) +JULIA_SYSIMG=$(build_private_libdir)/sys$(JULIA_LIBSUFFIX)$(CPUID_TAG).$(SHLIB_EXT) else -JULIA_SYSIMG=$(build_private_libdir)/sys-$(JULIA_BUILD_MODE)$(JULIA_LIBSUFFIX).$(SHLIB_EXT) +JULIA_SYSIMG=$(build_private_libdir)/sys-$(JULIA_BUILD_MODE)$(JULIA_LIBSUFFIX)$(CPUID_TAG).$(SHLIB_EXT) endif testall: check-whitespace $(JULIA_BUILD_MODE) cp $(JULIA_SYSIMG) $(BUILDROOT)/local.$(SHLIB_EXT) && $(JULIA_EXECUTABLE) -J $(call cygpath_w,$(BUILDROOT)/local.$(SHLIB_EXT)) -e 'true' && rm $(BUILDROOT)/local.$(SHLIB_EXT) diff --git a/src/ccall.cpp b/src/ccall.cpp index 01f622623db34..4c00356b10eb4 100644 --- a/src/ccall.cpp +++ b/src/ccall.cpp @@ -1495,7 +1495,7 @@ static jl_cgval_t emit_ccall(jl_codectx_t &ctx, jl_value_t **args, size_t nargs) } else { Value *notany = ctx.builder.CreateICmpNE( - boxed(ctx, runtime_sp, false), + boxed(ctx, runtime_sp), maybe_decay_untracked(literal_pointer_val(ctx, (jl_value_t*)jl_any_type))); error_unless(ctx, notany, "ccall: return type Ref{Any} is invalid. use Ptr{Any} instead."); always_error = false; diff --git a/src/cgutils.cpp b/src/cgutils.cpp index ff02a8b42cdb6..6d350e9ab94a9 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -683,8 +683,7 @@ static Value *emit_typeptr_addr(jl_codectx_t &ctx, Value *p) return emit_nthptr_addr(ctx, p, -offset); } -static Value *boxed(jl_codectx_t &ctx, const jl_cgval_t &v, bool gcooted=true); -static Value *boxed(jl_codectx_t &ctx, const jl_cgval_t &v, jl_value_t* type) = delete; // C++11 (temporary to prevent rebase error) +static Value *boxed(jl_codectx_t &ctx, const jl_cgval_t &v); static Value* mask_gc_bits(jl_codectx_t &ctx, Value *tag) { @@ -713,7 +712,7 @@ static jl_cgval_t emit_typeof(jl_codectx_t &ctx, const jl_cgval_t &p) if (p.constant) return mark_julia_const(jl_typeof(p.constant)); if (p.isboxed && !jl_is_leaf_type(p.typ)) { - return mark_julia_type(ctx, emit_typeof(ctx, p.V), true, jl_datatype_type, /*needsroot*/false); + return mark_julia_type(ctx, emit_typeof(ctx, p.V), true, jl_datatype_type); } if (p.TIndex) { Value *tindex = ctx.builder.CreateAnd(p.TIndex, ConstantInt::get(T_int8, 0x7f)); @@ -746,7 +745,7 @@ static jl_cgval_t emit_typeof(jl_codectx_t &ctx, const jl_cgval_t &p) if (!allunboxed) datatype = mask_gc_bits(ctx, datatype); datatype = maybe_decay_untracked(datatype); - return mark_julia_type(ctx, datatype, true, jl_datatype_type, /*needsroot*/false); + return mark_julia_type(ctx, datatype, true, jl_datatype_type); } jl_value_t *aty = p.typ; if (jl_is_type_type(aty)) { @@ -986,7 +985,7 @@ static void emit_type_error(jl_codectx_t &ctx, const jl_cgval_t &x, Value *type, Value *msg_val = stringConstPtr(ctx.builder, msg); ctx.builder.CreateCall(prepare_call(jltypeerror_func), { fname_val, msg_val, - maybe_decay_untracked(type), mark_callee_rooted(boxed(ctx, x, false))}); + maybe_decay_untracked(type), mark_callee_rooted(boxed(ctx, x))}); } static std::pair emit_isa(jl_codectx_t &ctx, const jl_cgval_t &x, jl_value_t *type, const std::string *msg) @@ -1080,7 +1079,7 @@ static void emit_typecheck(jl_codectx_t &ctx, const jl_cgval_t &x, jl_value_t *t static void emit_leafcheck(jl_codectx_t &ctx, Value *typ, const std::string &msg) { assert(typ->getType() == T_prjlvalue); - emit_typecheck(ctx, mark_julia_type(ctx, typ, true, jl_any_type, false), (jl_value_t*)jl_datatype_type, msg); + emit_typecheck(ctx, mark_julia_type(ctx, typ, true, jl_any_type), (jl_value_t*)jl_datatype_type, msg); Value *isleaf; isleaf = ctx.builder.CreateConstInBoundsGEP1_32(T_int8, emit_bitcast(ctx, decay_derived(typ), T_pint8), offsetof(jl_datatype_t, isleaftype)); isleaf = ctx.builder.CreateLoad(isleaf, tbaa_const); @@ -1205,7 +1204,7 @@ static void typed_store(jl_codectx_t &ctx, Value *ptr, Value *idx_0based, const jl_cgval_t &rhs, jl_value_t *jltype, MDNode *tbaa, Value *parent, // for the write barrier, NULL if no barrier needed - unsigned alignment = 0, bool root_box = true) // if the value to store needs a box, should we root it ? + unsigned alignment = 0) { bool isboxed; Type *elty = julia_type_to_llvm(jltype, &isboxed); @@ -1216,7 +1215,7 @@ static void typed_store(jl_codectx_t &ctx, r = emit_unbox(ctx, elty, rhs, jltype); } else { - r = maybe_decay_untracked(boxed(ctx, rhs, root_box)); + r = maybe_decay_untracked(boxed(ctx, rhs)); if (parent != NULL) emit_write_barrier(ctx, parent, r); } @@ -1287,7 +1286,7 @@ static bool emit_getfield_unknownidx(jl_codectx_t &ctx, maybe_null, minimum_field_size)); if (maybe_null) null_pointer_check(ctx, fld); - *ret = mark_julia_type(ctx, fld, true, jl_any_type, strct.gcroot || !strct.isimmutable); + *ret = mark_julia_type(ctx, fld, true, jl_any_type); return true; } else if (is_tupletype_homogeneous(stt->types)) { @@ -1389,7 +1388,7 @@ static jl_cgval_t emit_getfield_knownidx(jl_codectx_t &ctx, const jl_cgval_t &st Value *fldv = tbaa_decorate(strct.tbaa, Load); if (maybe_null) null_pointer_check(ctx, fldv); - return mark_julia_type(ctx, fldv, true, jfty, strct.gcroot || !strct.isimmutable); + return mark_julia_type(ctx, fldv, true, jfty); } else if (jl_is_uniontype(jfty)) { int fsz = jl_field_size(jt, idx); @@ -1982,7 +1981,7 @@ static Value *box_union(jl_codectx_t &ctx, const jl_cgval_t &vinfo, const SmallB // this is used to wrap values for generic contexts, where a // dynamically-typed value is required (e.g. argument to unknown function). // if it's already a pointer it's left alone. -static Value *boxed(jl_codectx_t &ctx, const jl_cgval_t &vinfo, bool gcrooted) +static Value *boxed(jl_codectx_t &ctx, const jl_cgval_t &vinfo) { jl_value_t *jt = vinfo.typ; if (jt == jl_bottom_type || jt == NULL) @@ -2016,12 +2015,6 @@ static Value *boxed(jl_codectx_t &ctx, const jl_cgval_t &vinfo, bool gcrooted) box = maybe_decay_untracked(box); } } - if (gcrooted) { - // make a gcroot for the new box - // (unless the caller explicitly said this was unnecessary) - Value *froot = emit_local_root(ctx); - ctx.builder.CreateStore(box, froot); - } return box; } @@ -2103,7 +2096,7 @@ static void emit_unionmove(jl_codectx_t &ctx, Value *dest, const jl_cgval_t &src static void emit_cpointercheck(jl_codectx_t &ctx, const jl_cgval_t &x, const std::string &msg) { Value *t = emit_typeof_boxed(ctx, x); - emit_typecheck(ctx, mark_julia_type(ctx, t, true, jl_any_type, false), (jl_value_t*)jl_datatype_type, msg); + emit_typecheck(ctx, mark_julia_type(ctx, t, true, jl_any_type), (jl_value_t*)jl_datatype_type, msg); Value *istype = ctx.builder.CreateICmpEQ(mark_callee_rooted(emit_datatype_name(ctx, t)), @@ -2185,7 +2178,7 @@ static void emit_setfield(jl_codectx_t &ctx, ConstantInt::get(T_size, jl_field_offset(sty, idx0))); jl_value_t *jfty = jl_svecref(sty->types, idx0); if (jl_field_isptr(sty, idx0)) { - Value *r = maybe_decay_untracked(boxed(ctx, rhs, false)); // don't need a temporary gcroot since it'll be rooted by strct + Value *r = maybe_decay_untracked(boxed(ctx, rhs)); // don't need a temporary gcroot since it'll be rooted by strct tbaa_decorate(strct.tbaa, ctx.builder.CreateStore(r, emit_bitcast(ctx, addr, T_pprjlvalue))); if (wb && strct.isboxed) diff --git a/src/codegen.cpp b/src/codegen.cpp index 9e3178ce4383a..c4fac43bd68ab 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -657,7 +657,7 @@ static inline jl_cgval_t mark_julia_slot(Value *v, jl_value_t *typ, Value *tinde return tagval; } -static inline jl_cgval_t mark_julia_type(jl_codectx_t &ctx, Value *v, bool isboxed, jl_value_t *typ, bool needsroot = true) +static inline jl_cgval_t mark_julia_type(jl_codectx_t &ctx, Value *v, bool isboxed, jl_value_t *typ) { if (jl_is_datatype(typ) && jl_is_datatype_singleton((jl_datatype_t*)typ)) { // no need to explicitly load/store a constant/ghost value @@ -687,17 +687,12 @@ static inline jl_cgval_t mark_julia_type(jl_codectx_t &ctx, Value *v, bool isbox } return mark_julia_slot(loc, typ, NULL, tbaa_stack); } - Value *froot = NULL; - if (needsroot && isboxed) { - froot = emit_local_root(ctx); - ctx.builder.CreateStore(v, froot); - } - return jl_cgval_t(v, froot, isboxed, typ, NULL); + return jl_cgval_t(v, NULL, isboxed, typ, NULL); } -static inline jl_cgval_t mark_julia_type(jl_codectx_t &ctx, Value *v, bool isboxed, jl_datatype_t *typ, bool needsroot = true) +static inline jl_cgval_t mark_julia_type(jl_codectx_t &ctx, Value *v, bool isboxed, jl_datatype_t *typ) { - return mark_julia_type(ctx, v, isboxed, (jl_value_t*)typ, needsroot); + return mark_julia_type(ctx, v, isboxed, (jl_value_t*)typ); } // see if it might be profitable (and cheap) to change the type of v to typ @@ -1019,13 +1014,7 @@ static jl_cgval_t convert_julia_type(jl_codectx_t &ctx, const jl_cgval_t &v, jl_ } if (makeboxed) { // convert to a simple isboxed value - Value *boxv = boxed(ctx, v, false); - Value *froot = NULL; - if (needsroot) { - froot = emit_local_root(ctx); - ctx.builder.CreateStore(maybe_decay_untracked(boxv), froot); - } - return jl_cgval_t(boxv, froot, true, typ, NULL); + return jl_cgval_t(boxed(ctx, v), NULL, true, typ, NULL); } } return jl_cgval_t(v, typ, new_tindex); @@ -2069,8 +2058,7 @@ static jl_cgval_t emit_getfield(jl_codectx_t &ctx, const jl_cgval_t &strct, jl_s mark_julia_const((jl_value_t*)name) }; Value *result = emit_jlcall(ctx, jlgetfield_func, maybe_decay_untracked(V_null), myargs_array, 2); - bool needsgcroot = true; // !arg1.isimmutable || !jl_is_leaf_type(arg1.typ) || !is_datatype_all_pointers((jl_datatype_t*)arg1.typ); // TODO: probably want this as a llvm pass - return mark_julia_type(ctx, result, true, jl_any_type, needsgcroot); + return mark_julia_type(ctx, result, true, jl_any_type); } static Value *emit_bits_compare(jl_codectx_t &ctx, const jl_cgval_t &arg1, const jl_cgval_t &arg2) @@ -2165,8 +2153,8 @@ static Value *emit_f_is(jl_codectx_t &ctx, const jl_cgval_t &arg1, const jl_cgva // which is already enough to ensure pointer uniqueness for this test // even if the other pointer managed to get garbage collected return ctx.builder.CreateICmpEQ( - mark_callee_rooted(boxed(ctx, arg1, false)), - mark_callee_rooted(boxed(ctx, arg2, false))); + mark_callee_rooted(boxed(ctx, arg1)), + mark_callee_rooted(boxed(ctx, arg2))); } if (jl_type_intersection(rt1, rt2) == (jl_value_t*)jl_bottom_type) // types are disjoint (exhaustive test) @@ -2218,7 +2206,7 @@ static Value *emit_f_is(jl_codectx_t &ctx, const jl_cgval_t &arg1, const jl_cgva JL_FEAT_REQUIRE(ctx, runtime); Value *varg1 = mark_callee_rooted(boxed(ctx, arg1)); - Value *varg2 = mark_callee_rooted(boxed(ctx, arg2, false)); // potentially unrooted! + Value *varg2 = mark_callee_rooted(boxed(ctx, arg2)); return ctx.builder.CreateTrunc(ctx.builder.CreateCall(prepare_call(jlegal_func), {varg1, varg2}), T_int1); } @@ -2322,7 +2310,7 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, } else if (f == jl_builtin_throw && nargs == 1) { - Value *arg1 = boxed(ctx, argv[1], false); // rooted by throw + Value *arg1 = boxed(ctx, argv[1]); raise_exception(ctx, arg1); *ret = jl_cgval_t(); return true; @@ -2520,8 +2508,7 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, emit_arrayptr(ctx, ary, ary_ex, isboxed), idx, val, ety, !isboxed ? tbaa_arraybuf : tbaa_ptrarraybuf, - data_owner, 0, - false); // don't need to root the box if we had to make one since it's being stored in the array immediatly + data_owner, 0); } *ret = ary; return true; @@ -2553,7 +2540,7 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, idx = emit_bounds_check(ctx, va_ary, NULL, idx, valen, boundscheck); idx = ctx.builder.CreateAdd(idx, ConstantInt::get(T_size, ctx.nReqArgs)); Value *v = tbaa_decorate(tbaa_value, ctx.builder.CreateLoad(ctx.builder.CreateGEP(ctx.argArray, idx))); - *ret = mark_julia_type(ctx, v, /*boxed*/ true, jl_any_type, /*needsgcroot*/ false); + *ret = mark_julia_type(ctx, v, /*boxed*/ true, jl_any_type); return true; } } @@ -2812,7 +2799,7 @@ static Value *emit_jlcall(jl_codectx_t &ctx, Value *theFptr, Value *theF, if (theF) theArgs.push_back(theF); for (size_t i = 0; i < nargs; i++) { - Value *arg = maybe_decay_untracked(boxed(ctx, argv[i], false)); + Value *arg = maybe_decay_untracked(boxed(ctx, argv[i])); theArgs.push_back(arg); } SmallVector argsT; @@ -2975,7 +2962,7 @@ static jl_cgval_t emit_invoke(jl_codectx_t &ctx, jl_expr_t *ex) emit_jlcall( ctx, prepare_call(jlinvoke_func), - boxed(ctx, lival, false), + boxed(ctx, lival), argv, nargs), true, rt); @@ -3136,7 +3123,7 @@ static jl_cgval_t emit_sparam(jl_codectx_t &ctx, size_t i) maybe_decay_untracked(literal_pointer_val(ctx, (jl_value_t*)jl_tvar_type))); jl_sym_t *name = (jl_sym_t*)jl_svecref(ctx.linfo->def.method->sparam_syms, i); undef_var_error_ifnot(ctx, isnull, name); - return mark_julia_type(ctx, sp, true, jl_any_type, false); + return mark_julia_type(ctx, sp, true, jl_any_type); } static jl_cgval_t emit_global(jl_codectx_t &ctx, jl_sym_t *sym) @@ -3304,8 +3291,7 @@ static jl_cgval_t emit_local(jl_codectx_t &ctx, jl_value_t *slotload) v = update_julia_type(ctx, v, typ); } else { - v = mark_julia_type(ctx, boxed, true, typ, - /*gc-root*/!vi.isArgument); // if an argument, doesn't need an additional root + v = mark_julia_type(ctx, boxed, true, typ); if (vi.usedUndef) isnull = box_isnull; } @@ -3446,7 +3432,7 @@ static void emit_assignment(jl_codectx_t &ctx, jl_value_t *l, jl_value_t *r) if (bp != NULL) { // it's a global JL_FEAT_REQUIRE(ctx, runtime); assert(bnd); - Value *rval = mark_callee_rooted(boxed(ctx, emit_expr(ctx, r), false)); // no root needed since this is about to be assigned to a global + Value *rval = mark_callee_rooted(boxed(ctx, emit_expr(ctx, r))); ctx.builder.CreateCall(prepare_call(jlcheckassign_func), { literal_pointer_val(ctx, bnd), rval }); @@ -3520,7 +3506,7 @@ static void emit_assignment(jl_codectx_t &ctx, jl_value_t *l, jl_value_t *r) } else { assert(!vi.pTIndex || rval_info.isboxed || rval_info.constant); - rval = maybe_decay_untracked(boxed(ctx, rval_info, false)); + rval = maybe_decay_untracked(boxed(ctx, rval_info)); } ctx.builder.CreateStore(maybe_decay_untracked(rval), vi.boxroot, vi.isVolatile); } @@ -3995,7 +3981,7 @@ static void emit_cfunc_invalidate( } assert(AI == gf_thunk->arg_end()); Value *gf_ret = emit_jlcall(ctx, jlapplygeneric_func, NULL, myargs, nargs); - jl_cgval_t gf_retbox = mark_julia_type(ctx, gf_ret, true, jl_any_type, /*needsroot*/false); + jl_cgval_t gf_retbox = mark_julia_type(ctx, gf_ret, true, jl_any_type); jl_value_t *astrt = lam->rettype; if (cc != jl_returninfo_t::Boxed) { emit_typecheck(ctx, gf_retbox, astrt, "cfunction"); @@ -4362,7 +4348,7 @@ static Function *gen_cfun_wrapper(jl_function_t *ff, jl_value_t *jlrettype, jl_t if (toboxed) { assert(!sig.sret); // return a jl_value_t* - r = boxed(ctx, retval, false); // no gcroot since this is on the return path + r = boxed(ctx, retval); } else if (sig.sret && jlfunc_sret) { // nothing to do @@ -4574,10 +4560,10 @@ static Function *gen_jlcall_wrapper(jl_method_instance_t *lam, const jl_returnin jl_cgval_t retval; switch (f.cc) { case jl_returninfo_t::Boxed: - retval = mark_julia_type(ctx, call, true, jlretty, /*needsroot*/false); + retval = mark_julia_type(ctx, call, true, jlretty); break; case jl_returninfo_t::Register: - retval = mark_julia_type(ctx, call, false, jlretty, /*needsroot*/false); + retval = mark_julia_type(ctx, call, false, jlretty); break; case jl_returninfo_t::SRet: retval = mark_julia_slot(result, jlretty, NULL, tbaa_stack); @@ -4596,7 +4582,7 @@ static Function *gen_jlcall_wrapper(jl_method_instance_t *lam, const jl_returnin retval = mark_julia_slot(NULL, jlretty, call, tbaa_stack); break; } - ctx.builder.CreateRet(boxed(ctx, retval, false)); // no gcroot needed since this on the return path + ctx.builder.CreateRet(boxed(ctx, retval)); assert(!ctx.roots); return w; } @@ -5219,17 +5205,17 @@ static std::unique_ptr emit_function( Argument *Arg = &*AI++; if (isboxed) maybe_mark_argument_dereferenceable(Arg, argType); - theArg = mark_julia_type(ctx, Arg, isboxed, argType, /*needsgcroot*/false); + theArg = mark_julia_type(ctx, Arg, isboxed, argType); } } else { if (i == 0) { // first (function) arg is separate in jlcall - theArg = mark_julia_type(ctx, fArg, true, vi.value.typ, /*needsgcroot*/false); + theArg = mark_julia_type(ctx, fArg, true, vi.value.typ); } else { Value *argPtr = ctx.builder.CreateGEP(argArray, ConstantInt::get(T_size, i-1)); - theArg = mark_julia_type(ctx, ctx.builder.CreateLoad(argPtr), true, vi.value.typ, /*needsgcroot*/false); + theArg = mark_julia_type(ctx, ctx.builder.CreateLoad(argPtr), true, vi.value.typ); if (ctx.debug_enabled && vi.dinfo && !vi.boxroot && !vi.value.V) { SmallVector addr; addr.push_back(llvm::dwarf::DW_OP_deref); @@ -5267,7 +5253,7 @@ static std::unique_ptr emit_function( } } else { - Value *argp = boxed(ctx, theArg, false); // skip the temporary gcroot since it would be folded to argp anyways + Value *argp = boxed(ctx, theArg); // skip the temporary gcroot since it would be folded to argp anyways ctx.builder.CreateStore(argp, vi.boxroot); if (!theArg.isboxed) emit_local_root(ctx, &vi); // create a root for vi @@ -5563,7 +5549,7 @@ static std::unique_ptr emit_function( Type *retty = f->getReturnType(); switch (returninfo.cc) { case jl_returninfo_t::Boxed: - retval = boxed(ctx, retvalinfo, false); // skip the gcroot on the return path + retval = boxed(ctx, retvalinfo); // skip the gcroot on the return path break; case jl_returninfo_t::Register: if (type_is_ghost(retty)) @@ -5607,7 +5593,7 @@ static std::unique_ptr emit_function( //assert(retvalinfo.isboxed); tindex = compute_tindex_unboxed(ctx, retvalinfo, jlrettype); tindex = ctx.builder.CreateOr(tindex, ConstantInt::get(T_int8, 0x80)); - data = maybe_decay_untracked(boxed(ctx, retvalinfo, false)); // skip the gcroot on the return path + data = maybe_decay_untracked(boxed(ctx, retvalinfo)); sret = NULL; } retval = UndefValue::get(retty); diff --git a/src/intrinsics.cpp b/src/intrinsics.cpp index 0d5e5264685ff..98dcb81ba6738 100644 --- a/src/intrinsics.cpp +++ b/src/intrinsics.cpp @@ -664,7 +664,7 @@ static jl_cgval_t emit_pointerset(jl_codectx_t &ctx, jl_cgval_t *argv) if (ety == (jl_value_t*)jl_any_type) { // unsafe_store to Ptr{Any} is allowed to implicitly drop GC roots. Instruction *store = ctx.builder.CreateAlignedStore( - emit_pointer_from_objref(ctx, boxed(ctx, x, false)), + emit_pointer_from_objref(ctx, boxed(ctx, x)), ctx.builder.CreateGEP(thePtr, im1), align_nb); tbaa_decorate(tbaa_data, store); } else {