Skip to content

Commit fe2f830

Browse files
vchuravyRAI CI (GitHub Action Automation)
authored andcommitted
Move safepoint emission to llvm-final-gc-lowering (JuliaLang#47393)
1 parent e805a1b commit fe2f830

File tree

5 files changed

+85
-19
lines changed

5 files changed

+85
-19
lines changed

src/codegen_shared.h

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <utility>
44
#include <llvm/ADT/ArrayRef.h>
55
#include <llvm/Support/Debug.h>
6+
#include <llvm/IR/Attributes.h>
67
#include <llvm/IR/DebugLoc.h>
78
#include <llvm/IR/IRBuilder.h>
89
#include <llvm/IR/MDBuilder.h>
@@ -233,20 +234,39 @@ static inline void emit_signal_fence(llvm::IRBuilder<> &builder)
233234
builder.CreateFence(AtomicOrdering::SequentiallyConsistent, SyncScope::SingleThread);
234235
}
235236

236-
static inline void emit_gc_safepoint(llvm::IRBuilder<> &builder, llvm::Value *ptls, llvm::MDNode *tbaa)
237+
static inline void emit_gc_safepoint(llvm::IRBuilder<> &builder, llvm::Value *ptls, llvm::MDNode *tbaa, bool final = false)
237238
{
239+
using namespace llvm;
240+
llvm::Value *signal_page = get_current_signal_page_from_ptls(builder, ptls, tbaa);
238241
emit_signal_fence(builder);
239-
builder.CreateLoad(getSizeTy(builder.getContext()), get_current_signal_page_from_ptls(builder, ptls, tbaa), true);
242+
Module *M = builder.GetInsertBlock()->getModule();
243+
LLVMContext &C = builder.getContext();
244+
// inline jlsafepoint_func->realize(M)
245+
if (final) {
246+
auto T_size = getSizeTy(builder.getContext());
247+
builder.CreateLoad(T_size, signal_page, true);
248+
}
249+
else {
250+
Function *F = M->getFunction("julia.safepoint");
251+
if (!F) {
252+
auto T_size = getSizeTy(builder.getContext());
253+
auto T_psize = T_size->getPointerTo();
254+
FunctionType *FT = FunctionType::get(Type::getVoidTy(C), {T_psize}, false);
255+
F = Function::Create(FT, Function::ExternalLinkage, "julia.safepoint", M);
256+
F->addFnAttr(Attribute::InaccessibleMemOrArgMemOnly);
257+
}
258+
builder.CreateCall(F, {signal_page});
259+
}
240260
emit_signal_fence(builder);
241261
}
242262

243-
static inline llvm::Value *emit_gc_state_set(llvm::IRBuilder<> &builder, llvm::Value *ptls, llvm::Value *state, llvm::Value *old_state)
263+
static inline llvm::Value *emit_gc_state_set(llvm::IRBuilder<> &builder, llvm::Value *ptls, llvm::Value *state, llvm::Value *old_state, bool final)
244264
{
245265
using namespace llvm;
246266
Type *T_int8 = state->getType();
247-
ptls = emit_bitcast_with_builder(builder, ptls, builder.getInt8PtrTy());
267+
llvm::Value *ptls_i8 = emit_bitcast_with_builder(builder, ptls, builder.getInt8PtrTy());
248268
Constant *offset = ConstantInt::getSigned(builder.getInt32Ty(), offsetof(jl_tls_states_t, gc_state));
249-
Value *gc_state = builder.CreateInBoundsGEP(T_int8, ptls, ArrayRef<Value*>(offset), "gc_state");
269+
Value *gc_state = builder.CreateInBoundsGEP(T_int8, ptls_i8, ArrayRef<Value*>(offset), "gc_state");
250270
if (old_state == nullptr) {
251271
old_state = builder.CreateLoad(T_int8, gc_state);
252272
cast<LoadInst>(old_state)->setOrdering(AtomicOrdering::Monotonic);
@@ -266,38 +286,38 @@ static inline llvm::Value *emit_gc_state_set(llvm::IRBuilder<> &builder, llvm::V
266286
passBB, exitBB);
267287
builder.SetInsertPoint(passBB);
268288
MDNode *tbaa = get_tbaa_const(builder.getContext());
269-
emit_gc_safepoint(builder, ptls, tbaa);
289+
emit_gc_safepoint(builder, ptls, tbaa, final);
270290
builder.CreateBr(exitBB);
271291
builder.SetInsertPoint(exitBB);
272292
return old_state;
273293
}
274294

275-
static inline llvm::Value *emit_gc_unsafe_enter(llvm::IRBuilder<> &builder, llvm::Value *ptls)
295+
static inline llvm::Value *emit_gc_unsafe_enter(llvm::IRBuilder<> &builder, llvm::Value *ptls, bool final)
276296
{
277297
using namespace llvm;
278298
Value *state = builder.getInt8(0);
279-
return emit_gc_state_set(builder, ptls, state, nullptr);
299+
return emit_gc_state_set(builder, ptls, state, nullptr, final);
280300
}
281301

282-
static inline llvm::Value *emit_gc_unsafe_leave(llvm::IRBuilder<> &builder, llvm::Value *ptls, llvm::Value *state)
302+
static inline llvm::Value *emit_gc_unsafe_leave(llvm::IRBuilder<> &builder, llvm::Value *ptls, llvm::Value *state, bool final)
283303
{
284304
using namespace llvm;
285305
Value *old_state = builder.getInt8(0);
286-
return emit_gc_state_set(builder, ptls, state, old_state);
306+
return emit_gc_state_set(builder, ptls, state, old_state, final);
287307
}
288308

289-
static inline llvm::Value *emit_gc_safe_enter(llvm::IRBuilder<> &builder, llvm::Value *ptls)
309+
static inline llvm::Value *emit_gc_safe_enter(llvm::IRBuilder<> &builder, llvm::Value *ptls, bool final)
290310
{
291311
using namespace llvm;
292312
Value *state = builder.getInt8(JL_GC_STATE_SAFE);
293-
return emit_gc_state_set(builder, ptls, state, nullptr);
313+
return emit_gc_state_set(builder, ptls, state, nullptr, final);
294314
}
295315

296-
static inline llvm::Value *emit_gc_safe_leave(llvm::IRBuilder<> &builder, llvm::Value *ptls, llvm::Value *state)
316+
static inline llvm::Value *emit_gc_safe_leave(llvm::IRBuilder<> &builder, llvm::Value *ptls, llvm::Value *state, bool final)
297317
{
298318
using namespace llvm;
299319
Value *old_state = builder.getInt8(JL_GC_STATE_SAFE);
300-
return emit_gc_state_set(builder, ptls, state, old_state);
320+
return emit_gc_state_set(builder, ptls, state, old_state, final);
301321
}
302322

303323
// Compatibility shims for LLVM attribute APIs that were renamed in LLVM 14.

src/llvm-final-gc-lowering.cpp

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ STATISTIC(GetGCFrameSlotCount, "Number of lowered getGCFrameSlotFunc intrinsics"
2727
STATISTIC(GCAllocBytesCount, "Number of lowered GCAllocBytesFunc intrinsics");
2828
STATISTIC(QueueGCRootCount, "Number of lowered queueGCRootFunc intrinsics");
2929
STATISTIC(QueueGCBindingCount, "Number of lowered queueGCBindingFunc intrinsics");
30+
STATISTIC(SafepointCount, "Number of lowered safepoint intrinsics");
3031

3132
using namespace llvm;
3233

@@ -72,6 +73,9 @@ struct FinalLowerGC: private JuliaPassContext {
7273

7374
// Lowers a `julia.queue_gc_binding` intrinsic.
7475
Value *lowerQueueGCBinding(CallInst *target, Function &F);
76+
77+
// Lowers a `julia.safepoint` intrinsic.
78+
Value *lowerSafepoint(CallInst *target, Function &F);
7579
};
7680

7781
Value *FinalLowerGC::lowerNewGCFrame(CallInst *target, Function &F)
@@ -202,6 +206,18 @@ Value *FinalLowerGC::lowerQueueGCBinding(CallInst *target, Function &F)
202206
return target;
203207
}
204208

209+
Value *FinalLowerGC::lowerSafepoint(CallInst *target, Function &F)
210+
{
211+
++SafepointCount;
212+
assert(target->arg_size() == 1);
213+
IRBuilder<> builder(target->getContext());
214+
builder.SetInsertPoint(target);
215+
auto T_size = getSizeTy(builder.getContext());
216+
Value* signal_page = target->getOperand(0);
217+
Value* load = builder.CreateLoad(T_size, signal_page, true);
218+
return load;
219+
}
220+
205221
Value *FinalLowerGC::lowerGCAllocBytes(CallInst *target, Function &F)
206222
{
207223
++GCAllocBytesCount;
@@ -317,16 +333,20 @@ static void replaceInstruction(
317333

318334
bool FinalLowerGC::runOnFunction(Function &F)
319335
{
320-
LLVM_DEBUG(dbgs() << "FINAL GC LOWERING: Processing function " << F.getName() << "\n");
321336
// Check availability of functions again since they might have been deleted.
322337
initFunctions(*F.getParent());
323-
if (!pgcstack_getter && !adoptthread_func)
338+
if (!pgcstack_getter && !adoptthread_func) {
339+
LLVM_DEBUG(dbgs() << "FINAL GC LOWERING: Skipping function " << F.getName() << "\n");
324340
return false;
341+
}
325342

326343
// Look for a call to 'julia.get_pgcstack'.
327344
pgcstack = getPGCstack(F);
328-
if (!pgcstack)
345+
if (!pgcstack) {
346+
LLVM_DEBUG(dbgs() << "FINAL GC LOWERING: Skipping function " << F.getName() << " no pgcstack\n");
329347
return false;
348+
}
349+
LLVM_DEBUG(dbgs() << "FINAL GC LOWERING: Processing function " << F.getName() << "\n");
330350

331351
// Acquire intrinsic functions.
332352
auto newGCFrameFunc = getOrNull(jl_intrinsics::newGCFrame);
@@ -336,6 +356,7 @@ bool FinalLowerGC::runOnFunction(Function &F)
336356
auto GCAllocBytesFunc = getOrNull(jl_intrinsics::GCAllocBytes);
337357
auto queueGCRootFunc = getOrNull(jl_intrinsics::queueGCRoot);
338358
auto queueGCBindingFunc = getOrNull(jl_intrinsics::queueGCBinding);
359+
auto safepointFunc = getOrNull(jl_intrinsics::safepoint);
339360

340361
// Lower all calls to supported intrinsics.
341362
for (BasicBlock &BB : F) {
@@ -347,6 +368,7 @@ bool FinalLowerGC::runOnFunction(Function &F)
347368
}
348369

349370
Value *callee = CI->getCalledOperand();
371+
assert(callee);
350372

351373
if (callee == newGCFrameFunc) {
352374
replaceInstruction(CI, lowerNewGCFrame(CI, F), it);
@@ -371,6 +393,10 @@ bool FinalLowerGC::runOnFunction(Function &F)
371393
else if (callee == queueGCBindingFunc) {
372394
replaceInstruction(CI, lowerQueueGCBinding(CI, F), it);
373395
}
396+
else if (callee == safepointFunc) {
397+
lowerSafepoint(CI, F);
398+
it = CI->eraseFromParent();
399+
}
374400
else {
375401
++it;
376402
}

src/llvm-pass-helpers.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ namespace jl_intrinsics {
119119
static const char *POP_GC_FRAME_NAME = "julia.pop_gc_frame";
120120
static const char *QUEUE_GC_ROOT_NAME = "julia.queue_gc_root";
121121
static const char *QUEUE_GC_BINDING_NAME = "julia.queue_gc_binding";
122+
static const char *SAFEPOINT_NAME = "julia.safepoint";
122123

123124
static auto T_size_t(const JuliaPassContext &context) {
124125
return sizeof(size_t) == sizeof(uint32_t) ?
@@ -229,6 +230,22 @@ namespace jl_intrinsics {
229230
intrinsic->addFnAttr(Attribute::InaccessibleMemOrArgMemOnly);
230231
return intrinsic;
231232
});
233+
234+
const IntrinsicDescription safepoint(
235+
SAFEPOINT_NAME,
236+
[](const JuliaPassContext &context) {
237+
auto T_size = getSizeTy(context.getLLVMContext());
238+
auto T_psize = T_size->getPointerTo();
239+
auto intrinsic = Function::Create(
240+
FunctionType::get(
241+
Type::getVoidTy(context.getLLVMContext()),
242+
{T_psize},
243+
false),
244+
Function::ExternalLinkage,
245+
SAFEPOINT_NAME);
246+
intrinsic->addFnAttr(Attribute::InaccessibleMemOrArgMemOnly);
247+
return intrinsic;
248+
});
232249
}
233250

234251
namespace jl_well_known {

src/llvm-pass-helpers.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,9 @@ namespace jl_intrinsics {
129129

130130
// `julia.queue_gc_binding`: an intrinsic that queues a binding for GC.
131131
extern const IntrinsicDescription queueGCBinding;
132+
133+
// `julia.safepoint`: an intrinsic that triggers a GC safepoint.
134+
extern const IntrinsicDescription safepoint;
132135
}
133136

134137
// A namespace for well-known Julia runtime function descriptions.

src/llvm-ptls.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ void LowerPTLS::fix_pgcstack_use(CallInst *pgcstack, Function *pgcstack_getter,
207207
IRBuilder<> builder(fastTerm->getParent());
208208
fastTerm->removeFromParent();
209209
MDNode *tbaa = tbaa_gcframe;
210-
Value *prior = emit_gc_unsafe_enter(builder, get_current_ptls_from_task(builder, get_current_task_from_pgcstack(builder, pgcstack), tbaa));
210+
Value *prior = emit_gc_unsafe_enter(builder, get_current_ptls_from_task(builder, get_current_task_from_pgcstack(builder, pgcstack), tbaa), true);
211211
builder.Insert(fastTerm);
212212
phi->addIncoming(pgcstack, fastTerm->getParent());
213213
// emit pre-return cleanup
@@ -219,7 +219,7 @@ void LowerPTLS::fix_pgcstack_use(CallInst *pgcstack, Function *pgcstack_getter,
219219
for (auto &BB : *pgcstack->getParent()->getParent()) {
220220
if (isa<ReturnInst>(BB.getTerminator())) {
221221
IRBuilder<> builder(BB.getTerminator());
222-
emit_gc_unsafe_leave(builder, get_current_ptls_from_task(builder, get_current_task_from_pgcstack(builder, phi), tbaa), last_gc_state);
222+
emit_gc_unsafe_leave(builder, get_current_ptls_from_task(builder, get_current_task_from_pgcstack(builder, phi), tbaa), last_gc_state, true);
223223
}
224224
}
225225
}

0 commit comments

Comments
 (0)