summaryrefslogtreecommitdiffstats
path: root/test/CodeGenCXX
diff options
context:
space:
mode:
authorFaisal Vali <faisalv@yahoo.com>2017-05-15 01:49:19 +0000
committerFaisal Vali <faisalv@yahoo.com>2017-05-15 01:49:19 +0000
commit0f9b7cd618ad70955e67f9c3c9b48321a13dc624 (patch)
tree940f2a7043f9c72dc3f41e1c79ec0914aca10b68 /test/CodeGenCXX
parent848b631d3a1e857e2ad2fe61f09ad6de50e89c25 (diff)
Fix PR32933: crash on lambda capture of VLA
https://bugs.llvm.org/show_bug.cgi?id=32933 Turns out clang wasn't really handling vla's (*) in C++11's for-range entirely correctly. For e.g. This would lead to generation of buggy IR: void foo(int b) { int vla[b]; b = -1; // This store would affect the '__end = vla + b' for (int &c : vla) c = 0; } Additionally, code-gen would get confused when VLA's were reference-captured by lambdas, and then used in a for-range, which would result in an attempt to generate IR for '__end = vla + b' within the lambda's body - without any capture of 'b' - hence the assertion. This patch modifies clang, so that for VLA's it translates the end pointer approximately into: __end = __begin + sizeof(vla)/sizeof(vla->getElementType()) As opposed to the __end = __begin + b; I considered passing a magic value into codegen - or having codegen special case the '__end' variable when it referred to a variably-modified type, but I decided against that approach, because it smelled like I would be increasing a complicated form of coupling, that I think would be even harder to maintain than the above approach (which can easily be optimized (-O1) to refer to the run-time bound that was calculated upon array's creation or copied into the lambda's closure object). (*) why oh why gcc would you enable this by default?! ;) git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@303026 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'test/CodeGenCXX')
-rw-r--r--test/CodeGenCXX/vla.cpp85
1 files changed, 84 insertions, 1 deletions
diff --git a/test/CodeGenCXX/vla.cpp b/test/CodeGenCXX/vla.cpp
index 4e22bba7d7..798a5ae0d9 100644
--- a/test/CodeGenCXX/vla.cpp
+++ b/test/CodeGenCXX/vla.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin %s -emit-llvm -o - | FileCheck %s
template<typename T>
struct S {
@@ -54,3 +54,86 @@ void test0(void *array, int n) {
// CHECK-NEXT: ret void
}
+
+
+void test2(int b) {
+ // CHECK-LABEL: define void {{.*}}test2{{.*}}(i32 %b)
+ int varr[b];
+ // get the address of %b by checking the first store that stores it
+ //CHECK: store i32 %b, i32* [[PTR_B:%.*]]
+
+ // get the size of the VLA by getting the first load of the PTR_B
+ //CHECK: [[VLA_NUM_ELEMENTS_PREZEXT:%.*]] = load i32, i32* [[PTR_B]]
+ //CHECK-NEXT: [[VLA_NUM_ELEMENTS_PRE:%.*]] = zext i32 [[VLA_NUM_ELEMENTS_PREZEXT]]
+
+ b = 15;
+ //CHECK: store i32 15, i32* [[PTR_B]]
+
+ // Now get the sizeof, and then divide by the element size
+
+
+ //CHECK: [[VLA_SIZEOF:%.*]] = mul nuw i64 4, [[VLA_NUM_ELEMENTS_PRE]]
+ //CHECK-NEXT: [[VLA_NUM_ELEMENTS_POST:%.*]] = udiv i64 [[VLA_SIZEOF]], 4
+ //CHECK-NEXT: [[VLA_END_PTR:%.*]] = getelementptr inbounds i32, i32* {{%.*}}, i64 [[VLA_NUM_ELEMENTS_POST]]
+ //CHECK-NEXT: store i32* [[VLA_END_PTR]], i32** %__end
+ for (int d : varr) 0;
+}
+
+#if 0
+ %0 = load i32, i32* %b.addr, align 4
+ %1 = zext i32 %0 to i64
+ %2 = load i32, i32* %c.addr, align 4
+ %3 = zext i32 %2 to i64
+ %4 = call i8* @llvm.stacksave()
+ store i8* %4, i8** %saved_stack, align 8
+ %5 = mul nuw i64 %1, %3
+ %vla = alloca i32, i64 %5, align 16
+ store i32 15, i32* %c.addr, align 4
+ store i32 15, i32* %b.addr, align 4
+ store i32* %vla, i32** %__range, align 8
+
+
+ %6 = load i32*, i32** %__range, align 8
+ store i32* %6, i32** %__begin, align 8
+ %7 = load i32*, i32** %__range, align 8
+ %8 = mul nuw i64 %1, %3
+ %9 = mul nuw i64 4, %8
+ %10 = mul nuw i64 4, %3
+ %div = udiv i64 %9, %10
+ %vla.index = mul nsw i64 %div, %3
+ %add.ptr = getelementptr inbounds i32, i32* %7, i64 %vla.index
+ store i32* %add.ptr, i32** %__end, align 8
+#endif
+
+void test3(int b, int c) {
+ // CHECK-LABEL: define void {{.*}}test3{{.*}}(i32 %b, i32 %c)
+ int varr[b][c];
+ // get the address of %b by checking the first store that stores it
+ //CHECK: store i32 %b, i32* [[PTR_B:%.*]]
+ //CHECK-NEXT: store i32 %c, i32* [[PTR_C:%.*]]
+
+ // get the size of the VLA by getting the first load of the PTR_B
+ //CHECK: [[VLA_DIM1_PREZEXT:%.*]] = load i32, i32* [[PTR_B]]
+ //CHECK-NEXT: [[VLA_DIM1_PRE:%.*]] = zext i32 [[VLA_DIM1_PREZEXT]]
+ //CHECK: [[VLA_DIM2_PREZEXT:%.*]] = load i32, i32* [[PTR_C]]
+ //CHECK-NEXT: [[VLA_DIM2_PRE:%.*]] = zext i32 [[VLA_DIM2_PREZEXT]]
+
+ b = 15;
+ c = 15;
+ //CHECK: store i32 15, i32* [[PTR_B]]
+ //CHECK: store i32 15, i32* [[PTR_C]]
+ // Now get the sizeof, and then divide by the element size
+
+ // multiply the two dimensions, then by the element type and then divide by the sizeof dim2
+ //CHECK: [[VLA_DIM1_X_DIM2:%.*]] = mul nuw i64 [[VLA_DIM1_PRE]], [[VLA_DIM2_PRE]]
+ //CHECK-NEXT: [[VLA_SIZEOF:%.*]] = mul nuw i64 4, [[VLA_DIM1_X_DIM2]]
+ //CHECK-NEXT: [[VLA_SIZEOF_DIM2:%.*]] = mul nuw i64 4, [[VLA_DIM2_PRE]]
+ //CHECK-NEXT: [[VLA_NUM_ELEMENTS:%.*]] = udiv i64 [[VLA_SIZEOF]], [[VLA_SIZEOF_DIM2]]
+ //CHECK-NEXT: [[VLA_END_INDEX:%.*]] = mul nsw i64 [[VLA_NUM_ELEMENTS]], [[VLA_DIM2_PRE]]
+ //CHECK-NEXT: [[VLA_END_PTR:%.*]] = getelementptr inbounds i32, i32* %7, i64 [[VLA_END_INDEX]]
+ //CHECK-NEXT: store i32* [[VLA_END_PTR]], i32** %__end
+
+ for (auto &d : varr) 0;
+}
+
+