@@ -259,6 +259,10 @@ struct State {
259
259
// of the value (but not the other way around).
260
260
std::map<int , int > LoadRefinements;
261
261
262
+ // GC preserves map. All safepoints dominated by the map key, but not any
263
+ // of its uses need to preserve the values listed in the map value.
264
+ std::map<Instruction *, std::vector<int >> GCPreserves;
265
+
262
266
// The assignment of numbers to safepoints. The indices in the map
263
267
// are indices into the next three maps which store safepoint properties
264
268
std::map<Instruction *, int > SafepointNumbering;
@@ -321,7 +325,8 @@ struct LateLowerGCFrame: public FunctionPass {
321
325
MDNode *tbaa_tag;
322
326
Function *ptls_getter;
323
327
Function *gc_flush_func;
324
- Function *gc_use_func;
328
+ Function *gc_preserve_begin_func;
329
+ Function *gc_preserve_end_func;
325
330
Function *pointer_from_objref_func;
326
331
Function *alloc_obj_func;
327
332
Function *pool_alloc_func;
@@ -753,17 +758,29 @@ State LateLowerGCFrame::LocalScan(Function &F) {
753
758
if (CI->canReturnTwice ()) {
754
759
S.ReturnsTwice .push_back (CI);
755
760
}
756
- if (isa<IntrinsicInst>(CI)) {
757
- // Intrinsics are never safepoints.
758
- continue ;
759
- }
760
761
if (auto callee = CI->getCalledFunction ()) {
762
+ if (callee == gc_preserve_begin_func) {
763
+ std::vector<int > args;
764
+ for (Use &U : CI->arg_operands ()) {
765
+ Value *V = U;
766
+ int Num = Number (S, V);
767
+ if (Num >= 0 )
768
+ args.push_back (Num);
769
+ }
770
+ S.GCPreserves [CI] = args;
771
+ continue ;
772
+ }
761
773
// Known functions emitted in codegen that are not safepoints
762
- if (callee == pointer_from_objref_func || callee == gc_use_func ||
774
+ if (callee == pointer_from_objref_func || callee == gc_preserve_begin_func ||
775
+ callee == gc_preserve_end_func ||
763
776
callee->getName () == " memcmp" ) {
764
777
continue ;
765
778
}
766
779
}
780
+ if (isa<IntrinsicInst>(CI)) {
781
+ // Intrinsics are never safepoints.
782
+ continue ;
783
+ }
767
784
int SafepointNumber = NoteSafepoint (S, BBS, CI);
768
785
BBS.HasSafepoint = true ;
769
786
BBS.TopmostSafepoint = SafepointNumber;
@@ -911,6 +928,7 @@ JL_USED_FUNC static void dumpSafepointsForBBName(Function &F, State &S, const ch
911
928
}
912
929
913
930
void LateLowerGCFrame::ComputeLiveSets (Function &F, State &S) {
931
+ DominatorTree *DT = nullptr ;
914
932
// Iterate over all safe points. Add to live sets all those variables that
915
933
// are now live across their parent block.
916
934
for (auto it : S.SafepointNumbering ) {
@@ -934,6 +952,33 @@ void LateLowerGCFrame::ComputeLiveSets(Function &F, State &S) {
934
952
if (RefinedPtr == -1 || HasBitSet (LS, RefinedPtr))
935
953
LS[Idx] = 0 ;
936
954
}
955
+ // If the function has GC preserves, figure out whether we need to
956
+ // add in any extra live values.
957
+ if (!S.GCPreserves .empty ()) {
958
+ if (!DT) {
959
+ DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree ();
960
+ }
961
+ for (auto it2 : S.GCPreserves ) {
962
+ if (!DT->dominates (it2.first , Safepoint))
963
+ continue ;
964
+ bool OutsideRange = false ;
965
+ for (const User *U : it2.first ->users ()) {
966
+ // If this is dominated by an end, we don't need to add
967
+ // the values to our live set.
968
+ if (DT->dominates (cast<Instruction>(U), Safepoint)) {
969
+ OutsideRange = true ;
970
+ break ;
971
+ }
972
+ }
973
+ if (OutsideRange)
974
+ continue ;
975
+ for (unsigned Num : it2.second ) {
976
+ if (Num >= LS.size ())
977
+ LS.resize (Num + 1 );
978
+ LS[Num] = 1 ;
979
+ }
980
+ }
981
+ }
937
982
}
938
983
// Compute the interference graph
939
984
for (int i = 0 ; i <= S.MaxPtrNumber ; ++i) {
@@ -1152,8 +1197,8 @@ bool LateLowerGCFrame::CleanupIR(Function &F) {
1152
1197
}
1153
1198
CallingConv::ID CC = CI->getCallingConv ();
1154
1199
auto callee = CI->getCalledValue ();
1155
- if ((gc_flush_func != nullptr && callee == gc_flush_func) ||
1156
- (gc_use_func != nullptr && callee == gc_use_func )) {
1200
+ if (callee && ( callee == gc_flush_func || callee == gc_preserve_begin_func
1201
+ || callee == gc_preserve_end_func )) {
1157
1202
/* No replacement */
1158
1203
} else if (pointer_from_objref_func != nullptr && callee == pointer_from_objref_func) {
1159
1204
auto *ASCI = new AddrSpaceCastInst (CI->getOperand (0 ),
@@ -1242,6 +1287,9 @@ bool LateLowerGCFrame::CleanupIR(Function &F) {
1242
1287
NewCall->takeName (CI);
1243
1288
CI->replaceAllUsesWith (NewCall);
1244
1289
}
1290
+ if (!CI->use_empty ()) {
1291
+ CI->replaceAllUsesWith (UndefValue::get (CI->getType ()));
1292
+ }
1245
1293
it = CI->eraseFromParent ();
1246
1294
ChangesMade = true ;
1247
1295
}
@@ -1421,7 +1469,8 @@ static void addRetNoAlias(Function *F)
1421
1469
bool LateLowerGCFrame::doInitialization (Module &M) {
1422
1470
ptls_getter = M.getFunction (" jl_get_ptls_states" );
1423
1471
gc_flush_func = M.getFunction (" julia.gcroot_flush" );
1424
- gc_use_func = M.getFunction (" julia.gc_use" );
1472
+ gc_preserve_begin_func = M.getFunction (" llvm.julia.gc_preserve_begin" );
1473
+ gc_preserve_end_func = M.getFunction (" llvm.julia.gc_preserve_end" );
1425
1474
pointer_from_objref_func = M.getFunction (" julia.pointer_from_objref" );
1426
1475
auto &ctx = M.getContext ();
1427
1476
T_size = M.getDataLayout ().getIntPtrType (ctx);
0 commit comments