Files
clang-p2996/clang/test/CodeGenCXX/cxx11-initializer-array-new.cpp
Faisal Vali 57ae056a5c Quick-Fix pointer arithmetic when performing multi-D new-array initialization.
clang still doesn't emit the right llvm code when initializing multi-D arrays it seems.

For e.g. the following code would still crash for me on Windows 7, 64 bit:

auto f4 = new int[100][200][300]{{{1,2,3}, {4, 5, 6}}, {{10, 20, 30}}};

It seems that the final new loop that iterates through each outermost array and memsets it to zero gets confused with its final ptr arithmetic.

This patch ensures that it converts the pointer to the allocated type (int [200][300]) before incrementing it (instead of using the base type: 'int').

Richard somewhat squeamishly approved the patch (as a quick fix to potentially make it into 3.4) - while exhorting for a more optimized fix in the future. http://llvm-reviews.chandlerc.com/D2398
 
Thanks Richard!

llvm-svn: 197294
2013-12-14 00:40:05 +00:00

108 lines
4.1 KiB
C++

// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++11 %s -emit-llvm -o - | FileCheck %s
// PR10878
struct S { S(); S(int); ~S(); int n; };
void *p = new S[2][3]{ { 1, 2, 3 }, { 4, 5, 6 } };
// CHECK-LABEL: define
// CHECK: %[[ALLOC:.*]] = call noalias i8* @_Znam(i64 32)
// CHECK: %[[COOKIE:.*]] = bitcast i8* %[[ALLOC]] to i64*
// CHECK: store i64 6, i64* %[[COOKIE]]
// CHECK: %[[START_AS_i8:.*]] = getelementptr inbounds i8* %[[ALLOC]], i64 8
// CHECK: %[[START_AS_S:.*]] = bitcast i8* %[[START_AS_i8]] to %[[S:.*]]*
//
// Explicit initializers:
//
// { 1, 2, 3 }
//
// CHECK: %[[S_0:.*]] = bitcast %[[S]]* %[[START_AS_S]] to [3 x %[[S]]]*
//
// CHECK: %[[S_0_0:.*]] = getelementptr inbounds [3 x %[[S]]]* %[[S_0]], i64 0, i64 0
// CHECK: call void @_ZN1SC1Ei(%[[S]]* %[[S_0_0]], i32 1)
// CHECK: %[[S_0_1:.*]] = getelementptr inbounds %[[S]]* %[[S_0_0]], i64 1
// CHECK: call void @_ZN1SC1Ei(%[[S]]* %[[S_0_1]], i32 2)
// CHECK: %[[S_0_2:.*]] = getelementptr inbounds %[[S]]* %[[S_0_1]], i64 1
// CHECK: call void @_ZN1SC1Ei(%[[S]]* %[[S_0_2]], i32 3)
//
// { 4, 5, 6 }
//
// CHECK: %[[S_1:.*]] = getelementptr [3 x %[[S]]]* %[[S_0]], i32 1
//
// CHECK: %[[S_1_0:.*]] = getelementptr inbounds [3 x %[[S]]]* %[[S_1]], i64 0, i64 0
// CHECK: call void @_ZN1SC1Ei(%[[S]]* %[[S_1_0]], i32 4)
// CHECK: %[[S_1_1:.*]] = getelementptr inbounds %[[S]]* %[[S_1_0]], i64 1
// CHECK: call void @_ZN1SC1Ei(%[[S]]* %[[S_1_1]], i32 5)
// CHECK: %[[S_1_2:.*]] = getelementptr inbounds %[[S]]* %[[S_1_1]], i64 1
// CHECK: call void @_ZN1SC1Ei(%[[S]]* %[[S_1_2]], i32 6)
//
// CHECK-NOT: br i1
// CHECK-NOT: call
// CHECK: }
int n;
void *q = new S[n][3]{ { 1, 2, 3 }, { 4, 5, 6 } };
// CHECK-LABEL: define
//
// CHECK: load i32* @n
// CHECK: call {{.*}} @llvm.umul.with.overflow.i64(i64 %[[N:.*]], i64 12)
// CHECK: %[[ELTS:.*]] = mul i64 %[[N]], 3
// CHECK: call {{.*}} @llvm.uadd.with.overflow.i64(i64 %{{.*}}, i64 8)
// CHECK: %[[ALLOC:.*]] = call noalias i8* @_Znam(i64 %{{.*}})
//
// CHECK: %[[COOKIE:.*]] = bitcast i8* %[[ALLOC]] to i64*
// CHECK: store i64 %[[ELTS]], i64* %[[COOKIE]]
// CHECK: %[[START_AS_i8:.*]] = getelementptr inbounds i8* %[[ALLOC]], i64 8
// CHECK: %[[START_AS_S:.*]] = bitcast i8* %[[START_AS_i8]] to %[[S]]*
// CHECK: %[[END_AS_S:.*]] = getelementptr inbounds %[[S]]* %[[START_AS_S]], i64 %[[ELTS]]
//
// Explicit initializers:
//
// { 1, 2, 3 }
//
// CHECK: %[[S_0:.*]] = bitcast %[[S]]* %[[START_AS_S]] to [3 x %[[S]]]*
//
// CHECK: %[[S_0_0:.*]] = getelementptr inbounds [3 x %[[S]]]* %[[S_0]], i64 0, i64 0
// CHECK: call void @_ZN1SC1Ei(%[[S]]* %[[S_0_0]], i32 1)
// CHECK: %[[S_0_1:.*]] = getelementptr inbounds %[[S]]* %[[S_0_0]], i64 1
// CHECK: call void @_ZN1SC1Ei(%[[S]]* %[[S_0_1]], i32 2)
// CHECK: %[[S_0_2:.*]] = getelementptr inbounds %[[S]]* %[[S_0_1]], i64 1
// CHECK: call void @_ZN1SC1Ei(%[[S]]* %[[S_0_2]], i32 3)
//
// { 4, 5, 6 }
//
// CHECK: %[[S_1:.*]] = getelementptr [3 x %[[S]]]* %[[S_0]], i32 1
//
// CHECK: %[[S_1_0:.*]] = getelementptr inbounds [3 x %[[S]]]* %[[S_1]], i64 0, i64 0
// CHECK: call void @_ZN1SC1Ei(%[[S]]* %[[S_1_0]], i32 4)
// CHECK: %[[S_1_1:.*]] = getelementptr inbounds %[[S]]* %[[S_1_0]], i64 1
// CHECK: call void @_ZN1SC1Ei(%[[S]]* %[[S_1_1]], i32 5)
// CHECK: %[[S_1_2:.*]] = getelementptr inbounds %[[S]]* %[[S_1_1]], i64 1
// CHECK: call void @_ZN1SC1Ei(%[[S]]* %[[S_1_2]], i32 6)
//
// CHECK: %[[S_2:.*]] = getelementptr [3 x %[[S]]]* %[[S_1]], i32 1
// CHECK: %[[S_2_AS_S:.*]] = bitcast [3 x %[[S]]]* %[[S_2]] to %[[S]]*
// CHECK: icmp eq %[[S]]* %[[S_2_AS_S]], %[[END_AS_S]]
// CHECK: br i1
//
// S[n-2][3] initialization loop:
//
// CHECK: %[[END_INNER:.*]] = getelementptr inbounds %[[S]]* %{{.*}}, i64 3
// CHECK: br label
//
// S[3] initialization loop:
//
// CHECK: call void @_ZN1SC1Ev(%[[S]]*
// CHECK: %[[NEXT_INNER:.*]] = getelementptr inbounds %[[S]]* %{{.*}}, i64 1
// CHECK: icmp eq %[[S]]* %[[NEXT_INNER]], %[[END_INNER]]
// CHECK: br i1
//
// CHECK: %[[NEXT_OUTER:.*]] = getelementptr [3 x %[[S]]]* %{{.*}}, i32 1
// CHECK: %[[NEXT_OUTER_AS_S:.*]] = bitcast [3 x %[[S]]]* %[[NEXT_OUTER]] to %[[S]]*
// CHECK: icmp eq %[[S]]* %[[NEXT_OUTER_AS_S]], %[[END_AS_S]]
// CHECK: br i1
//
// CHECK: }