Index: lib/Transforms/Scalar/RewriteStatepointsForGC.cpp =================================================================== --- lib/Transforms/Scalar/RewriteStatepointsForGC.cpp +++ lib/Transforms/Scalar/RewriteStatepointsForGC.cpp @@ -2313,6 +2313,18 @@ LLVMContext &Ctx = F.getContext(); MDBuilder Builder(Ctx); + // These are the attributes that are still valid after RS4GC. The invalid one + // is MD_invariant_load. + unsigned KnownIDs[] = {LLVMContext::MD_tbaa, + LLVMContext::MD_range, + LLVMContext::MD_alias_scope, + LLVMContext::MD_noalias, + LLVMContext::MD_nonnull, + LLVMContext::MD_dereferenceable, + LLVMContext::MD_dereferenceable_or_null, + LLVMContext::MD_invariant_group, + LLVMContext::MD_align}; + for (Instruction &I : instructions(F)) { if (const MDNode *MD = I.getMetadata(LLVMContext::MD_tbaa)) { assert(MD->getNumOperands() < 5 && "unrecognized metadata shape!"); @@ -2333,6 +2345,12 @@ I.setMetadata(LLVMContext::MD_tbaa, MutableTBAA); } + // After RS4GC is completed, the operand of a load instruction (i.e. + // address) could have been relocated. So, remove the invariant_load + // metadata that's invalid after RS4GC. + if (isa(I) && I.getMetadata(LLVMContext::MD_invariant_load)) + I.dropUnknownNonDebugMetadata(KnownIDs); + if (CallSite CS = CallSite(&I)) { for (int i = 0, e = CS.arg_size(); i != e; i++) if (isa(CS.getArgument(i)->getType())) Index: test/Transforms/RewriteStatepointsForGC/drop-invalid-metadata.ll =================================================================== --- /dev/null +++ test/Transforms/RewriteStatepointsForGC/drop-invalid-metadata.ll @@ -0,0 +1,61 @@ +; RUN: opt -S -rewrite-statepoints-for-gc < %s | FileCheck %s + +; This test checks that metadata that's invalid after RS4GC is dropped. +; We can miscompile if optimizations scheduled after RS4GC uses the +; metadata that's infact invalid. + +; Confirm that loadedval instruction does not contain invariant.load metadata. +; Since loadedval is not marked invariant, it will prevent incorrectly sinking +; %loadedval in LICM and avoid creation of an unrelocated use of %baseaddr. +define void @test() gc "statepoint-example" { +; CHECK-LABEL: @test +; CHECK: %loadedval = load i32, i32 addrspace(1)* %baseaddr, align 8, !range !0 +bb: + br label %outerloopHdr + +outerloopHdr: ; preds = %bb6, %bb + %baseaddr = phi i32 addrspace(1)* [ undef, %bb ], [ %tmp4, %bb6 ] +; LICM may sink this load to exit block after RS4GC because it's tagged invariant. + %loadedval = load i32, i32 addrspace(1)* %baseaddr, align 8, !range !0, !invariant.load !1 + br label %innerloopHdr + +innerloopHdr: ; preds = %innerlooplatch, %outerloopHdr + %tmp4 = phi i32 addrspace(1)* [ %baseaddr, %outerloopHdr ], [ %gep, %innerlooplatch ] + br label %innermostloophdr + +innermostloophdr: ; preds = %bb6, %innerloopHdr + br i1 undef, label %exitblock, label %bb6 + +bb6: ; preds = %innermostloophdr + switch i32 undef, label %innermostloophdr [ + i32 0, label %outerloopHdr + i32 1, label %innerlooplatch + ] + +innerlooplatch: ; preds = %bb6 + call void @bar() + %gep = getelementptr inbounds i32, i32 addrspace(1)* %tmp4, i64 8 + br label %innerloopHdr + +exitblock: ; preds = %innermostloophdr + %tmp13 = add i32 42, %loadedval + call void @baz(i32 %tmp13) + unreachable +} + +declare void @bar() + +declare void @baz(i32) + +declare token @llvm.experimental.gc.statepoint.p0f_isVoidi32f(i64, i32, void (i32)*, i32, i32, ...) + +; Function Attrs: nounwind readonly +declare i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token, i32, i32) #0 + +declare token @llvm.experimental.gc.statepoint.p0f_isVoidf(i64, i32, void ()*, i32, i32, ...) + +attributes #0 = { nounwind readonly } + +!0 = !{i32 0, i32 2147483647} +!1 = !{} +!2 = !{i32 10, i32 1}