Skip to content

Commit ece8814

Browse files
committed
codegen: optimize const fields of mutable objects
For example, we seek to eliminate the gc frame from this function, as observed here: ```julia julia> code_llvm((BitSet,), raw=true) do x; r = x.bits; GC.safepoint(); @inbounds r[1]; end ; Function Signature: var"mmtk#3"(Base.BitSet) ; @ REPL[1]:1 within `mmtk#3` define swiftcc i64 @"julia_#3_494"(ptr nonnull swiftself %pgcstack, ptr noundef nonnull align 8 dereferenceable(16) %"x::BitSet") #0 !dbg !5 { top: call void @llvm.dbg.declare(metadata ptr %"x::BitSet", metadata !21, metadata !DIExpression()), !dbg !22 %ptls_field = getelementptr inbounds ptr, ptr %pgcstack, i64 2 %ptls_load = load ptr, ptr %ptls_field, align 8, !tbaa !23 %0 = getelementptr inbounds ptr, ptr %ptls_load, i64 2 %safepoint = load ptr, ptr %0, align 8, !tbaa !27 fence syncscope("singlethread") seq_cst %1 = load volatile i64, ptr %safepoint, align 8, !dbg !22 fence syncscope("singlethread") seq_cst ; ┌ @ Base.jl:49 within `getproperty` %"x::BitSet.bits" = load atomic ptr, ptr %"x::BitSet" unordered, align 8, !dbg !29, !tbaa !27, !alias.scope !33, !noalias !36, !nonnull !11, !dereferenceable !41, !align !42 ; └ ; ┌ @ gcutils.jl:253 within `safepoint` %ptls_load4 = load ptr, ptr %ptls_field, align 8, !dbg !43, !tbaa !23 %2 = getelementptr inbounds ptr, ptr %ptls_load4, i64 2, !dbg !43 %safepoint5 = load ptr, ptr %2, align 8, !dbg !43, !tbaa !27 fence syncscope("singlethread") seq_cst, !dbg !43 %3 = load volatile i64, ptr %safepoint5, align 8, !dbg !43 fence syncscope("singlethread") seq_cst, !dbg !43 ; └ ; ┌ @ essentials.jl:892 within `getindex` %4 = load ptr, ptr %"x::BitSet.bits", align 8, !dbg !46, !tbaa !49, !alias.scope !52, !noalias !53 %5 = load i64, ptr %4, align 8, !dbg !46, !tbaa !54, !alias.scope !57, !noalias !58 ret i64 %5, !dbg !46 ; └ } ```
1 parent f66fd47 commit ece8814

File tree

2 files changed

+32
-42
lines changed

2 files changed

+32
-42
lines changed

src/cgutils.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -2664,6 +2664,8 @@ static MDNode *best_field_tbaa(jl_codectx_t &ctx, const jl_cgval_t &strct, jl_da
26642664
return ctx.tbaa().tbaa_arraysize;
26652665
}
26662666
}
2667+
if (strct.V && jl_field_isconst(jt, idx) && isa<Argument>(strct.V->stripInBoundsOffsets())) // TODO: we use our isLoadFromConstGV helper here instead instead of just isa<Argument> (but without PhiNode handling)
2668+
return ctx.tbaa().tbaa_const;
26672669
return tbaa;
26682670
}
26692671

src/codegen.cpp

+30-42
Original file line numberDiff line numberDiff line change
@@ -8267,18 +8267,18 @@ static jl_llvm_functions_t
82678267

82688268
// step 7. allocate local variables slots
82698269
// must be in the first basic block for the llvm mem2reg pass to work
8270-
auto allocate_local = [&](jl_varinfo_t &varinfo, jl_sym_t *s) {
8270+
auto allocate_local = [&ctx, &dbuilder, &debuginfo, topdebugloc, va, debug_enabled, M](jl_varinfo_t &varinfo, jl_sym_t *s, int i) {
82718271
jl_value_t *jt = varinfo.value.typ;
82728272
assert(!varinfo.boxroot); // variables shouldn't have memory locs already
82738273
if (varinfo.value.constant) {
82748274
// no need to explicitly load/store a constant/ghost value
82758275
alloc_def_flag(ctx, varinfo);
82768276
return;
82778277
}
8278-
else if (varinfo.isArgument && !(specsig && i == (size_t)ctx.vaSlot)) {
8279-
// if we can unbox it, just use the input pointer
8280-
if (i != (size_t)ctx.vaSlot && jl_is_concrete_immutable(jt))
8281-
return;
8278+
else if (varinfo.isArgument && (!va || ctx.vaSlot == -1 || i != ctx.vaSlot)) {
8279+
// just use the input pointer, if we have it
8280+
// (we will need to attach debuginfo later to it)
8281+
return;
82828282
}
82838283
else if (jl_is_uniontype(jt)) {
82848284
bool allunbox;
@@ -8289,6 +8289,7 @@ static jl_llvm_functions_t
82898289
varinfo.value = mark_julia_slot(lv, jt, NULL, ctx.tbaa().tbaa_stack);
82908290
varinfo.pTIndex = emit_static_alloca(ctx, getInt8Ty(ctx.builder.getContext()));
82918291
setName(ctx.emission_context, varinfo.pTIndex, "tindex");
8292+
// TODO: attach debug metadata to this variable
82928293
}
82938294
else if (allunbox) {
82948295
// all ghost values just need a selector allocated
@@ -8297,6 +8298,7 @@ static jl_llvm_functions_t
82978298
varinfo.pTIndex = lv;
82988299
varinfo.value.tbaa = NULL;
82998300
varinfo.value.isboxed = false;
8301+
// TODO: attach debug metadata to this variable
83008302
}
83018303
if (lv || allunbox)
83028304
alloc_def_flag(ctx, varinfo);
@@ -8323,29 +8325,21 @@ static jl_llvm_functions_t
83238325
}
83248326
return;
83258327
}
8326-
if (!varinfo.isArgument || // always need a slot if the variable is assigned
8327-
specsig || // for arguments, give them stack slots if they aren't in `argArray` (otherwise, will use that pointer)
8328-
(va && (int)i == ctx.vaSlot) || // or it's the va arg tuple
8329-
i == 0) { // or it is the first argument (which isn't in `argArray`)
8330-
AllocaInst *av = new AllocaInst(ctx.types().T_prjlvalue, M->getDataLayout().getAllocaAddrSpace(),
8331-
nullptr, Align(sizeof(jl_value_t*)), jl_symbol_name(s), /*InsertBefore*/ctx.topalloca);
8332-
StoreInst *SI = new StoreInst(Constant::getNullValue(ctx.types().T_prjlvalue), av, false, Align(sizeof(void*)));
8333-
SI->insertAfter(ctx.topalloca);
8334-
varinfo.boxroot = av;
8335-
if (debug_enabled && varinfo.dinfo) {
8336-
DIExpression *expr;
8337-
if ((Metadata*)varinfo.dinfo->getType() == debuginfo.jl_pvalue_dillvmt) {
8338-
expr = dbuilder.createExpression();
8339-
}
8340-
else {
8341-
SmallVector<uint64_t, 8> addr;
8342-
addr.push_back(llvm::dwarf::DW_OP_deref);
8343-
expr = dbuilder.createExpression(addr);
8344-
}
8345-
dbuilder.insertDeclare(av, varinfo.dinfo, expr,
8346-
topdebugloc,
8347-
ctx.builder.GetInsertBlock());
8348-
}
8328+
// otherwise give it a boxroot in this function
8329+
AllocaInst *av = new AllocaInst(ctx.types().T_prjlvalue, M->getDataLayout().getAllocaAddrSpace(),
8330+
nullptr, Align(sizeof(jl_value_t*)), jl_symbol_name(s), /*InsertBefore*/ctx.topalloca);
8331+
StoreInst *SI = new StoreInst(Constant::getNullValue(ctx.types().T_prjlvalue), av, false, Align(sizeof(void*)));
8332+
SI->insertAfter(ctx.topalloca);
8333+
varinfo.boxroot = av;
8334+
if (debug_enabled && varinfo.dinfo) {
8335+
SmallVector<uint64_t, 1> addr;
8336+
DIExpression *expr;
8337+
if ((Metadata*)varinfo.dinfo->getType() != debuginfo.jl_pvalue_dillvmt)
8338+
addr.push_back(llvm::dwarf::DW_OP_deref);
8339+
expr = dbuilder.createExpression(addr);
8340+
dbuilder.insertDeclare(av, varinfo.dinfo, expr,
8341+
topdebugloc,
8342+
ctx.builder.GetInsertBlock());
83498343
}
83508344
};
83518345

@@ -8359,7 +8353,7 @@ static jl_llvm_functions_t
83598353
varinfo.usedUndef = false;
83608354
continue;
83618355
}
8362-
allocate_local(varinfo, s);
8356+
allocate_local(varinfo, s, (int)i);
83638357
}
83648358

83658359
std::map<int, int> upsilon_to_phic;
@@ -8402,7 +8396,7 @@ static jl_llvm_functions_t
84028396
vi.used = true;
84038397
vi.isVolatile = true;
84048398
vi.value = mark_julia_type(ctx, (Value*)NULL, false, typ);
8405-
allocate_local(vi, jl_symbol("phic"));
8399+
allocate_local(vi, jl_symbol("phic"), -1);
84068400
}
84078401
}
84088402
}
@@ -8542,7 +8536,7 @@ static jl_llvm_functions_t
85428536
ctx.builder.CreateAlignedLoad(ctx.types().T_prjlvalue, argPtr, Align(sizeof(void*))),
85438537
false, vi.value.typ));
85448538
theArg = mark_julia_type(ctx, load, true, vi.value.typ);
8545-
if (debug_enabled && vi.dinfo && !vi.boxroot && !vi.value.V) {
8539+
if (debug_enabled && vi.dinfo && !vi.boxroot) {
85468540
SmallVector<uint64_t, 8> addr;
85478541
addr.push_back(llvm::dwarf::DW_OP_deref);
85488542
addr.push_back(llvm::dwarf::DW_OP_plus_uconst);
@@ -8561,21 +8555,15 @@ static jl_llvm_functions_t
85618555
assert(vi.value.V == NULL && "unexpected variable slot created for argument");
85628556
// keep track of original (possibly boxed) value to avoid re-boxing or moving
85638557
vi.value = theArg;
8564-
if (specsig && theArg.V && debug_enabled && vi.dinfo) {
8565-
SmallVector<uint64_t, 8> addr;
8566-
Value *parg;
8558+
if (debug_enabled && vi.dinfo && theArg.V) {
85678559
if (theArg.ispointer()) {
8568-
parg = theArg.V;
8569-
if ((Metadata*)vi.dinfo->getType() != debuginfo.jl_pvalue_dillvmt)
8570-
addr.push_back(llvm::dwarf::DW_OP_deref);
8560+
dbuilder.insertDeclare(theArg.V, vi.dinfo, dbuilder.createExpression(),
8561+
topdebugloc, ctx.builder.GetInsertBlock());
85718562
}
85728563
else {
8573-
parg = ctx.builder.CreateAlloca(theArg.V->getType(), NULL, jl_symbol_name(s));
8574-
ctx.builder.CreateStore(theArg.V, parg);
8564+
dbuilder.insertDbgValueIntrinsic(theArg.V, vi.dinfo, dbuilder.createExpression(),
8565+
topdebugloc, ctx.builder.GetInsertBlock());
85758566
}
8576-
dbuilder.insertDeclare(parg, vi.dinfo, dbuilder.createExpression(addr),
8577-
topdebugloc,
8578-
ctx.builder.GetInsertBlock());
85798567
}
85808568
}
85818569
else {

0 commit comments

Comments
 (0)