|
| 1 | +// This file is a part of Julia. License is MIT: https://julialang.org/license |
| 2 | + |
| 3 | +#define DEBUG_TYPE "gc_safepoint" |
| 4 | +#undef DEBUG |
| 5 | +#include "llvm-version.h" |
| 6 | + |
| 7 | +#include <llvm-c/Core.h> |
| 8 | +#include <llvm-c/Types.h> |
| 9 | + |
| 10 | +#include <llvm/IR/Value.h> |
| 11 | +#include <llvm/IR/LegacyPassManager.h> |
| 12 | +#include <llvm/Analysis/LoopInfo.h> |
| 13 | +#include <llvm/IR/Function.h> |
| 14 | +#include <llvm/IR/Instructions.h> |
| 15 | +#include <llvm/IR/IntrinsicInst.h> |
| 16 | +#include <llvm/IR/Module.h> |
| 17 | +#include <llvm/IR/Operator.h> |
| 18 | +#include <llvm/IR/IRBuilder.h> |
| 19 | +#include <llvm/Pass.h> |
| 20 | +#include <llvm/Support/Debug.h> |
| 21 | + |
| 22 | +#include "codegen_shared.h" |
| 23 | +#include "julia.h" |
| 24 | +#include "julia_internal.h" |
| 25 | +#include "julia_assert.h" |
| 26 | +#include "llvm-pass-helpers.h" |
| 27 | + |
| 28 | +using namespace llvm; |
| 29 | + |
| 30 | +struct GCSafepoint : public FunctionPass, private JuliaPassContext { |
| 31 | + static char ID; |
| 32 | + GCSafepoint() : FunctionPass(ID) |
| 33 | + {} |
| 34 | + |
| 35 | +protected: |
| 36 | + void getAnalysisUsage(AnalysisUsage &AU) const override |
| 37 | + { |
| 38 | + AU.addRequired<LoopInfoWrapperPass>(); |
| 39 | + AU.addPreserved<LoopInfoWrapperPass>(); |
| 40 | + } |
| 41 | + |
| 42 | +private: |
| 43 | + CallInst *pgcstack; |
| 44 | + void emitGCSafepoint(IRBuilder<> &B); |
| 45 | + Value *getCurrentSignalPage(IRBuilder<> &B); |
| 46 | + |
| 47 | + bool runOnFunction(Function &F) override; |
| 48 | +}; |
| 49 | + |
| 50 | +Value *GCSafepoint::getCurrentSignalPage(IRBuilder<> &B) |
| 51 | +{ |
| 52 | + assert(pgcstack); |
| 53 | + int nthfield = offsetof(jl_tls_states_t, safepoint) / sizeof(void *); |
| 54 | + Value *field = B.CreateInBoundsGEP(T_ppjlvalue, pgcstack, ConstantInt::get(T_size, nthfield)); |
| 55 | + field = B.CreateBitCast(field, PointerType::get(PointerType::get(T_size, 0), 0)); |
| 56 | + // TODO: TBAA annotation |
| 57 | + return B.CreateLoad(field); |
| 58 | +} |
| 59 | + |
| 60 | +void GCSafepoint::emitGCSafepoint(IRBuilder<> &B) |
| 61 | +{ |
| 62 | + B.CreateCall(getOrDeclare(jl_intrinsics::GCRootFlush)); |
| 63 | + B.CreateFence(AtomicOrdering::SequentiallyConsistent, SyncScope::SingleThread); |
| 64 | + B.CreateLoad(T_size, getCurrentSignalPage(B), true); |
| 65 | + B.CreateFence(AtomicOrdering::SequentiallyConsistent, SyncScope::SingleThread); |
| 66 | +} |
| 67 | + |
| 68 | +bool GCSafepoint::runOnFunction(Function &F) |
| 69 | +{ |
| 70 | + LLVM_DEBUG(dbgs() << "GCSafepoint: Processing function " << F.getName() << "\n"); |
| 71 | + // Check availability of functions again since they might have been deleted. |
| 72 | + initAll(*F.getParent()); |
| 73 | + |
| 74 | + IRBuilder<> B(F.getEntryBlock().getFirstNonPHI()); |
| 75 | + |
| 76 | + pgcstack = getPGCstack(F); |
| 77 | + if (!pgcstack) { |
| 78 | + LLVM_DEBUG(dbgs() << "GCSafepoint: Function " << F.getName() << " has no pgcstack, inserting one\n"); |
| 79 | + pgcstack = B.CreateCall(getOrDeclare(jl_intrinsics::getPGCStack)); |
| 80 | + } |
| 81 | + B.SetInsertPoint(pgcstack->getNextNode()); |
| 82 | + |
| 83 | + LLVM_DEBUG(dbgs() << "GCSafepoint: Inserting Safepoint at function entry of " << F.getName() << "\n"); |
| 84 | + emitGCSafepoint(B); |
| 85 | + |
| 86 | + LoopInfo &LI = getAnalysis<LoopInfoWrapperPass>(F).getLoopInfo(); |
| 87 | + for (auto *Loop : LI.getLoopsInPreorder()) { |
| 88 | + // Iterate over backedges |
| 89 | + BasicBlock *Header = Loop->getHeader(); |
| 90 | + for (const auto Edge : children<Inverse<BasicBlock *>>(Header)) { |
| 91 | + if (!Loop->contains(Edge)) |
| 92 | + continue; |
| 93 | + B.SetInsertPoint(Edge->getTerminator()); |
| 94 | + LLVM_DEBUG(dbgs() << "GCSafepoint: Inserting Safepoint at loop backedge: " << *Edge << "\n"); |
| 95 | + emitGCSafepoint(B); |
| 96 | + } |
| 97 | + } |
| 98 | + |
| 99 | + return true; |
| 100 | +} |
| 101 | + |
| 102 | +char GCSafepoint::ID = 0; |
| 103 | +static RegisterPass<GCSafepoint> X("GCSafepoint", "Insert safepoints", |
| 104 | + false /* Only looks at CFG */, |
| 105 | + false /* Analysis Pass */); |
| 106 | + |
| 107 | +Pass *createGCSafepointPass() |
| 108 | +{ |
| 109 | + return new GCSafepoint(); |
| 110 | +} |
| 111 | + |
| 112 | +extern "C" JL_DLLEXPORT void LLVMExtraAddGCSafepointPass(LLVMPassManagerRef PM) |
| 113 | +{ |
| 114 | + unwrap(PM)->add(createGCSafepointPass()); |
| 115 | +} |
0 commit comments