Hi hfinkel, dberlin, Generate path-aware tbaa for unions. This fixes an aliasing issue described in bug 21725.
http://reviews.llvm.org/D8056 Files: lib/CodeGen/CGExpr.cpp lib/CodeGen/CodeGenTBAA.cpp test/CodeGen/tbaa-union.cpp EMAIL PREFERENCES http://reviews.llvm.org/settings/panel/emailpreferences/
Index: lib/CodeGen/CGExpr.cpp
===================================================================
--- lib/CodeGen/CGExpr.cpp
+++ lib/CodeGen/CGExpr.cpp
@@ -2684,8 +2684,6 @@
if (rec->isUnion()) {
// For unions, there is no pointer adjustment.
assert(!type->isReferenceType() && "union has reference member");
- // TODO: handle path-aware TBAA for union.
- TBAAPath = false;
} else {
// For structs, we GEP to the field that the record layout suggests.
unsigned idx = CGM.getTypes().getCGRecordLayout(rec).getLLVMFieldNo(field);
Index: lib/CodeGen/CodeGenTBAA.cpp
===================================================================
--- lib/CodeGen/CodeGenTBAA.cpp
+++ lib/CodeGen/CodeGenTBAA.cpp
@@ -232,7 +232,7 @@
return false;
// RD can be struct, union, class, interface or enum.
// For now, we only handle struct and class.
- if (RD->isStruct() || RD->isClass())
+ if (RD->isStruct() || RD->isClass() || RD->isUnion())
return true;
}
return false;
Index: test/CodeGen/tbaa-union.cpp
===================================================================
--- /dev/null
+++ test/CodeGen/tbaa-union.cpp
@@ -0,0 +1,165 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - -O1 %s | FileCheck %s
+//
+// Check that we generate !tbaa.struct metadata for union copies - when they are large enough
+union A {
+ short s;
+ int i;
+ char c;
+ int j[4];
+};
+
+void copy(union A *a, union A *b) {
+ *a = *b;
+}
+
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %{{.*}}, i8* %{{.*}}, i64 16, i32 4, i1 false), !tbaa.struct [[UNION_A:!.*]]
+
+union B {
+ char c1;
+ union A a;
+ int ii;
+};
+
+void copy2(union B *a, union B *b) {
+ *a = *b;
+}
+
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %{{.*}}, i8* %{{.*}}, i64 16, i32 4, i1 false), !tbaa.struct [[UNION_B:!.*]]
+
+typedef _Complex int T2;
+typedef _Complex char T5;
+typedef _Complex int T7;
+typedef struct T4 { T5 field0; T7 field1; } T4;
+typedef union T1 { T2 field0; T4 field1; } T1;
+
+void copy3 (T1 *a, T1 *b) {
+ *a = *b;
+}
+
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %{{.*}}, i8* %{{.*}}, i64 12, i32 4, i1 false), !tbaa.struct [[UNION_T1:!.*]]
+
+
+union U0 {
+ short s;
+ int i;
+};
+
+U0 g_u0;
+U0* g_pu0=&g_u0;
+
+int same_union_0() {
+ *g_pu0=g_u0;
+ return g_u0.i;
+}
+
+// CHECK: load i32, i32* getelementptr inbounds (%{{.*}}* @g_u0, i64 0, i32 0), align 4, !tbaa [[TAG_UNION_U0__I:!.*]]
+
+int same_union_1() {
+ g_u0.s=123;
+ g_u0.i=456;
+ return g_u0.i;
+}
+// CHECK: store i32 456, i32* getelementptr inbounds (%{{.*}}* @g_u0, i64 0, i32 0), align 4, !tbaa [[TAG_UNION_U0__I]]
+
+int same_union_2() {
+ g_u0.i=456;
+ g_u0.s=123;
+ return g_u0.i;
+}
+// CHECK: store i32 456, i32* getelementptr inbounds (%{{.*}}* @g_u0, i64 0, i32 0), align 4, !tbaa [[TAG_UNION_U0__I]]
+// CHECK-NEXT: store i16 123, i16* bitcast (%{{.*}}* @g_u0 to i16*), align 4, !tbaa [[TAG_UNION_U0__S:!.*]]
+// CHECK-NEXT: load i32, i32* getelementptr inbounds (%{{.*}}* @g_u0, i64 0, i32 0), align 4, !tbaa [[TAG_UNION_U0__I]]
+
+
+int aliasing_access_0() {
+ g_u0.s=123; // access 'short' member of U0
+ g_pu0->i=456; // access 'int' member of U0
+ // Both accesses of a U0 -> reordering NOT allowed.
+
+ return g_u0.i; // should return 456
+}
+// CHECK: store i16 123, i16* bitcast (%{{.*}}* @g_u0 to i16*), align 4, !tbaa [[TAG_UNION_U0__S]]
+// CHECK-NEXT: load i32*, i32** bitcast (%{{.*}} @g_pu0 to i32**), align 8, !tbaa [[TAG_POINTER:!.*]]
+// CHECK-NEXT: store i32 456, i32* %{{.*}}, align 4, !tbaa [[TAG_UNION_U0__I]]
+// CHECK-NEXT: load i32, i32* getelementptr inbounds (%{{.*}}* @g_u0, i64 0, i32 0), align 4, !tbaa [[TAG_UNION_U0__I]]
+
+int aliasing_access_1() {
+ int* pi=&g_pu0->i;
+
+ g_u0.s=123; // access 'short' member of U0
+ *pi=456; // access 'int'
+ // There exists an 'int' member of U0 -> reordering NOT allowed.
+
+ return g_u0.i; // should return 456
+}
+
+// CHECK: load i32*, i32** bitcast (%{{.*}}* @g_pu0 to i32**), align 8, !tbaa [[TAG_POINTER]]
+// CHECK-NEXT: store i16 123, i16* bitcast (%{{.*}}* @g_u0 to i16*), align 4, !tbaa [[TAG_UNION_U0__S]]
+// CHECK-NEXT: store i32 456, i32* %{{.*}}, align 4, !tbaa [[TAG_INT:!.*]]
+// CHECK-NEXT: load i32, i32* getelementptr inbounds (%{{.*}}* @g_u0, i64 0, i32 0), align 4, !tbaa [[TAG_UNION_U0__I]]
+
+
+int aliasing_access_2() {
+ short* ps=&g_u0.s;
+ int* pi=&g_pu0->i;
+
+ *ps=123; // access 'short'
+ *pi=456; // access 'int'
+ // no relationship between 'short' and 'int' -> reordering allowed !
+
+ return g_u0.i; // anything can happen
+}
+
+int aliasing_access_2b() {
+ short& ps=g_u0.s;
+ int* pi=&g_pu0->i;
+
+ ps=123; // access 'short'
+ *pi=456; // access 'int'
+ // no relationship between 'short' and 'int' -> reordering allowed !
+
+ return g_u0.i; // anything can happen
+}
+
+// CHECK: store i16 123, i16* bitcast (%{{.*}}* @g_u0 to i16*), align 4, !tbaa [[TAG_SHORT:!.*]]
+// CHECK: store i32 456, i32* %{{.*}}, align 4, !tbaa [[TAG_INT]]
+// CHECK: load i32, i32* getelementptr inbounds (%{{.*}}* @g_u0, i64 0, i32 0), align 4, !tbaa [[TAG_UNION_U0__I]]
+
+int aliasing_access_3(short* ps, int* pi) {
+ *ps=123; // access 'short'
+ *pi=456; // access 'int'
+ // no relationship between 'short' and 'int' -> reordering allowed !
+
+ return g_u0.i; // anything can happen
+}
+
+// CHECK: store i16 123, i16* %ps, align 2, !tbaa [[TAG_SHORT]]
+// CHECK: store i32 456, i32* %pi, align 4, !tbaa [[TAG_INT]]
+// CHECK: load i32, i32* getelementptr inbounds (%{{.*}}* @g_u0, i64 0, i32 0), align 4, !tbaa [[TAG_UNION_U0__I]]
+
+void aliasing_access_4(short* ps, int* pi) {
+ *ps=123; // access 'short'
+ *pi=456; // access 'int'
+ // no relationship between 'short' and 'int' -> reordering allowed !
+}
+
+// CHECK: store i16 123, i16* %ps, align 2, !tbaa [[TAG_SHORT]]
+// CHECK: store i32 456, i32* %pi, align 4, !tbaa [[TAG_INT]]
+
+
+
+// (offset, size) = (0,8) char; (0,2) char; (4,8) char
+// CHECK: [[UNION_A]] = !{i64 0, i64 2, [[TAG_SHORT]], i64 0, i64 4, [[TAG_INT]], i64 0, i64 1, [[TAG_CHAR:!.*]], i64 0, i64 16, [[TAG_CHAR]]}
+// CHECK: [[TAG_SHORT]] = !{[[SHORT:!.*]], [[SHORT]], i64 0}
+// CHECK: [[SHORT]] = !{!"short", [[CHAR:!.*]],
+// CHECK: [[CHAR]] = !{!"omnipotent char", !{{.*}}}
+// CHECK: [[TAG_INT]] = !{[[INT:!.*]], [[INT]], i64 0}
+// CHECK: [[INT]] = !{!"int", [[CHAR]]
+// CHECK: [[TAG_CHAR]] = !{[[CHAR]], [[CHAR]], i64 0}
+// CHECK: [[UNION_B]] = !{i64 0, i64 1, [[TAG_CHAR]], i64 0, i64 2, [[TAG_SHORT]], i64 0, i64 4, [[TAG_INT]], i64 0, i64 1, [[TAG_CHAR]], i64 0, i64 16, [[TAG_CHAR]], i64 0, i64 4, [[TAG_INT]]}
+// CHECK: [[UNION_T1]] = !{i64 0, i64 8, [[TAG_CHAR]], i64 0, i64 2, [[TAG_CHAR]], i64 4, i64 8, [[TAG_CHAR]]}
+// CHECK: [[TAG_POINTER]] = !{[[POINTER:!.*]], [[POINTER]], i64 0}
+// CHECK: [[POINTER]] = !{!"any pointer", [[CHAR]], i64 0}
+// CHECK: [[TAG_UNION_U0__I]] = !{[[UNION_U0:!.*]], [[INT]], i64 0}
+// CHECK: [[UNION_U0]] = !{!"_ZTS2U0", [[SHORT]], i64 0, [[INT]], i64 0}
+// CHECK: [[TAG_UNION_U0__S]] = !{[[UNION_U0]], [[SHORT]], i64 0}
_______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
