Skip to content

Commit 2ed8561

Browse files
authored
codegen: slightly optimize gc-frame allocation (#58794)
Try to avoid allocating frames for some very simple function that only have the safepoint on entry and don't define any values themselves.
1 parent b06d260 commit 2ed8561

File tree

4 files changed

+159
-189
lines changed

4 files changed

+159
-189
lines changed

src/cgutils.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -341,11 +341,11 @@ static void find_perm_offsets(jl_datatype_t *typ, SmallVectorImpl<unsigned> &res
341341
}
342342

343343
// load a pointer to N inlined_roots into registers (as a SmallVector)
344-
static llvm::SmallVector<Value*,0> load_gc_roots(jl_codectx_t &ctx, Value *inline_roots_ptr, size_t npointers, bool isVolatile=false)
344+
static llvm::SmallVector<Value*,0> load_gc_roots(jl_codectx_t &ctx, Value *inline_roots_ptr, size_t npointers, MDNode *tbaa, bool isVolatile=false)
345345
{
346346
SmallVector<Value*,0> gcroots(npointers);
347347
Type *T_prjlvalue = ctx.types().T_prjlvalue;
348-
auto roots_ai = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_gcframe);
348+
auto roots_ai = jl_aliasinfo_t::fromTBAA(ctx, tbaa);
349349
for (size_t i = 0; i < npointers; i++) {
350350
auto *ptr = ctx.builder.CreateAlignedLoad(T_prjlvalue, emit_ptrgep(ctx, inline_roots_ptr, i * sizeof(jl_value_t*)), Align(sizeof(void*)), isVolatile);
351351
roots_ai.decorateInst(ptr);

src/codegen.cpp

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5054,7 +5054,7 @@ static jl_cgval_t emit_call_specfun_other(jl_codectx_t &ctx, bool is_opaque_clos
50545054
break;
50555055
case jl_returninfo_t::SRet:
50565056
assert(result);
5057-
retval = mark_julia_slot(result, jlretty, NULL, ctx.tbaa().tbaa_gcframe, load_gc_roots(ctx, return_roots, returninfo.return_roots));
5057+
retval = mark_julia_slot(result, jlretty, NULL, ctx.tbaa().tbaa_gcframe, load_gc_roots(ctx, return_roots, returninfo.return_roots, ctx.tbaa().tbaa_gcframe));
50585058
break;
50595059
case jl_returninfo_t::Union: {
50605060
Value *box = ctx.builder.CreateExtractValue(call, 0);
@@ -5603,7 +5603,7 @@ static jl_cgval_t emit_varinfo(jl_codectx_t &ctx, jl_varinfo_t &vi, jl_sym_t *va
56035603
T_prjlvalue = AT->getElementType();
56045604
}
56055605
assert(T_prjlvalue == ctx.types().T_prjlvalue);
5606-
v.inline_roots = load_gc_roots(ctx, varslot, nroots, vi.isVolatile);
5606+
v.inline_roots = load_gc_roots(ctx, varslot, nroots, ctx.tbaa().tbaa_gcframe, vi.isVolatile);
56075607
}
56085608
if (vi.usedUndef) {
56095609
assert(vi.defFlag);
@@ -6927,7 +6927,7 @@ static void emit_specsig_to_specsig(
69276927
auto tracked = CountTrackedPointers(et);
69286928
SmallVector<Value*,0> roots;
69296929
if (tracked.count && !tracked.all) {
6930-
roots = load_gc_roots(ctx, &*AI, tracked.count);
6930+
roots = load_gc_roots(ctx, &*AI, tracked.count, ctx.tbaa().tbaa_const);
69316931
++AI;
69326932
}
69336933
myargs[i] = mark_julia_slot(arg_v, jt, NULL, ctx.tbaa().tbaa_const, roots);
@@ -8511,7 +8511,7 @@ static jl_llvm_functions_t
85118511
ctx.spvals_ptr = &*AI++;
85128512
}
85138513
}
8514-
// step 6. set up GC frame and special arguments
8514+
// step 6a. set up special arguments and attributes
85158515
Function::arg_iterator AI = f->arg_begin();
85168516
SmallVector<AttributeSet, 0> attrs(f->arg_size()); // function declaration attributes
85178517

@@ -8558,7 +8558,11 @@ static jl_llvm_functions_t
85588558
attrs[Arg->getArgNo()] = AttributeSet::get(Arg->getContext(), param);
85598559
}
85608560

8561+
// step 6b. Setup the GC frame and entry safepoint before any loads
85618562
allocate_gc_frame(ctx, b0);
8563+
if (params.safepoint_on_entry && JL_FEAT_TEST(ctx, safepoint_on_entry))
8564+
emit_gc_safepoint(ctx.builder, ctx.types().T_size, get_current_ptls(ctx), ctx.tbaa().tbaa_const);
8565+
85628566
Value *last_age = NULL;
85638567
Value *world_age_field = NULL;
85648568
if (ctx.is_opaque_closure) {
@@ -8716,7 +8720,14 @@ static jl_llvm_functions_t
87168720
SmallVector<Value*,0> roots;
87178721
auto tracked = CountTrackedPointers(llvmArgType);
87188722
if (tracked.count && !tracked.all) {
8719-
roots = load_gc_roots(ctx, &*AI, tracked.count);
8723+
Argument *RootArg = &*AI;
8724+
roots = load_gc_roots(ctx, RootArg, tracked.count, ctx.tbaa().tbaa_const);
8725+
AttrBuilder param(ctx.builder.getContext(), f->getAttributes().getParamAttrs(Arg->getArgNo()));
8726+
param.addAttribute(Attribute::NonNull);
8727+
param.addAttribute(Attribute::NoUndef);
8728+
param.addDereferenceableAttr(tracked.count * sizeof(void*));
8729+
param.addAlignmentAttr(alignof(void*));
8730+
attrs[RootArg->getArgNo()] = AttributeSet::get(Arg->getContext(), param);
87208731
++AI;
87218732
}
87228733
theArg = mark_julia_slot(Arg, argType, NULL, ctx.tbaa().tbaa_const, roots); // this argument is by-pointer
@@ -9026,11 +9037,7 @@ static jl_llvm_functions_t
90269037

90279038
Instruction &prologue_end = ctx.builder.GetInsertBlock()->back();
90289039

9029-
// step 11a. Emit the entry safepoint
9030-
if (params.safepoint_on_entry && JL_FEAT_TEST(ctx, safepoint_on_entry))
9031-
emit_gc_safepoint(ctx.builder, ctx.types().T_size, get_current_ptls(ctx), ctx.tbaa().tbaa_const);
9032-
9033-
// step 11b. Do codegen in control flow order
9040+
// step 11. Do codegen in control flow order
90349041
SmallVector<int, 0> workstack;
90359042
DenseMap<size_t, BasicBlock*> BB;
90369043
DenseMap<size_t, BasicBlock*> come_from_bb;

src/llvm-gc-interface-passes.h

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -251,11 +251,13 @@ struct BBState {
251251
// These get updated during dataflow
252252
LargeSparseBitVector LiveIn;
253253
LargeSparseBitVector LiveOut;
254-
SmallVector<int, 0> Safepoints;
255-
int TopmostSafepoint = -1;
254+
// auto Safepoints = std::range(LastSafepoint, FirstSafepoint);
256255
bool HasSafepoint = false;
257-
// Have we gone through this basic block in our local scan yet?
258-
bool Done = false;
256+
// This lets us refine alloca tracking to avoid creating GC frames in
257+
// some simple functions that only have the initial safepoint.
258+
int FirstSafepoint = -1;
259+
int LastSafepoint = -1;
260+
int FirstSafepointAfterFirstDef = -1;
259261
};
260262

261263
struct State {
@@ -292,21 +294,18 @@ struct State {
292294
// of its uses need to preserve the values listed in the map value.
293295
std::map<Instruction *, SmallVector<int, 0>> GCPreserves;
294296

295-
// The assignment of numbers to safepoints. The indices in the map
296-
// are indices into the next three maps which store safepoint properties
297-
std::map<Instruction *, int> SafepointNumbering;
297+
// The assignment of numbers to safepoints. These have the same ordering as
298+
// LiveSets, LiveIfLiveOut, and CalleeRoots.
299+
SmallVector<Instruction*, 0> SafepointNumbering;
298300

299-
// Reverse mapping index -> safepoint
300-
SmallVector<Instruction *, 0> ReverseSafepointNumbering;
301-
302-
// Instructions that can return twice. For now, all values live at these
303-
// instructions will get their own, dedicated GC frame slots, because they
304-
// have unobservable control flow, so we can't be sure where they're
305-
// actually live. All of these are also considered safepoints.
306-
SmallVector<Instruction *, 0> ReturnsTwice;
301+
// Safepoint number of instructions that can return twice. For now, all
302+
// values live at these instructions will get their own, dedicated GC frame
303+
// slots, because they have unobservable control flow, so we can't be sure
304+
// where they're actually live.
305+
SmallVector<int, 0> ReturnsTwice;
307306

308307
// The set of values live at a particular safepoint
309-
SmallVector< LargeSparseBitVector , 0> LiveSets;
308+
SmallVector<LargeSparseBitVector, 0> LiveSets;
310309
// Those values that - if live out from our parent basic block - are live
311310
// at this safepoint.
312311
SmallVector<SmallVector<int, 0>> LiveIfLiveOut;
@@ -332,7 +331,7 @@ struct LateLowerGCFrame: private JuliaPassContext {
332331
Value *pgcstack;
333332
Function *smallAllocFunc;
334333

335-
void MaybeNoteDef(State &S, BBState &BBS, Value *Def, const ArrayRef<int> &SafepointsSoFar,
334+
bool MaybeNoteDef(State &S, BBState &BBS, Value *Def,
336335
SmallVector<int, 1> &&RefinedPtr = SmallVector<int, 1>());
337336
void NoteUse(State &S, BBState &BBS, Value *V, LargeSparseBitVector &Uses, Function &F);
338337
void NoteUse(State &S, BBState &BBS, Value *V, Function &F) {

0 commit comments

Comments
 (0)