brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.2 KiB · a693dbc Raw
303 lines · cpp
1// RUN: %clang_cc1 %s -fblocks -triple x86_64-apple-darwin -emit-llvm -o - | FileCheck %s2 3// CHECK: @[[BLOCK_DESCRIPTOR22:.*]] = internal constant { i64, i64, ptr, ptr, ptr, ptr } { i64 0, i64 36, ptr @__copy_helper_block_8_32c22_ZTSN12_GLOBAL__N_11BE, ptr @__destroy_helper_block_8_32c22_ZTSN12_GLOBAL__N_11BE, ptr @{{.*}}, ptr null }, align 84 5namespace test0 {6  // CHECK-LABEL: define{{.*}} void @_ZN5test04testEi(7  // CHECK: define internal void @___ZN5test04testEi_block_invoke{{.*}}(8  // CHECK: define internal void @___ZN5test04testEi_block_invoke_2{{.*}}(9  void test(int x) {10    ^{ ^{ (void) x; }; };11  }12}13 14extern void (^out)();15 16namespace test1 {17  // Capturing const objects doesn't require a local block.18  // CHECK-LABEL: define{{.*}} void @_ZN5test15test1Ev()19  // CHECK:   store ptr @__block_literal_global{{.*}}, ptr @out20  void test1() {21    const int NumHorsemen = 4;22    out = ^{ (void) NumHorsemen; };23  }24 25  // That applies to structs too...26  // CHECK-LABEL: define{{.*}} void @_ZN5test15test2Ev()27  // CHECK:   store ptr @__block_literal_global{{.*}}, ptr @out28  struct loc { double x, y; };29  void test2() {30    const loc target = { 5, 6 };31    out = ^{ (void) target; };32  }33 34  // ...unless they have mutable fields...35  // CHECK-LABEL: define{{.*}} void @_ZN5test15test3Ev()36  // CHECK:   [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],37  // CHECK:   store ptr [[BLOCK]], ptr @out38  struct mut { mutable int x; };39  void test3() {40    const mut obj = { 5 };41    out = ^{ (void) obj; };42  }43 44  // ...or non-trivial destructors...45  // CHECK-LABEL: define{{.*}} void @_ZN5test15test4Ev()46  // CHECK:   [[OBJ:%.*]] = alloca47  // CHECK:   [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],48  // CHECK:   store ptr [[BLOCK]], ptr @out49  struct scope { int x; ~scope(); };50  void test4() {51    const scope obj = { 5 };52    out = ^{ (void) obj; };53  }54 55  // ...or non-trivial copy constructors, but it's not clear how to do56  // that and still have a constant initializer in '03.57}58 59namespace test2 {60  struct A {61    A();62    A(const A &);63    ~A();64  };65 66  struct B {67    B();68    B(const B &);69    ~B();70  };71 72  // CHECK-LABEL: define{{.*}} void @_ZN5test24testEv()73  void test() {74    __block A a;75    __block B b;76    ^{ (void)a; (void)b; };77  }78 79  // CHECK-LABEL: define internal void @__Block_byref_object_copy80  // CHECK: call void @_ZN5test21AC1ERKS0_(81 82  // CHECK-LABEL: define internal void @__Block_byref_object_dispose83  // CHECK: call void @_ZN5test21AD1Ev(84 85  // CHECK-LABEL: define internal void @__Block_byref_object_copy86  // CHECK: call void @_ZN5test21BC1ERKS0_(87 88  // CHECK-LABEL: define internal void @__Block_byref_object_dispose89  // CHECK: call void @_ZN5test21BD1Ev(90}91 92// Make sure we mark destructors for parameters captured in blocks.93namespace test3 {94  struct A {95    A(const A&);96    ~A();97  };98 99  struct B : A {100  };101 102  void test(B b) {103    extern void consume(void(^)());104    consume(^{ (void) b; });105  }106}107 108namespace test4 {109  struct A {110    A();111    ~A();112  };113 114  void foo(A a);115 116  void test() {117    extern void consume(void(^)());118    consume(^{ return foo(A()); });119  }120  // CHECK-LABEL: define{{.*}} void @_ZN5test44testEv()121  // CHECK-LABEL: define internal void @___ZN5test44testEv_block_invoke122  // CHECK: [[TMP:%.*]] = alloca [[A:%.*]], align 1123  // CHECK-NEXT: store ptr [[BLOCKDESC:%.*]], ptr {{.*}}, align 8124  // CHECK:      call void @_ZN5test41AC1Ev(ptr {{[^,]*}} [[TMP]])125  // CHECK-NEXT: call void @_ZN5test43fooENS_1AE(ptr noundef [[TMP]])126  // CHECK-NEXT: call void @_ZN5test41AD1Ev(ptr {{[^,]*}} [[TMP]])127  // CHECK-NEXT: ret void128}129 130namespace test5 {131  struct A {132    unsigned afield;133    A();134    A(const A&);135    ~A();136    void foo() const;137  };138 139  void doWithBlock(void(^)());140 141  void test(bool cond) {142    A x;143    void (^b)() = (cond ? ^{ x.foo(); } : (void(^)()) 0);144    doWithBlock(b);145  }146 147  // CHECK-LABEL:    define{{.*}} void @_ZN5test54testEb(148  // CHECK:      [[COND:%.*]] = alloca i8149  // CHECK-NEXT: [[X:%.*]] = alloca [[A:%.*]], align 4150  // CHECK-NEXT: [[B:%.*]] = alloca ptr, align 8151  // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:.*]], align 8152  // CHECK-NEXT: [[COND_CLEANUP_SAVE:%.*]] = alloca ptr, align 8153  // CHECK-NEXT: [[CLEANUP_ACTIVE:%.*]] = alloca i1154  // CHECK-NEXT: [[T0:%.*]] = zext i1155  // CHECK-NEXT: store i8 [[T0]], ptr [[COND]], align 1156  // CHECK-NEXT: call void @_ZN5test51AC1Ev(ptr {{[^,]*}} [[X]])157  // CHECK-NEXT: [[T0:%.*]] = load i8, ptr [[COND]], align 1158  // CHECK-NEXT: [[T1:%.*]] = trunc i8 [[T0]] to i1159  // CHECK-NEXT: store i1 false, ptr [[CLEANUP_ACTIVE]]160  // CHECK-NEXT: br i1 [[T1]],161 162  // CHECK-NOT:  br163  // CHECK:      [[CAPTURE:%.*]] = getelementptr inbounds nuw [[BLOCK_T]], ptr [[BLOCK]], i32 0, i32 5164  // CHECK-NEXT: call void @_ZN5test51AC1ERKS0_(ptr {{[^,]*}} [[CAPTURE]], ptr noundef nonnull align {{[0-9]+}} dereferenceable({{[0-9]+}}) [[X]])165  // CHECK-NEXT: store ptr [[CAPTURE]], ptr [[COND_CLEANUP_SAVE]], align 8166  // CHECK-NEXT: store i1 true, ptr [[CLEANUP_ACTIVE]]167  // CHECK-NEXT: br label168  // CHECK:      br label169  // CHECK:      phi170  // CHECK-NEXT: store171  // CHECK-NEXT: load172  // CHECK-NEXT: call void @_ZN5test511doWithBlockEU13block_pointerFvvE(173  // CHECK-NEXT: [[T0:%.*]] = load i1, ptr [[CLEANUP_ACTIVE]]174  // CHECK-NEXT: br i1 [[T0]]175  // CHECK:      [[T3:%.*]] = load ptr, ptr [[COND_CLEANUP_SAVE]], align 8176  // CHECK-NEXT: call void @_ZN5test51AD1Ev(ptr {{[^,]*}} [[T3]])177  // CHECK-NEXT: br label178  // CHECK:      call void @_ZN5test51AD1Ev(ptr {{[^,]*}} [[X]])179  // CHECK-NEXT: ret void180}181 182namespace test6 {183  struct A {184    A();185    ~A();186  };187 188  void foo(const A &, void (^)());189  void bar();190 191  void test() {192    // Make sure that the temporary cleanup isn't somehow captured193    // within the block.194    foo(A(), ^{ bar(); });195    bar();196  }197 198  // CHECK-LABEL:    define{{.*}} void @_ZN5test64testEv()199  // CHECK:      [[TEMP:%.*]] = alloca [[A:%.*]], align 1200  // CHECK-NEXT: call void @_ZN5test61AC1Ev(ptr {{[^,]*}} [[TEMP]])201  // CHECK-NEXT: call void @_ZN5test63fooERKNS_1AEU13block_pointerFvvE(202  // CHECK-NEXT: call void @_ZN5test61AD1Ev(ptr {{[^,]*}} [[TEMP]])203  // CHECK-NEXT: call void @_ZN5test63barEv()204  // CHECK-NEXT: ret void205}206 207namespace test7 {208  int f() {209    static int n;210    int *const p = &n;211    return ^{ return *p; }();212  }213}214 215namespace test8 {216  // failure to capture this after skipping rebuild of the 'this' pointer.217  struct X {218    int x;219 220    template<typename T>221    int foo() {222      return ^ { return x; }();223    }224  };225 226  template int X::foo<int>();227}228 229namespace test9 {230  struct B {231    void *p;232    B();233    B(const B&);234    ~B();235  };236 237  void use_block(void (^)());238  void use_block_2(void (^)(), const B &a);239 240  // Ensuring that creating a non-trivial capture copy expression241  // doesn't end up stealing the block registration for the block we242  // just parsed.  That block must have captures or else it won't243  // force registration.  Must occur within a block for some reason.244  void test() {245    B x;246    use_block(^{247        int y;248        use_block_2(^{ (void)y; }, x);249    });250  }251}252 253namespace test10 {254  // Check that 'v' is included in the copy helper function name to indicate255  // the constructor taking a volatile parameter is called to copy the captured256  // object.257 258  // CHECK-LABEL: define linkonce_odr hidden void @__copy_helper_block_8_32c16_ZTSVN6test101BE(259  // CHECK: call void @_ZN6test101BC1ERVKS0_(260  // CHECK-LABEL: define linkonce_odr hidden void @__destroy_helper_block_8_32c16_ZTSVN6test101BE(261  // CHECK: call void @_ZN6test101BD1Ev(262 263  struct B {264    int a;265    B();266    B(const B &);267    B(const volatile B &);268    ~B();269  };270 271  void test() {272    volatile B x;273    ^{ (void)x; };274  }275}276 277// Copy/dispose helper functions and block descriptors of blocks that capture278// objects that are non-external and non-trivial have internal linkage.279 280// CHECK-LABEL: define internal void @_ZN12_GLOBAL__N_14testEv(281// CHECK: store ptr @[[BLOCK_DESCRIPTOR22]], ptr %{{.*}}, align 8282 283// CHECK-LABEL: define internal void @__copy_helper_block_8_32c22_ZTSN12_GLOBAL__N_11BE(284// CHECK-LABEL: define internal void @__destroy_helper_block_8_32c22_ZTSN12_GLOBAL__N_11BE(285 286namespace {287  struct B {288    int a;289    B();290    B(const B &);291    ~B();292  };293 294  void test() {295    B x;296    ^{ (void)x; };297  }298}299 300void callTest() {301  test();302}303