|
| 1 | +// This file is a part of Julia. License is MIT: https://julialang.org/license |
| 2 | + |
1 | 3 | #include "llvm-gc-interface-passes.h"
|
2 | 4 |
|
3 | 5 | void LateLowerGCFrame::CleanupGCPreserve(Function &F, CallInst *CI, Value *callee, Type *T_size) {
|
@@ -45,3 +47,99 @@ void LateLowerGCFrame::CleanupGCPreserve(Function &F, CallInst *CI, Value *calle
|
45 | 47 | builder.CreateCall(getOrDeclare(jl_well_known::GCPreserveEndHook), {});
|
46 | 48 | }
|
47 | 49 | }
|
| 50 | + |
| 51 | +Value* LateLowerGCFrame::lowerGCAllocBytesLate(CallInst *target, Function &F) |
| 52 | +{ |
| 53 | + assert(target->arg_size() == 3); |
| 54 | + |
| 55 | + IRBuilder<> builder(target); |
| 56 | + auto ptls = target->getArgOperand(0); |
| 57 | + auto type = target->getArgOperand(2); |
| 58 | + if (auto CI = dyn_cast<ConstantInt>(target->getArgOperand(1))) { |
| 59 | + size_t sz = (size_t)CI->getZExtValue(); |
| 60 | + // This is strongly architecture and OS dependent |
| 61 | + int osize; |
| 62 | + int offset = jl_gc_classify_pools(sz, &osize); |
| 63 | + if (offset >= 0) { |
| 64 | + // In this case instead of lowering julia.gc_alloc_bytes to jl_gc_small_alloc |
| 65 | + // We do a slowpath/fastpath check and lower it only on the slowpath, returning |
| 66 | + // the cursor and updating it in the fastpath. |
| 67 | + auto pool_osize_i32 = ConstantInt::get(Type::getInt32Ty(F.getContext()), osize); |
| 68 | + auto pool_osize = ConstantInt::get(Type::getInt64Ty(F.getContext()), osize); |
| 69 | + |
| 70 | + // Should we generate fastpath allocation sequence here? We should always generate fastpath here for MMTk. |
| 71 | + // Setting this to false will increase allocation overhead a lot, and should only be used for debugging. |
| 72 | + const bool INLINE_FASTPATH_ALLOCATION = true; |
| 73 | + |
| 74 | + if (INLINE_FASTPATH_ALLOCATION) { |
| 75 | + // Assuming we use the first immix allocator. |
| 76 | + // FIXME: We should get the allocator index and type from MMTk. |
| 77 | + auto allocator_offset = offsetof(jl_tls_states_t, gc_tls) + offsetof(jl_gc_tls_states_t, mmtk_mutator) + offsetof(MMTkMutatorContext, allocators) + offsetof(Allocators, immix); |
| 78 | + |
| 79 | + auto cursor_pos = ConstantInt::get(Type::getInt64Ty(target->getContext()), allocator_offset + offsetof(ImmixAllocator, cursor)); |
| 80 | + auto limit_pos = ConstantInt::get(Type::getInt64Ty(target->getContext()), allocator_offset + offsetof(ImmixAllocator, limit)); |
| 81 | + |
| 82 | + auto cursor_tls_i8 = builder.CreateGEP(Type::getInt8Ty(target->getContext()), ptls, cursor_pos); |
| 83 | + auto cursor_ptr = builder.CreateBitCast(cursor_tls_i8, PointerType::get(Type::getInt64Ty(target->getContext()), 0), "cursor_ptr"); |
| 84 | + auto cursor = builder.CreateLoad(Type::getInt64Ty(target->getContext()), cursor_ptr, "cursor"); |
| 85 | + |
| 86 | + // offset = 8 |
| 87 | + auto delta_offset = builder.CreateNSWSub(ConstantInt::get(Type::getInt64Ty(target->getContext()), 0), ConstantInt::get(Type::getInt64Ty(target->getContext()), 8)); |
| 88 | + auto delta_cursor = builder.CreateNSWSub(ConstantInt::get(Type::getInt64Ty(target->getContext()), 0), cursor); |
| 89 | + auto delta_op = builder.CreateNSWAdd(delta_offset, delta_cursor); |
| 90 | + // alignment 16 (15 = 16 - 1) |
| 91 | + auto delta = builder.CreateAnd(delta_op, ConstantInt::get(Type::getInt64Ty(target->getContext()), 15), "delta"); |
| 92 | + auto result = builder.CreateNSWAdd(cursor, delta, "result"); |
| 93 | + |
| 94 | + auto new_cursor = builder.CreateNSWAdd(result, pool_osize); |
| 95 | + |
| 96 | + auto limit_tls_i8 = builder.CreateGEP(Type::getInt8Ty(target->getContext()), ptls, limit_pos); |
| 97 | + auto limit_ptr = builder.CreateBitCast(limit_tls_i8, PointerType::get(Type::getInt64Ty(target->getContext()), 0), "limit_ptr"); |
| 98 | + auto limit = builder.CreateLoad(Type::getInt64Ty(target->getContext()), limit_ptr, "limit"); |
| 99 | + |
| 100 | + auto gt_limit = builder.CreateICmpSGT(new_cursor, limit); |
| 101 | + |
| 102 | + auto slowpath = BasicBlock::Create(target->getContext(), "slowpath", target->getFunction()); |
| 103 | + auto fastpath = BasicBlock::Create(target->getContext(), "fastpath", target->getFunction()); |
| 104 | + |
| 105 | + auto next_instr = target->getNextNode(); |
| 106 | + SmallVector<uint32_t, 2> Weights{1, 9}; |
| 107 | + |
| 108 | + MDBuilder MDB(F.getContext()); |
| 109 | + SplitBlockAndInsertIfThenElse(gt_limit, next_instr, &slowpath, &fastpath, false, false, MDB.createBranchWeights(Weights)); |
| 110 | + |
| 111 | + builder.SetInsertPoint(next_instr); |
| 112 | + auto phiNode = builder.CreatePHI(target->getCalledFunction()->getReturnType(), 2, "phi_fast_slow"); |
| 113 | + |
| 114 | + // slowpath |
| 115 | + builder.SetInsertPoint(slowpath); |
| 116 | + auto pool_offs = ConstantInt::get(Type::getInt32Ty(F.getContext()), 1); |
| 117 | + auto new_call = builder.CreateCall(smallAllocFunc, { ptls, pool_offs, pool_osize_i32, type }); |
| 118 | + new_call->setAttributes(new_call->getCalledFunction()->getAttributes()); |
| 119 | + builder.CreateBr(next_instr->getParent()); |
| 120 | + |
| 121 | + // fastpath |
| 122 | + builder.SetInsertPoint(fastpath); |
| 123 | + builder.CreateStore(new_cursor, cursor_ptr); |
| 124 | + |
| 125 | + // ptls->gc_tls.gc_num.allocd += osize; |
| 126 | + auto pool_alloc_pos = ConstantInt::get(Type::getInt64Ty(target->getContext()), offsetof(jl_tls_states_t, gc_tls_common) + offsetof(jl_gc_tls_states_common_t, gc_num)); |
| 127 | + auto pool_alloc_i8 = builder.CreateGEP(Type::getInt8Ty(target->getContext()), ptls, pool_alloc_pos); |
| 128 | + auto pool_alloc_tls = builder.CreateBitCast(pool_alloc_i8, PointerType::get(Type::getInt64Ty(target->getContext()), 0), "pool_alloc"); |
| 129 | + auto pool_allocd = builder.CreateLoad(Type::getInt64Ty(target->getContext()), pool_alloc_tls); |
| 130 | + auto pool_allocd_total = builder.CreateAdd(pool_allocd, pool_osize); |
| 131 | + builder.CreateStore(pool_allocd_total, pool_alloc_tls); |
| 132 | + |
| 133 | + auto v_raw = builder.CreateNSWAdd(result, ConstantInt::get(Type::getInt64Ty(target->getContext()), sizeof(jl_taggedvalue_t))); |
| 134 | + auto v_as_ptr = builder.CreateIntToPtr(v_raw, smallAllocFunc->getReturnType()); |
| 135 | + builder.CreateBr(next_instr->getParent()); |
| 136 | + |
| 137 | + phiNode->addIncoming(new_call, slowpath); |
| 138 | + phiNode->addIncoming(v_as_ptr, fastpath); |
| 139 | + phiNode->takeName(target); |
| 140 | + return phiNode; |
| 141 | + } |
| 142 | + } |
| 143 | + } |
| 144 | + return target; |
| 145 | +} |
0 commit comments