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