diff --git a/src/llvm-gc-interface-passes.h b/src/llvm-gc-interface-passes.h index d33567e887118..278987858eab7 100644 --- a/src/llvm-gc-interface-passes.h +++ b/src/llvm-gc-interface-passes.h @@ -353,10 +353,11 @@ struct LateLowerGCFrame: private JuliaPassContext { State LocalScan(Function &F); void ComputeLiveness(State &S); void ComputeLiveSets(State &S); - SmallVector ColorRoots(const State &S); + std::pair, int> ColorRoots(const State &S); void PlaceGCFrameStore(State &S, unsigned R, unsigned MinColorRoot, ArrayRef Colors, Value *GCFrame, Instruction *InsertBefore); - void PlaceGCFrameStores(State &S, unsigned MinColorRoot, ArrayRef Colors, Value *GCFrame); - void PlaceRootsAndUpdateCalls(SmallVectorImpl &Colors, State &S, std::map>); + void PlaceGCFrameStores(State &S, unsigned MinColorRoot, ArrayRef Colors, int PreAssignedColors, Value *GCFrame); + void PlaceGCFrameReset(State &S, unsigned R, unsigned MinColorRoot, ArrayRef Colors, Value *GCFrame, Instruction *InsertBefore); + void PlaceRootsAndUpdateCalls(ArrayRef Colors, int PreAssignedColors, State &S, std::map>); void CleanupWriteBarriers(Function &F, State *S, const SmallVector &WriteBarriers, bool *CFGModified); bool CleanupIR(Function &F, State *S, bool *CFGModified); void NoteUseChain(State &S, BBState &BBS, User *TheUser); diff --git a/src/llvm-late-gc-lowering.cpp b/src/llvm-late-gc-lowering.cpp index 1d390a5115207..3e372ec9884e7 100644 --- a/src/llvm-late-gc-lowering.cpp +++ b/src/llvm-late-gc-lowering.cpp @@ -1820,7 +1820,7 @@ JL_USED_FUNC static void dumpColorAssignments(const State &S, const ArrayRef LateLowerGCFrame::ColorRoots(const State &S) { +std::pair, int> LateLowerGCFrame::ColorRoots(const State &S) { SmallVector Colors; Colors.resize(S.MaxPtrNumber + 1, -1); PEOIterator Ordering(S.Neighbors); @@ -1862,7 +1862,7 @@ SmallVector LateLowerGCFrame::ColorRoots(const State &S) { NewColor += PreAssignedColors; Colors[ActiveElement] = NewColor; } - return Colors; + return {Colors, PreAssignedColors}; } // Size of T is assumed to be `sizeof(void*)` @@ -2292,8 +2292,21 @@ void LateLowerGCFrame::PlaceGCFrameStore(State &S, unsigned R, unsigned MinColor new StoreInst(Val, slotAddress, InsertBefore); } +void LateLowerGCFrame::PlaceGCFrameReset(State &S, unsigned R, unsigned MinColorRoot, + ArrayRef Colors, Value *GCFrame, + Instruction *InsertBefore) { + // Get the slot address. + auto slotAddress = CallInst::Create( + getOrDeclare(jl_intrinsics::getGCFrameSlot), + {GCFrame, ConstantInt::get(Type::getInt32Ty(InsertBefore->getContext()), Colors[R] + MinColorRoot)}, + "gc_slot_addr_" + StringRef(std::to_string(Colors[R] + MinColorRoot)), InsertBefore); + // Reset the slot to NULL. + Value *Val = ConstantPointerNull::get(T_prjlvalue); + new StoreInst(Val, slotAddress, InsertBefore); +} + void LateLowerGCFrame::PlaceGCFrameStores(State &S, unsigned MinColorRoot, - ArrayRef Colors, Value *GCFrame) + ArrayRef Colors, int PreAssignedColors, Value *GCFrame) { for (auto &BB : *S.F) { const BBState &BBS = S.BBStates[&BB]; @@ -2306,6 +2319,15 @@ void LateLowerGCFrame::PlaceGCFrameStores(State &S, unsigned MinColorRoot, for(auto rit = BBS.Safepoints.rbegin(); rit != BBS.Safepoints.rend(); ++rit ) { const LargeSparseBitVector &NowLive = S.LiveSets[*rit]; + // reset slots which are no longer alive + for (int Idx : *LastLive) { + if (Idx >= PreAssignedColors && !HasBitSet(NowLive, Idx)) { + PlaceGCFrameReset(S, Idx, MinColorRoot, Colors, GCFrame, + S.ReverseSafepointNumbering[*rit]); + } + } + // store values which are alive in this safepoint but + // haven't been stored in the GC frame before for (int Idx : NowLive) { if (!HasBitSet(*LastLive, Idx)) { PlaceGCFrameStore(S, Idx, MinColorRoot, Colors, GCFrame, @@ -2317,7 +2339,7 @@ void LateLowerGCFrame::PlaceGCFrameStores(State &S, unsigned MinColorRoot, } } -void LateLowerGCFrame::PlaceRootsAndUpdateCalls(SmallVectorImpl &Colors, State &S, +void LateLowerGCFrame::PlaceRootsAndUpdateCalls(ArrayRef Colors, int PreAssignedColors, State &S, std::map>) { auto F = S.F; auto T_int32 = Type::getInt32Ty(F->getContext()); @@ -2439,7 +2461,7 @@ void LateLowerGCFrame::PlaceRootsAndUpdateCalls(SmallVectorImpl &Colors, St pushGcframe->setArgOperand(1, NRoots); // Insert GC frame stores - PlaceGCFrameStores(S, AllocaSlot - 2, Colors, gcframe); + PlaceGCFrameStores(S, AllocaSlot - 2, Colors, PreAssignedColors, gcframe); // Insert GCFrame pops for (auto &BB : *F) { if (isa(BB.getTerminator())) { @@ -2464,9 +2486,9 @@ bool LateLowerGCFrame::runOnFunction(Function &F, bool *CFGModified) { State S = LocalScan(F); ComputeLiveness(S); - SmallVector Colors = ColorRoots(S); + auto Colors = ColorRoots(S); std::map> CallFrames; // = OptimizeCallFrames(S, Ordering); - PlaceRootsAndUpdateCalls(Colors, S, CallFrames); + PlaceRootsAndUpdateCalls(Colors.first, Colors.second, S, CallFrames); CleanupIR(F, &S, CFGModified); return true; } diff --git a/test/compiler/codegen.jl b/test/compiler/codegen.jl index ae04250964554..fcb3beb87b5a5 100644 --- a/test/compiler/codegen.jl +++ b/test/compiler/codegen.jl @@ -1003,3 +1003,25 @@ end @test f55768(Vector) @test f55768(Vector{T} where T) @test !f55768(Vector{S} where S) + +# test that values get rooted correctly over throw +for a in ((@noinline Ref{Int}(2)), + (@noinline Ref{Int}(3)), + 5, + (@noinline Ref{Int}(4)), + 6) + @test a[] != 0 + try + b = (@noinline Ref{Int}(5), + @noinline Ref{Int}(6), + @noinline Ref{Int}(7), + @noinline Ref{Int}(8), + @noinline Ref{Int}(9), + @noinline Ref{Int}(10), + @noinline Ref{Int}(11)) + GC.gc(true) + GC.@preserve b throw(a) + catch ex + @test ex === a + end +end diff --git a/test/llvmpasses/returnstwicegc.ll b/test/llvmpasses/returnstwicegc.ll index 511cbb505519b..eb1c6444129c3 100644 --- a/test/llvmpasses/returnstwicegc.ll +++ b/test/llvmpasses/returnstwicegc.ll @@ -1,6 +1,6 @@ ; This file is a part of Julia. License is MIT: https://julialang.org/license -; RUN: opt --load-pass-plugin=libjulia-codegen%shlibext -passes='function(LateLowerGCFrame,FinalLowerGC)' -S %s | FileCheck %s --check-prefixes=OPAQUE +; RUN: opt --load-pass-plugin=libjulia-codegen%shlibext -passes='function(LateLowerGCFrame,FinalLowerGC)' -S %s | FileCheck %s declare void @boxed_simple({} addrspace(10)*, {} addrspace(10)*) @@ -13,7 +13,12 @@ declare void @one_arg_boxed({} addrspace(10)*) define void @try_catch(i64 %a, i64 %b) { ; Because of the returns_twice function, we need to keep aboxed live everywhere -; OPAQUE: %gcframe = alloca ptr addrspace(10), i32 4 +; CHECK: %gcframe = alloca ptr addrspace(10), i32 4 +; CHECK: store ptr addrspace(10) %aboxed, ptr [[slot_0:%.*]], +; CHECK-NOT: store {{.*}} ptr [[slot_0]] +; CHECK: store ptr addrspace(10) %bboxed, ptr {{%.*}} +; CHECK-NOT: store {{.*}} ptr [[slot_0]] + top: %sigframe = alloca [208 x i8], align 16 %sigframe.sub = getelementptr inbounds [208 x i8], [208 x i8]* %sigframe, i64 0, i64 0