Index: lib/Analysis/IPA/GlobalsModRef.cpp =================================================================== --- lib/Analysis/IPA/GlobalsModRef.cpp +++ lib/Analysis/IPA/GlobalsModRef.cpp @@ -675,6 +675,52 @@ if ((GV1 || GV2) && GV1 != GV2) return NoAlias; + // There are particular cases where we can conclude no-alias between + // a non-addr-taken global and some other underlying object. Specifically, + // a non-addr-taken global is known to not be captured by any function. It + // is also incorrect for a transformation to introduce a capture of + // a global in a way that is observable when it was not there previously. + // One function being transformed to introduce a capture which could + // possibly be observed (via loading from a global for example) within + // another function is never safe. If the observation is made through + // non-atomic operations on different threads, it is a data-race and UB. If + // the observation is well defined, by being observed the transformation + // would have changed program behavior by introducing the capture, making + // it an invalid transform. + // + // This property does require that transformation which *temporarily* + // capture a global that was not previously captured, prior to restoring + // it, cannot rely on the results of GMR::alias. This seems a reasonable + // restriction, although currently there is no way to enforce it. There is + // also no realistic optimization pass that would make this mistake. The + // closest example is a transformation pass which does reg2mem of SSA + // values but stores them into global variables temporarily before + // restoring the global variable's value. This could be useful to expose + // "benign" races for example. However, it seems reasonable to require that + // a pass which introduces captures of global variables in this way to + // either not trust AA results while the capture is active, or to be forced + // to operate as a module pass that cannot co-exist with an alias analysis + // such as GMR. + if ((GV1 || GV2) && GV1 != GV2) { + const Value *UV = GV1 ? UV2 : UV1; + + // In order to know that the underlying object cannot alias the + // non-addr-taken global, we must know that it would have to be an + // escape. Thus if the underlying object is a function argument, a load + // from a global, or the return of a function, it cannot alias. + if (isa(UV) || isa(UV) || isa(UV)) { + // Arguments to functions or returns from functions are inherently + // capturing, so we can immediately classify those as not aliasing any + // non-addr-taken globals. + return NoAlias; + } else if (auto *LI = dyn_cast(UV)) { + // A pointer loaded from a global would have been captured, and we know + // that GV is non-addr-taken, so no alias. + if (isa(LI->getPointerOperand())) + return NoAlias; + } + } + // Otherwise if they are both derived from the same addr-taken global, we // can't know the two accesses don't overlap. }