Abstract IR generation of array cookies into the C++ ABI class and
implement ARM array cookies. Also fix a few unfortunate bugs:
- throwing dtors in deletes prevented the allocation from being deleted
- adding the cookie to the new[] size was not being considered for
overflow (and, more seriously, was screwing up the earlier checks)
- deleting an array via a pointer to array of class type was not
causing any destructors to be run and was passing the unadjusted
pointer to the deallocator
- lots of address-space problems, in case anyone wants to support
free store in a variant address space :)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@112814 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/test/CodeGenCXX/arm.cpp b/test/CodeGenCXX/arm.cpp
index b4c8c83..fb962e0 100644
--- a/test/CodeGenCXX/arm.cpp
+++ b/test/CodeGenCXX/arm.cpp
@@ -1,4 +1,6 @@
-// RUN: %clang_cc1 %s -triple=thumbv7-apple-darwin3.0.0-iphoneos -fno-use-cxa-atexit -target-abi apcs-gnu -emit-llvm -o - -fexceptions | FileCheck %s
+// RUN: %clang_cc1 %s -triple=thumbv7-apple-darwin3.0.0-iphoneos -fno-use-cxa-atexit -target-abi apcs-gnu -emit-llvm -o - -fexceptions | Filecheck %s
+
+typedef typeof(sizeof(int)) size_t;
class foo {
public:
@@ -88,6 +90,153 @@
C c = 10;
}
+ // Tests at eof
+}
+
+namespace test3 {
+ struct A {
+ int x;
+ ~A();
+ };
+
+ void a() {
+ // CHECK: define void @_ZN5test31aEv()
+ // CHECK: call noalias i8* @_Znam(i32 48)
+ // CHECK: store i32 4
+ // CHECK: store i32 10
+ A *x = new A[10];
+ }
+
+ void b(int n) {
+ // CHECK: define void @_ZN5test31bEi(
+ // CHECK: [[N:%.*]] = load i32*
+ // CHECK: @llvm.umul.with.overflow.i32(i32 [[N]], i32 4)
+ // CHECK: @llvm.uadd.with.overflow.i32(i32 {{.*}}, i32 8)
+ // CHECK: [[SZ:%.*]] = select
+ // CHECK: call noalias i8* @_Znam(i32 [[SZ]])
+ // CHECK: store i32 4
+ // CHECK: store i32 [[N]]
+ A *x = new A[n];
+ }
+
+ void c() {
+ // CHECK: define void @_ZN5test31cEv()
+ // CHECK: call noalias i8* @_Znam(i32 808)
+ // CHECK: store i32 4
+ // CHECK: store i32 200
+ A (*x)[20] = new A[10][20];
+ }
+
+ void d(int n) {
+ // CHECK: define void @_ZN5test31dEi(
+ // CHECK: [[N:%.*]] = load i32*
+ // CHECK: [[NE:%.*]] = mul i32 [[N]], 20
+ // CHECK: @llvm.umul.with.overflow.i32(i32 [[N]], i32 80)
+ // CHECK: @llvm.uadd.with.overflow.i32(i32 {{.*}}, i32 8)
+ // CHECK: [[SZ:%.*]] = select
+ // CHECK: call noalias i8* @_Znam(i32 [[SZ]])
+ // CHECK: store i32 4
+ // CHECK: store i32 [[NE]]
+ A (*x)[20] = new A[n][20];
+ }
+
+ void e(A *x) {
+ // CHECK: define void @_ZN5test31eEPNS_1AE(
+ // CHECK: icmp eq {{.*}}, null
+ // CHECK: getelementptr {{.*}}, i64 -8
+ // CHECK: getelementptr {{.*}}, i64 4
+ // CHECK: bitcast {{.*}} to i32*
+ // CHECK: load
+ // CHECK: invoke {{.*}} @_ZN5test31AD1Ev
+ // CHECK: call void @_ZdaPv
+ delete [] x;
+ }
+
+ void f(A (*x)[20]) {
+ // CHECK: define void @_ZN5test31fEPA20_NS_1AE(
+ // CHECK: icmp eq {{.*}}, null
+ // CHECK: getelementptr {{.*}}, i64 -8
+ // CHECK: getelementptr {{.*}}, i64 4
+ // CHECK: bitcast {{.*}} to i32*
+ // CHECK: load
+ // CHECK: invoke {{.*}} @_ZN5test31AD1Ev
+ // CHECK: call void @_ZdaPv
+ delete [] x;
+ }
+}
+
+namespace test4 {
+ struct A {
+ int x;
+ void operator delete[](void *, size_t sz);
+ };
+
+ void a() {
+ // CHECK: define void @_ZN5test41aEv()
+ // CHECK: call noalias i8* @_Znam(i32 48)
+ // CHECK: store i32 4
+ // CHECK: store i32 10
+ A *x = new A[10];
+ }
+
+ void b(int n) {
+ // CHECK: define void @_ZN5test41bEi(
+ // CHECK: [[N:%.*]] = load i32*
+ // CHECK: @llvm.umul.with.overflow.i32(i32 [[N]], i32 4)
+ // CHECK: @llvm.uadd.with.overflow.i32(i32 {{.*}}, i32 8)
+ // CHECK: [[SZ:%.*]] = select
+ // CHECK: call noalias i8* @_Znam(i32 [[SZ]])
+ // CHECK: store i32 4
+ // CHECK: store i32 [[N]]
+ A *x = new A[n];
+ }
+
+ void c() {
+ // CHECK: define void @_ZN5test41cEv()
+ // CHECK: call noalias i8* @_Znam(i32 808)
+ // CHECK: store i32 4
+ // CHECK: store i32 200
+ A (*x)[20] = new A[10][20];
+ }
+
+ void d(int n) {
+ // CHECK: define void @_ZN5test41dEi(
+ // CHECK: [[N:%.*]] = load i32*
+ // CHECK: [[NE:%.*]] = mul i32 [[N]], 20
+ // CHECK: @llvm.umul.with.overflow.i32(i32 [[N]], i32 80)
+ // CHECK: @llvm.uadd.with.overflow.i32(i32 {{.*}}, i32 8)
+ // CHECK: [[SZ:%.*]] = select
+ // CHECK: call noalias i8* @_Znam(i32 [[SZ]])
+ // CHECK: store i32 4
+ // CHECK: store i32 [[NE]]
+ A (*x)[20] = new A[n][20];
+ }
+
+ void e(A *x) {
+ // CHECK: define void @_ZN5test41eEPNS_1AE(
+ // CHECK: [[ALLOC:%.*]] = getelementptr inbounds {{.*}}, i64 -8
+ // CHECK: getelementptr inbounds {{.*}}, i64 4
+ // CHECK: bitcast
+ // CHECK: [[T0:%.*]] = load i32*
+ // CHECK: [[T1:%.*]] = mul i32 4, [[T0]]
+ // CHECK: [[T2:%.*]] = add i32 [[T1]], 8
+ // CHECK: call void @_ZN5test41AdaEPvm(i8* [[ALLOC]], i32 [[T2]])
+ delete [] x;
+ }
+
+ void f(A (*x)[20]) {
+ // CHECK: define void @_ZN5test41fEPA20_NS_1AE(
+ // CHECK: [[ALLOC:%.*]] = getelementptr inbounds {{.*}}, i64 -8
+ // CHECK: getelementptr inbounds {{.*}}, i64 4
+ // CHECK: bitcast
+ // CHECK: [[T0:%.*]] = load i32*
+ // CHECK: [[T1:%.*]] = mul i32 4, [[T0]]
+ // CHECK: [[T2:%.*]] = add i32 [[T1]], 8
+ // CHECK: call void @_ZN5test41AdaEPvm(i8* [[ALLOC]], i32 [[T2]])
+ delete [] x;
+ }
+}
+
// CHECK: define linkonce_odr [[C:%.*]]* @_ZTv0_n12_N5test21CD1Ev(
// CHECK: call [[C]]* @_ZN5test21CD1Ev(
// CHECK: ret [[C]]* undef
@@ -95,7 +244,6 @@
// CHECK: define linkonce_odr void @_ZTv0_n12_N5test21CD0Ev(
// CHECK: call void @_ZN5test21CD0Ev(
// CHECK: ret void
-}
// CHECK: @_GLOBAL__D_a()
// CHECK: call %class.bar* @_ZN3barD1Ev(%class.bar* @baz)
diff --git a/test/CodeGenCXX/delete.cpp b/test/CodeGenCXX/delete.cpp
index 87f8698..ec13d0c 100644
--- a/test/CodeGenCXX/delete.cpp
+++ b/test/CodeGenCXX/delete.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -emit-llvm -o - | FileCheck %s
void t1(int *a) {
delete a;
@@ -57,3 +57,41 @@
// CHECK: define linkonce_odr void @_ZN5test01AD1Ev
// CHECK: define linkonce_odr void @_ZN5test01AdlEPv
}
+
+namespace test1 {
+ struct A {
+ int x;
+ ~A();
+ };
+
+ // CHECK: define void @_ZN5test14testEPA10_A20_NS_1AE(
+ void test(A (*arr)[10][20]) {
+ delete [] arr;
+ // CHECK: icmp eq [10 x [20 x [[S:%.*]]]]* [[PTR:%.*]], null
+ // CHECK-NEXT: br i1
+
+ // CHECK: [[ARR:%.*]] = getelementptr inbounds [10 x [20 x [[S]]]]* [[PTR]], i32 0, i32 0, i32 0
+ // CHECK-NEXT: bitcast {{.*}} to i8*
+ // CHECK-NEXT: [[ALLOC:%.*]] = getelementptr inbounds {{.*}}, i64 -8
+ // CHECK-NEXT: bitcast i8* [[ALLOC]] to i64*
+ // CHECK-NEXT: load
+ // CHECK-NEXT: store i64 {{.*}}, i64* [[IDX:%.*]]
+
+ // CHECK: load i64* [[IDX]]
+ // CHECK-NEXT: icmp ne {{.*}}, 0
+ // CHECK-NEXT: br i1
+
+ // CHECK: load i64* [[IDX]]
+ // CHECK-NEXT: [[I:%.*]] = sub i64 {{.*}}, 1
+ // CHECK-NEXT: getelementptr inbounds [[S]]* [[ARR]], i64 [[I]]
+ // CHECK-NEXT: call void @_ZN5test11AD1Ev(
+ // CHECK-NEXT: br label
+
+ // CHECK: load i64* [[IDX]]
+ // CHECK-NEXT: sub
+ // CHECK-NEXT: store {{.*}}, i64* [[IDX]]
+ // CHECK-NEXT: br label
+
+ // CHECK: call void @_ZdaPv(i8* [[ALLOC]])
+ }
+}
diff --git a/test/CodeGenCXX/new.cpp b/test/CodeGenCXX/new.cpp
index 42d7c9f..d52ebbe 100644
--- a/test/CodeGenCXX/new.cpp
+++ b/test/CodeGenCXX/new.cpp
@@ -155,6 +155,7 @@
void f() {
// CHECK: call i8* @_ZN5AllocnaEm(i64 808)
// CHECK: store i64 200
+ // CHECK: call void @_ZN5AllocD1Ev(
// CHECK: call void @_ZN5AllocdaEPv(i8*
delete[] new Alloc[10][20];
}
diff --git a/test/CodeGenCXX/operator-new.cpp b/test/CodeGenCXX/operator-new.cpp
index df3c114..db56cda 100644
--- a/test/CodeGenCXX/operator-new.cpp
+++ b/test/CodeGenCXX/operator-new.cpp
@@ -21,9 +21,9 @@
void *f2(long N) {
return new int[N];
-// SANE: call{{.*}}@llvm.umul.with.overflow
-// SANE: extractvalue
-// SANE: br i1
-// SANE: = phi {{.*}} [ {{.*}} ], [ -1,
-// SANE: call noalias i8* @_Znaj(
+// SANE: [[UWO:%.*]] = call {{.*}} @llvm.umul.with.overflow
+// SANE-NEXT: [[OVER:%.*]] = extractvalue {{.*}} [[UWO]], 1
+// SANE-NEXT: [[SUM:%.*]] = extractvalue {{.*}} [[UWO]], 0
+// SANE-NEXT: [[RESULT:%.*]] = select i1 [[OVER]], i32 -1, i32 [[SUM]]
+// SANE-NEXT: call noalias i8* @_Znaj(i32 [[RESULT]])
}