llvm.org GIT mirror llvm / 8cedcc7
[RS4GC] Drop invalid metadata after pointers are relocated Summary: After RS4GC, we should drop metadata that is no longer valid. These metadata is used by optimizations scheduled after RS4GC, and can cause a miscompile. One such metadata is invariant.load which is used by LICM sinking transform. After rewriting statepoints, the address of a load maybe relocated. With invariant.load metadata on a load instruction, LICM sinking assumes the loaded value (from a dererenceable address) to be invariant, and rematerializes the load operand and the load at the exit block. This transforms the IR to have an unrelocated use of the address after a statepoint, which is incorrect. Other metadata we conservatively remove are related to dereferenceability and noalias metadata. This patch drops such metadata on store and load instructions after rewriting statepoints. Reviewers: reames, sanjoy, apilipenko Reviewed by: reames Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D33756 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@305234 91177308-0d34-0410-b5e6-96231b3b80d8 Anna Thomas 2 years ago
2 changed file(s) with 146 addition(s) and 17 deletion(s). Raw diff Collapse all Expand all
8888 Changed |= runOnFunction(F);
8989
9090 if (Changed) {
91 // stripNonValidAttributes asserts that shouldRewriteStatepointsIn
91 // stripNonValidAttributesAndMetadata asserts that shouldRewriteStatepointsIn
9292 // returns true for at least one function in the module. Since at least
9393 // one function changed, we know that the precondition is satisfied.
94 stripNonValidAttributes(M);
94 stripNonValidAttributesAndMetadata(M);
9595 }
9696
9797 return Changed;
104104 AU.addRequired();
105105 }
106106
107 /// The IR fed into RewriteStatepointsForGC may have had attributes implying
108 /// dereferenceability that are no longer valid/correct after
109 /// RewriteStatepointsForGC has run. This is because semantically, after
107 /// The IR fed into RewriteStatepointsForGC may have had attributes and
108 /// metadata implying dereferenceability that are no longer valid/correct after
109 /// RewriteStatepointsForGC has run. This is because semantically, after
110110 /// RewriteStatepointsForGC runs, all calls to gc.statepoint "free" the entire
111 /// heap. stripNonValidAttributes (conservatively) restores correctness
112 /// by erasing all attributes in the module that externally imply
113 /// dereferenceability.
114 /// Similar reasoning also applies to the noalias attributes. gc.statepoint
115 /// can touch the entire heap including noalias objects.
116 void stripNonValidAttributes(Module &M);
117
118 // Helpers for stripNonValidAttributes
119 void stripNonValidAttributesFromBody(Function &F);
111 /// heap. stripNonValidAttributesAndMetadata (conservatively) restores
112 /// correctness by erasing all attributes in the module that externally imply
113 /// dereferenceability. Similar reasoning also applies to the noalias
114 /// attributes and metadata. gc.statepoint can touch the entire heap including
115 /// noalias objects.
116 void stripNonValidAttributesAndMetadata(Module &M);
117
118 // Helpers for stripNonValidAttributesAndMetadata
119 void stripNonValidAttributesAndMetadataFromBody(Function &F);
120120 void stripNonValidAttributesFromPrototype(Function &F);
121 // Certain metadata on instructions are invalid after running RS4GC.
122 // Optimizations that run after RS4GC can incorrectly use this metadata to
123 // optimize functions. We drop such metadata on the instruction.
124 void stripInvalidMetadataFromInstruction(Instruction &I);
121125 };
122126 } // namespace
123127
23052309 RemoveNonValidAttrAtIndex(Ctx, F, AttributeList::ReturnIndex);
23062310 }
23072311
2308 void RewriteStatepointsForGC::stripNonValidAttributesFromBody(Function &F) {
2312 void RewriteStatepointsForGC::stripInvalidMetadataFromInstruction(Instruction &I) {
2313
2314 if (!isa(I) && !isa(I))
2315 return;
2316 // These are the attributes that are still valid on loads and stores after
2317 // RS4GC.
2318 // The metadata implying dereferenceability and noalias are (conservatively)
2319 // dropped. This is because semantically, after RewriteStatepointsForGC runs,
2320 // all calls to gc.statepoint "free" the entire heap. Also, gc.statepoint can
2321 // touch the entire heap including noalias objects. Note: The reasoning is
2322 // same as stripping the dereferenceability and noalias attributes that are
2323 // analogous to the metadata counterparts.
2324 // We also drop the invariant.load metadata on the load because that metadata
2325 // implies the address operand to the load points to memory that is never
2326 // changed once it became dereferenceable. This is no longer true after RS4GC.
2327 // Similar reasoning applies to invariant.group metadata, which applies to
2328 // loads within a group.
2329 unsigned ValidMetadataAfterRS4GC[] = {LLVMContext::MD_tbaa,
2330 LLVMContext::MD_range,
2331 LLVMContext::MD_alias_scope,
2332 LLVMContext::MD_nontemporal,
2333 LLVMContext::MD_nonnull,
2334 LLVMContext::MD_align,
2335 LLVMContext::MD_type};
2336
2337 // Drops all metadata on the instruction other than ValidMetadataAfterRS4GC.
2338 I.dropUnknownNonDebugMetadata(ValidMetadataAfterRS4GC);
2339
2340 }
2341
2342 void RewriteStatepointsForGC::stripNonValidAttributesAndMetadataFromBody(Function &F) {
23092343 if (F.empty())
23102344 return;
23112345
23122346 LLVMContext &Ctx = F.getContext();
23132347 MDBuilder Builder(Ctx);
2348
23142349
23152350 for (Instruction &I : instructions(F)) {
23162351 if (const MDNode *MD = I.getMetadata(LLVMContext::MD_tbaa)) {
23312366 Builder.createTBAAStructTagNode(Base, Access, Offset);
23322367 I.setMetadata(LLVMContext::MD_tbaa, MutableTBAA);
23332368 }
2369
2370 stripInvalidMetadataFromInstruction(I);
23342371
23352372 if (CallSite CS = CallSite(&I)) {
23362373 for (int i = 0, e = CS.arg_size(); i != e; i++)
23562393 return false;
23572394 }
23582395
2359 void RewriteStatepointsForGC::stripNonValidAttributes(Module &M) {
2396 void RewriteStatepointsForGC::stripNonValidAttributesAndMetadata(Module &M) {
23602397 #ifndef NDEBUG
23612398 assert(any_of(M, shouldRewriteStatepointsIn) && "precondition!");
23622399 #endif
23652402 stripNonValidAttributesFromPrototype(F);
23662403
23672404 for (Function &F : M)
2368 stripNonValidAttributesFromBody(F);
2405 stripNonValidAttributesAndMetadataFromBody(F);
23692406 }
23702407
23712408 bool RewriteStatepointsForGC::runOnFunction(Function &F) {
0 ; RUN: opt -S -rewrite-statepoints-for-gc < %s | FileCheck %s
1
2 ; This test checks that metadata that's invalid after RS4GC is dropped.
3 ; We can miscompile if optimizations scheduled after RS4GC uses the
4 ; metadata that's infact invalid.
5
6 declare void @bar()
7
8 declare void @baz(i32)
9 ; Confirm that loadedval instruction does not contain invariant.load metadata.
10 ; but contains the range metadata.
11 ; Since loadedval is not marked invariant, it will prevent incorrectly sinking
12 ; %loadedval in LICM and avoid creation of an unrelocated use of %baseaddr.
13 define void @test_invariant_load() gc "statepoint-example" {
14 ; CHECK-LABEL: @test_invariant_load
15 ; CHECK: %loadedval = load i32, i32 addrspace(1)* %baseaddr, align 8, !range !0
16 bb:
17 br label %outerloopHdr
18
19 outerloopHdr: ; preds = %bb6, %bb
20 %baseaddr = phi i32 addrspace(1)* [ undef, %bb ], [ %tmp4, %bb6 ]
21 ; LICM may sink this load to exit block after RS4GC because it's tagged invariant.
22 %loadedval = load i32, i32 addrspace(1)* %baseaddr, align 8, !range !0, !invariant.load !1
23 br label %innerloopHdr
24
25 innerloopHdr: ; preds = %innerlooplatch, %outerloopHdr
26 %tmp4 = phi i32 addrspace(1)* [ %baseaddr, %outerloopHdr ], [ %gep, %innerlooplatch ]
27 br label %innermostloophdr
28
29 innermostloophdr: ; preds = %bb6, %innerloopHdr
30 br i1 undef, label %exitblock, label %bb6
31
32 bb6: ; preds = %innermostloophdr
33 switch i32 undef, label %innermostloophdr [
34 i32 0, label %outerloopHdr
35 i32 1, label %innerlooplatch
36 ]
37
38 innerlooplatch: ; preds = %bb6
39 call void @bar()
40 %gep = getelementptr inbounds i32, i32 addrspace(1)* %tmp4, i64 8
41 br label %innerloopHdr
42
43 exitblock: ; preds = %innermostloophdr
44 %tmp13 = add i32 42, %loadedval
45 call void @baz(i32 %tmp13)
46 unreachable
47 }
48
49 ; drop the noalias metadata.
50 define void @test_noalias(i32 %x, i32 addrspace(1)* %p, i32 addrspace(1)* %q) gc "statepoint-example" {
51 ; CHECK-LABEL: test_noalias
52 ; CHECK: %y = load i32, i32 addrspace(1)* %q, align 16
53 ; CHECK: gc.statepoint
54 ; CHECK: %p.relocated
55 ; CHECK-NEXT: %p.relocated.casted = bitcast i8 addrspace(1)* %p.relocated to i32 addrspace(1)*
56 ; CHECK-NEXT: store i32 %x, i32 addrspace(1)* %p.relocated.casted, align 16
57 entry:
58 %y = load i32, i32 addrspace(1)* %q, align 16, !noalias !3
59 call void @baz(i32 %x)
60 store i32 %x, i32 addrspace(1)* %p, align 16, !noalias !4
61 ret void
62 }
63
64 ; drop the dereferenceable metadata
65 define void @test_dereferenceable(i32 addrspace(1)* addrspace(1)* %p, i32 %x, i32 addrspace(1)* %q) gc "statepoint-example" {
66 ; CHECK-LABEL: test_dereferenceable
67 ; CHECK: %v1 = load i32 addrspace(1)*, i32 addrspace(1)* addrspace(1)* %p
68 ; CHECK-NEXT: %v2 = load i32, i32 addrspace(1)* %v1
69 ; CHECK: gc.statepoint
70 %v1 = load i32 addrspace(1)*, i32 addrspace(1)* addrspace(1)* %p, !dereferenceable !5
71 %v2 = load i32, i32 addrspace(1)* %v1
72 call void @baz(i32 %x)
73 store i32 %v2, i32 addrspace(1)* %q, align 16
74 ret void
75 }
76
77 declare token @llvm.experimental.gc.statepoint.p0f_isVoidi32f(i64, i32, void (i32)*, i32, i32, ...)
78
79 ; Function Attrs: nounwind readonly
80 declare i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token, i32, i32) #0
81
82 declare token @llvm.experimental.gc.statepoint.p0f_isVoidf(i64, i32, void ()*, i32, i32, ...)
83
84 attributes #0 = { nounwind readonly }
85
86 !0 = !{i32 0, i32 2147483647}
87 !1 = !{}
88 !2 = !{i32 10, i32 1}
89 !3 = !{!3}
90 !4 = !{!4}
91 !5 = !{i64 8}