llvm-project/clang/test/CodeGen/captured-statements-nested.c
Ben Langmuir 3b4c30b7e7 CodeGen for CapturedStmts
EmitCapturedStmt creates a captured struct containing all of the captured
variables, and then emits a call to the outlined function.  This is similar in
principle to EmitBlockLiteral.

GenerateCapturedFunction actually produces the outlined function.  It is based
on GenerateBlockFunction, but is much simpler.  The function type is determined
by the parameters that are in the CapturedDecl.

Some changes have been added to this patch that were reviewed as part of the
serialization patch and moving the parameters to the captured decl.

Differential Revision: http://llvm-reviews.chandlerc.com/D640

llvm-svn: 181536
2013-05-09 19:17:11 +00:00

127 lines
3.4 KiB
C

// RUN: %clang_cc1 -fblocks -emit-llvm %s -o %t
// RUN: FileCheck %s -input-file=%t -check-prefix=CHECK1
// RUN: FileCheck %s -input-file=%t -check-prefix=CHECK2
struct A {
int a;
float b;
char c;
};
void test_nest_captured_stmt(int param) {
int w;
// CHECK1: %struct.anon{{.*}} = type { i32*, i32* }
// CHECK1: %struct.anon{{.*}} = type { i32*, i32*, i32**, i32* }
// CHECK1: [[T:%struct.anon.*]] = type { i32*, i32*, %struct.A*, i32**, i32* }
#pragma clang __debug captured
{
int x;
int *y = &w;
#pragma clang __debug captured
{
struct A z;
#pragma clang __debug captured
{
w = x = z.a = 1;
*y = param;
z.b = 0.1f;
z.c = 'c';
// CHECK1: define internal void @__captured_stmt{{.*}}([[T]]
//
// CHECK1: getelementptr inbounds [[T]]* {{.*}}, i32 0, i32 2
// CHECK1-NEXT: load %struct.A**
// CHECK1-NEXT: getelementptr inbounds %struct.A*
// CHECK1-NEXT: store i32 1
//
// CHECK1: getelementptr inbounds [[T]]* {{.*}}, i32 0, i32 1
// CHECK1-NEXT: load i32**
// CHECK1-NEXT: store i32 1
//
// CHECK1: getelementptr inbounds [[T]]* {{.*}}, i32 0, i32 0
// CHECK1-NEXT: load i32**
// CHECK1-NEXT: store i32 1
//
// CHECK1: getelementptr inbounds [[T]]* {{.*}}, i32 0, i32 4
// CHECK1-NEXT: load i32**
// CHECK1-NEXT: load i32*
// CHECK1-NEXT: getelementptr inbounds [[T]]* {{.*}}, i32 0, i32 3
// CHECK1-NEXT: load i32***
// CHECK1-NEXT: load i32**
// CHECK1-NEXT: store i32
//
// CHECK1: getelementptr inbounds [[T]]* {{.*}}, i32 0, i32 2
// CHECK1-NEXT: load %struct.A**
// CHECK1-NEXT: getelementptr inbounds %struct.A*
// CHECK1-NEXT: store float
//
// CHECK1: getelementptr inbounds [[T]]* {{.*}}, i32 0, i32 2
// CHECK1-NEXT: load %struct.A**
// CHECK1-NEXT: getelementptr inbounds %struct.A*
// CHECK1-NEXT: store i8 99
}
}
}
}
void test_nest_block() {
__block int x;
int y;
^{
int z;
x = z;
#pragma clang __debug captured
{
z = y; // OK
}
}();
// CHECK2: define internal void @{{.*}}test_nest_block_block_invoke
//
// CHECK2: [[Z:%[0-9a-z_]*]] = alloca i32
// CHECK2: alloca %struct.anon{{.*}}
//
// CHECK2: store i32
// CHECK2: store i32* [[Z]]
//
// CHECK2: getelementptr inbounds %struct.anon
// CHECK2-NEXT: getelementptr inbounds
// CHECK2-NEXT: store i32*
//
// CHECK2: call void @__captured_stmt
int a;
#pragma clang __debug captured
{
__block int b;
int c;
__block int d;
^{
b = a;
b = c;
b = d;
}();
}
// CHECK2: alloca %struct.__block_byref_b
// CHECK2-NEXT: [[C:%[0-9a-z_]*]] = alloca i32
// CHECK2-NEXT: alloca %struct.__block_byref_d
//
// CHECK2: bitcast %struct.__block_byref_b*
// CHECK2-NEXT: store i8*
//
// CHECK2: [[CapA:%[0-9a-z_.]*]] = getelementptr inbounds {{.*}}, i32 0, i32 7
//
// CHECK2: getelementptr inbounds %struct.anon{{.*}}, i32 0, i32 0
// CHECK2: load i32**
// CHECK2: load i32*
// CHECK2: store i32 {{.*}}, i32* [[CapA]]
//
// CHECK2: [[CapC:%[0-9a-z_.]*]] = getelementptr inbounds {{.*}}, i32 0, i32 8
// CHECK2-NEXT: [[Val:%[0-9a-z_]*]] = load i32* [[C]]
// CHECK2-NEXT: store i32 [[Val]], i32* [[CapC]]
//
// CHECK2: bitcast %struct.__block_byref_d*
// CHECK2-NEXT: store i8*
}