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

Reply via email to