llvm.org GIT mirror llvm / 685fd43
Revert "[RS4GC] Strip off invariant.start because memory locations arent invariant" This reverts commit r317215, investigating the test failure. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@317217 91177308-0d34-0410-b5e6-96231b3b80d8 Anna Thomas 1 year, 10 months ago
2 changed file(s) with 10 addition(s) and 93 deletion(s). Raw diff Collapse all Expand all
124124 Changed |= runOnFunction(F);
125125
126126 if (Changed) {
127 // stripNonValidData asserts that shouldRewriteStatepointsIn
127 // stripNonValidAttributesAndMetadata 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 stripNonValidData(M);
130 stripNonValidAttributesAndMetadata(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. stripNonValidData (conservatively) restores
148 /// heap. stripNonValidAttributesAndMetadata (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 /// 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);
153 void stripNonValidAttributesAndMetadata(Module &M);
154
155 // Helpers for stripNonValidAttributesAndMetadata
156 void stripNonValidAttributesAndMetadataFromBody(Function &F);
159157 void stripNonValidAttributesFromPrototype(Function &F);
160158
161159 // Certain metadata on instructions are invalid after running RS4GC.
23862384 I.dropUnknownNonDebugMetadata(ValidMetadataAfterRS4GC);
23872385 }
23882386
2389 void RewriteStatepointsForGC::stripNonValidDataFromBody(Function &F) {
2387 void RewriteStatepointsForGC::stripNonValidAttributesAndMetadataFromBody(Function &F) {
23902388 if (F.empty())
23912389 return;
23922390
23932391 LLVMContext &Ctx = F.getContext();
23942392 MDBuilder Builder(Ctx);
23952393
2396 // Set of invariantstart instructions that we need to remove.
2397 // Use this to avoid invalidating the instruction iterator.
2398 SmallVector InvariantStartInstructions;
2399
24002394 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
24132395 if (const MDNode *MD = I.getMetadata(LLVMContext::MD_tbaa)) {
24142396 assert(MD->getNumOperands() < 5 && "unrecognized metadata shape!");
24152397 bool IsImmutableTBAA =
24382420 if (isa(CS.getType()))
24392421 RemoveNonValidAttrAtIndex(Ctx, CS, AttributeList::ReturnIndex);
24402422 }
2441 }
2442
2443 // Delete the invariant.start instructions and any corresponding uses that
2444 // don't have further uses, for example invariant.end.
2445 for (auto *II : InvariantStartInstructions) {
2446 for (auto *U : II->users())
2447 if (auto *I = dyn_cast(U))
2448 if (U->hasNUses(0))
2449 I->eraseFromParent();
2450 // We cannot just delete the remaining uses of II, so we RAUW undef.
2451 II->replaceAllUsesWith(UndefValue::get(II->getType()));
2452 II->eraseFromParent();
24532423 }
24542424 }
24552425
24672437 return false;
24682438 }
24692439
2470 void RewriteStatepointsForGC::stripNonValidData(Module &M) {
2440 void RewriteStatepointsForGC::stripNonValidAttributesAndMetadata(Module &M) {
24712441 #ifndef NDEBUG
24722442 assert(llvm::any_of(M, shouldRewriteStatepointsIn) && "precondition!");
24732443 #endif
24762446 stripNonValidAttributesFromPrototype(F);
24772447
24782448 for (Function &F : M)
2479 stripNonValidDataFromBody(F);
2449 stripNonValidAttributesAndMetadataFromBody(F);
24802450 }
24812451
24822452 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 ; CHECK-LABEL: taken:
90 ; CHECK-NOT: llvm.invariant.end
91 taken:
92 store i32 %v2, i32 addrspace(1)* %q, align 16
93 call void @llvm.invariant.end.p1i32({}* %invst, i64 4, i32 addrspace(1)* %v1)
94 ret void
95
96 ; CHECK-LABEL: untaken:
97 ; CHECK: gc.statepoint
98 untaken:
99 %foo = call i32 @escaping.invariant.start({}* %invst)
100 call void @dummy(i32 %foo)
101 ret void
102 }
103
104 ; invariant.start and end is removed. No other uses.
105 define void @test_inv_start2(i1 %cond, i32 addrspace(1)* addrspace(1)* %p, i32 %x, i32 addrspace(1)* %q) gc "statepoint-example" {
106 ; CHECK-LABEL: test_inv_start2
107 ; CHECK-NOT: invariant.start
108 ; CHECK: gc.statepoint
109 %v1 = load i32 addrspace(1)*, i32 addrspace(1)* addrspace(1)* %p
110 %invst = call {}* @llvm.invariant.start.p1i32(i64 1, i32 addrspace(1)* %v1)
111 %v2 = load i32, i32 addrspace(1)* %v1
112 call void @baz(i32 %x)
113 br i1 %cond, label %taken, label %untaken
114
115 ; CHECK-LABEL: taken:
116 ; CHECK-NOT: llvm.invariant.end
117 taken:
118 store i32 %v2, i32 addrspace(1)* %q, align 16
119 call void @llvm.invariant.end.p1i32({}* %invst, i64 4, i32 addrspace(1)* %v1)
120 ret void
121
122 ; CHECK-LABEL: untaken:
123 untaken:
124 ret void
125 }
126 declare {}* @llvm.invariant.start.p1i32(i64, i32 addrspace(1)* nocapture) nounwind readonly
127 declare void @llvm.invariant.end.p1i32({}*, i64, i32 addrspace(1)* nocapture) nounwind
128 declare i32 @escaping.invariant.start({}*) nounwind
129 declare void @dummy(i32)
13077 declare token @llvm.experimental.gc.statepoint.p0f_isVoidi32f(i64, i32, void (i32)*, i32, i32, ...)
13178
13279 ; Function Attrs: nounwind readonly