328 lines · plain
1// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-runtime-has-weak -fblocks -fobjc-arc -O2 -disable-llvm-passes -o - %s | FileCheck %s2 3struct NSFastEnumerationState;4@interface NSArray5- (unsigned long) countByEnumeratingWithState: (struct NSFastEnumerationState*) state6 objects: (id*) buffer7 count: (unsigned long) bufferSize;8@end;9NSArray *nsarray() { return 0; }10// CHECK: define{{.*}} ptr @_Z7nsarrayv()11 12void use(id);13 14// The analogous ObjC testcase test46 in arr.m.15void test0(__weak id *wp, __weak volatile id *wvp) {16 extern id test0_helper(void);17 18 // TODO: this is sub-optimal, we should retain at the actual call site.19 // TODO: in the non-volatile case, we do not need to be reloading.20 21 // CHECK: [[T1:%.*]] = call noundef ptr @_Z12test0_helperv() [ "clang.arc.attachedcall"(ptr @llvm.objc.retainAutoreleasedReturnValue) ]22 // CHECK-NEXT: call void (...) @llvm.objc.clang.arc.noop.use(ptr [[T1]])23 // CHECK-NEXT: [[T2:%.*]] = load ptr, ptr {{%.*}}, align 824 // CHECK-NEXT: [[T3:%.*]] = call ptr @llvm.objc.storeWeak(ptr [[T2]], ptr [[T1]])25 // CHECK-NEXT: [[T4:%.*]] = call ptr @llvm.objc.retain(ptr [[T3]])26 // CHECK-NEXT: store ptr [[T4]], ptr27 // CHECK-NEXT: call void @llvm.objc.release(ptr [[T1]])28 id x = *wp = test0_helper();29 30 // CHECK: [[T1:%.*]] = call noundef ptr @_Z12test0_helperv() [ "clang.arc.attachedcall"(ptr @llvm.objc.retainAutoreleasedReturnValue) ]31 // CHECK-NEXT: call void (...) @llvm.objc.clang.arc.noop.use(ptr [[T1]])32 // CHECK-NEXT: [[T2:%.*]] = load ptr, ptr {{%.*}}, align 833 // CHECK-NEXT: [[T3:%.*]] = call ptr @llvm.objc.storeWeak(ptr [[T2]], ptr [[T1]])34 // CHECK-NEXT: [[T4:%.*]] = call ptr @llvm.objc.loadWeakRetained(ptr [[T2]])35 // CHECK-NEXT: store ptr [[T4]], ptr36 // CHECK-NEXT: call void @llvm.objc.release(ptr [[T1]])37 id y = *wvp = test0_helper();38}39 40struct Test1_helper { Test1_helper(); };41@interface Test1 @end42@implementation Test1 { Test1_helper x; } @end43// CHECK: define internal noundef ptr @"\01-[Test1 .cxx_construct]"(44// CHECK: call void @_ZN12Test1_helperC1Ev(45// CHECK-NEXT: load46// CHECK-NEXT: ret ptr47 48void test34(int cond) {49 __strong id strong;50 __weak id weak;51 extern void test34_sink(id *);52 test34_sink(cond ? &strong : 0);53 test34_sink(cond ? &weak : 0);54 55 // CHECK-LABEL: define{{.*}} void @_Z6test34i(56 // CHECK: [[COND:%.*]] = alloca i3257 // CHECK-NEXT: [[STRONG:%.*]] = alloca ptr58 // CHECK-NEXT: [[WEAK:%.*]] = alloca ptr59 // CHECK-NEXT: [[TEMP1:%.*]] = alloca ptr60 // CHECK-NEXT: [[TEMP2:%.*]] = alloca ptr61 // CHECK-NEXT: [[CONDCLEANUPSAVE:%.*]] = alloca ptr62 // CHECK-NEXT: [[CONDCLEANUP:%.*]] = alloca i163 // CHECK-NEXT: store i3264 // CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[STRONG]])65 // CHECK-NEXT: store ptr null, ptr [[STRONG]]66 // CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[WEAK]])67 // CHECK-NEXT: call ptr @llvm.objc.initWeak(ptr [[WEAK]], ptr null)68 69 // CHECK-NEXT: [[T0:%.*]] = load i32, ptr [[COND]]70 // CHECK-NEXT: [[T1:%.*]] = icmp ne i32 [[T0]], 071 // CHECK: [[ARG:%.*]] = phi ptr72 // CHECK-NEXT: [[T0:%.*]] = icmp eq ptr [[ARG]], null73 // CHECK-NEXT: [[T1:%.*]] = select i1 [[T0]], ptr null, ptr [[TEMP1]]74 // CHECK-NEXT: br i1 [[T0]],75 // CHECK: [[T0:%.*]] = load ptr, ptr [[ARG]]76 // CHECK-NEXT: store ptr [[T0]], ptr [[TEMP1]]77 // CHECK-NEXT: br label78 // CHECK: [[W0:%.*]] = phi ptr [ [[T0]], {{%.*}} ], [ poison, {{%.*}} ]79 // CHECK: call void @_Z11test34_sinkPU15__autoreleasingP11objc_object(ptr noundef [[T1]])80 // CHECK-NEXT: [[T0:%.*]] = icmp eq ptr [[ARG]], null81 // CHECK-NEXT: br i1 [[T0]],82 // CHECK: [[T0:%.*]] = load ptr, ptr [[TEMP1]]83 // CHECK-NEXT: [[T1:%.*]] = call ptr @llvm.objc.retain(ptr [[T0]])84 // CHECK-NEXT: call void (...) @llvm.objc.clang.arc.use(ptr [[W0]])85 // CHECK-NEXT: [[T2:%.*]] = load ptr, ptr [[ARG]]86 // CHECK-NEXT: store ptr [[T1]], ptr [[ARG]]87 // CHECK-NEXT: call void @llvm.objc.release(ptr [[T2]])88 // CHECK-NEXT: br label89 90 // CHECK: [[T0:%.*]] = load i32, ptr [[COND]]91 // CHECK-NEXT: [[T1:%.*]] = icmp ne i32 [[T0]], 092 // CHECK: [[ARG:%.*]] = phi ptr93 // CHECK-NEXT: [[T0:%.*]] = icmp eq ptr [[ARG]], null94 // CHECK-NEXT: [[T1:%.*]] = select i1 [[T0]], ptr null, ptr [[TEMP2]]95 // CHECK-NEXT: store i1 false, ptr [[CONDCLEANUP]]96 // CHECK-NEXT: br i1 [[T0]],97 // CHECK: [[T0:%.*]] = call ptr @llvm.objc.loadWeakRetained(ptr [[ARG]])98 // CHECK-NEXT: store ptr [[T0]], ptr [[CONDCLEANUPSAVE]]99 // CHECK-NEXT: store i1 true, ptr [[CONDCLEANUP]]100 // CHECK-NEXT: store ptr [[T0]], ptr [[TEMP2]]101 // CHECK-NEXT: br label102 // CHECK: call void @_Z11test34_sinkPU15__autoreleasingP11objc_object(ptr noundef [[T1]])103 // CHECK-NEXT: [[T0:%.*]] = icmp eq ptr [[ARG]], null104 // CHECK-NEXT: br i1 [[T0]],105 // CHECK: [[T0:%.*]] = load ptr, ptr [[TEMP2]]106 // CHECK-NEXT: call ptr @llvm.objc.storeWeak(ptr [[ARG]], ptr [[T0]])107 // CHECK-NEXT: br label108 109 // CHECK: call void @llvm.objc.destroyWeak(ptr [[WEAK]])110 // CHECK: ret void111}112 113struct Test35_Helper {114 static id makeObject1() __attribute__((ns_returns_retained));115 id makeObject2() __attribute__((ns_returns_retained));116 static id makeObject3();117 id makeObject4();118};119 120// CHECK-LABEL: define{{.*}} void @_Z6test3513Test35_HelperPS_121void test35(Test35_Helper x0, Test35_Helper *x0p) {122 // CHECK: call void @llvm.lifetime.start123 // CHECK: call noundef ptr @_ZN13Test35_Helper11makeObject1Ev124 // CHECK-NOT: call ptr @llvm.objc.retain125 id obj1 = Test35_Helper::makeObject1();126 // CHECK: call void @llvm.lifetime.start127 // CHECK: call noundef ptr @_ZN13Test35_Helper11makeObject2Ev128 // CHECK-NOT: call ptr @llvm.objc.retain129 id obj2 = x0.makeObject2();130 // CHECK: call void @llvm.lifetime.start131 // CHECK: call noundef ptr @_ZN13Test35_Helper11makeObject2Ev132 // CHECK-NOT: call ptr @llvm.objc.retain133 id obj3 = x0p->makeObject2();134 id (Test35_Helper::*pmf)() __attribute__((ns_returns_retained))135 = &Test35_Helper::makeObject2;136 // CHECK: call void @llvm.lifetime.start137 // CHECK: call noundef ptr %138 // CHECK-NOT: call ptr @llvm.objc.retain139 id obj4 = (x0.*pmf)();140 // CHECK: call void @llvm.lifetime.start141 // CHECK: call noundef ptr %142 // CHECK-NOT: call ptr @llvm.objc.retain143 id obj5 = (x0p->*pmf)();144 145 // CHECK: call void @llvm.objc.release146 // CHECK: call void @llvm.lifetime.end147 // CHECK: call void @llvm.objc.release148 // CHECK: call void @llvm.lifetime.end149 // CHECK: call void @llvm.objc.release150 // CHECK: call void @llvm.lifetime.end151 // CHECK: call void @llvm.objc.release152 // CHECK: call void @llvm.lifetime.end153 // CHECK: call void @llvm.objc.release154 // CHECK: call void @llvm.lifetime.end155 // CHECK-NEXT: ret void156}157 158// CHECK-LABEL: define{{.*}} void @_Z7test35b13Test35_HelperPS_159void test35b(Test35_Helper x0, Test35_Helper *x0p) {160 // CHECK: call void @llvm.lifetime.start161 // CHECK: call noundef ptr @_ZN13Test35_Helper11makeObject3Ev{{.*}} [ "clang.arc.attachedcall"(ptr @llvm.objc.retainAutoreleasedReturnValue) ]162 id obj1 = Test35_Helper::makeObject3();163 // CHECK: call void @llvm.lifetime.start164 // CHECK: call noundef ptr @_ZN13Test35_Helper11makeObject4Ev{{.*}} [ "clang.arc.attachedcall"(ptr @llvm.objc.retainAutoreleasedReturnValue) ]165 id obj2 = x0.makeObject4();166 // CHECK: call void @llvm.lifetime.start167 // CHECK: call noundef ptr @_ZN13Test35_Helper11makeObject4Ev{{.*}} [ "clang.arc.attachedcall"(ptr @llvm.objc.retainAutoreleasedReturnValue) ]168 id obj3 = x0p->makeObject4();169 id (Test35_Helper::*pmf)() = &Test35_Helper::makeObject4;170 // CHECK: call void @llvm.lifetime.start171 // CHECK: call noundef ptr %{{.*}} [ "clang.arc.attachedcall"(ptr @llvm.objc.retainAutoreleasedReturnValue) ]172 id obj4 = (x0.*pmf)();173 // CHECK: call void @llvm.lifetime.start174 // CHECK: call noundef ptr %{{.*}} [ "clang.arc.attachedcall"(ptr @llvm.objc.retainAutoreleasedReturnValue) ]175 id obj5 = (x0p->*pmf)();176 177 // CHECK: call void @llvm.objc.release178 // CHECK: call void @llvm.lifetime.end179 // CHECK: call void @llvm.objc.release180 // CHECK: call void @llvm.lifetime.end181 // CHECK: call void @llvm.lifetime.end182 // CHECK: call void @llvm.objc.release183 // CHECK: call void @llvm.lifetime.end184 // CHECK: call void @llvm.objc.release185 // CHECK: call void @llvm.lifetime.end186 // CHECK: call void @llvm.objc.release187 // CHECK: call void @llvm.lifetime.end188 // CHECK-NEXT: ret void189}190 191// CHECK-LABEL: define{{.*}} ptr @_Z6test36P11objc_object(192id test36(id z) {193 // CHECK: llvm.objc.retain194 // CHECK: llvm.objc.retain195 // CHECK: llvm.objc.release196 // CHECK: llvm.objc.autoreleaseReturnValue197 return z;198}199 200@interface Test37201+ alloc;202- init;203- (NSArray *) array;204@end205template <class T> void test37(T *a) {206 for (id x in a.array) {207 use(x);208 }209}210extern template void test37<Test37>(Test37 *a);211template void test37<Test37>(Test37 *a);212// CHECK-LABEL: define weak_odr void @_Z6test37I6Test37EvPT_(213// CHECK: [[T2:%.*]] = call noundef ptr @objc_msgSend({{.*}} [ "clang.arc.attachedcall"(ptr @llvm.objc.retainAutoreleasedReturnValue) ]214// CHECK-NEXT: call void (...) @llvm.objc.clang.arc.noop.use({{.*}} [[T2]])215 216// Make sure it's not immediately released before starting the iteration.217// CHECK-NEXT: load ptr, ptr @OBJC_SELECTOR_REFERENCES_218// CHECK-NEXT: @objc_msgSend219 220// This bitcast is for the mutation check.221// CHECK: @objc_enumerationMutation222 223// This bitcast is for the 'next' message send.224// CHECK: load ptr, ptr @OBJC_SELECTOR_REFERENCES_225// CHECK-NEXT: @objc_msgSend226 227// This bitcast is for the final release.228// CHECK: call void @llvm.objc.release(ptr [[T2]])229 230template<typename T>231void send_release() {232 [Test37 array];233}234 235// CHECK-LABEL: define weak_odr void @_Z12send_releaseIiEvv(236// CHECK: call noundef ptr @objc_msgSend{{.*}} [ "clang.arc.attachedcall"(ptr @llvm.objc.retainAutoreleasedReturnValue) ]237// CHECK-NEXT: call void (...) @llvm.objc.clang.arc.noop.use(238// CHECK-NEXT: call void @llvm.objc.release239// CHECK-NEXT: ret void240template void send_release<int>();241 242template<typename T>243Test37 *instantiate_init() {244 Test37 *result = [[Test37 alloc] init];245 return result;246}247 248// CHECK-LABEL: define weak_odr noundef ptr @_Z16instantiate_initIiEP6Test37v249// CHECK: call noundef ptr @objc_msgSend250// CHECK: call noundef ptr @objc_msgSend251// CHECK: call ptr @llvm.objc.retain252// CHECK: call void @llvm.objc.release253// CHECK: call ptr @llvm.objc.autoreleaseReturnValue254template Test37* instantiate_init<int>();255 256// Just make sure that the AST invariants hold properly here,257// i.e. that we don't crash.258// The block should get bound in the full-expression outside259// the statement-expression.260template <class T> class Test38 {261 void test(T x) {262 ^{ (void) x; }, ({ x; });263 }264};265// CHECK-LABEL: define weak_odr void @_ZN6Test38IiE4testEi(266template class Test38<int>;267 268class Test39_base1 {269 virtual void foo();270};271class Test39_base2 {272 virtual id bar();273};274class Test39 : Test39_base1, Test39_base2 { // base2 is at non-zero offset275 virtual id bar();276};277id Test39::bar() { return 0; }278// Note lack of autorelease.279// CHECK-LABEL: define{{.*}} ptr @_ZThn8_N6Test393barEv(280// CHECK: call noundef ptr @_ZN6Test393barEv(281// CHECK-NEXT: ret ptr282 283// Just a basic correctness check that IR-gen still works after instantiating284// a non-dependent message send that requires writeback.285@interface Test40286+ (void) foo:(id *)errorPtr;287@end288template <class T> void test40_helper() {289 id x;290 [Test40 foo: &x];291};292template void test40_helper<int>();293// CHECK-LABEL: define weak_odr void @_Z13test40_helperIiEvv()294// CHECK: [[X:%.*]] = alloca ptr295// CHECK-NEXT: [[TEMP:%.*]] = alloca ptr296// CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[X]])297// CHECK-NEXT: store ptr null, ptr [[X]]298// CHECK: [[T0:%.*]] = load ptr, ptr [[X]]299// CHECK-NEXT: store ptr [[T0]], ptr [[TEMP]]300// CHECK: @objc_msgSend301// CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[TEMP]]302// CHECK-NEXT: call ptr @llvm.objc.retain(ptr [[T0]])303 304// Check that moves out of __weak variables are compiled to use objc_moveWeak.305void test41(__weak id &&x) {306 __weak id y = static_cast<__weak id &&>(x);307}308// CHECK-LABEL: define{{.*}} void @_Z6test41OU6__weakP11objc_object309// CHECK: [[X:%.*]] = alloca ptr310// CHECK: [[Y:%.*]] = alloca ptr311// CHECK: [[T0:%.*]] = load ptr, ptr [[X]]312// CHECK-NEXT: call void @llvm.objc.moveWeak(ptr [[Y]], ptr [[T0]])313// CHECK-NEXT: call void @llvm.objc.destroyWeak(ptr [[Y]])314 315void test42() {316 __attribute__((ns_returns_retained)) id test42_0();317 id test42_1(id);318 void test42_2(id &&);319 test42_2(test42_1(test42_0()));320}321 322// Check that the pointer returned by test42_0 is released after the full expression.323 324// CHECK-LABEL: define void @_Z6test42v()325// CHECK: %[[CALL:.*]] = call noundef ptr @_Z8test42_0v()326// CHECK: call void @_Z8test42_2OU15__autoreleasingP11objc_object(327// CHECK: call void @llvm.objc.release(ptr %[[CALL]])328