First of all, this patch fixed the issue with AttrEscaped. Now AttrEscaped always may-alias AttrGlobal/AttrArgXXX.
To compensate for the precision loss introduced by the fix, we add yet another StratifiedAttr called "AttrExternal". This is an attribute designed specifically for global values and argument values, to distinguish the values themselves from the memory they point to (which are still tagged with "AttrGlobal"/"AttrArgXXX" respectively). The biggest difference between AttrExternal and AttrGlobal/AttrArgXXX/AttrUnknown is that the former does not alias AttrEscaped value, while the latter may.
Here's an example:
declare @external(i32*) global @g = i32 0 define void @foo(i32* %x) { %a = alloca i32 call @external(i32* %a) ret void }
Let's assume for now that we tag %a as AttrEscaped (this hasn't happened yet but will happen in the next patch). Since %a is an identifiable stack allocation, neither %x nor @g can alias it.
- %x cannot alias %a because %a is allocated after %x therefore there's no way %x can be assigned the value of %a without pointer-guessing, which is UB.
- @g cannot alias %a because @g is also an identifiable allocation. It is also a global, therefore a constant, whose value cannot be changed to the value of %a
Of course, if we try to load from @g or %x, the result may alias %a. However, if that happens, the analysis will tag the loaded value as AttrUnknown, hence it is still sound.