george.burgess.iv created this revision.
george.burgess.iv added reviewers: joerg, rsmith.
george.burgess.iv added a subscriber: cfe-commits.

Mostly asking for a review to verify that you guys are happy with this approach.

Given that Hal said struct-path-tbaa doesn't really deal with arrays (yet), I 
decided to ignore -fno-struct-path-tbaa. If that changes in the future, we can 
relax this when that flag is given, too.

https://reviews.llvm.org/D24999

Files:
  include/clang/Basic/LangOptions.def
  lib/AST/ExprConstant.cpp
  lib/Frontend/CompilerInvocation.cpp
  test/CodeGen/object-size.c
  test/CodeGen/pass-object-size.c

Index: test/CodeGen/pass-object-size.c
===================================================================
--- test/CodeGen/pass-object-size.c
+++ test/CodeGen/pass-object-size.c
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -O0 %s -o - 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -O0 %s -o - 2>&1 | FileCheck %s --check-prefixes STRICT,CHECK
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -O0 %s -o - -relaxed-aliasing 2>&1 | FileCheck %s --check-prefixes NOSTRICT,CHECK
 
 typedef unsigned long size_t;
 
@@ -59,8 +60,10 @@
 
 // CHECK-LABEL: define void @test2
 void test2(struct Foo *t) {
-  // CHECK: [[VAR:%[0-9]+]] = call i64 @llvm.objectsize
-  // CHECK: call i32 @ObjectSize1(i8* %{{.*}}, i64 [[VAR]])
+  // NOSTRICT: [[VAR:%[0-9]+]] = call i64 @llvm.objectsize
+  // NOSTRICT: call i32 @ObjectSize1(i8* %{{.*}}, i64 [[VAR]])
+  //
+  // STRICT: call i32 @ObjectSize1(i8* %{{.*}}, i64 36)
   gi = ObjectSize1(&t->t[1]);
   // CHECK: call i32 @ObjectSize3(i8* %{{.*}}, i64 36)
   gi = ObjectSize3(&t->t[1]);
@@ -169,8 +172,10 @@
 
   // CHECK: call i32 @_Z27NoViableOverloadObjectSize0PvU17pass_object_size0(i8* %{{.*}}, i64 %{{.*}})
   gi = NoViableOverloadObjectSize0(&t[1].t[1]);
-  // CHECK: [[VAR:%[0-9]+]] = call i64 @llvm.objectsize
-  // CHECK: call i32 @_Z27NoViableOverloadObjectSize1PvU17pass_object_size1(i8* %{{.*}}, i64 [[VAR]])
+  // NOSTRICT: [[VAR:%[0-9]+]] = call i64 @llvm.objectsize
+  // NOSTRICT: call i32 @_Z27NoViableOverloadObjectSize1PvU17pass_object_size1(i8* %{{.*}}, i64 [[VAR]])
+  //
+  // STRICT: call i32 @_Z27NoViableOverloadObjectSize1PvU17pass_object_size1(i8* %{{.*}}, i64 36)
   gi = NoViableOverloadObjectSize1(&t[1].t[1]);
   // CHECK: call i32 @_Z27NoViableOverloadObjectSize2PvU17pass_object_size2(i8* %{{.*}}, i64 %{{.*}})
   gi = NoViableOverloadObjectSize2(&t[1].t[1]);
@@ -276,8 +281,10 @@
 
 // CHECK-LABEL: define void @test8
 void test8(struct Foo *t) {
-  // CHECK: [[VAR:%[0-9]+]] = call i64 @llvm.objectsize
-  // CHECK: call i32 @"\01Identity"(i8* %{{.*}}, i64 [[VAR]])
+  // NOSTRICT: [[VAR:%[0-9]+]] = call i64 @llvm.objectsize
+  // NOSTRICT: call i32 @"\01Identity"(i8* %{{.*}}, i64 [[VAR]])
+  //
+  // STRICT: call i32 @"\01Identity"(i8* %{{.*}}, i64 36)
   gi = AsmObjectSize1(&t[1].t[1]);
   // CHECK: call i32 @"\01Identity"(i8* %{{.*}}, i64 36)
   gi = AsmObjectSize3(&t[1].t[1]);
Index: test/CodeGen/object-size.c
===================================================================
--- test/CodeGen/object-size.c
+++ test/CodeGen/object-size.c
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm %s -o - 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm %s -o - 2>&1 | FileCheck %s --check-prefixes=STRICT,CHECK
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm %s -o - 2>&1 -relaxed-aliasing | FileCheck %s --check-prefixes=NOSTRICT,CHECK
 
 #define strcpy(dest, src) \
   ((__builtin_object_size(dest, 0) != -1ULL) \
@@ -276,7 +277,8 @@
 
   // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
   gi = __builtin_object_size(&p->t[5], 0);
-  // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
+  // NOSTRICT: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
+  // STRICT: store i32 20
   gi = __builtin_object_size(&p->t[5], 1);
   // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true)
   gi = __builtin_object_size(&p->t[5], 2);
@@ -444,7 +446,8 @@
 
   // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
   gi = __builtin_object_size(ss->snd, 0);
-  // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
+  // NOSTRICT: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
+  // STRICT: store i32 2
   gi = __builtin_object_size(ss->snd, 1);
   // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true)
   gi = __builtin_object_size(ss->snd, 2);
@@ -505,7 +508,8 @@
   // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
   gi = __builtin_object_size(ds1[9].snd, 1);
 
-  // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
+  // NOSTRICT: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
+  // STRICT: store i32 2
   gi = __builtin_object_size(&ss[9].snd[0], 1);
 
   // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
@@ -529,7 +533,8 @@
   struct sockaddr *sa;
   // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
   gi = __builtin_object_size(sa->sa_data, 0);
-  // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
+  // NOSTRICT: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
+  // STRICT: store i32 14
   gi = __builtin_object_size(sa->sa_data, 1);
   // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true)
   gi = __builtin_object_size(sa->sa_data, 2);
Index: lib/Frontend/CompilerInvocation.cpp
===================================================================
--- lib/Frontend/CompilerInvocation.cpp
+++ lib/Frontend/CompilerInvocation.cpp
@@ -2170,6 +2170,8 @@
                       Args.hasArg(OPT_cl_unsafe_math_optimizations) ||
                       Args.hasArg(OPT_cl_fast_relaxed_math);
 
+  Opts.StrictAliasing = !Args.hasArg(OPT_relaxed_aliasing);
+
   Opts.RetainCommentsFromSystemHeaders =
       Args.hasArg(OPT_fretain_comments_from_system_headers);
 
Index: lib/AST/ExprConstant.cpp
===================================================================
--- lib/AST/ExprConstant.cpp
+++ lib/AST/ExprConstant.cpp
@@ -6826,21 +6826,19 @@
   // struct Foo *F = (struct Foo *)malloc(sizeof(struct Foo) + strlen(Bar));
   // strcpy(&F->c[0], Bar);
   //
-  // So, if we see that we're examining an array at the end of a struct with an
-  // unknown base, we give up instead of breaking code that behaves this way.
-  // Note that we only do this when Type=1, because Type=3 is a lower bound, so
-  // answering conservatively is fine.
+  // So, if we see that we're examining a 1-length (or 0-length) array at the
+  // end of a struct with an unknown base, we give up instead of breaking code
+  // that behaves this way. Note that we only do this when Type=1, because
+  // Type=3 is a lower bound, so answering conservatively is fine.
   //
-  // We used to be a bit more aggressive here; we'd only be conservative if the
-  // array at the end was flexible, or if it had 0 or 1 elements. This broke
-  // some common standard library extensions (PR30346), but was otherwise
-  // seemingly fine. It may be useful to reintroduce this behavior with some
-  // sort of whitelist. OTOH, it seems that GCC is always conservative with the
-  // last element in structs (if it's an array), so our current behavior is more
-  // compatible than a whitelisting approach would be.
+  // This check is relaxed a bit if strict aliasing is off, since there's a
+  // nontrivial amount of code that treats the array size at the end of a struct
+  // as a suggestion, rather than a constraint (PR30346).
+  bool RelaxedEndOfObjectChecks = !Info.Ctx.getLangOpts().StrictAliasing;
   if (End.InvalidBase && SubobjectOnly && Type == 1 &&
       End.Designator.Entries.size() == End.Designator.MostDerivedPathLength &&
       End.Designator.MostDerivedIsArrayElement &&
+      (RelaxedEndOfObjectChecks || End.Designator.MostDerivedArraySize < 2) &&
       isDesignatorAtObjectEnd(Info.Ctx, End))
     return false;
 
Index: include/clang/Basic/LangOptions.def
===================================================================
--- include/clang/Basic/LangOptions.def
+++ include/clang/Basic/LangOptions.def
@@ -167,6 +167,7 @@
 COMPATIBLE_LANGOPT(FastMath          , 1, 0, "fast FP math optimizations, and __FAST_MATH__ predefined macro")
 COMPATIBLE_LANGOPT(FiniteMathOnly    , 1, 0, "__FINITE_MATH_ONLY__ predefined macro")
 COMPATIBLE_LANGOPT(UnsafeFPMath      , 1, 0, "Unsafe Floating Point Math")
+COMPATIBLE_LANGOPT(StrictAliasing    , 1, 0, "Using strict aliasing rules")
 
 BENIGN_LANGOPT(ObjCGCBitmapPrint , 1, 0, "printing of GC's bitmap layout for __weak/__strong ivars")
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to