From 3653b3898647d4c2528afde1f54bd3e65e3aa8ee Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Tue, 10 Sep 2024 12:51:55 -0400 Subject: [PATCH] drop typed GEP calls (#55708) Now that we use LLVM 18, and almost have LLVM 19 support, do cleanup to remove LLVM 15/16 type pointer support. LLVM now slightly prefers that we rewrite our complex GEP to use a simple emit_ptrgep call instead, which is also much simpler for julia to emit also. --- src/ccall.cpp | 11 +- src/cgutils.cpp | 126 ++++++-------------- src/codegen.cpp | 123 ++++++++----------- src/intrinsics.cpp | 4 +- src/llvm-alloc-opt.cpp | 21 +--- src/llvm-codegen-shared.h | 45 +++---- src/llvm-late-gc-lowering.cpp | 72 +---------- src/llvm-ptls.cpp | 4 +- test/llvmpasses/alloc-opt-gcframe.ll | 2 +- test/llvmpasses/late-lower-gc-addrspaces.ll | 56 ++++----- test/llvmpasses/late-lower-gc.ll | 70 +++++------ test/llvmpasses/names.jl | 3 +- 12 files changed, 187 insertions(+), 350 deletions(-) diff --git a/src/ccall.cpp b/src/ccall.cpp index 7ab8cfa974d6f..eac130ea43189 100644 --- a/src/ccall.cpp +++ b/src/ccall.cpp @@ -1854,8 +1854,8 @@ static jl_cgval_t emit_ccall(jl_codectx_t &ctx, jl_value_t **args, size_t nargs) ctx.builder.SetInsertPoint(checkBB); auto signal_page_load = ctx.builder.CreateLoad( ctx.types().T_size, - ctx.builder.CreateConstInBoundsGEP1_32(ctx.types().T_size, - get_current_signal_page_from_ptls(ctx.builder, ctx.types().T_size, get_current_ptls(ctx), ctx.tbaa().tbaa_const), -1), + emit_ptrgep(ctx, get_current_signal_page_from_ptls(ctx.builder, get_current_ptls(ctx), ctx.tbaa().tbaa_const), + -sizeof(size_t)), true); setName(ctx.emission_context, signal_page_load, "signal_page_load"); ctx.builder.CreateBr(contBB); @@ -1870,8 +1870,7 @@ static jl_cgval_t emit_ccall(jl_codectx_t &ctx, jl_value_t **args, size_t nargs) auto obj = emit_pointer_from_objref(ctx, boxed(ctx, argv[0])); // T_pprjlvalue // The inbounds gep makes it more clear to LLVM that the resulting value is not // a null pointer. - auto strp = ctx.builder.CreateConstInBoundsGEP1_32(ctx.types().T_prjlvalue, obj, 1); - setName(ctx.emission_context, strp, "string_ptr"); + auto strp = emit_ptrgep(ctx, obj, ctx.types().sizeof_ptr, "string_ptr"); JL_GC_POP(); return mark_or_box_ccall_result(ctx, strp, retboxed, rt, unionall, static_rt); } @@ -1882,9 +1881,7 @@ static jl_cgval_t emit_ccall(jl_codectx_t &ctx, jl_value_t **args, size_t nargs) auto obj = emit_pointer_from_objref(ctx, boxed(ctx, argv[0])); // T_pprjlvalue // The inbounds gep makes it more clear to LLVM that the resulting value is not // a null pointer. - auto strp = ctx.builder.CreateConstInBoundsGEP1_32( - ctx.types().T_prjlvalue, obj, (sizeof(jl_sym_t) + sizeof(void*) - 1) / sizeof(void*)); - setName(ctx.emission_context, strp, "symbol_name"); + auto strp = emit_ptrgep(ctx, obj, sizeof(jl_sym_t), "symbol_name"); JL_GC_POP(); return mark_or_box_ccall_result(ctx, strp, retboxed, rt, unionall, static_rt); } diff --git a/src/cgutils.cpp b/src/cgutils.cpp index bec84d9901279..2a234f399f5c1 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -130,14 +130,8 @@ static Value *stringConstPtr( } // Doesn't need to be aligned, we shouldn't operate on these like julia objects GlobalVariable *gv = get_pointer_to_constant(emission_context, Data, Align(1), "_j_str_" + StringRef(ctxt.data(), ctxt.size()), *M); - Value *zero = ConstantInt::get(Type::getInt32Ty(irbuilder.getContext()), 0); - Value *Args[] = { zero, zero }; - auto gep = irbuilder.CreateInBoundsGEP(gv->getValueType(), - // AddrSpaceCast in case globals are in non-0 AS - irbuilder.CreateAddrSpaceCast(gv, gv->getValueType()->getPointerTo(0)), - Args); - setName(emission_context, gep, "string_const_ptr"); - return gep; + // AddrSpaceCast in case globals are in non-0 AS + return irbuilder.CreateAddrSpaceCast(gv, gv->getValueType()->getPointerTo(0)); } @@ -621,12 +615,6 @@ static unsigned convert_struct_offset(jl_codectx_t &ctx, Type *lty, unsigned byt return convert_struct_offset(ctx.builder.GetInsertBlock()->getModule()->getDataLayout(), lty, byte_offset); } -static Value *emit_struct_gep(jl_codectx_t &ctx, Type *lty, Value *base, unsigned byte_offset) -{ - unsigned idx = convert_struct_offset(ctx, lty, byte_offset); - return ctx.builder.CreateConstInBoundsGEP2_32(lty, base, 0, idx); -} - static Type *_julia_struct_to_llvm(jl_codegen_params_t *ctx, LLVMContext &ctxt, jl_value_t *jt, bool *isboxed, bool llvmcall=false); static Type *_julia_type_to_llvm(jl_codegen_params_t *ctx, LLVMContext &ctxt, jl_value_t *jt, bool *isboxed) @@ -1200,10 +1188,10 @@ static Value *emit_typeof(jl_codectx_t &ctx, const jl_cgval_t &p, bool maybenull static Value *emit_datatype_types(jl_codectx_t &ctx, Value *dt) { Value *Ptr = decay_derived(ctx, dt); - Value *Idx = ConstantInt::get(ctx.types().T_size, offsetof(jl_datatype_t, types) / sizeof(void*)); + unsigned Idx = offsetof(jl_datatype_t, types); jl_aliasinfo_t ai = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_const); auto types = ai.decorateInst(ctx.builder.CreateAlignedLoad( - ctx.types().T_pjlvalue, ctx.builder.CreateInBoundsGEP(ctx.types().T_pjlvalue, Ptr, Idx), Align(sizeof(void*)))); + ctx.types().T_pjlvalue, emit_ptrgep(ctx, Ptr, Idx), Align(sizeof(void*)))); setName(ctx.emission_context, types, "datatype_types"); return types; } @@ -1222,16 +1210,13 @@ static Value *emit_datatype_size(jl_codectx_t &ctx, Value *dt, bool add_isunion= { jl_aliasinfo_t ai = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_const); Value *Ptr = decay_derived(ctx, dt); - Value *Idx = ConstantInt::get(ctx.types().T_size, offsetof(jl_datatype_t, layout) / sizeof(int32_t*)); - Ptr = ctx.builder.CreateInBoundsGEP(getPointerTy(ctx.builder.getContext()), Ptr, Idx); + Ptr = emit_ptrgep(ctx, Ptr, offsetof(jl_datatype_t, layout)); Ptr = ai.decorateInst(ctx.builder.CreateAlignedLoad(getPointerTy(ctx.builder.getContext()), Ptr, Align(sizeof(int32_t*)))); - Idx = ConstantInt::get(ctx.types().T_size, offsetof(jl_datatype_layout_t, size) / sizeof(int32_t)); - Value *SizePtr = ctx.builder.CreateInBoundsGEP(getInt32Ty(ctx.builder.getContext()), Ptr, Idx); + Value *SizePtr = emit_ptrgep(ctx, Ptr, offsetof(jl_datatype_layout_t, size)); Value *Size = ai.decorateInst(ctx.builder.CreateAlignedLoad(getInt32Ty(ctx.builder.getContext()), SizePtr, Align(sizeof(int32_t)))); setName(ctx.emission_context, Size, "datatype_size"); if (add_isunion) { - Idx = ConstantInt::get(ctx.types().T_size, offsetof(jl_datatype_layout_t, flags) / sizeof(int8_t)); - Value *FlagPtr = ctx.builder.CreateInBoundsGEP(getInt8Ty(ctx.builder.getContext()), Ptr, Idx); + Value *FlagPtr = emit_ptrgep(ctx, Ptr, offsetof(jl_datatype_layout_t, flags)); Value *Flag = ai.decorateInst(ctx.builder.CreateAlignedLoad(getInt16Ty(ctx.builder.getContext()), FlagPtr, Align(sizeof(int16_t)))); Flag = ctx.builder.CreateLShr(Flag, 4); Flag = ctx.builder.CreateAnd(Flag, ConstantInt::get(Flag->getType(), 1)); @@ -1308,7 +1293,7 @@ static Value *emit_datatype_mutabl(jl_codectx_t &ctx, Value *dt) static Value *emit_datatype_isprimitivetype(jl_codectx_t &ctx, Value *typ) { Value *isprimitive; - isprimitive = ctx.builder.CreateConstInBoundsGEP1_32(getInt8Ty(ctx.builder.getContext()), decay_derived(ctx, typ), offsetof(jl_datatype_t, hash) + sizeof(((jl_datatype_t*)nullptr)->hash)); + isprimitive = emit_ptrgep(ctx, decay_derived(ctx, typ), offsetof(jl_datatype_t, hash) + sizeof(((jl_datatype_t*)nullptr)->hash)); jl_aliasinfo_t ai = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_const); isprimitive = ai.decorateInst(ctx.builder.CreateAlignedLoad(getInt8Ty(ctx.builder.getContext()), isprimitive, Align(1))); isprimitive = ctx.builder.CreateLShr(isprimitive, 7); @@ -1320,10 +1305,7 @@ static Value *emit_datatype_isprimitivetype(jl_codectx_t &ctx, Value *typ) static Value *emit_datatype_name(jl_codectx_t &ctx, Value *dt) { unsigned n = offsetof(jl_datatype_t, name) / sizeof(char*); - Value *vptr = ctx.builder.CreateInBoundsGEP( - ctx.types().T_pjlvalue, - maybe_decay_tracked(ctx, dt), - ConstantInt::get(ctx.types().T_size, n)); + Value *vptr = emit_ptrgep(ctx, maybe_decay_tracked(ctx, dt), n * sizeof(jl_value_t*)); jl_aliasinfo_t ai = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_const); auto name = ai.decorateInst(ctx.builder.CreateAlignedLoad(ctx.types().T_pjlvalue, vptr, Align(sizeof(void*)))); setName(ctx.emission_context, name, "datatype_name"); @@ -1522,7 +1504,7 @@ static Value *emit_typeof(jl_codectx_t &ctx, Value *v, bool maybenull, bool just // we lied a bit: this wasn't really an object (though it was valid for GC rooting) // and we need to use it as an index to get the real object now Module *M = jl_Module; - Value *smallp = ctx.builder.CreateInBoundsGEP(getInt8Ty(ctx.builder.getContext()), prepare_global_in(M, jl_small_typeof_var), tag); + Value *smallp = emit_ptrgep(ctx, prepare_global_in(M, jl_small_typeof_var), tag); jl_aliasinfo_t ai = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_const); auto small = ctx.builder.CreateAlignedLoad(typetag->getType(), smallp, M->getDataLayout().getPointerABIAlignment(0)); small->setMetadata(LLVMContext::MD_nonnull, MDNode::get(M->getContext(), None)); @@ -1802,7 +1784,7 @@ static void emit_typecheck(jl_codectx_t &ctx, const jl_cgval_t &x, jl_value_t *t static Value *emit_isconcrete(jl_codectx_t &ctx, Value *typ) { Value *isconcrete; - isconcrete = ctx.builder.CreateConstInBoundsGEP1_32(getInt8Ty(ctx.builder.getContext()), decay_derived(ctx, typ), offsetof(jl_datatype_t, hash) + sizeof(((jl_datatype_t*)nullptr)->hash)); + isconcrete = emit_ptrgep(ctx, decay_derived(ctx, typ), offsetof(jl_datatype_t, hash) + sizeof(((jl_datatype_t*)nullptr)->hash)); jl_aliasinfo_t ai = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_const); isconcrete = ai.decorateInst(ctx.builder.CreateAlignedLoad(getInt8Ty(ctx.builder.getContext()), isconcrete, Align(1))); isconcrete = ctx.builder.CreateLShr(isconcrete, 1); @@ -2848,36 +2830,14 @@ static jl_cgval_t emit_getfield_knownidx(jl_codectx_t &ctx, const jl_cgval_t &st if (strct.ispointer()) { auto tbaa = best_field_tbaa(ctx, strct, jt, idx, byte_offset); Value *staddr = data_pointer(ctx, strct); - bool isboxed; - Type *lt = julia_type_to_llvm(ctx, (jl_value_t*)jt, &isboxed); Value *addr; - if (isboxed) { - // byte_offset == 0 is an important special case here, e.g. - // for single field wrapper types. Introducing the bitcast - // can pessimize mem2reg - if (byte_offset > 0) { - addr = ctx.builder.CreateInBoundsGEP( - getInt8Ty(ctx.builder.getContext()), - staddr, - ConstantInt::get(ctx.types().T_size, byte_offset)); - } - else { - addr = staddr; - } - } - else { - if (jl_is_vecelement_type((jl_value_t*)jt)) - addr = staddr; // VecElement types are unwrapped in LLVM. - else if (isa(lt)) - addr = emit_struct_gep(ctx, lt, staddr, byte_offset); - else - addr = ctx.builder.CreateConstInBoundsGEP2_32(lt, staddr, 0, idx); - if (addr != staddr) { - setNameWithField(ctx.emission_context, addr, get_objname, jt, idx, Twine("_ptr")); - } - } - if (jl_field_isptr(jt, idx)) { + if (jl_is_vecelement_type((jl_value_t*)jt) || byte_offset == 0) + addr = staddr; // VecElement types are unwrapped in LLVM. + else + addr = emit_ptrgep(ctx, staddr, byte_offset); + if (addr != staddr) setNameWithField(ctx.emission_context, addr, get_objname, jt, idx, Twine("_ptr")); + if (jl_field_isptr(jt, idx)) { LoadInst *Load = ctx.builder.CreateAlignedLoad(ctx.types().T_prjlvalue, addr, Align(sizeof(void*))); setNameWithField(ctx.emission_context, Load, get_objname, jt, idx, Twine()); Load->setOrdering(order <= jl_memory_order_notatomic ? AtomicOrdering::Unordered : get_llvm_atomic_order(order)); @@ -2894,14 +2854,7 @@ static jl_cgval_t emit_getfield_knownidx(jl_codectx_t &ctx, const jl_cgval_t &st bool isptr = (union_max == 0); assert(!isptr && fsz < jl_field_size(jt, idx)); (void)isptr; size_t fsz1 = jl_field_size(jt, idx) - 1; - Value *ptindex; - if (isboxed) { - ptindex = ctx.builder.CreateConstInBoundsGEP1_32( - getInt8Ty(ctx.builder.getContext()), staddr, byte_offset + fsz1); - } - else { - ptindex = emit_struct_gep(ctx, cast(lt), staddr, byte_offset + fsz1); - } + Value *ptindex = emit_ptrgep(ctx, staddr, byte_offset + fsz1); auto val = emit_unionload(ctx, addr, ptindex, jfty, fsz, al, tbaa, !jl_field_isconst(jt, idx), union_max, strct.tbaa); if (val.V && val.V != addr) { setNameWithField(ctx.emission_context, val.V, get_objname, jt, idx, Twine()); @@ -2957,15 +2910,15 @@ static jl_cgval_t emit_getfield_knownidx(jl_codectx_t &ctx, const jl_cgval_t &st for (; i < fsz / align; i++) { unsigned fld = st_idx + i; Value *fldv = ctx.builder.CreateExtractValue(obj, ArrayRef(fld)); - Value *fldp = ctx.builder.CreateConstInBoundsGEP1_32(ET, lv, i); + Value *fldp = emit_ptrgep(ctx, lv, i * align); ctx.builder.CreateAlignedStore(fldv, fldp, Align(align)); } // emit remaining bytes up to tindex if (i < ptindex - st_idx) { - Value *staddr = ctx.builder.CreateConstInBoundsGEP1_32(ET, lv, i); + Value *staddr = emit_ptrgep(ctx, lv, i * align); for (; i < ptindex - st_idx; i++) { Value *fldv = ctx.builder.CreateExtractValue(obj, ArrayRef(st_idx + i)); - Value *fldp = ctx.builder.CreateConstInBoundsGEP1_32(getInt8Ty(ctx.builder.getContext()), staddr, i); + Value *fldp = emit_ptrgep(ctx, staddr, i); ctx.builder.CreateAlignedStore(fldv, fldp, Align(1)); } } @@ -3105,7 +3058,7 @@ static Value *emit_genericmemoryowner(jl_codectx_t &ctx, Value *t) LI->setMetadata(LLVMContext::MD_nonnull, MDNode::get(ctx.builder.getContext(), None)); jl_aliasinfo_t aliasinfo_mem = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_memoryown); aliasinfo_mem.decorateInst(LI); - addr = ctx.builder.CreateConstInBoundsGEP1_32(ctx.types().T_prjlvalue, m, JL_SMALL_BYTE_ALIGNMENT / sizeof(void*)); + addr = emit_ptrgep(ctx, m, JL_SMALL_BYTE_ALIGNMENT); Value *foreign = ctx.builder.CreateICmpNE(addr, decay_derived(ctx, LI)); return emit_guarded_test(ctx, foreign, t, [&] { addr = ctx.builder.CreateConstInBoundsGEP1_32(ctx.types().T_jlgenericmemory, m, 1); @@ -3867,19 +3820,14 @@ static jl_cgval_t emit_setfield(jl_codectx_t &ctx, auto tbaa = best_field_tbaa(ctx, strct, sty, idx0, byte_offset); Value *addr = data_pointer(ctx, strct); if (byte_offset > 0) { - addr = ctx.builder.CreateInBoundsGEP( - getInt8Ty(ctx.builder.getContext()), - addr, - ConstantInt::get(ctx.types().T_size, byte_offset)); + addr = emit_ptrgep(ctx, addr, byte_offset); setNameWithField(ctx.emission_context, addr, get_objname, sty, idx0, Twine("_ptr")); } jl_value_t *jfty = jl_field_type(sty, idx0); bool isboxed = jl_field_isptr(sty, idx0); if (!isboxed && jl_is_uniontype(jfty)) { size_t fsz1 = jl_field_size(sty, idx0) - 1; - Value *ptindex = ctx.builder.CreateInBoundsGEP(getInt8Ty(ctx.builder.getContext()), - addr, - ConstantInt::get(ctx.types().T_size, fsz1)); + Value *ptindex = emit_ptrgep(ctx, addr, fsz1); setNameWithField(ctx.emission_context, ptindex, get_objname, sty, idx0, Twine(".tindex_ptr")); return union_store(ctx, addr, ptindex, rhs, cmp, jfty, tbaa, ctx.tbaa().tbaa_unionselbyte, Order, FailOrder, @@ -3971,8 +3919,8 @@ static jl_cgval_t emit_new_struct(jl_codectx_t &ctx, jl_value_t *ty, size_t narg if (!init_as_value) { // avoid unboxing the argument explicitly // and use memcpy instead - Instruction *inst; - dest = inst = cast(ctx.builder.CreateConstInBoundsGEP2_32(lt, strct, 0, llvm_idx)); + Instruction *inst = cast(emit_ptrgep(ctx, strct, offs)); + dest = inst; // Our promotion point needs to come before // A) All of our arguments' promotion points // B) Any instructions we insert at any of our arguments' promotion points @@ -4025,16 +3973,16 @@ static jl_cgval_t emit_new_struct(jl_codectx_t &ctx, jl_value_t *ty, size_t narg // emit all of the align-sized words unsigned i = 0; for (; i < fsz1 / al; i++) { - Value *fldp = ctx.builder.CreateConstInBoundsGEP1_32(ET, lv, i); + Value *fldp = emit_ptrgep(ctx, lv, i * al); jl_aliasinfo_t ai = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_stack); Value *fldv = ai.decorateInst(ctx.builder.CreateAlignedLoad(ET, fldp, Align(al))); strct = ctx.builder.CreateInsertValue(strct, fldv, ArrayRef(llvm_idx + i)); } // emit remaining bytes up to tindex if (i < ptindex - llvm_idx) { - Value *staddr = ctx.builder.CreateConstInBoundsGEP1_32(ET, lv, i); + Value *staddr = emit_ptrgep(ctx, lv, i * al); for (; i < ptindex - llvm_idx; i++) { - Value *fldp = ctx.builder.CreateConstInBoundsGEP1_32(getInt8Ty(ctx.builder.getContext()), staddr, i); + Value *fldp = emit_ptrgep(ctx, staddr, i); jl_aliasinfo_t ai = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_stack); Value *fldv = ai.decorateInst(ctx.builder.CreateAlignedLoad(getInt8Ty(ctx.builder.getContext()), fldp, Align(1))); strct = ctx.builder.CreateInsertValue(strct, fldv, ArrayRef(llvm_idx + i)); @@ -4047,7 +3995,7 @@ static jl_cgval_t emit_new_struct(jl_codectx_t &ctx, jl_value_t *ty, size_t narg fval = ctx.builder.CreateInsertValue(strct, fval, ArrayRef(llvm_idx)); } else { - Value *ptindex = emit_struct_gep(ctx, lt, strct, offs + fsz1); + Value *ptindex = emit_ptrgep(ctx, strct, offs + fsz1); jl_aliasinfo_t ai = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_unionselbyte); ai.decorateInst(ctx.builder.CreateAlignedStore(tindex, ptindex, Align(1))); if (!rhs_union.isghost) @@ -4083,14 +4031,15 @@ static jl_cgval_t emit_new_struct(jl_codectx_t &ctx, jl_value_t *ty, size_t narg if (!jl_field_isptr(sty, i) && jl_is_uniontype(jl_field_type(sty, i))) { unsigned offs = jl_field_offset(sty, i); int fsz = jl_field_size(sty, i) - 1; - unsigned llvm_idx = convert_struct_offset(ctx, cast(lt), offs + fsz); - if (init_as_value) + if (init_as_value) { + unsigned llvm_idx = convert_struct_offset(ctx, cast(lt), offs + fsz); strct = ctx.builder.CreateInsertValue(strct, ConstantInt::get(getInt8Ty(ctx.builder.getContext()), 0), ArrayRef(llvm_idx)); + } else { jl_aliasinfo_t ai = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_unionselbyte); ai.decorateInst(ctx.builder.CreateAlignedStore( ConstantInt::get(getInt8Ty(ctx.builder.getContext()), 0), - ctx.builder.CreateConstInBoundsGEP2_32(lt, strct, 0, llvm_idx), + emit_ptrgep(ctx, strct, offs + fsz), Align(1))); } } @@ -4126,8 +4075,7 @@ static jl_cgval_t emit_new_struct(jl_codectx_t &ctx, jl_value_t *ty, size_t narg jl_aliasinfo_t ai = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_unionselbyte); ai.decorateInst(ctx.builder.CreateAlignedStore( ConstantInt::get(getInt8Ty(ctx.builder.getContext()), 0), - ctx.builder.CreateInBoundsGEP(getInt8Ty(ctx.builder.getContext()), strct, - ConstantInt::get(ctx.types().T_size, jl_field_offset(sty, i) + jl_field_size(sty, i) - 1)), + emit_ptrgep(ctx, strct, jl_field_offset(sty, i) + jl_field_size(sty, i) - 1), Align(1))); } } @@ -4169,9 +4117,7 @@ static Value *emit_defer_signal(jl_codectx_t &ctx) { ++EmittedDeferSignal; Value *ptls = get_current_ptls(ctx); - Constant *offset = ConstantInt::getSigned(getInt32Ty(ctx.builder.getContext()), - offsetof(jl_tls_states_t, defer_signal) / sizeof(sig_atomic_t)); - return ctx.builder.CreateInBoundsGEP(ctx.types().T_sigatomic, ptls, ArrayRef(offset), "jl_defer_signal"); + return emit_ptrgep(ctx, ptls, offsetof(jl_tls_states_t, defer_signal)); } #ifndef JL_NDEBUG diff --git a/src/codegen.cpp b/src/codegen.cpp index 9f80791f2882d..9184e4895ab6d 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2161,6 +2161,20 @@ static inline GlobalVariable *prepare_global_in(Module *M, GlobalVariable *G) return cast(local); } +static Value *emit_ptrgep(jl_codectx_t &ctx, Value *base, size_t byte_offset, const Twine &Name="") +{ + auto *gep = ctx.builder.CreateConstInBoundsGEP1_32(getInt8Ty(ctx.builder.getContext()), base, byte_offset); + setName(ctx.emission_context, gep, Name); + return gep; +} + +static Value *emit_ptrgep(jl_codectx_t &ctx, Value *base, Value *byte_offset, const Twine &Name="") +{ + auto *gep = ctx.builder.CreateInBoundsGEP(getInt8Ty(ctx.builder.getContext()), base, byte_offset, Name); + setName(ctx.emission_context, gep, Name); + return gep; +} + // --- convenience functions for tagging llvm values with julia types --- @@ -2211,7 +2225,7 @@ static void undef_derived_strct(jl_codectx_t &ctx, Value *ptr, jl_datatype_t *st size_t i, np = sty->layout->npointers; auto T_prjlvalue = JuliaType::get_prjlvalue_ty(ctx.builder.getContext()); for (i = 0; i < np; i++) { - Value *fld = ctx.builder.CreateConstInBoundsGEP1_32(T_prjlvalue, ptr, jl_ptr_offset(sty, i)); + Value *fld = emit_ptrgep(ctx, ptr, jl_ptr_offset(sty, i) * sizeof(jl_value_t*)); jl_aliasinfo_t ai = jl_aliasinfo_t::fromTBAA(ctx, tbaa); ai.decorateInst(ctx.builder.CreateStore(Constant::getNullValue(T_prjlvalue), fld)); } @@ -3542,8 +3556,6 @@ static Value *emit_bits_compare(jl_codectx_t &ctx, jl_cgval_t arg1, jl_cgval_t a return ctx.builder.CreateICmpEQ(answer, ConstantInt::get(getInt32Ty(ctx.builder.getContext()), 0)); } else if (sz > 512 && jl_struct_try_layout(sty) && sty->layout->flags.isbitsegal) { - Type *TInt8 = getInt8Ty(ctx.builder.getContext()); - Type *TInt1 = getInt1Ty(ctx.builder.getContext()); Value *varg1 = arg1.ispointer() ? data_pointer(ctx, arg1) : value_to_pointer(ctx, arg1).V; Value *varg2 = arg2.ispointer() ? data_pointer(ctx, arg2) : @@ -3562,8 +3574,8 @@ static Value *emit_bits_compare(jl_codectx_t &ctx, jl_cgval_t arg1, jl_cgval_t a Value *ptr1 = varg1; Value *ptr2 = varg2; if (desc.offset != 0) { - ptr1 = ctx.builder.CreateConstInBoundsGEP1_32(TInt8, ptr1, desc.offset); - ptr2 = ctx.builder.CreateConstInBoundsGEP1_32(TInt8, ptr2, desc.offset); + ptr1 = emit_ptrgep(ctx, ptr1, desc.offset); + ptr2 = emit_ptrgep(ctx, ptr2, desc.offset); } Value *new_ptr1 = ptr1; @@ -3573,7 +3585,7 @@ static Value *emit_bits_compare(jl_codectx_t &ctx, jl_cgval_t arg1, jl_cgval_t a PHINode *answerphi = nullptr; if (desc.nrepeats != 1) { // Set up loop - endptr1 = ctx.builder.CreateConstInBoundsGEP1_32(TInt8, ptr1, desc.nrepeats * (desc.data_bytes + desc.padding_bytes));; + endptr1 = emit_ptrgep(ctx, ptr1, desc.nrepeats * (desc.data_bytes + desc.padding_bytes));; BasicBlock *currBB = ctx.builder.GetInsertBlock(); loopBB = BasicBlock::Create(ctx.builder.getContext(), "egal_loop", ctx.f); @@ -3581,6 +3593,7 @@ static Value *emit_bits_compare(jl_codectx_t &ctx, jl_cgval_t arg1, jl_cgval_t a ctx.builder.CreateBr(loopBB); ctx.builder.SetInsertPoint(loopBB); + Type *TInt1 = getInt1Ty(ctx.builder.getContext()); answerphi = ctx.builder.CreatePHI(TInt1, 2); answerphi->addIncoming(answer ? answer : ConstantInt::get(TInt1, 1), currBB); answer = answerphi; @@ -3588,11 +3601,11 @@ static Value *emit_bits_compare(jl_codectx_t &ctx, jl_cgval_t arg1, jl_cgval_t a PHINode *itr1 = ctx.builder.CreatePHI(ptr1->getType(), 2); PHINode *itr2 = ctx.builder.CreatePHI(ptr2->getType(), 2); - new_ptr1 = ctx.builder.CreateConstInBoundsGEP1_32(TInt8, itr1, desc.data_bytes + desc.padding_bytes); + new_ptr1 = emit_ptrgep(ctx, itr1, desc.data_bytes + desc.padding_bytes); itr1->addIncoming(ptr1, currBB); itr1->addIncoming(new_ptr1, loopBB); - Value *new_ptr2 = ctx.builder.CreateConstInBoundsGEP1_32(TInt8, itr2, desc.data_bytes + desc.padding_bytes); + Value *new_ptr2 = emit_ptrgep(ctx, itr2, desc.data_bytes + desc.padding_bytes); itr2->addIncoming(ptr2, currBB); itr2->addIncoming(new_ptr2, loopBB); @@ -4074,7 +4087,7 @@ static bool emit_f_opmemory(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, ptindex = ctx.builder.CreateInBoundsGEP(AT, data, mlen); data = ctx.builder.CreateInBoundsGEP(AT, data, idx0); } - ptindex = ctx.builder.CreateInBoundsGEP(getInt8Ty(ctx.builder.getContext()), ptindex, idx0); + ptindex = emit_ptrgep(ctx, ptindex, idx0); *ret = union_store(ctx, data, ptindex, val, cmp, ety, ctx.tbaa().tbaa_arraybuf, ctx.tbaa().tbaa_arrayselbyte, Order, FailOrder, @@ -4089,7 +4102,7 @@ static bool emit_f_opmemory(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, assert(ptr); lock = ptr; // ptr += sizeof(lock); - ptr = ctx.builder.CreateConstInBoundsGEP1_32(getInt8Ty(ctx.builder.getContext()), ptr, LLT_ALIGN(sizeof(jl_mutex_t), JL_SMALL_BYTE_ALIGNMENT)); + ptr = emit_ptrgep(ctx, ptr, LLT_ALIGN(sizeof(jl_mutex_t), JL_SMALL_BYTE_ALIGNMENT)); } Value *data_owner = NULL; // owner object against which the write barrier must check if (isboxed || layout->first_ptr >= 0) { // if elements are just bits, don't need a write barrier @@ -4204,7 +4217,7 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, #ifdef _P64 nva = ctx.builder.CreateTrunc(nva, getInt32Ty(ctx.builder.getContext())); #endif - Value *theArgs = ctx.builder.CreateInBoundsGEP(ctx.types().T_prjlvalue, ctx.argArray, ConstantInt::get(ctx.types().T_size, ctx.nReqArgs)); + Value *theArgs = emit_ptrgep(ctx, ctx.argArray, ctx.nReqArgs * sizeof(jl_value_t*)); Value *r = ctx.builder.CreateCall(prepare_call(jlapplygeneric_func), { theF, theArgs, nva }); *ret = mark_julia_type(ctx, r, true, jl_any_type); return true; @@ -4354,7 +4367,7 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, ptindex = ctx.builder.CreateInBoundsGEP(AT, data, mlen); data = ctx.builder.CreateInBoundsGEP(AT, data, idx0); } - ptindex = ctx.builder.CreateInBoundsGEP(getInt8Ty(ctx.builder.getContext()), ptindex, idx0); + ptindex = emit_ptrgep(ctx, ptindex, idx0); size_t elsz_c = 0, al_c = 0; int union_max = jl_islayout_inline(ety, &elsz_c, &al_c); assert(union_max && LLT_ALIGN(elsz_c, al_c) == elsz && al_c == al); @@ -4367,7 +4380,7 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, assert(ptr); lock = ptr; // ptr += sizeof(lock); - ptr = ctx.builder.CreateConstInBoundsGEP1_32(getInt8Ty(ctx.builder.getContext()), ptr, LLT_ALIGN(sizeof(jl_mutex_t), JL_SMALL_BYTE_ALIGNMENT)); + ptr = emit_ptrgep(ctx, ptr, LLT_ALIGN(sizeof(jl_mutex_t), JL_SMALL_BYTE_ALIGNMENT)); emit_lockstate_value(ctx, lock, true); } *ret = typed_load(ctx, ptr, nullptr, ety, @@ -4458,10 +4471,10 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, if (needlock) { // n.b. no actual lock acquire needed, as the check itself only needs to load a single pointer and check for null // elem += sizeof(lock); - elem = ctx.builder.CreateConstInBoundsGEP1_32(getInt8Ty(ctx.builder.getContext()), elem, LLT_ALIGN(sizeof(jl_mutex_t), JL_SMALL_BYTE_ALIGNMENT)); + elem = emit_ptrgep(ctx, elem, LLT_ALIGN(sizeof(jl_mutex_t), JL_SMALL_BYTE_ALIGNMENT)); } if (!isboxed) - elem = ctx.builder.CreateConstInBoundsGEP1_32(ctx.types().T_prjlvalue, elem, layout->first_ptr); + elem = emit_ptrgep(ctx, elem, layout->first_ptr * sizeof(void*)); // emit this using the same type as jl_builtin_memoryrefget // so that LLVM may be able to load-load forward them and fold the result auto tbaa = isboxed ? ctx.tbaa().tbaa_ptrarraybuf : ctx.tbaa().tbaa_arraybuf; @@ -4549,7 +4562,7 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, if (load->getPointerOperand() == ctx.slots[ctx.vaSlot].boxroot && ctx.argArray) { Value *valen = emit_n_varargs(ctx); jl_cgval_t va_ary( // fake instantiation of a cgval, in order to call emit_bounds_check (it only checks the `.V` field) - ctx.builder.CreateInBoundsGEP(ctx.types().T_prjlvalue, ctx.argArray, ConstantInt::get(ctx.types().T_size, ctx.nReqArgs)), + emit_ptrgep(ctx, ctx.argArray, ctx.nReqArgs * sizeof(jl_value_t*)), NULL, NULL); Value *idx = emit_unbox(ctx, ctx.types().T_size, fld, (jl_value_t*)jl_long_type); idx = emit_bounds_check(ctx, va_ary, NULL, idx, valen, boundscheck); @@ -4899,7 +4912,7 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, if (!jl_field_isptr(stt, fieldidx)) offs += ((jl_datatype_t*)jl_field_type(stt, fieldidx))->layout->first_ptr; Value *ptr = data_pointer(ctx, obj); - Value *addr = ctx.builder.CreateConstInBoundsGEP1_32(ctx.types().T_prjlvalue, ptr, offs); + Value *addr = emit_ptrgep(ctx, ptr, offs * sizeof(jl_value_t*)); // emit this using the same type as emit_getfield_knownidx // so that LLVM may be able to load-load forward them and fold the result jl_aliasinfo_t ai = jl_aliasinfo_t::fromTBAA(ctx, tbaa); @@ -5583,10 +5596,7 @@ static jl_cgval_t emit_sparam(jl_codectx_t &ctx, size_t i) } } assert(ctx.spvals_ptr != NULL); - Value *bp = ctx.builder.CreateConstInBoundsGEP1_32( - ctx.types().T_prjlvalue, - ctx.spvals_ptr, - i + sizeof(jl_svec_t) / sizeof(jl_value_t*)); + Value *bp = emit_ptrgep(ctx, ctx.spvals_ptr, i * sizeof(jl_value_t*) + sizeof(jl_svec_t)); jl_aliasinfo_t ai = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_const); Value *sp = ai.decorateInst(ctx.builder.CreateAlignedLoad(ctx.types().T_prjlvalue, bp, Align(sizeof(void*)))); setName(ctx.emission_context, sp, "sparam"); @@ -5639,10 +5649,7 @@ static jl_cgval_t emit_isdefined(jl_codectx_t &ctx, jl_value_t *sym, int allow_i } } assert(ctx.spvals_ptr != NULL); - Value *bp = ctx.builder.CreateConstInBoundsGEP1_32( - ctx.types().T_prjlvalue, - ctx.spvals_ptr, - i + sizeof(jl_svec_t) / sizeof(jl_value_t*)); + Value *bp = emit_ptrgep(ctx, ctx.spvals_ptr, i * sizeof(jl_value_t*) + sizeof(jl_svec_t)); jl_aliasinfo_t ai = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_const); Value *sp = ai.decorateInst(ctx.builder.CreateAlignedLoad(ctx.types().T_prjlvalue, bp, Align(sizeof(void*)))); isnull = ctx.builder.CreateICmpNE(emit_typeof(ctx, sp, false, true), emit_tagfrom(ctx, jl_tvar_type)); @@ -6753,34 +6760,26 @@ static void allocate_gc_frame(jl_codectx_t &ctx, BasicBlock *b0, bool or_new=fal static Value *get_current_task(jl_codectx_t &ctx) { - return get_current_task_from_pgcstack(ctx.builder, ctx.types().T_size, ctx.pgcstack); + return get_current_task_from_pgcstack(ctx.builder, ctx.pgcstack); } // Get PTLS through current task. static Value *get_current_ptls(jl_codectx_t &ctx) { - return get_current_ptls_from_task(ctx.builder, ctx.types().T_size, get_current_task(ctx), ctx.tbaa().tbaa_gcframe); + return get_current_ptls_from_task(ctx.builder, get_current_task(ctx), ctx.tbaa().tbaa_gcframe); } // Get the address of the world age of the current task static Value *get_tls_world_age_field(jl_codectx_t &ctx) { Value *ct = get_current_task(ctx); - return ctx.builder.CreateInBoundsGEP( - ctx.types().T_size, - ct, - ConstantInt::get(ctx.types().T_size, offsetof(jl_task_t, world_age) / ctx.types().sizeof_ptr), - "world_age"); + return emit_ptrgep(ctx, ct, offsetof(jl_task_t, world_age), "world_age"); } static Value *get_scope_field(jl_codectx_t &ctx) { Value *ct = get_current_task(ctx); - return ctx.builder.CreateInBoundsGEP( - ctx.types().T_prjlvalue, - ct, - ConstantInt::get(ctx.types().T_size, offsetof(jl_task_t, scope) / ctx.types().sizeof_ptr), - "current_scope"); + return emit_ptrgep(ctx, ct, offsetof(jl_task_t, scope), "current_scope"); } static Function *emit_tojlinvoke(jl_code_instance_t *codeinst, StringRef theFptrName, Module *M, jl_codegen_params_t ¶ms) @@ -6912,10 +6911,7 @@ static void emit_cfunc_invalidate( case jl_returninfo_t::SRet: { if (return_roots) { Value *root1 = gf_thunk->arg_begin() + 1; // root1 has type [n x {}*]* - #if JL_LLVM_VERSION < 170000 - assert(cast(root1->getType())->isOpaqueOrPointeeTypeMatches(get_returnroots_type(ctx, return_roots))); - #endif - root1 = ctx.builder.CreateConstInBoundsGEP2_32(get_returnroots_type(ctx, return_roots), root1, 0, 0); + // store the whole object in the first slot ctx.builder.CreateStore(gf_ret, root1); } Align alignment(julia_alignment(rettype)); @@ -7094,10 +7090,7 @@ static Function* gen_cfun_wrapper( if (calltype) { LoadInst *lam_max = ctx.builder.CreateAlignedLoad( ctx.types().T_size, - ctx.builder.CreateConstInBoundsGEP1_32( - ctx.types().T_size, - literal_pointer_val(ctx, (jl_value_t*)codeinst), - offsetof(jl_code_instance_t, max_world) / ctx.types().sizeof_ptr), + emit_ptrgep(ctx, literal_pointer_val(ctx, (jl_value_t*)codeinst), offsetof(jl_code_instance_t, max_world)), ctx.types().alignof_ptr); age_ok = ctx.builder.CreateICmpUGE(lam_max, world_v); } @@ -7178,7 +7171,7 @@ static Function* gen_cfun_wrapper( *closure_types = jl_alloc_vec_any(0); jl_array_ptr_1d_push(*closure_types, jargty); Value *runtime_dt = ctx.builder.CreateAlignedLoad(ctx.types().T_prjlvalue, - ctx.builder.CreateConstInBoundsGEP1_32(ctx.types().T_prjlvalue, nestPtr, jl_array_nrows(*closure_types)), + emit_ptrgep(ctx, nestPtr, jl_array_nrows(*closure_types) * ctx.types().sizeof_ptr), Align(sizeof(void*))); BasicBlock *boxedBB = BasicBlock::Create(ctx.builder.getContext(), "isboxed", cw); BasicBlock *loadBB = BasicBlock::Create(ctx.builder.getContext(), "need-load", cw); @@ -7244,7 +7237,7 @@ static Function* gen_cfun_wrapper( *closure_types = jl_alloc_vec_any(0); jl_array_ptr_1d_push(*closure_types, jargty); Value *runtime_dt = ctx.builder.CreateAlignedLoad(ctx.types().T_prjlvalue, - ctx.builder.CreateConstInBoundsGEP1_32(ctx.types().T_prjlvalue, nestPtr, jl_array_nrows(*closure_types)), + emit_ptrgep(ctx, nestPtr, jl_array_nrows(*closure_types) * ctx.types().sizeof_ptr), Align(sizeof(void*))); Value *strct = box_ccall_result(ctx, val, runtime_dt, jargty); inputarg = mark_julia_type(ctx, strct, true, jargty_proper); @@ -7823,7 +7816,7 @@ static Function *gen_invoke_wrapper(jl_method_instance_t *lam, jl_value_t *jlret theArg = funcArg; } else { - Value *argPtr = ctx.builder.CreateConstInBoundsGEP1_32(ctx.types().T_prjlvalue, argArray, i - 1); + Value *argPtr = emit_ptrgep(ctx, argArray, (i - 1) * ctx.types().sizeof_ptr); jl_aliasinfo_t ai = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_const); theArg = ai.decorateInst(maybe_mark_load_dereferenceable( ctx.builder.CreateAlignedLoad(ctx.types().T_prjlvalue, argPtr, Align(sizeof(void*))), @@ -7850,7 +7843,7 @@ static Function *gen_invoke_wrapper(jl_method_instance_t *lam, jl_value_t *jlret theArg = funcArg; else theArg = ctx.builder.CreateAlignedLoad(ctx.types().T_prjlvalue, - ctx.builder.CreateConstInBoundsGEP1_32(ctx.types().T_prjlvalue, argArray, retarg - 1), + emit_ptrgep(ctx, argArray, (retarg - 1) * ctx.types().sizeof_ptr), Align(sizeof(void*))); retval = mark_julia_type(ctx, theArg, true, jl_any_type); } @@ -7969,7 +7962,7 @@ static jl_returninfo_t get_specsig_function(jl_codectx_t &ctx, Module *M, Value param.addAttribute(Attribute::NoCapture); param.addAttribute(Attribute::NoUndef); attrs.push_back(AttributeSet::get(ctx.builder.getContext(), param)); - fsig.push_back(get_returnroots_type(ctx, props.return_roots)->getPointerTo(0)); + fsig.push_back(ctx.types().T_ptr); argnames.push_back("return_roots"); } @@ -8069,9 +8062,9 @@ static jl_returninfo_t get_specsig_function(jl_codectx_t &ctx, Module *M, Value return props; } -static void emit_sret_roots(jl_codectx_t &ctx, bool isptr, Value *Src, Type *T, Value *Shadow, Type *ShadowT, unsigned count) +static void emit_sret_roots(jl_codectx_t &ctx, bool isptr, Value *Src, Type *T, Value *Shadow, unsigned count) { - unsigned emitted = TrackWithShadow(Src, T, isptr, Shadow, ShadowT, ctx.builder); //This comes from Late-GC-Lowering?? + unsigned emitted = TrackWithShadow(Src, T, isptr, Shadow, ctx.builder); //This comes from Late-GC-Lowering?? assert(emitted == count); (void)emitted; (void)count; } @@ -8773,9 +8766,7 @@ static jl_llvm_functions_t // Load closure world Value *oc_this = decay_derived(ctx, &*AI++); Value *argaddr = oc_this; - Value *worldaddr = ctx.builder.CreateInBoundsGEP( - getInt8Ty(ctx.builder.getContext()), argaddr, - ConstantInt::get(ctx.types().T_size, offsetof(jl_opaque_closure_t, world))); + Value *worldaddr = emit_ptrgep(ctx, argaddr, offsetof(jl_opaque_closure_t, world)); jl_cgval_t closure_world = typed_load(ctx, worldaddr, NULL, (jl_value_t*)jl_long_type, nullptr, nullptr, false, AtomicOrdering::NotAtomic, false, ctx.types().alignof_ptr.value()); @@ -8783,9 +8774,7 @@ static jl_llvm_functions_t emit_unbox_store(ctx, closure_world, world_age_field, ctx.tbaa().tbaa_gcframe, ctx.types().alignof_ptr); // Load closure env - Value *envaddr = ctx.builder.CreateInBoundsGEP( - getInt8Ty(ctx.builder.getContext()), argaddr, - ConstantInt::get(ctx.types().T_size, offsetof(jl_opaque_closure_t, captures))); + Value *envaddr = emit_ptrgep(ctx, argaddr, offsetof(jl_opaque_closure_t, captures)); jl_cgval_t closure_env = typed_load(ctx, envaddr, NULL, (jl_value_t*)jl_any_type, nullptr, nullptr, true, AtomicOrdering::NotAtomic, false, sizeof(void*)); @@ -8800,7 +8789,7 @@ static jl_llvm_functions_t theArg = mark_julia_type(ctx, fArg, true, vi.value.typ); } else { - Value *argPtr = ctx.builder.CreateConstInBoundsGEP1_32(ctx.types().T_prjlvalue, argArray, i - 1); + Value *argPtr = emit_ptrgep(ctx, argArray, (i - 1) * ctx.types().sizeof_ptr); jl_aliasinfo_t ai = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_const); Value *load = ai.decorateInst(maybe_mark_load_dereferenceable( ctx.builder.CreateAlignedLoad(ctx.types().T_prjlvalue, argPtr, Align(sizeof(void*))), @@ -8876,10 +8865,8 @@ static jl_llvm_functions_t restTuple = ctx.builder.CreateCall(F, { Constant::getNullValue(ctx.types().T_prjlvalue), - ctx.builder.CreateInBoundsGEP(ctx.types().T_prjlvalue, argArray, - ConstantInt::get(ctx.types().T_size, nreq - 1)), - ctx.builder.CreateSub(argCount, - ConstantInt::get(getInt32Ty(ctx.builder.getContext()), nreq - 1)) }); + emit_ptrgep(ctx, argArray, (nreq - 1) * sizeof(jl_value_t*)), + ctx.builder.CreateSub(argCount, ctx.builder.getInt32(nreq - 1)) }); restTuple->setAttributes(F->getAttributes()); ctx.builder.CreateStore(restTuple, vi.boxroot); } @@ -9319,7 +9306,7 @@ static jl_llvm_functions_t if (retvalinfo.ispointer()) { if (returninfo.return_roots) { Type *store_ty = julia_type_to_llvm(ctx, retvalinfo.typ); - emit_sret_roots(ctx, true, data_pointer(ctx, retvalinfo), store_ty, f->arg_begin() + 1, get_returnroots_type(ctx, returninfo.return_roots), returninfo.return_roots); + emit_sret_roots(ctx, true, data_pointer(ctx, retvalinfo), store_ty, f->arg_begin() + 1, returninfo.return_roots); } if (returninfo.cc == jl_returninfo_t::SRet) { assert(jl_is_concrete_type(jlrettype)); @@ -9336,7 +9323,7 @@ static jl_llvm_functions_t Value *Val = retvalinfo.V; if (returninfo.return_roots) { assert(julia_type_to_llvm(ctx, retvalinfo.typ) == store_ty); - emit_sret_roots(ctx, false, Val, store_ty, f->arg_begin() + 1, get_returnroots_type(ctx, returninfo.return_roots), returninfo.return_roots); + emit_sret_roots(ctx, false, Val, store_ty, f->arg_begin() + 1, returninfo.return_roots); } ctx.builder.CreateAlignedStore(Val, sret, Align(julia_alignment(retvalinfo.typ))); assert(retvalinfo.TIndex == NULL && "unreachable"); // unimplemented representation @@ -9447,11 +9434,7 @@ static jl_llvm_functions_t ctx.builder.CreateBr(handlr); } ctx.builder.SetInsertPoint(tryblk); - auto ehptr = ctx.builder.CreateInBoundsGEP( - ctx.types().T_ptr, - ct, - ConstantInt::get(ctx.types().T_size, offsetof(jl_task_t, eh) / ctx.types().sizeof_ptr), - "eh"); + auto ehptr = emit_ptrgep(ctx, ct, offsetof(jl_task_t, eh)); ctx.builder.CreateAlignedStore(ehbuf, ehptr, ctx.types().alignof_ptr); } } diff --git a/src/intrinsics.cpp b/src/intrinsics.cpp index 4bfe3f184d24b..194b45886bb0d 100644 --- a/src/intrinsics.cpp +++ b/src/intrinsics.cpp @@ -767,7 +767,7 @@ static jl_cgval_t emit_pointerref(jl_codectx_t &ctx, ArrayRef argv) LLT_ALIGN(size, jl_datatype_align(ety)))); setName(ctx.emission_context, im1, "pointerref_offset"); Value *thePtr = emit_unbox(ctx, getPointerTy(ctx.builder.getContext()), e, e.typ); - thePtr = ctx.builder.CreateInBoundsGEP(getInt8Ty(ctx.builder.getContext()), thePtr, im1); + thePtr = emit_ptrgep(ctx, thePtr, im1); setName(ctx.emission_context, thePtr, "pointerref_src"); MDNode *tbaa = best_tbaa(ctx.tbaa(), ety); emit_memcpy(ctx, strct, jl_aliasinfo_t::fromTBAA(ctx, tbaa), thePtr, jl_aliasinfo_t::fromTBAA(ctx, nullptr), size, Align(sizeof(jl_value_t*)), Align(align_nb)); @@ -848,7 +848,7 @@ static jl_cgval_t emit_pointerset(jl_codectx_t &ctx, ArrayRef argv) im1 = ctx.builder.CreateMul(im1, ConstantInt::get(ctx.types().T_size, LLT_ALIGN(size, jl_datatype_align(ety)))); setName(ctx.emission_context, im1, "pointerset_offset"); - auto gep = ctx.builder.CreateInBoundsGEP(getInt8Ty(ctx.builder.getContext()), thePtr, im1); + auto gep = emit_ptrgep(ctx, thePtr, im1); setName(ctx.emission_context, gep, "pointerset_ptr"); emit_memcpy(ctx, gep, jl_aliasinfo_t::fromTBAA(ctx, nullptr), x, size, Align(align_nb), Align(julia_alignment(ety))); } diff --git a/src/llvm-alloc-opt.cpp b/src/llvm-alloc-opt.cpp index 5984ad55d221c..188955fd50972 100644 --- a/src/llvm-alloc-opt.cpp +++ b/src/llvm-alloc-opt.cpp @@ -770,26 +770,7 @@ void Optimizer::moveToStack(CallInst *orig_inst, size_t sz, bool has_ref, AllocF user->replaceUsesOfWith(orig_i, replace); } else if (isa(user) || isa(user)) { - #if JL_LLVM_VERSION >= 170000 - #ifndef JL_NDEBUG - auto cast_t = PointerType::get(user->getType(), new_i->getType()->getPointerAddressSpace()); - Type *new_t = new_i->getType(); - assert(cast_t == new_t); - #endif - auto replace_i = new_i; - #else - auto cast_t = PointerType::getWithSamePointeeType(cast(user->getType()), new_i->getType()->getPointerAddressSpace()); - auto replace_i = new_i; - Type *new_t = new_i->getType(); - if (cast_t != new_t) { - // Shouldn't get here when using opaque pointers, so the new BitCastInst is fine - assert(cast_t->getContext().supportsTypedPointers()); - replace_i = new BitCastInst(replace_i, cast_t, "", user); - replace_i->setDebugLoc(user->getDebugLoc()); - replace_i->takeName(user); - } - #endif - push_frame(user, replace_i); + push_frame(user, new_i); } else if (auto gep = dyn_cast(user)) { SmallVector IdxOperands(gep->idx_begin(), gep->idx_end()); diff --git a/src/llvm-codegen-shared.h b/src/llvm-codegen-shared.h index 242dab021f101..956c04dbc7ded 100644 --- a/src/llvm-codegen-shared.h +++ b/src/llvm-codegen-shared.h @@ -125,7 +125,7 @@ struct CountTrackedPointers { CountTrackedPointers(llvm::Type *T, bool ignore_loaded=false); }; -unsigned TrackWithShadow(llvm::Value *Src, llvm::Type *T, bool isptr, llvm::Value *Dst, llvm::Type *DTy, llvm::IRBuilder<> &irbuilder); +unsigned TrackWithShadow(llvm::Value *Src, llvm::Type *T, bool isptr, llvm::Value *Dst, llvm::IRBuilder<> &irbuilder); llvm::SmallVector ExtractTrackedValues(llvm::Value *Src, llvm::Type *STy, bool isptr, llvm::IRBuilder<> &irbuilder, llvm::ArrayRef perm_offsets={}); static inline void llvm_dump(llvm::Value *v) @@ -187,45 +187,39 @@ static inline llvm::Instruction *tbaa_decorate(llvm::MDNode *md, llvm::Instructi } // Get PTLS through current task. -static inline llvm::Value *get_current_task_from_pgcstack(llvm::IRBuilder<> &builder, llvm::Type *T_size, llvm::Value *pgcstack) +static inline llvm::Value *get_current_task_from_pgcstack(llvm::IRBuilder<> &builder, llvm::Value *pgcstack) { using namespace llvm; - auto T_pjlvalue = JuliaType::get_pjlvalue_ty(builder.getContext()); + auto i8 = builder.getInt8Ty(); const int pgcstack_offset = offsetof(jl_task_t, gcstack); - return builder.CreateInBoundsGEP( - T_pjlvalue, pgcstack, - ConstantInt::get(T_size, -(pgcstack_offset / sizeof(void *))), - "current_task"); + return builder.CreateConstInBoundsGEP1_32(i8, pgcstack, -pgcstack_offset, "current_task"); } // Get PTLS through current task. -static inline llvm::Value *get_current_ptls_from_task(llvm::IRBuilder<> &builder, llvm::Type *T_size, llvm::Value *current_task, llvm::MDNode *tbaa) +static inline llvm::Value *get_current_ptls_from_task(llvm::IRBuilder<> &builder, llvm::Value *current_task, llvm::MDNode *tbaa) { using namespace llvm; - auto T_pjlvalue = JuliaType::get_pjlvalue_ty(builder.getContext()); + auto i8 = builder.getInt8Ty(); + auto T_ptr = builder.getPtrTy(); const int ptls_offset = offsetof(jl_task_t, ptls); - llvm::Value *pptls = builder.CreateInBoundsGEP( - T_pjlvalue, current_task, - ConstantInt::get(T_size, ptls_offset / sizeof(void *)), - "ptls_field"); - LoadInst *ptls_load = builder.CreateAlignedLoad(T_pjlvalue, - pptls, Align(sizeof(void *)), "ptls_load"); + llvm::Value *pptls = builder.CreateConstInBoundsGEP1_32(i8, current_task, ptls_offset, "ptls_field"); + LoadInst *ptls_load = builder.CreateAlignedLoad(T_ptr, pptls, Align(sizeof(void *)), "ptls_load"); // Note: Corresponding store (`t->ptls = ptls`) happens in `ctx_switch` of tasks.c. tbaa_decorate(tbaa, ptls_load); return ptls_load; } // Get signal page through current task. -static inline llvm::Value *get_current_signal_page_from_ptls(llvm::IRBuilder<> &builder, llvm::Type *T_size, llvm::Value *ptls, llvm::MDNode *tbaa) +static inline llvm::Value *get_current_signal_page_from_ptls(llvm::IRBuilder<> &builder, llvm::Value *ptls, llvm::MDNode *tbaa) { using namespace llvm; // return builder.CreateCall(prepare_call(reuse_signal_page_func)); - auto T_psize = T_size->getPointerTo(); - int nthfield = offsetof(jl_tls_states_t, safepoint) / sizeof(void *); - llvm::Value *psafepoint = builder.CreateInBoundsGEP( - T_psize, ptls, ConstantInt::get(T_size, nthfield)); + auto T_ptr = builder.getPtrTy(); + auto i8 = builder.getInt8Ty(); + int nthfield = offsetof(jl_tls_states_t, safepoint); + llvm::Value *psafepoint = builder.CreateConstInBoundsGEP1_32(i8, ptls, nthfield); LoadInst *ptls_load = builder.CreateAlignedLoad( - T_psize, psafepoint, Align(sizeof(void *)), "safepoint"); + T_ptr, psafepoint, Align(sizeof(void *)), "safepoint"); tbaa_decorate(tbaa, ptls_load); return ptls_load; } @@ -239,7 +233,7 @@ static inline void emit_signal_fence(llvm::IRBuilder<> &builder) static inline void emit_gc_safepoint(llvm::IRBuilder<> &builder, llvm::Type *T_size, llvm::Value *ptls, llvm::MDNode *tbaa, bool final = false) { using namespace llvm; - llvm::Value *signal_page = get_current_signal_page_from_ptls(builder, T_size, ptls, tbaa); + llvm::Value *signal_page = get_current_signal_page_from_ptls(builder, ptls, tbaa); emit_signal_fence(builder); Module *M = builder.GetInsertBlock()->getModule(); LLVMContext &C = builder.getContext(); @@ -250,8 +244,7 @@ static inline void emit_gc_safepoint(llvm::IRBuilder<> &builder, llvm::Type *T_s else { Function *F = M->getFunction("julia.safepoint"); if (!F) { - auto T_psize = T_size->getPointerTo(); - FunctionType *FT = FunctionType::get(Type::getVoidTy(C), {T_psize}, false); + FunctionType *FT = FunctionType::get(Type::getVoidTy(C), {T_size->getPointerTo()}, false); F = Function::Create(FT, Function::ExternalLinkage, "julia.safepoint", M); #if JL_LLVM_VERSION >= 160000 F->setMemoryEffects(MemoryEffects::inaccessibleOrArgMemOnly()); @@ -268,8 +261,8 @@ static inline llvm::Value *emit_gc_state_set(llvm::IRBuilder<> &builder, llvm::T { using namespace llvm; Type *T_int8 = state->getType(); - Constant *offset = ConstantInt::getSigned(builder.getInt32Ty(), offsetof(jl_tls_states_t, gc_state)); - Value *gc_state = builder.CreateInBoundsGEP(T_int8, ptls, ArrayRef(offset), "gc_state"); + unsigned offset = offsetof(jl_tls_states_t, gc_state); + Value *gc_state = builder.CreateConstInBoundsGEP1_32(T_int8, ptls, offset, "gc_state"); if (old_state == nullptr) { old_state = builder.CreateLoad(T_int8, gc_state); cast(old_state)->setOrdering(AtomicOrdering::Monotonic); diff --git a/src/llvm-late-gc-lowering.cpp b/src/llvm-late-gc-lowering.cpp index e08f08860dfaf..8d1d5ff73b261 100644 --- a/src/llvm-late-gc-lowering.cpp +++ b/src/llvm-late-gc-lowering.cpp @@ -350,15 +350,7 @@ void LateLowerGCFrame::LiftSelect(State &S, SelectInst *SI) { ConstantInt::get(Type::getInt32Ty(Cond->getContext()), i), "", SI); } - #if JL_LLVM_VERSION >= 170000 assert(FalseElem->getType() == TrueElem->getType()); - #else - if (FalseElem->getType() != TrueElem->getType()) { - // Shouldn't get here when using opaque pointers, so the new BitCastInst is fine - assert(FalseElem->getContext().supportsTypedPointers()); - FalseElem = new BitCastInst(FalseElem, TrueElem->getType(), "", SI); - } - #endif SelectInst *SelectBase = SelectInst::Create(Cond, TrueElem, FalseElem, "gclift", SI); int Number = ++S.MaxPtrNumber; S.AllPtrNumbering[SelectBase] = Number; @@ -427,33 +419,7 @@ void LateLowerGCFrame::LiftPhi(State &S, PHINode *Phi) { BaseElem = Base; else BaseElem = IncomingBases[i]; - #if JL_LLVM_VERSION >= 170000 assert(BaseElem->getType() == T_prjlvalue); - #else - if (BaseElem->getType() != T_prjlvalue) { - // Shouldn't get here when using opaque pointers, so the new BitCastInst is fine - assert(BaseElem->getContext().supportsTypedPointers()); - auto &remap = CastedRoots[i][BaseElem]; - if (!remap) { - if (auto constant = dyn_cast(BaseElem)) { - remap = ConstantExpr::getBitCast(constant, T_prjlvalue, ""); - } else { - Instruction *InsertBefore; - if (auto arg = dyn_cast(BaseElem)) { - InsertBefore = &*arg->getParent()->getEntryBlock().getFirstInsertionPt(); - } else { - assert(isa(BaseElem) && "Unknown value type detected!"); - InsertBefore = cast(BaseElem)->getNextNonDebugInstruction(); - } - while (isa(InsertBefore)) { - InsertBefore = InsertBefore->getNextNonDebugInstruction(); - } - remap = new BitCastInst(BaseElem, T_prjlvalue, "", InsertBefore); - } - } - BaseElem = remap; - } - #endif lift->addIncoming(BaseElem, IncomingBB); } } @@ -1528,14 +1494,11 @@ SmallVector ExtractTrackedValues(Value *Src, Type *STy, bool isptr, I return Ptrs; } -unsigned TrackWithShadow(Value *Src, Type *STy, bool isptr, Value *Dst, Type *DTy, IRBuilder<> &irbuilder) { +unsigned TrackWithShadow(Value *Src, Type *STy, bool isptr, Value *Dst, IRBuilder<> &irbuilder) { auto Ptrs = ExtractTrackedValues(Src, STy, isptr, irbuilder); for (unsigned i = 0; i < Ptrs.size(); ++i) { - Value *Elem = Ptrs[i];// Dst has type `[n x {}*]*` - Value *Slot = irbuilder.CreateConstInBoundsGEP2_32(DTy, Dst, 0, i); - #if JL_LLVM_VERSION < 170000 - assert(cast(Dst->getType())->isOpaqueOrPointeeTypeMatches(DTy)); - #endif + Value *Elem = Ptrs[i]; + Value *Slot = irbuilder.CreateConstInBoundsGEP1_32(irbuilder.getInt8Ty(), Dst, i * sizeof(void*)); StoreInst *shadowStore = irbuilder.CreateAlignedStore(Elem, Slot, Align(sizeof(void*))); shadowStore->setOrdering(AtomicOrdering::NotAtomic); // TODO: shadowStore->setMetadata(LLVMContext::MD_tbaa, tbaa_gcframe); @@ -2133,7 +2096,7 @@ bool LateLowerGCFrame::CleanupIR(Function &F, State *S, bool *CFGModified) { // the type tag. (Note that if the size is not a constant, it will call // gc_alloc_obj, and will redundantly set the tag.) auto allocBytesIntrinsic = getOrDeclare(jl_intrinsics::GCAllocBytes); - auto ptls = get_current_ptls_from_task(builder, T_size, CI->getArgOperand(0), tbaa_gcframe); + auto ptls = get_current_ptls_from_task(builder, CI->getArgOperand(0), tbaa_gcframe); auto newI = builder.CreateCall( allocBytesIntrinsic, { @@ -2319,15 +2282,7 @@ void LateLowerGCFrame::PlaceGCFrameStore(State &S, unsigned R, unsigned MinColor // Pointee types don't have semantics, so the optimizer is // free to rewrite them if convenient. We need to change // it back here for the store. - #if JL_LLVM_VERSION >= 170000 assert(Val->getType() == T_prjlvalue); - #else - if (Val->getType() != T_prjlvalue) { - // Shouldn't get here when using opaque pointers, so the new BitCastInst is fine - assert(Val->getContext().supportsTypedPointers()); - Val = new BitCastInst(Val, T_prjlvalue, "", InsertBefore); - } - #endif new StoreInst(Val, slotAddress, InsertBefore); } @@ -2407,18 +2362,7 @@ void LateLowerGCFrame::PlaceRootsAndUpdateCalls(SmallVectorImpl &Colors, St for (CallInst *II : ToDelete) { II->eraseFromParent(); } - #if JL_LLVM_VERSION >= 170000 assert(slotAddress->getType() == AI->getType()); - #else - if (slotAddress->getType() != AI->getType()) { - // If we're replacing an ArrayAlloca, the pointer element type may need to be fixed up - // Shouldn't get here when using opaque pointers, so the new BitCastInst is fine - assert(slotAddress->getContext().supportsTypedPointers()); - auto BCI = new BitCastInst(slotAddress, AI->getType()); - BCI->insertAfter(slotAddress); - slotAddress = BCI; - } - #endif AI->replaceAllUsesWith(slotAddress); AI->eraseFromParent(); AI = NULL; @@ -2443,15 +2387,7 @@ void LateLowerGCFrame::PlaceRootsAndUpdateCalls(SmallVectorImpl &Colors, St slotAddress->insertAfter(gcframe); auto ValExpr = std::make_pair(Base, isa(Base->getType()) ? -1 : i); auto Elem = MaybeExtractScalar(S, ValExpr, SI); - #if JL_LLVM_VERSION >= 170000 assert(Elem->getType() == T_prjlvalue); - #else - if (Elem->getType() != T_prjlvalue) { - // Shouldn't get here when using opaque pointers, so the new BitCastInst is fine - assert(Elem->getContext().supportsTypedPointers()); - Elem = new BitCastInst(Elem, T_prjlvalue, "", SI); - } - #endif //auto Idxs = ArrayRef(Tracked[i]); //Value *Elem = ExtractScalar(Base, true, Idxs, SI); Value *shadowStore = new StoreInst(Elem, slotAddress, SI); diff --git a/src/llvm-ptls.cpp b/src/llvm-ptls.cpp index 736c1acd9525a..488dd46cade21 100644 --- a/src/llvm-ptls.cpp +++ b/src/llvm-ptls.cpp @@ -191,7 +191,7 @@ void LowerPTLS::fix_pgcstack_use(CallInst *pgcstack, Function *pgcstack_getter, builder.SetInsertPoint(fastTerm->getParent()); fastTerm->removeFromParent(); MDNode *tbaa = tbaa_gcframe; - Value *prior = emit_gc_unsafe_enter(builder, T_size, get_current_ptls_from_task(builder, T_size, get_current_task_from_pgcstack(builder, T_size, pgcstack), tbaa), true); + Value *prior = emit_gc_unsafe_enter(builder, T_size, get_current_ptls_from_task(builder, get_current_task_from_pgcstack(builder, pgcstack), tbaa), true); builder.Insert(fastTerm); phi->addIncoming(pgcstack, fastTerm->getParent()); // emit pre-return cleanup @@ -203,7 +203,7 @@ void LowerPTLS::fix_pgcstack_use(CallInst *pgcstack, Function *pgcstack_getter, for (auto &BB : *pgcstack->getParent()->getParent()) { if (isa(BB.getTerminator())) { builder.SetInsertPoint(BB.getTerminator()); - emit_gc_unsafe_leave(builder, T_size, get_current_ptls_from_task(builder, T_size, get_current_task_from_pgcstack(builder, T_size, phi), tbaa), last_gc_state, true); + emit_gc_unsafe_leave(builder, T_size, get_current_ptls_from_task(builder, get_current_task_from_pgcstack(builder, phi), tbaa), last_gc_state, true); } } } diff --git a/test/llvmpasses/alloc-opt-gcframe.ll b/test/llvmpasses/alloc-opt-gcframe.ll index e8644899f0914..f53a4d5c01df7 100644 --- a/test/llvmpasses/alloc-opt-gcframe.ll +++ b/test/llvmpasses/alloc-opt-gcframe.ll @@ -10,7 +10,7 @@ target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" ; CHECK-NOT: @julia.gc_alloc_obj ; OPAQUE: %current_task = getelementptr inbounds ptr, ptr %gcstack, i64 -12 -; OPAQUE: [[ptls_field:%.*]] = getelementptr inbounds ptr, ptr %current_task, i64 16 +; OPAQUE: [[ptls_field:%.*]] = getelementptr inbounds i8, ptr %current_task, ; OPAQUE-NEXT: [[ptls_load:%.*]] = load ptr, ptr [[ptls_field]], align 8, !tbaa !0 ; OPAQUE-NEXT: %v = call noalias nonnull align {{[0-9]+}} dereferenceable({{[0-9]+}}) ptr addrspace(10) @ijl_gc_small_alloc(ptr [[ptls_load]], i32 [[SIZE_T:[0-9]+]], i32 16, i64 {{.*}} @tag {{.*}}) ; OPAQUE: store atomic ptr addrspace(10) @tag, ptr addrspace(10) {{.*}} unordered, align 8, !tbaa !4 diff --git a/test/llvmpasses/late-lower-gc-addrspaces.ll b/test/llvmpasses/late-lower-gc-addrspaces.ll index 702e44b2b0e28..9c041664a9682 100644 --- a/test/llvmpasses/late-lower-gc-addrspaces.ll +++ b/test/llvmpasses/late-lower-gc-addrspaces.ll @@ -1,6 +1,6 @@ ; This file is a part of Julia. License is MIT: https://julialang.org/license -; RUN: opt --load-pass-plugin=libjulia-codegen%shlibext -passes='function(LateLowerGCFrame)' -S %s | FileCheck %s --check-prefixes=CHECK,OPAQUE +; RUN: opt --load-pass-plugin=libjulia-codegen%shlibext -passes='function(LateLowerGCFrame)' -S %s | FileCheck %s target triple = "amdgcn-amd-amdhsa" target datalayout = "e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5-G1-ni:7-ni:10:11:12:13" @@ -19,28 +19,28 @@ define void @gc_frame_lowering(i64 %a, i64 %b) { top: ; CHECK-LABEL: @gc_frame_lowering -; OPAQUE: %gcframe = call ptr @julia.new_gc_frame(i32 2) -; OPAQUE: %pgcstack = call ptr @julia.get_pgcstack() +; CHECK: %gcframe = call ptr @julia.new_gc_frame(i32 2) +; CHECK: %pgcstack = call ptr @julia.get_pgcstack() %pgcstack = call {}*** @julia.get_pgcstack() -; OPAQUE-NEXT: call void @julia.push_gc_frame(ptr %gcframe, i32 2) -; OPAQUE-NEXT: call ptr addrspace(10) @jl_box_int64 +; CHECK-NEXT: call void @julia.push_gc_frame(ptr %gcframe, i32 2) +; CHECK-NEXT: call ptr addrspace(10) @jl_box_int64 %aboxed = call {} addrspace(10)* @jl_box_int64(i64 signext %a) -; OPAQUE: [[GEP0:%.*]] = call ptr @julia.get_gc_frame_slot(ptr %gcframe, i32 [[GEPSLOT0:[0-9]+]]) -; OPAQUE-NEXT: store ptr addrspace(10) %aboxed, ptr [[GEP0]] +; CHECK: [[GEP0:%.*]] = call ptr @julia.get_gc_frame_slot(ptr %gcframe, i32 [[GEPSLOT0:[0-9]+]]) +; CHECK-NEXT: store ptr addrspace(10) %aboxed, ptr [[GEP0]] %bboxed = call {} addrspace(10)* @jl_box_int64(i64 signext %b) ; CHECK-NEXT: %bboxed = ; Make sure the same gc slot isn't re-used -; OPAQUE-NOT: call ptr @julia.get_gc_frame_slot(ptr %gcframe, i32 [[GEPSLOT0]]) -; OPAQUE: [[GEP1:%.*]] = call ptr @julia.get_gc_frame_slot(ptr %gcframe, i32 [[GEPSLOT1:[0-9]+]]) -; OPAQUE-NEXT: store ptr addrspace(10) %bboxed, ptr [[GEP1]] +; CHECK-NOT: call ptr @julia.get_gc_frame_slot(ptr %gcframe, i32 [[GEPSLOT0]]) +; CHECK: [[GEP1:%.*]] = call ptr @julia.get_gc_frame_slot(ptr %gcframe, i32 [[GEPSLOT1:[0-9]+]]) +; CHECK-NEXT: store ptr addrspace(10) %bboxed, ptr [[GEP1]] ; CHECK-NEXT: call void @boxed_simple call void @boxed_simple({} addrspace(10)* %aboxed, {} addrspace(10)* %bboxed) -; OPAQUE-NEXT: call void @julia.pop_gc_frame(ptr %gcframe) +; CHECK-NEXT: call void @julia.pop_gc_frame(ptr %gcframe) ret void } @@ -51,14 +51,14 @@ top: %0 = bitcast {}*** %pgcstack to {}** %current_task = getelementptr inbounds {}*, {}** %0, i64 -12 -; OPAQUE: %current_task = getelementptr inbounds ptr, ptr %0, i64 -12 -; OPAQUE-NEXT: [[ptls_field:%.*]] = getelementptr inbounds ptr, ptr %current_task, i64 16 -; OPAQUE-NEXT: [[ptls_load:%.*]] = load ptr, ptr [[ptls_field]], align 8, !tbaa !0 -; OPAQUE-NEXT: %v = call noalias nonnull ptr addrspace(10) @julia.gc_alloc_bytes(ptr [[ptls_load]], [[SIZE_T:i.[0-9]+]] 8, i64 {{.*}} @tag {{.*}}) -; OPAQUE-NEXT: [[V_HEADROOM:%.*]] = getelementptr inbounds ptr addrspace(10), ptr addrspace(10) %v, i64 -1 -; OPAQUE-NEXT: store atomic ptr addrspace(10) @tag, ptr addrspace(10) [[V_HEADROOM]] unordered, align 8, !tbaa !4 +; CHECK: %current_task = getelementptr inbounds ptr, ptr %0, i64 -12 +; CHECK-NEXT: [[ptls_field:%.*]] = getelementptr inbounds i8, ptr %current_task, +; CHECK-NEXT: [[ptls_load:%.*]] = load ptr, ptr [[ptls_field]], align 8, !tbaa !0 +; CHECK-NEXT: %v = call noalias nonnull ptr addrspace(10) @julia.gc_alloc_bytes(ptr [[ptls_load]], [[SIZE_T:i.[0-9]+]] 8, i64 {{.*}} @tag {{.*}}) +; CHECK-NEXT: [[V_HEADROOM:%.*]] = getelementptr inbounds ptr addrspace(10), ptr addrspace(10) %v, i64 -1 +; CHECK-NEXT: store atomic ptr addrspace(10) @tag, ptr addrspace(10) [[V_HEADROOM]] unordered, align 8, !tbaa !4 %v = call noalias {} addrspace(10)* @julia.gc_alloc_obj({}** %current_task, i64 8, {} addrspace(10)* @tag) -; OPAQUE-NEXT: ret ptr addrspace(10) %v +; CHECK-NEXT: ret ptr addrspace(10) %v ret {} addrspace(10)* %v } @@ -74,20 +74,20 @@ top: %0 = bitcast {}*** %pgcstack to {}** %current_task = getelementptr inbounds {}*, {}** %0, i64 -12 -; OPAQUE: %current_task = getelementptr inbounds ptr, ptr %0, i64 -12 -; OPAQUE-NEXT: [[ptls_field:%.*]] = getelementptr inbounds ptr, ptr %current_task, i64 16 -; OPAQUE-NEXT: [[ptls_load:%.*]] = load ptr, ptr [[ptls_field]], align 8, !tbaa !0 -; OPAQUE-NEXT: %v = call noalias nonnull ptr addrspace(10) @julia.gc_alloc_bytes(ptr [[ptls_load]], [[SIZE_T:i.[0-9]+]] 8, i64 {{.*}} @tag {{.*}}) -; OPAQUE-NEXT: [[V_HEADROOM:%.*]] = getelementptr inbounds ptr addrspace(10), ptr addrspace(10) %v, i64 -1 -; OPAQUE-NEXT: store atomic ptr addrspace(10) @tag, ptr addrspace(10) [[V_HEADROOM]] unordered, align 8, !tbaa !4 +; CHECK: %current_task = getelementptr inbounds ptr, ptr %0, i64 -12 +; CHECK-NEXT: [[ptls_field:%.*]] = getelementptr inbounds i8, ptr %current_task, +; CHECK-NEXT: [[ptls_load:%.*]] = load ptr, ptr [[ptls_field]], align 8, !tbaa !0 +; CHECK-NEXT: %v = call noalias nonnull ptr addrspace(10) @julia.gc_alloc_bytes(ptr [[ptls_load]], [[SIZE_T:i.[0-9]+]] 8, i64 {{.*}} @tag {{.*}}) +; CHECK-NEXT: [[V_HEADROOM:%.*]] = getelementptr inbounds ptr addrspace(10), ptr addrspace(10) %v, i64 -1 +; CHECK-NEXT: store atomic ptr addrspace(10) @tag, ptr addrspace(10) [[V_HEADROOM]] unordered, align 8, !tbaa !4 %v = call noalias {} addrspace(10)* @julia.gc_alloc_obj({}** %current_task, i64 8, {} addrspace(10)* @tag) -; OPAQUE-NEXT: %v64 = bitcast ptr addrspace(10) %v to ptr addrspace(10) +; CHECK-NEXT: %v64 = bitcast ptr addrspace(10) %v to ptr addrspace(10) %v64 = bitcast {} addrspace(10)* %v to i64 addrspace(10)* -; OPAQUE-NEXT: %loadedval = load i64, ptr addrspace(10) %v64, align 8, !range !7 +; CHECK-NEXT: %loadedval = load i64, ptr addrspace(10) %v64, align 8, !range !7 %loadedval = load i64, i64 addrspace(10)* %v64, align 8, !range !0, !invariant.load !1 -; OPAQUE-NEXT: store i64 %loadedval, ptr addrspace(10) %v64, align 8, !noalias !8 +; CHECK-NEXT: store i64 %loadedval, ptr addrspace(10) %v64, align 8, !noalias !8 store i64 %loadedval, i64 addrspace(10)* %v64, align 8, !noalias !2 -; OPAQUE-NEXT: %lv2 = load i64, ptr addrspace(10) %v64, align 8, !tbaa !11, !range !7 +; CHECK-NEXT: %lv2 = load i64, ptr addrspace(10) %v64, align 8, !tbaa !11, !range !7 %lv2 = load i64, i64 addrspace(10)* %v64, align 8, !range !0, !tbaa !4 ; CHECK-NEXT: ret void ret void diff --git a/test/llvmpasses/late-lower-gc.ll b/test/llvmpasses/late-lower-gc.ll index 093cab1358141..d294847db8f9d 100644 --- a/test/llvmpasses/late-lower-gc.ll +++ b/test/llvmpasses/late-lower-gc.ll @@ -1,6 +1,6 @@ ; This file is a part of Julia. License is MIT: https://julialang.org/license -; RUN: opt --load-pass-plugin=libjulia-codegen%shlibext -passes='function(LateLowerGCFrame)' -S %s | FileCheck %s --check-prefixes=CHECK,OPAQUE +; RUN: opt --load-pass-plugin=libjulia-codegen%shlibext -passes='function(LateLowerGCFrame)' -S %s | FileCheck %s @tag = external addrspace(10) global {}, align 16 @@ -16,28 +16,28 @@ define void @gc_frame_lowering(i64 %a, i64 %b) { top: ; CHECK-LABEL: @gc_frame_lowering -; OPAQUE: %gcframe = call ptr @julia.new_gc_frame(i32 2) -; OPAQUE: %pgcstack = call ptr @julia.get_pgcstack() +; CHECK: %gcframe = call ptr @julia.new_gc_frame(i32 2) +; CHECK: %pgcstack = call ptr @julia.get_pgcstack() %pgcstack = call {}*** @julia.get_pgcstack() -; OPAQUE-NEXT: call void @julia.push_gc_frame(ptr %gcframe, i32 2) -; OPAQUE-NEXT: call ptr addrspace(10) @jl_box_int64 +; CHECK-NEXT: call void @julia.push_gc_frame(ptr %gcframe, i32 2) +; CHECK-NEXT: call ptr addrspace(10) @jl_box_int64 %aboxed = call {} addrspace(10)* @jl_box_int64(i64 signext %a) -; OPAQUE: [[GEP0:%.*]] = call ptr @julia.get_gc_frame_slot(ptr %gcframe, i32 [[GEPSLOT0:[0-9]+]]) -; OPAQUE-NEXT: store ptr addrspace(10) %aboxed, ptr [[GEP0]] +; CHECK: [[GEP0:%.*]] = call ptr @julia.get_gc_frame_slot(ptr %gcframe, i32 [[GEPSLOT0:[0-9]+]]) +; CHECK-NEXT: store ptr addrspace(10) %aboxed, ptr [[GEP0]] %bboxed = call {} addrspace(10)* @jl_box_int64(i64 signext %b) ; CHECK-NEXT: %bboxed = ; Make sure the same gc slot isn't re-used -; OPAQUE-NOT: call ptr @julia.get_gc_frame_slot(ptr %gcframe, i32 [[GEPSLOT0]]) -; OPAQUE: [[GEP1:%.*]] = call ptr @julia.get_gc_frame_slot(ptr %gcframe, i32 [[GEPSLOT1:[0-9]+]]) -; OPAQUE-NEXT: store ptr addrspace(10) %bboxed, ptr [[GEP1]] +; CHECK-NOT: call ptr @julia.get_gc_frame_slot(ptr %gcframe, i32 [[GEPSLOT0]]) +; CHECK: [[GEP1:%.*]] = call ptr @julia.get_gc_frame_slot(ptr %gcframe, i32 [[GEPSLOT1:[0-9]+]]) +; CHECK-NEXT: store ptr addrspace(10) %bboxed, ptr [[GEP1]] ; CHECK-NEXT: call void @boxed_simple call void @boxed_simple({} addrspace(10)* %aboxed, {} addrspace(10)* %bboxed) -; OPAQUE-NEXT: call void @julia.pop_gc_frame(ptr %gcframe) +; CHECK-NEXT: call void @julia.pop_gc_frame(ptr %gcframe) ret void } @@ -48,14 +48,14 @@ top: %0 = bitcast {}*** %pgcstack to {}** %current_task = getelementptr inbounds {}*, {}** %0, i64 -12 -; OPAQUE: %current_task = getelementptr inbounds ptr, ptr %0, i64 -12 -; OPAQUE-NEXT: [[ptls_field:%.*]] = getelementptr inbounds ptr, ptr %current_task, i64 16 -; OPAQUE-NEXT: [[ptls_load:%.*]] = load ptr, ptr [[ptls_field]], align 8, !tbaa !0 -; OPAQUE-NEXT: %v = call noalias nonnull ptr addrspace(10) @julia.gc_alloc_bytes(ptr [[ptls_load]], [[SIZE_T:i.[0-9]+]] 8, i64 {{.*}} @tag {{.*}}) -; OPAQUE-NEXT: [[V_HEADROOM:%.*]] = getelementptr inbounds ptr addrspace(10), ptr addrspace(10) %v, i64 -1 -; OPAQUE-NEXT: store atomic ptr addrspace(10) @tag, ptr addrspace(10) [[V_HEADROOM]] unordered, align 8, !tbaa !4 +; CHECK: %current_task = getelementptr inbounds ptr, ptr %0, i64 -12 +; CHECK-NEXT: [[ptls_field:%.*]] = getelementptr inbounds i8, ptr %current_task, +; CHECK-NEXT: [[ptls_load:%.*]] = load ptr, ptr [[ptls_field]], align 8, !tbaa !0 +; CHECK-NEXT: %v = call noalias nonnull ptr addrspace(10) @julia.gc_alloc_bytes(ptr [[ptls_load]], [[SIZE_T:i.[0-9]+]] 8, i64 {{.*}} @tag {{.*}}) +; CHECK-NEXT: [[V_HEADROOM:%.*]] = getelementptr inbounds ptr addrspace(10), ptr addrspace(10) %v, i64 -1 +; CHECK-NEXT: store atomic ptr addrspace(10) @tag, ptr addrspace(10) [[V_HEADROOM]] unordered, align 8, !tbaa !4 %v = call noalias {} addrspace(10)* @julia.gc_alloc_obj({}** %current_task, i64 8, {} addrspace(10)* @tag) -; OPAQUE-NEXT: ret ptr addrspace(10) %v +; CHECK-NEXT: ret ptr addrspace(10) %v ret {} addrspace(10)* %v } @@ -71,20 +71,20 @@ top: %0 = bitcast {}*** %pgcstack to {}** %current_task = getelementptr inbounds {}*, {}** %0, i64 -12 -; OPAQUE: %current_task = getelementptr inbounds ptr, ptr %0, i64 -12 -; OPAQUE-NEXT: [[ptls_field:%.*]] = getelementptr inbounds ptr, ptr %current_task, i64 16 -; OPAQUE-NEXT: [[ptls_load:%.*]] = load ptr, ptr [[ptls_field]], align 8, !tbaa !0 -; OPAQUE-NEXT: %v = call noalias nonnull ptr addrspace(10) @julia.gc_alloc_bytes(ptr [[ptls_load]], [[SIZE_T:i.[0-9]+]] 8, i64 {{.*}} @tag {{.*}}) -; OPAQUE-NEXT: [[V_HEADROOM:%.*]] = getelementptr inbounds ptr addrspace(10), ptr addrspace(10) %v, i64 -1 -; OPAQUE-NEXT: store atomic ptr addrspace(10) @tag, ptr addrspace(10) [[V_HEADROOM]] unordered, align 8, !tbaa !4 +; CHECK: %current_task = getelementptr inbounds ptr, ptr %0, i64 -12 +; CHECK-NEXT: [[ptls_field:%.*]] = getelementptr inbounds i8, ptr %current_task, +; CHECK-NEXT: [[ptls_load:%.*]] = load ptr, ptr [[ptls_field]], align 8, !tbaa !0 +; CHECK-NEXT: %v = call noalias nonnull ptr addrspace(10) @julia.gc_alloc_bytes(ptr [[ptls_load]], [[SIZE_T:i.[0-9]+]] 8, i64 {{.*}} @tag {{.*}}) +; CHECK-NEXT: [[V_HEADROOM:%.*]] = getelementptr inbounds ptr addrspace(10), ptr addrspace(10) %v, i64 -1 +; CHECK-NEXT: store atomic ptr addrspace(10) @tag, ptr addrspace(10) [[V_HEADROOM]] unordered, align 8, !tbaa !4 %v = call noalias {} addrspace(10)* @julia.gc_alloc_obj({}** %current_task, i64 8, {} addrspace(10)* @tag) -; OPAQUE-NEXT: %v64 = bitcast ptr addrspace(10) %v to ptr addrspace(10) +; CHECK-NEXT: %v64 = bitcast ptr addrspace(10) %v to ptr addrspace(10) %v64 = bitcast {} addrspace(10)* %v to i64 addrspace(10)* -; OPAQUE-NEXT: %loadedval = load i64, ptr addrspace(10) %v64, align 8, !range !7 +; CHECK-NEXT: %loadedval = load i64, ptr addrspace(10) %v64, align 8, !range !7 %loadedval = load i64, i64 addrspace(10)* %v64, align 8, !range !0, !invariant.load !1 -; OPAQUE-NEXT: store i64 %loadedval, ptr addrspace(10) %v64, align 8, !noalias !8 +; CHECK-NEXT: store i64 %loadedval, ptr addrspace(10) %v64, align 8, !noalias !8 store i64 %loadedval, i64 addrspace(10)* %v64, align 8, !noalias !2 -; OPAQUE-NEXT: %lv2 = load i64, ptr addrspace(10) %v64, align 8, !tbaa !11, !range !7 +; CHECK-NEXT: %lv2 = load i64, ptr addrspace(10) %v64, align 8, !tbaa !11, !range !7 %lv2 = load i64, i64 addrspace(10)* %v64, align 8, !range !0, !tbaa !4 ; CHECK-NEXT: ret void ret void @@ -162,13 +162,13 @@ define void @decayar([2 x {} addrspace(10)* addrspace(11)*] %ar) { ; CHECK-LABEL: @decayar -; OPAQUE: %gcframe = call ptr @julia.new_gc_frame(i32 2) -; OPAQUE: [[gc_slot_addr_:%.*]]1 = call ptr @julia.get_gc_frame_slot(ptr %gcframe, i32 1) -; OPAQUE: store ptr addrspace(10) %l0, ptr [[gc_slot_addr_:%.*]], align 8 -; OPAQUE: [[gc_slot_addr_:%.*]] = call ptr @julia.get_gc_frame_slot(ptr %gcframe, i32 0) -; OPAQUE: store ptr addrspace(10) %l1, ptr [[gc_slot_addr_:%.*]], align 8 -; OPAQUE: %r = call i32 @callee_root(ptr addrspace(10) %l0, ptr addrspace(10) %l1) -; OPAQUE: call void @julia.pop_gc_frame(ptr %gcframe) +; CHECK: %gcframe = call ptr @julia.new_gc_frame(i32 2) +; CHECK: [[gc_slot_addr_:%.*]]1 = call ptr @julia.get_gc_frame_slot(ptr %gcframe, i32 1) +; CHECK: store ptr addrspace(10) %l0, ptr [[gc_slot_addr_:%.*]], align 8 +; CHECK: [[gc_slot_addr_:%.*]] = call ptr @julia.get_gc_frame_slot(ptr %gcframe, i32 0) +; CHECK: store ptr addrspace(10) %l1, ptr [[gc_slot_addr_:%.*]], align 8 +; CHECK: %r = call i32 @callee_root(ptr addrspace(10) %l0, ptr addrspace(10) %l1) +; CHECK: call void @julia.pop_gc_frame(ptr %gcframe) !0 = !{i64 0, i64 23} !1 = !{!1} diff --git a/test/llvmpasses/names.jl b/test/llvmpasses/names.jl index fe692d0fab787..1ab2204044804 100644 --- a/test/llvmpasses/names.jl +++ b/test/llvmpasses/names.jl @@ -135,7 +135,8 @@ emit(f2, Float64, Float64, Float64, Float64, Float64, Float64, Float64) # CHECK: define {{(swiftcc )?}}nonnull ptr @julia_f5 # CHECK-SAME: %"a::A" -# CHECK: %"a::A.b_ptr.c_ptr.d +# CHECK: %"a::A.d +# COM: this text check relies on our LLVM code emission being relatively poor, which is not always the case emit(f5, A) # CHECK: define {{(swiftcc )?}}nonnull ptr @julia_f6