<font size=2 face="sans-serif">Hello all,</font><br><br><font size=2 face="sans-serif">I'm new to the llvm community. I'm
learning how things work. I noticed that there has been some interest
in improving how unions are handled. Bug 21725 is one example. I
figured it might be a interesting place to start. I discussed this
with a couple people, and below is a suggestion on how to represent unions.
I would like some comments on how this fits in with how things are
done in llvm.</font><br><br><font size=2 face="sans-serif">Later,</font><br><font size=2 face="sans-serif">Steven Perron</font><br><br><font size=2 face="sans-serif">Motivation</font><br><font size=2 face="sans-serif">==========</font><br><br><font size=2 face="sans-serif">The main motivation for this is functional
correctness of code using unions.</font><br><font size=2 face="sans-serif">See </font><a href="https://llvm.org/bugs/show_bug.cgi?id=21725"><font size=2 face="sans-serif">https://llvm.org/bugs/show_bug.cgi?id=21725</font></a><font size=2 face="sans-serif">for one example. The problem is</font><br><font size=2 face="sans-serif">that the basic alias analysis (or any
other alias analysis) will not always have</font><br><font size=2 face="sans-serif">enough information to be able see that
the two references definitely overlap.</font><br><font size=2 face="sans-serif">When this happens, the lack of alias
information for unions could allow</font><br><font size=2 face="sans-serif">undesired optimizations.</font><br><br><br><font size=2 face="sans-serif">Current state</font><br><font size=2 face="sans-serif">=============</font><br><br><font size=2 face="sans-serif">For this RFC, we are interested in how
the type based aliasing is represented</font><br><font size=2 face="sans-serif">for non-scalar data types. In
C/C++, this will be arrays, structs, classes, and</font><br><font size=2 face="sans-serif">unions. We will not mention classes
again because for this purpose they are the</font><br><font size=2 face="sans-serif">exact same as structs.</font><br><br><font size=2 face="sans-serif">We will start with structs. To
help with the aliasing of structs, There is a</font><br><font size=2 face="sans-serif">format for the type based aliasing meta
data known as the struct-path. Here is</font><br><font size=2 face="sans-serif">example IR:</font><br><br><font size=2 face="sans-serif"> %0 = load i32, i32* getelementptr
inbounds (%struct.S, %struct.S* @s, i32 0, %i32 2), align 4, !tbaa !2</font><br><font size=2 face="sans-serif"> %1 = load i32, i32* getelementptr
inbounds (%struct.S, %struct.S* @s, i32 0, %i32 3), align 4, !tbaa !7</font><br><font size=2 face="sans-serif"> ...</font><br><font size=2 face="sans-serif"> !2 = !{!3, !6, i64 800}</font><br><font size=2 face="sans-serif"> !3 = !{!"S", !4, i64
0, !4, i64 400, !6, i64 800, !6, i64 804}</font><br><font size=2 face="sans-serif"> !4 = !{!"omnipotent char",
!5, i64 0}</font><br><font size=2 face="sans-serif"> !5 = !{!"Simple C/C++ TBAA"}</font><br><font size=2 face="sans-serif"> !6 = !{!"int", !4, i64
0}</font><br><font size=2 face="sans-serif"> !7 = !{!3, !6, i64 804}</font><br><br><font size=2 face="sans-serif">The two loads are loads of different
int members of the same struct. The type</font><br><font size=2 face="sans-serif">based aliasing gives them different
meta data tags (!2 and !7). This allows the</font><br><font size=2 face="sans-serif">analysis to determine that they are
different solely from the type based</font><br><font size=2 face="sans-serif">aliasing information. Looking
at !2, it points to !3 with offset 800. This</font><br><font size=2 face="sans-serif">offset is used to identify which member
of the struct is being accessed.</font><br><br><font size=2 face="sans-serif">Next we will consider arrays. When
there is an array access, the type based</font><br><font size=2 face="sans-serif">aliasing views it as an access of the
type of the element. In general, this is</font><br><font size=2 face="sans-serif">not a problem. For C/C++, there
is no real difference between an array</font><br><font size=2 face="sans-serif">reference and a dereference of a pointer.
However, this causes a lose of</font><br><font size=2 face="sans-serif">information when accessing arrays that
are part of a struct or union.</font><br><br><font size=2 face="sans-serif">Here is an example:</font><br><br><font size=2 face="sans-serif"> %arrayidx = getelementptr inbounds
[100 x i32], [100 x i32]* getelementptr %inbounds (%struct.S, %struct.S*
@s, i32 0, i32 0), i64 0, i64 %idxprom</font><br><font size=2 face="sans-serif"> %1 = load i32, i32* %arrayidx,
align 4, !tbaa !1</font><br><font size=2 face="sans-serif"> ...</font><br><font size=2 face="sans-serif"> !1 = !{!2, !2, i64 0}</font><br><font size=2 face="sans-serif"> !2 = !{!"int", !3,
i64 0}</font><br><br><font size=2 face="sans-serif">This is an access to an array of integers
in a struct of type S. Note that the</font><br><font size=2 face="sans-serif">type on the load is "int".
The type bases alias information has lost that this</font><br><font size=2 face="sans-serif">is a reference to a member of a struct.</font><br><br><font size=2 face="sans-serif">We finish by considering unions. Like
arrays, an access to a member of a union</font><br><font size=2 face="sans-serif">is treated as if is it type of the type
of the member being accessed. Here is</font><br><font size=2 face="sans-serif">an example:</font><br><br><font size=2 face="sans-serif"> %4 = load i32, i32* getelementptr
inbounds (%union.U, %union.U* @u, i32 0, i32 %0), align 4, !tbaa !2</font><br><font size=2 face="sans-serif"> ...</font><br><font size=2 face="sans-serif"> !2 = !{!3, !3, i64 0}</font><br><font size=2 face="sans-serif"> !3 = !{!"int", !4,
i64 0}</font><br><br><font size=2 face="sans-serif">Here we lose the information that the
reference is part of a union, so we cannot</font><br><font size=2 face="sans-serif">tell that this memory may overlap with
something of a different type. Clang</font><br><font size=2 face="sans-serif">currently relies on other aliasing analysis
like the basic alias analysis to</font><br><font size=2 face="sans-serif">observer that the two references are
aliased.</font><br><br><font size=2 face="sans-serif">Proposed changes for arrays</font><br><font size=2 face="sans-serif">===========================</font><br><br><font size=2 face="sans-serif">To deal with array references, they
should be treated as if all array accesses</font><br><font size=2 face="sans-serif">are accesses to the first member of
the array. For the purpose of type based</font><br><font size=2 face="sans-serif">aliasing, this should be good enough.
The offset in the tag would be the</font><br><font size=2 face="sans-serif">offset of the start of the array plus,
if applicable, the offset needed to</font><br><font size=2 face="sans-serif">access the member of the array element
as if the element was a top-level struct</font><br><font size=2 face="sans-serif">member at offset 0. Note that
the values for the indexing of the array is not</font><br><font size=2 face="sans-serif">included. Thus, accesses to an
element of the last dimension of a</font><br><font size=2 face="sans-serif">multidimensional array appears the same
as an access to a flattened version of</font><br><font size=2 face="sans-serif">the multidimensional array. Then,
in the struct path, the array member's offset</font><br><font size=2 face="sans-serif">will be the starting offset of the array,
as it is now. What will change in the</font><br><font size=2 face="sans-serif">struct path is the type node for the
array. The type node will become the type</font><br><font size=2 face="sans-serif">of the array element instead of "omnipotent
char", as it is now.</font><br><br><font size=2 face="sans-serif">This change is a must to be able to
get union aliasing correct because we need</font><br><font size=2 face="sans-serif">to know when an array is part of a union
that may overlap with other members.</font><br><br><br><br><font size=2 face="sans-serif">Proposed changes for unions</font><br><font size=2 face="sans-serif">============================</font><br><br><font size=2 face="sans-serif">To properly deal with unions, there
are a few issues that need to be dealt with.</font><br><br><font size=2 face="sans-serif">1) Unions have to somehow be represented
in the TBAA. As was pointed out above,</font><br><font size=2 face="sans-serif">this information is currently lost.</font><br><br><font size=2 face="sans-serif">2) With the struct path TBAA, it is
assumed that the length of a member extends</font><br><font size=2 face="sans-serif">to the start of the next. This
will not be true for unions.</font><br><br><font size=2 face="sans-serif">3) With the current struct path TBAA,
you can determine which member is</font><br><font size=2 face="sans-serif">reference by looking at the offset.
That is not true with unions because every</font><br><font size=2 face="sans-serif">member starts at offset 0. We
will need another way of doing this for unions.</font><br><br><font size=2 face="sans-serif">Any solution we come up with will have
to get around these three problems.</font><br><br><font size=2 face="sans-serif">To deal with unions, we will use the
change in bug 21725 (see link above). This</font><br><font size=2 face="sans-serif">will treat a union as if it is a struct.
However, the important change to make</font><br><font size=2 face="sans-serif">the unions work is that the length of
the memory reference will have to be taken</font><br><font size=2 face="sans-serif">into consideration when looking at the
type based aliasing. This should be easy</font><br><font size=2 face="sans-serif">enough because TypeBasedAAResult::alias
takes two arguments of type</font><br><font size=2 face="sans-serif">MemoryLocation, and they contain the
size information that is needed. This</font><br><font size=2 face="sans-serif">should easy take care of the first two
problems.</font><br><br><font size=2 face="sans-serif">In TypeBasedAAResult::alias, we will
also have to deal with the fact that unions</font><br><font size=2 face="sans-serif">have multiple members all at offset
0. This means that, unlike structs, the</font><br><font size=2 face="sans-serif">compiler will not be able to tell which
member of the union the memory reference</font><br><font size=2 face="sans-serif">actually used. To deal with this,
TypeBasedAAResult::alias (and the functions</font><br><font size=2 face="sans-serif">it calls) will have to acts as if all
of the unions members could have been</font><br><font size=2 face="sans-serif">accessed. So the search along
the tree will follow all of the member instead of</font><br><font size=2 face="sans-serif">just one as we currently do with structs.
Changes to the algorithm can be made</font><br><font size=2 face="sans-serif">to avoid traversing the same TBAA nodes
multiple times. The section at the end</font><br><font size=2 face="sans-serif">explores the consequences of this decision
and a possible alternative.</font><br><br><font size=2 face="sans-serif">Examples</font><br><font size=2 face="sans-serif">========</font><br><br><font size=2 face="sans-serif">Source code for the example</font><br><font size=2 face="sans-serif">---------------------------</font><br><br><font size=2 face="sans-serif">struct S</font><br><font size=2 face="sans-serif">{</font><br><font size=2 face="sans-serif"> int b;</font><br><font size=2 face="sans-serif"> struct T</font><br><font size=2 face="sans-serif"> {</font><br><font size=2 face="sans-serif"> int a[10];</font><br><font size=2 face="sans-serif"> } t;</font><br><font size=2 face="sans-serif">} s;</font><br><br><font size=2 face="sans-serif">struct C</font><br><font size=2 face="sans-serif">{</font><br><font size=2 face="sans-serif"> int a;</font><br><font size=2 face="sans-serif"> int b;</font><br><font size=2 face="sans-serif">};</font><br><br><font size=2 face="sans-serif">struct R</font><br><font size=2 face="sans-serif">{</font><br><font size=2 face="sans-serif"> union {</font><br><font size=2 face="sans-serif"> struct C a[10];</font><br><font size=2 face="sans-serif"> struct C b[10];</font><br><font size=2 face="sans-serif"> } u;</font><br><font size=2 face="sans-serif"> int c;</font><br><font size=2 face="sans-serif">} r;</font><br><br><font size=2 face="sans-serif">union U</font><br><font size=2 face="sans-serif">{</font><br><font size=2 face="sans-serif"> int i;</font><br><font size=2 face="sans-serif"> float f;</font><br><font size=2 face="sans-serif">} u;</font><br><br><font size=2 face="sans-serif">struct Q</font><br><font size=2 face="sans-serif">{</font><br><font size=2 face="sans-serif"> int a;</font><br><font size=2 face="sans-serif"> union U u;</font><br><font size=2 face="sans-serif">} q;</font><br><br><font size=2 face="sans-serif">int foo()</font><br><font size=2 face="sans-serif">{</font><br><font size=2 face="sans-serif"> return s.t.a[4] + s.b + r.u.b[3].b
+ u.i + u.f + q.u.i + q.u.f + q.a + r.c;</font><br><font size=2 face="sans-serif">}</font><br><br><font size=2 face="sans-serif">----------------------------</font><br><font size=2 face="sans-serif">Current llvm-ir</font><br><font size=2 face="sans-serif">----------------------------</font><br><br><font size=2 face="sans-serif">*** IR Dump Before Module Verifier ***</font><br><font size=2 face="sans-serif">; Function Attrs: nounwind</font><br><font size=2 face="sans-serif">define signext i32 @foo() #0 {</font><br><font size=2 face="sans-serif">entry:</font><br><font size=2 face="sans-serif"> %0 = load i32, i32* getelementptr
inbounds (%struct.S, %struct.S* @s, i32 0, i32 1, i32 0, i64 4), align
4, !tbaa !2</font><br><font size=2 face="sans-serif"> %1 = load i32, i32* getelementptr
inbounds (%struct.S, %struct.S* @s, i32 0, i32 0), align 4, !tbaa !6</font><br><font size=2 face="sans-serif"> %add = add nsw i32 %0, %1</font><br><font size=2 face="sans-serif"> %2 = load i32, i32* getelementptr
inbounds (%struct.R, %struct.R* @r, i32 0, i32 0, i32 0, i64 3, i32 1),
align 4, !tbaa !9</font><br><font size=2 face="sans-serif"> %add1 = add nsw i32 %add, %2</font><br><font size=2 face="sans-serif"> %3 = load i32, i32* getelementptr
inbounds (%union.U, %union.U* @u, i32 0, i32 0), align 4, !tbaa !2</font><br><font size=2 face="sans-serif"> %add2 = add nsw i32 %add1, %3</font><br><font size=2 face="sans-serif"> %conv = sitofp i32 %add2 to float</font><br><font size=2 face="sans-serif"> %4 = load float, float* bitcast
(%union.U* @u to float*), align 4, !tbaa !11</font><br><font size=2 face="sans-serif"> %add3 = fadd float %conv, %4</font><br><font size=2 face="sans-serif"> %5 = load i32, i32* getelementptr
inbounds (%struct.Q, %struct.Q* @q, i32 0, i32 1, i32 0), align 4, !tbaa
!2</font><br><font size=2 face="sans-serif"> %conv4 = sitofp i32 %5 to float</font><br><font size=2 face="sans-serif"> %add5 = fadd float %add3, %conv4</font><br><font size=2 face="sans-serif"> %6 = load float, float* bitcast
(%union.U* getelementptr inbounds (%struct.Q, %struct.Q* @q, i32 0, i32
1) to float*), align 4, !tbaa !11</font><br><font size=2 face="sans-serif"> %add6 = fadd float %add5, %6</font><br><font size=2 face="sans-serif"> %7 = load i32, i32* getelementptr
inbounds (%struct.Q, %struct.Q* @q, i32 0, i32 0), align 4, !tbaa !13</font><br><font size=2 face="sans-serif"> %conv7 = sitofp i32 %7 to float</font><br><font size=2 face="sans-serif"> %add8 = fadd float %add6, %conv7</font><br><font size=2 face="sans-serif"> %8 = load i32, i32* getelementptr
inbounds (%struct.R, %struct.R* @r, i32 0, i32 1), align 4, !tbaa !15</font><br><font size=2 face="sans-serif"> %conv9 = sitofp i32 %8 to float</font><br><font size=2 face="sans-serif"> %add10 = fadd float %add8, %conv9</font><br><font size=2 face="sans-serif"> %conv11 = fptosi float %add10
to i32</font><br><font size=2 face="sans-serif"> ret i32 %conv11</font><br><font size=2 face="sans-serif">}</font><br><br><font size=2 face="sans-serif">!0 = !{i32 1, !"PIC Level",
i32 2}</font><br><font size=2 face="sans-serif">!1 = !{!"clang version 4.0.0 (trunk
290896)"}</font><br><font size=2 face="sans-serif">!2 = !{!3, !3, i64 0}</font><br><font size=2 face="sans-serif">!3 = !{!"int", !4, i64 0}</font><br><font size=2 face="sans-serif">!4 = !{!"omnipotent char",
!5, i64 0}</font><br><font size=2 face="sans-serif">!5 = !{!"Simple C/C++ TBAA"}</font><br><font size=2 face="sans-serif">!6 = !{!7, !3, i64 0}</font><br><font size=2 face="sans-serif">!7 = !{!"S", !3, i64 0, !8,
i64 4}</font><br><font size=2 face="sans-serif">!8 = !{!"T", !4, i64 0}</font><br><font size=2 face="sans-serif">!9 = !{!10, !3, i64 4}</font><br><font size=2 face="sans-serif">!10 = !{!"C", !3, i64 0, !3,
i64 4}</font><br><font size=2 face="sans-serif">!11 = !{!12, !12, i64 0}</font><br><font size=2 face="sans-serif">!12 = !{!"float", !4, i64
0}</font><br><font size=2 face="sans-serif">!13 = !{!14, !3, i64 0}</font><br><font size=2 face="sans-serif">!14 = !{!"Q", !3, i64 0, !4,
i64 4}</font><br><font size=2 face="sans-serif">!15 = !{!16, !3, i64 80}</font><br><font size=2 face="sans-serif">!16 = !{!"R", !4, i64 0, !3,
i64 80}</font><br><br><font size=2 face="sans-serif">----------------------------</font><br><font size=2 face="sans-serif">Suggested new llvm-ir</font><br><font size=2 face="sans-serif">----------------------------</font><br><br><font size=2 face="sans-serif">*** IR Dump Before Module Verifier ***</font><br><font size=2 face="sans-serif">; Function Attrs: nounwind</font><br><font size=2 face="sans-serif">define signext i32 @foo() #0 {</font><br><font size=2 face="sans-serif">entry:</font><br><font size=2 face="sans-serif"> %0 = load i32, i32* getelementptr
inbounds (%struct.S, %struct.S* @s, i32 0, i32 1, i32 0, i64 4), align
4, !tbaa !2</font><br><font size=2 face="sans-serif"> %1 = load i32, i32* getelementptr
inbounds (%struct.S, %struct.S* @s, i32 0, i32 0), align 4, !tbaa !6</font><br><font size=2 face="sans-serif"> %add = add nsw i32 %0, %1</font><br><font size=2 face="sans-serif"> %2 = load i32, i32* getelementptr
inbounds (%struct.R, %struct.R* @r, i32 0, i32 0, i32 0, i64 3, i32 1),
align 4, !tbaa !9</font><br><font size=2 face="sans-serif"> %add1 = add nsw i32 %add, %2</font><br><font size=2 face="sans-serif"> %3 = load i32, i32* getelementptr
inbounds (%union.U, %union.U* @u, i32 0, i32 0), align 4, !tbaa !18
// Need to change to reference the union "U", not just the scalar.</font><br><font size=2 face="sans-serif"> %add2 = add nsw i32 %add1, %3</font><br><font size=2 face="sans-serif"> %conv = sitofp i32 %add2 to float</font><br><font size=2 face="sans-serif"> %4 = load float, float* bitcast
(%union.U* @u to float*), align 4, !tbaa !11</font><br><font size=2 face="sans-serif"> %add3 = fadd float %conv, %4</font><br><font size=2 face="sans-serif"> %5 = load i32, i32* getelementptr
inbounds (%struct.Q, %struct.Q* @q, i32 0, i32 1, i32 0), align 4, !tbaa
!19 // Need to reference
the top level struct "Q", and not just the scalar.</font><br><font size=2 face="sans-serif"> %conv4 = sitofp i32 %5 to float</font><br><font size=2 face="sans-serif"> %add5 = fadd float %add3, %conv4</font><br><font size=2 face="sans-serif"> %6 = load float, float* bitcast
(%union.U* getelementptr inbounds (%struct.Q, %struct.Q* @q, i32 0, i32
1) to float*), align 4, !tbaa !20 // Need to reference the
struct "Q".</font><br><font size=2 face="sans-serif"> %add6 = fadd float %add5, %6</font><br><font size=2 face="sans-serif"> %7 = load i32, i32* getelementptr
inbounds (%struct.Q, %struct.Q* @q, i32 0, i32 0), align 4, !tbaa !13</font><br><font size=2 face="sans-serif"> %conv7 = sitofp i32 %7 to float</font><br><font size=2 face="sans-serif"> %add8 = fadd float %add6, %conv7</font><br><font size=2 face="sans-serif"> %8 = load i32, i32* getelementptr
inbounds (%struct.R, %struct.R* @r, i32 0, i32 1), align 4, !tbaa !15</font><br><font size=2 face="sans-serif"> %conv9 = sitofp i32 %8 to float</font><br><font size=2 face="sans-serif"> %add10 = fadd float %add8, %conv9</font><br><font size=2 face="sans-serif"> %conv11 = fptosi float %add10
to i32</font><br><font size=2 face="sans-serif"> ret i32 %conv11</font><br><font size=2 face="sans-serif">}</font><br><br><font size=2 face="sans-serif">!0 = !{i32 1, !"PIC Level",
i32 2}</font><br><font size=2 face="sans-serif">!1 = !{!"clang version 4.0.0 (trunk
290896)"}</font><br><font size=2 face="sans-serif">!2 = !{!7, !3, i64 4}
// Need to change to point to the struct "S"
with the starting offset of the array.</font><br><font size=2 face="sans-serif">!3 = !{!"int", !4, i64 0}</font><br><font size=2 face="sans-serif">!4 = !{!"omnipotent char",
!5, i64 0}</font><br><font size=2 face="sans-serif">!5 = !{!"Simple C/C++ TBAA"}</font><br><font size=2 face="sans-serif">!6 = !{!7, !3, i64 0}</font><br><font size=2 face="sans-serif">!7 = !{!"S", !3, i64 0, !8,
i64 4}</font><br><font size=2 face="sans-serif">!8 = !{!"T", !3, i64 0}
// Use "int" for the type of the
array instead of "omnipotent char.".</font><br><font size=2 face="sans-serif">!9 = !{!16, !3, i64 44}
// Point to the outermost struct "R" instead
of "C". Add the offset of the array in "R" and
the offset of the member in "C".</font><br><font size=2 face="sans-serif">!10 = !{!"C", !3, i64 0, !3,
i64 4}</font><br><font size=2 face="sans-serif">!11 = !{!17, !12, i64 0}
// Need to point to the union "U" instead
of using the scalar.</font><br><font size=2 face="sans-serif">!12 = !{!"float", !4, i64
0}</font><br><font size=2 face="sans-serif">!13 = !{!14, !3, i64 0}</font><br><font size=2 face="sans-serif">!14 = !{!"Q", !3, i64 0, !17,
i64 4} //
Use the union "U" as the type for the member.</font><br><font size=2 face="sans-serif">!15 = !{!16, !3, i64 80}</font><br><font size=2 face="sans-serif">!16 = !{!"R", !21, i64 0,
!3, i64 80}
// Have the first member point to the union "R.u".</font><br><font size=2 face="sans-serif">!17 = !{!"U", !3, i64 0, !12,
i64 0} //
Introduce the struct path for the union.</font><br><font size=2 face="sans-serif">!18 = !{!17, !3, i64 0}
// Tag for a union reference goes through the union.</font><br><font size=2 face="sans-serif">!19 = !{!14, !3, i64 4}
// Tag for a union reference inside a struct points
to the top level struct.</font><br><font size=2 face="sans-serif">!20 = !{!14, !11, i64 4}
// Same as !19 except for the float.</font><br><font size=2 face="sans-serif">!21 = !{!"R.u", !10, i64 0,
!10, i64 0} //
Add a struct path for the union defined in "R". </font><br><br><br><font size=2 face="sans-serif">Multiple members at the same offset</font><br><font size=2 face="sans-serif">===================================</font><br><br><font size=2 face="sans-serif">Consider the following example:</font><br><br><font size=2 face="sans-serif">union U {</font><br><font size=2 face="sans-serif"> int a;</font><br><font size=2 face="sans-serif"> float b;</font><br><font size=2 face="sans-serif">};</font><br><br><font size=2 face="sans-serif">int foo( U * u, int * i, float * f )</font><br><font size=2 face="sans-serif">{</font><br><font size=2 face="sans-serif"> *i = 0;</font><br><font size=2 face="sans-serif"> *f = 100.0;</font><br><font size=2 face="sans-serif"> return u->a;</font><br><font size=2 face="sans-serif">}</font><br><br><font size=2 face="sans-serif">With the changes I described above,
the reference "u->a" will alias both "*i"</font><br><font size=2 face="sans-serif">and "*f" because, when we
see the struct-path for the union, we will follow path</font><br><font size=2 face="sans-serif">for "a" and "b".
This may be more conservative than we want. It might also be</font><br><font size=2 face="sans-serif">exactly what we want.</font><br><br><font size=2 face="sans-serif">The difficulty in being more precise
is that, in general, we cannot know which</font><br><font size=2 face="sans-serif">member of the union was access with
the current information in the llvm-ir. If</font><br><font size=2 face="sans-serif">we want to fix this we can create a
new scalar to represent the members</font><br><font size=2 face="sans-serif">which will be used as the scalar meta
data in the tag. Then, when a struct-path</font><br><font size=2 face="sans-serif">node for a union is reached, we will
have to search each possible path to see if</font><br><font size=2 face="sans-serif">it reaches the scalar node on the tag.
If it does, that is the path we follow.</font><br><br><font size=2 face="sans-serif">With this change, the llvm-ir for the
example would be:</font><br><br><font size=2 face="sans-serif">define signext i32 @foo(%union.U* %u,
i32* %i, float* %f) #0 {</font><br><font size=2 face="sans-serif">entry:</font><br><font size=2 face="sans-serif"> store i32 0, i32* %i, align 4,
!tbaa !2</font><br><font size=2 face="sans-serif"> store float 1.000000e+02, float*
%f, align 4, !tbaa !6</font><br><font size=2 face="sans-serif"> %a = bitcast %union.U* %u to
i32*</font><br><font size=2 face="sans-serif"> %0 = load i32, i32* %a, align
4, !tbaa !11 // Use the new tag</font><br><font size=2 face="sans-serif"> ret i32 %0</font><br><font size=2 face="sans-serif">}</font><br><br><font size=2 face="sans-serif">!0 = !{i32 1, !"PIC Level",
i32 2}</font><br><font size=2 face="sans-serif">!1 = !{!"clang version 4.0.0 (trunk
290896)"}</font><br><font size=2 face="sans-serif">!2 = !{!3, !3, i64 0}</font><br><font size=2 face="sans-serif">!3 = !{!"int", !4, i64 0}</font><br><font size=2 face="sans-serif">!4 = !{!"omnipotent char",
!5, i64 0}</font><br><font size=2 face="sans-serif">!5 = !{!"Simple C/C++ TBAA"}</font><br><font size=2 face="sans-serif">!6 = !{!7, !7, i64 0}</font><br><font size=2 face="sans-serif">!7 = !{!"float", !4, i64 0}</font><br><font size=2 face="sans-serif">!8 = !{!"U", !9, i64 0, !10,
i64 0} // The struct path for the union with special members.</font><br><font size=2 face="sans-serif">!9 = !{!"U.a", !3, 0}
// The member of
the union.</font><br><font size=2 face="sans-serif">!10 = !{!"U.b", !7, 0}
// The member of
the union.</font><br><font size=2 face="sans-serif">!11 = !{!8, !9, 0}
// The new tag where
the scalar is the union member instead of the generic "int".</font><br><br><br><br><font size=2 face="sans-serif">Read versus write aliasing</font><br><font size=2 face="sans-serif">==========================</font><br><br><font size=2 face="sans-serif">It has come to my attention that there
is a question about whether the read</font><br><font size=2 face="sans-serif">versus write aliasing matters for union
aliasing. Maybe there is something in</font><br><font size=2 face="sans-serif">the C/C++ specification I am missing,
but I believe we need to handle this as</font><br><font size=2 face="sans-serif">well. Suppose we take an example
similar to the one in defect 21725:</font><br><br><font size=2 face="sans-serif">#include <stdio.h></font><br><br><font size=2 face="sans-serif">union U {</font><br><font size=2 face="sans-serif"> short s;</font><br><font size=2 face="sans-serif"> int i;</font><br><font size=2 face="sans-serif">} u;</font><br><br><font size=2 face="sans-serif">int v = 987;</font><br><font size=2 face="sans-serif">union U* up = &u;</font><br><br><font size=2 face="sans-serif">int foo()</font><br><font size=2 face="sans-serif">{</font><br><font size=2 face="sans-serif"> int temp
= u.s;</font><br><font size=2 face="sans-serif"> up->i
= 123; // 123</font><br><font size=2 face="sans-serif"> printf("%d\n",
up->i);</font><br><font size=2 face="sans-serif"> printf("%hd\n",
temp);</font><br><font size=2 face="sans-serif"> return 0;</font><br><font size=2 face="sans-serif">}</font><br><br><font size=2 face="sans-serif">In this case, if the read of "u.s"
is not aliased to the write of "up->i" and</font><br><font size=2 face="sans-serif">they are reordered, then "temp"
could get the wrong value.</font><BR>