Hi,

I think the assumption that intrinsics can't read any global is, indeed, the problem here. `@llvm.objc.autoreleasePoolPop` may call any number of `-dealloc` methods with arbitrary side effects (though if they cause resurrection then that's undefined behaviour), so there should be no assumptions about the memory that it will read and write.

This check looks wrong, the documentation in Intrinsics.td states:

> By default, intrinsics are assumed to have side
> effects, so this property is only necessary if you have defined one of
> the memory properties listed above.

Looking at the other intrinsics, the ones that don't touch memory (mostly?) seem to have the IntrNoMem attribute set. I think that should GlobalsAA should probably check that intrinsics either have that attribute set or one of the others that restricts the memory it can touch (e.g. IntrArgMemOnly).

David

On 31/10/2019 23:55, Alina Sbirlea wrote:
Following up on this, AFAICT this is working as intended on the LLVM side.

The different decision is made in GlobalsAA + MemoryDependencyAnalysis.
IIUC, the logic there is along the lines of: if I have a global G that's "internal" ("static" in C), and an intrinsic method M, then M cannot read from or write to G. In the LLVM IR for the test, @deallocCalled is an internal global, @llvm.objc.autoreleasePoolPop is an intrinsic, hence @llvm.objc.autoreleasePoolPop cannot read or write @deallocCalled.

Please note however that there are a couple of things that I found and intend to fix in GlobalsAA, but they do not seem to affect this case.

The one problem in particular that I thought was relevant here is that the "MayReadAnyGlobal" is not set on a path in GlobalsAAResult::AnalyzeCallGraph, but should apply when the function is not an intrinsic (judging by the other code paths). If @llvm.objc.autoreleasePoolPop was not an intrinsic, then with the fix in D69690 <https://reviews.llvm.org/D69690> would resolve this miscompile. Perhaps we should not rely on the assumption that intrinsics are restricted to this behavior in GlobalsAA?

Best,
Alina


On Thu, Oct 17, 2019 at 3:00 PM Alina Sbirlea <alina.sbir...@gmail.com <mailto:alina.sbir...@gmail.com>> wrote:

    I only got a chance to look more into this now. I can reproduce it
    with re-inserting the "static".

    The miscompile is not related to MemorySSA, i.e. disabling all uses
    of MemorySSA doesn't help.
    It appears to be a GVN bug, but I haven't tracked it further than this.

    To repro, see attached .ll files. The only difference is the global
    variable being static or not, which in IR translates to internal or
    dso_local.
    A simple `opt -O3 AssociatedObject_O0_*.ll` shows the difference you
    mention.

    Reducing the pipeline, I believe the result after the following
    command is incorrect.
    `opt -globals-aa -gvn AssociatedObject_O0_*.ll`
    I'll need to dig deeper to confirm and track down the bug inside the
    pass.


    Thanks,
    Alina


    On Mon, Sep 30, 2019 at 4:30 AM David Chisnall
    <david.chisn...@cl.cam.ac.uk <mailto:david.chisn...@cl.cam.ac.uk>>
    wrote:

        Hi,

        Yes, I believe it does still reproduce (at least, with the most
        recent
        build that I tried).  We worked around the clang bug to make the
        test pass:

        
https://github.com/gnustep/libobjc2/commit/eab35fce379eb6ab1423dbb6d7908cb782f13458#diff-7f1eea7fdb5c7c3bf21f08d1cfe98a19

        Reintroducing the 'static' on deallocCalled reduces the test
        case to
        unconditionally failing the assert immediately after the pop,
        and DCEs
        the rest of the code.

        David

        On 11/09/2019 01:17, Alina Sbirlea wrote:
         > Hi David,
         >
         > Does this still reproduce?
         > I'm seeing the load after the call to autoreleasePoolPop at
        ToT, but
         > perhaps I'm not using the proper flags?
         > I only checked out the github repo and did "clang
         > -fobjc-runtime=gnustep-2.0 -O3 -emit-llvm -S
         > libobjc2/Test/AssociatedObject.m" with a ToT clang.
         >
         > Thanks,
         > Alina
         >
         >
         > On Sun, Feb 24, 2019 at 9:56 AM Pete Cooper via llvm-commits
         > <llvm-comm...@lists.llvm.org
        <mailto:llvm-comm...@lists.llvm.org>
        <mailto:llvm-comm...@lists.llvm.org
        <mailto:llvm-comm...@lists.llvm.org>>> wrote:
         >
         >     Hey David
         >
         >     Thanks for letting me know, and analysing it this far!
         >
         >     I also can't see anything wrong with the intrinsic.  Its just
         >     defined as:
         >
         >         def int_objc_autoreleasePoolPop             :
        Intrinsic<[],
         >         [llvm_ptr_ty]>;
         >
         >
         >     which (I believe) means it has unmodelled side effects so
        it should
         >     have been fine for your example.
         >
         >     I'll try build the same file you did and see if I can
        reproduce.
         >
         >     Cheers,
         >     Pete
         >
         >>     On Feb 24, 2019, at 7:48 AM, David Chisnall via Phabricator
         >>     <revi...@reviews.llvm.org
        <mailto:revi...@reviews.llvm.org>
        <mailto:revi...@reviews.llvm.org
        <mailto:revi...@reviews.llvm.org>>> wrote:
         >>
         >>     theraven added a comment.
         >>     Herald added a project: LLVM.
         >>
         >>     After some bisection, it appears that this is the
        revision that
         >>     introduced the regression in the GNUstep Objective-C
        runtime test
         >>     suite that I reported on the list a few weeks ago.  In
        this is the
         >>     test (compiled with `-fobjc-runtime=gnustep-2.0 -O3` and
        an ELF
         >>     triple):
         >>
         >>
        https://github.com/gnustep/libobjc2/blob/master/Test/AssociatedObject.m
         >>
         >>     After this change, Early CSE w/ MemorySSA is determining
        that the
         >>     second load of `deallocCalled` is redundant.  The code
        goes from:
         >>
         >>        %7 = load i1, i1* @deallocCalled, align 1
         >>        br i1 %7, label %8, label %9
         >>
         >>      ; <label>:8:                                      ;
        preds = %0
         >>        call void @__assert(i8* getelementptr inbounds ([5 x
        i8], [5 x
         >>     i8]* @__func__.main, i64 0, i64 0), i8* getelementptr
        inbounds
         >>     ([27 x i8], [27 x i8]* @.str, i64 0, i64 0), i32 26, i8*
         >>     getelementptr inbounds ([15 x i8], [15 x i8]* @.str.1,
        i64 0, i64
         >>     0)) #5
         >>        unreachable
         >>
         >>      ; <label>:9:                                      ;
        preds = %0
         >>        call void @llvm.objc.autoreleasePoolPop(i8* %1)
         >>        %10 = load i1, i1* @deallocCalled, align 1
         >>        br i1 %10, label %12, label %11
         >>
         >>      ; <label>:11:                                     ;
        preds = %9
         >>        call void @__assert(i8* getelementptr inbounds ([5 x
        i8], [5 x
         >>     i8]* @__func__.main, i64 0, i64 0), i8* getelementptr
        inbounds
         >>     ([27 x i8], [27 x i8]* @.str, i64 0, i64 0), i32 29, i8*
         >>     getelementptr inbounds ([14 x i8], [14 x i8]* @.str.2,
        i64 0, i64
         >>     0)) #5
         >>        unreachable
         >>
         >>     to:
         >>
         >>        %7 = load i1, i1* @deallocCalled, align 1
         >>        br i1 %7, label %8, label %9
         >>
         >>      ; <label>:8:                                      ;
        preds = %0
         >>        call void @__assert(i8* getelementptr inbounds ([5 x
        i8], [5 x
         >>     i8]* @__func__.main, i64 0, i64 0), i8* getelementptr
        inbounds
         >>     ([27 x i8], [27 x i8]* @.str, i64 0, i64 0), i32 26, i8*
         >>     getelementptr inbounds ([15 x i8], [15 x i8]* @.str.1,
        i64 0, i64
         >>     0)) #5
         >>        unreachable
         >>
         >>      ; <label>:9:                                      ;
        preds = %0
         >>        call void @llvm.objc.autoreleasePoolPop(i8* %1)
         >>        br i1 %7, label %11, label %10
         >>
         >>      ; <label>:10:                                     ;
        preds = %9
         >>        call void @__assert(i8* getelementptr inbounds ([5 x
        i8], [5 x
         >>     i8]* @__func__.main, i64 0, i64 0), i8* getelementptr
        inbounds
         >>     ([27 x i8], [27 x i8]* @.str, i64 0, i64 0), i32 29, i8*
         >>     getelementptr inbounds ([14 x i8], [14 x i8]* @.str.2,
        i64 0, i64
         >>     0)) #5
         >>        unreachable
         >>
         >>     Later optimisations then determine that, because the
        assert does
         >>     not return, the only possible value for %7 is false and
        cause the
         >>     second assert to fire unconditionally.
         >>
         >>     It appears that we are not correctly modelling the side
        effects of
         >>     the `llvm.objc.autoreleasePoolPop` intrinsic, but it's not
         >>     entirely clear why not.  The same test compiled for the
        macos
         >>     runtime does not appear to exhibit the same behaviour.  The
         >>     previous revision, where we emitted a call to
         >>     `objc_autoreleasePoolPop` and not the intrinsic worked
        correctly,
         >>     but with this change the optimisers are assuming that no
        globals
         >>     can be modified across an autorelease pool pop operation (at
         >>     least, in some situations).
         >>
         >>     Looking at the definition of the intrinsic, I don't see
        anything
         >>     wrong, so I still suspect that there is a MemorySSA bug
        that this
         >>     has uncovered, rather than anything wrong in this series of
         >>     commits.  Any suggestions as to where to look would be
        appreciated.
         >>
         >>
         >>     Repository:
         >>      rL LLVM
         >>
         >>     CHANGES SINCE LAST ACTION
         >> https://reviews.llvm.org/D55802/new/
         >>
         >> https://reviews.llvm.org/D55802
         >>
         >>
         >>
         >
         >     _______________________________________________
         >     llvm-commits mailing list
         > llvm-comm...@lists.llvm.org
        <mailto:llvm-comm...@lists.llvm.org>
        <mailto:llvm-comm...@lists.llvm.org
        <mailto:llvm-comm...@lists.llvm.org>>
         > https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
         >

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to