已开启
fix: keep finalizer object field loads in loop under LICM #607
fix: keep finalizer object field loads in loop under LICM #607
已开启
duan创建于 18 天前
2 个文件变更+45-0
@@ -1213,6 +1213,13 @@ bool llvm::canSinkOrHoistInst(Instruction &I, AAResults *AA, DominatorTree *DT,
1213 MemorySSA *MSSA = MSSAU.getMemorySSA();1213 MemorySSA *MSSA = MSSAU.getMemorySSA();
1214 // Loads have extra constraints we have to verify before we can hoist them.1214 // Loads have extra constraints we have to verify before we can hoist them.
1215 if (LoadInst *LI = dyn_cast<LoadInst>(&I)) {1215 if (LoadInst *LI = dyn_cast<LoadInst>(&I)) {
1216+ // Avoid moving a read of a finalizer object's field out of the loop.
1217+ // Hoisting/sinking that read removes the only remaining SSA use of the
1218+ // finalizer object inside the loop, so GC liveness reports it dead and
1219+ // the GC collects it while the source program still references it, running
1220+ // its ~init() (finalizer) prematurely.
1221+ if (CJPipeline && maybeCJFinalizerObj(LI->getPointerOperand()))
1222+ return false;
1216 if (!LI->isUnordered())1223 if (!LI->isUnordered())
1217 return false; // Don't sink/hoist volatile or ordered atomic loads!1224 return false; // Don't sink/hoist volatile or ordered atomic loads!
1218 1225 
@@ -0,0 +1,38 @@
1+; RUN: opt < %s -licm --cangjie-pipeline -S | FileCheck %s
2+ 
3+; A finalizer object's field load must NOT be hoisted (or sunk) out of a loop.
4+; Hoisting removes the only SSA use of the finalizer object inside the loop,
5+; so GC liveness reports it dead and the GC runs its ~init() while the source
6+; program still references it.
7+ 
8+%KlassInfo.0 = type { [0 x %KlassInfo.0*] }
9+@_ZN7default1AE.objKlass = weak_odr global %KlassInfo.0 { [0 x %KlassInfo.0*] zeroinitializer }
10+ 
11+declare i8 addrspace(1)* @CJ_MCC_NewFinalizer(i8*, i32)
12+declare void @use_obj(i8 addrspace(1)*)
13+ 
14+; CHECK-LABEL: define void @finalizer_field_not_hoisted
15+; The load of the finalizer object field must stay inside the loop body.
16+; CHECK: br label %loop
17+; CHECK-NOT: %[[L:.*]] = load i8 addrspace(1)*, i8 addrspace(1)* addrspace(1)*
18+; CHECK: loop:
19+; CHECK: %[[L:.*]] = load i8 addrspace(1)*, i8 addrspace(1)* addrspace(1)*
20+; CHECK: call void @use_obj(i8 addrspace(1)* %[[L]])
21+define void @finalizer_field_not_hoisted() gc "cangjie" {
22+entry:
23+ %0 = call noalias i8 addrspace(1)* @CJ_MCC_NewFinalizer(i8* bitcast (%KlassInfo.0* @_ZN7default1AE.objKlass to i8*), i32 16)
24+ %1 = getelementptr i8, i8 addrspace(1)* %0, i64 8
25+ %2 = bitcast i8 addrspace(1)* %1 to i8 addrspace(1)* addrspace(1)*
26+ br label %loop
27+ 
28+loop:
29+ %3 = phi i64 [ 0, %entry ], [ %5, %loop ]
30+ %4 = load i8 addrspace(1)*, i8 addrspace(1)* addrspace(1)* %2, align 8
31+ call void @use_obj(i8 addrspace(1)* %4)
32+ %5 = add i64 %3, 1
33+ %6 = icmp slt i64 %5, 10
34+ br i1 %6, label %loop, label %exit
35+ 
36+exit:
37+ ret void
38+}