llvm.org GIT mirror llvm / 0c059ef
Strip off invariant.start because memory locations arent invariant The original change was reverted in rL317217 because of the failure in the RS4GC testcase. I couldn't reproduce the failure on my local machine (macbook) but could reproduce it on a linux box. The failure was around removing the uses of invariant.start. The fix here is to just RAUW undef (which was the first implementation in D39388). This is perfectly valid IR as discussed in the review. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@317225 91177308-0d34-0410-b5e6-96231b3b80d8 Anna Thomas 1 year, 10 months ago
2 changed file(s) with 82 addition(s) and 10 deletion(s). Raw diff Collapse all Expand all
124124 Changed |= runOnFunction(F);
125125
126126 if (Changed) {
127 // stripNonValidAttributesAndMetadata asserts that shouldRewriteStatepointsIn
127 // stripNonValidData asserts that shouldRewriteStatepointsIn
128128 // returns true for at least one function in the module. Since at least
129129 // one function changed, we know that the precondition is satisfied.
130 stripNonValidAttributesAndMetadata(M);
130 stripNonValidData(M);
131131 }
132132
133133 return Changed;
145145 /// metadata implying dereferenceability that are no longer valid/correct after
146146 /// RewriteStatepointsForGC has run. This is because semantically, after
147147 /// RewriteStatepointsForGC runs, all calls to gc.statepoint "free" the entire
148 /// heap. stripNonValidAttributesAndMetadata (conservatively) restores
148 /// heap. stripNonValidData (conservatively) restores
149149 /// correctness by erasing all attributes in the module that externally imply
150150 /// dereferenceability. Similar reasoning also applies to the noalias
151151 /// attributes and metadata. gc.statepoint can touch the entire heap including
152152 /// noalias objects.
153 void stripNonValidAttributesAndMetadata(Module &M);
154
155 // Helpers for stripNonValidAttributesAndMetadata
156 void stripNonValidAttributesAndMetadataFromBody(Function &F);
153 /// Apart from attributes and metadata, we also remove instructions that imply
154 /// constant physical memory: llvm.invariant.start.
155 void stripNonValidData(Module &M);
156
157 // Helpers for stripNonValidData
158 void stripNonValidDataFromBody(Function &F);
157159 void stripNonValidAttributesFromPrototype(Function &F);
158160
159161 // Certain metadata on instructions are invalid after running RS4GC.
23842386 I.dropUnknownNonDebugMetadata(ValidMetadataAfterRS4GC);
23852387 }
23862388
2387 void RewriteStatepointsForGC::stripNonValidAttributesAndMetadataFromBody(Function &F) {
2389 void RewriteStatepointsForGC::stripNonValidDataFromBody(Function &F) {
23882390 if (F.empty())
23892391 return;
23902392
23912393 LLVMContext &Ctx = F.getContext();
23922394 MDBuilder Builder(Ctx);
23932395
2396 // Set of invariantstart instructions that we need to remove.
2397 // Use this to avoid invalidating the instruction iterator.
2398 SmallVector InvariantStartInstructions;
2399
23942400 for (Instruction &I : instructions(F)) {
2401 // invariant.start on memory location implies that the referenced memory
2402 // location is constant and unchanging. This is no longer true after
2403 // RewriteStatepointsForGC runs because there can be calls to gc.statepoint
2404 // which frees the entire heap and the presence of invariant.start allows
2405 // the optimizer to sink the load of a memory location past a statepoint,
2406 // which is incorrect.
2407 if (auto *II = dyn_cast(&I))
2408 if (II->getIntrinsicID() == Intrinsic::invariant_start) {
2409 InvariantStartInstructions.push_back(II);
2410 continue;
2411 }
2412
23952413 if (const MDNode *MD = I.getMetadata(LLVMContext::MD_tbaa)) {
23962414 assert(MD->getNumOperands() < 5 && "unrecognized metadata shape!");
23972415 bool IsImmutableTBAA =
24202438 if (isa(CS.getType()))
24212439 RemoveNonValidAttrAtIndex(Ctx, CS, AttributeList::ReturnIndex);
24222440 }
2441 }
2442
2443 // Delete the invariant.start instructions and RAUW undef.
2444 for (auto *II : InvariantStartInstructions) {
2445 II->replaceAllUsesWith(UndefValue::get(II->getType()));
2446 II->eraseFromParent();
24232447 }
24242448 }
24252449
24372461 return false;
24382462 }
24392463
2440 void RewriteStatepointsForGC::stripNonValidAttributesAndMetadata(Module &M) {
2464 void RewriteStatepointsForGC::stripNonValidData(Module &M) {
24412465 #ifndef NDEBUG
24422466 assert(llvm::any_of(M, shouldRewriteStatepointsIn) && "precondition!");
24432467 #endif
24462470 stripNonValidAttributesFromPrototype(F);
24472471
24482472 for (Function &F : M)
2449 stripNonValidAttributesAndMetadataFromBody(F);
2473 stripNonValidDataFromBody(F);
24502474 }
24512475
24522476 bool RewriteStatepointsForGC::runOnFunction(Function &F) {
7474 ret void
7575 }
7676
77 ; invariant.start allows us to sink the load past the baz statepoint call into taken block, which is
78 ; incorrect. remove the invariant.start and RAUW undef.
79 define void @test_inv_start(i1 %cond, i32 addrspace(1)* addrspace(1)* %p, i32 %x, i32 addrspace(1)* %q) gc "statepoint-example" {
80 ; CHECK-LABEL: test_inv_start
81 ; CHECK-NOT: invariant.start
82 ; CHECK: gc.statepoint
83 %v1 = load i32 addrspace(1)*, i32 addrspace(1)* addrspace(1)* %p
84 %invst = call {}* @llvm.invariant.start.p1i32(i64 1, i32 addrspace(1)* %v1)
85 %v2 = load i32, i32 addrspace(1)* %v1
86 call void @baz(i32 %x)
87 br i1 %cond, label %taken, label %untaken
88
89 taken:
90 store i32 %v2, i32 addrspace(1)* %q, align 16
91 call void @llvm.invariant.end.p1i32({}* %invst, i64 4, i32 addrspace(1)* %v1)
92 ret void
93
94 ; CHECK-LABEL: untaken:
95 ; CHECK: gc.statepoint
96 untaken:
97 %foo = call i32 @escaping.invariant.start({}* %invst)
98 call void @dummy(i32 %foo)
99 ret void
100 }
101
102 ; invariant.start is removed and the uses are undef'ed.
103 define void @test_inv_start2(i1 %cond, i32 addrspace(1)* addrspace(1)* %p, i32 %x, i32 addrspace(1)* %q) gc "statepoint-example" {
104 ; CHECK-LABEL: test_inv_start2
105 ; CHECK-NOT: invariant.start
106 ; CHECK: gc.statepoint
107 %v1 = load i32 addrspace(1)*, i32 addrspace(1)* addrspace(1)* %p
108 %invst = call {}* @llvm.invariant.start.p1i32(i64 1, i32 addrspace(1)* %v1)
109 %v2 = load i32, i32 addrspace(1)* %v1
110 call void @baz(i32 %x)
111 br i1 %cond, label %taken, label %untaken
112
113 taken:
114 store i32 %v2, i32 addrspace(1)* %q, align 16
115 call void @llvm.invariant.end.p1i32({}* %invst, i64 4, i32 addrspace(1)* %v1)
116 ret void
117
118 untaken:
119 ret void
120 }
121 declare {}* @llvm.invariant.start.p1i32(i64, i32 addrspace(1)* nocapture) nounwind readonly
122 declare void @llvm.invariant.end.p1i32({}*, i64, i32 addrspace(1)* nocapture) nounwind
123 declare i32 @escaping.invariant.start({}*) nounwind
124 declare void @dummy(i32)
77125 declare token @llvm.experimental.gc.statepoint.p0f_isVoidi32f(i64, i32, void (i32)*, i32, i32, ...)
78126
79127 ; Function Attrs: nounwind readonly