xref: /llvm-project/clang/test/CodeGenObjC/direct-method.m (revision 158d72d728261c1e54dc77931372b2322c52849f)
1// RUN: %clang_cc1 -emit-llvm -fobjc-arc -triple x86_64-apple-darwin10 %s -o - | FileCheck %s
2
3struct my_complex_struct {
4  int a, b;
5};
6
7struct my_aggregate_struct {
8  int a, b;
9  char buf[128];
10};
11
12__attribute__((objc_root_class))
13@interface Root
14- (int)getInt __attribute__((objc_direct));
15@property(direct, readonly) int intProperty;
16@property(direct, readonly) int intProperty2;
17@property(direct, readonly) id objectProperty;
18@end
19
20@implementation Root
21// CHECK-LABEL: define hidden i32 @"\01-[Root intProperty2]"
22- (int)intProperty2 {
23  return 42;
24}
25
26// CHECK-LABEL: define hidden i32 @"\01-[Root getInt]"(
27- (int)getInt __attribute__((objc_direct)) {
28  // loading parameters
29  // CHECK-LABEL: entry:
30  // CHECK-NEXT: [[RETVAL:%.*]] = alloca
31  // CHECK-NEXT: [[SELFADDR:%.*]] = alloca ptr,
32  // CHECK-NEXT: store ptr %{{.*}}, ptr [[SELFADDR]],
33
34  // self nil-check
35  // CHECK-NEXT: [[SELF:%.*]] = load ptr, ptr [[SELFADDR]],
36  // CHECK-NEXT: [[NILCHECK:%.*]] = icmp eq ptr [[SELF]], null
37  // CHECK-NEXT: br i1 [[NILCHECK]],
38
39  // setting return value to nil
40  // CHECK-LABEL: objc_direct_method.self_is_nil:
41  // CHECK-NEXT: call void @llvm.memset{{[^(]*}}({{[^,]*}}[[RETVAL]], i8 0,
42  // CHECK-NEXT: br label
43
44  // set value
45  // CHECK-LABEL: objc_direct_method.cont:
46  // CHECK: store{{.*}}[[RETVAL]],
47  // CHECK-NEXT: br label
48
49  // return
50  // CHECK-LABEL: return:
51  // CHECK: {{%.*}} = load{{.*}}[[RETVAL]],
52  // CHECK-NEXT: ret
53  return 42;
54}
55
56// CHECK-LABEL: define hidden i32 @"\01+[Root classGetInt]"(
57+ (int)classGetInt __attribute__((objc_direct)) {
58  // loading parameters
59  // CHECK-LABEL: entry:
60  // CHECK-NEXT: [[SELFADDR:%.*]] = alloca ptr,
61  // CHECK-NEXT: store ptr %{{.*}}, ptr [[SELFADDR]],
62
63  // [self self]
64  // CHECK-NEXT: [[SELF:%.*]] = load ptr, ptr [[SELFADDR]],
65  // CHECK-NEXT: [[SELFSEL:%.*]] = load ptr, ptr @OBJC_SELECTOR_REFERENCES_
66  // CHECK-NEXT: [[SELF0:%.*]] = call {{.*}} @objc_msgSend
67  // CHECK-NEXT: store ptr [[SELF0]], ptr [[SELFADDR]],
68
69  // return
70  // CHECK-NEXT: ret
71  return 42;
72}
73
74// CHECK-LABEL: define hidden i64 @"\01-[Root getComplex]"(
75- (struct my_complex_struct)getComplex __attribute__((objc_direct)) {
76  // loading parameters
77  // CHECK-LABEL: entry:
78  // CHECK-NEXT: [[RETVAL:%.*]] = alloca
79  // CHECK-NEXT: [[SELFADDR:%.*]] = alloca ptr,
80  // CHECK-NEXT: store ptr %{{.*}}, ptr [[SELFADDR]],
81
82  // self nil-check
83  // CHECK-NEXT: [[SELF:%.*]] = load ptr, ptr [[SELFADDR]],
84  // CHECK-NEXT: [[NILCHECK:%.*]] = icmp eq ptr [[SELF]], null
85  // CHECK-NEXT: br i1 [[NILCHECK]],
86
87  // setting return value to nil
88  // CHECK-LABEL: objc_direct_method.self_is_nil:
89  // CHECK-NEXT: call void @llvm.memset{{[^(]*}}({{[^,]*}}[[RETVAL]], i8 0,
90  // CHECK-NEXT: br label
91
92  // set value
93  // CHECK-LABEL: objc_direct_method.cont:
94  // CHECK-NEXT: call void @llvm.memcpy{{[^(]*}}({{[^,]*}}[[RETVAL]],
95  // CHECK-NEXT: br label
96
97  // return
98  // CHECK-LABEL: return:
99  // CHECK-NEXT: {{%.*}} = load{{.*}}[[RETVAL]],
100  // CHECK-NEXT: ret
101  struct my_complex_struct st = {.a = 42};
102  return st;
103}
104
105// CHECK-LABEL: define hidden i64 @"\01+[Root classGetComplex]"(
106+ (struct my_complex_struct)classGetComplex __attribute__((objc_direct)) {
107  struct my_complex_struct st = {.a = 42};
108  return st;
109  // CHECK: ret i64
110}
111
112// CHECK-LABEL: define hidden void @"\01-[Root getAggregate]"(
113- (struct my_aggregate_struct)getAggregate __attribute__((objc_direct)) {
114  // CHECK: ptr dead_on_unwind noalias writable sret(%struct.my_aggregate_struct) align 4 [[RETVAL:%[^,]*]],
115
116  // loading parameters
117  // CHECK-LABEL: entry:
118  // CHECK-NEXT: [[SELFADDR:%.*]] = alloca ptr,
119  // CHECK-NEXT: store ptr %{{.*}}, ptr [[SELFADDR]],
120
121  // self nil-check
122  // CHECK-NEXT: [[SELF:%.*]] = load ptr, ptr [[SELFADDR]],
123  // CHECK-NEXT: [[NILCHECK:%.*]] = icmp eq ptr [[SELF]], null
124  // CHECK-NEXT: br i1 [[NILCHECK]],
125
126  // setting return value to nil
127  // CHECK-LABEL: objc_direct_method.self_is_nil:
128  // CHECK-NEXT: call void @llvm.memset{{[^(]*}}({{[^,]*}}[[RETVAL]], i8 0,
129  // CHECK-NEXT: br label
130
131  // set value
132  // CHECK-LABEL: objc_direct_method.cont:
133  // CHECK: br label
134
135  // return
136  // CHECK-LABEL: return:
137  // CHECK: ret void
138  struct my_aggregate_struct st = {.a = 42};
139  return st;
140}
141
142// CHECK-LABEL: define hidden void @"\01+[Root classGetAggregate]"(
143+ (struct my_aggregate_struct)classGetAggregate __attribute__((objc_direct)) {
144  struct my_aggregate_struct st = {.a = 42};
145  return st;
146  // CHECK: ret void
147}
148
149// CHECK-LABEL: define hidden void @"\01-[Root accessCmd]"(
150- (void)accessCmd __attribute__((objc_direct)) {
151  // CHECK-LABEL: entry:
152  // CHECK-NEXT: [[SELFADDR:%.*]] = alloca ptr,
153  // CHECK-NEXT: [[CMDVAL:%_cmd]] = alloca ptr,
154
155  // loading the _cmd selector
156  // CHECK-LABEL: objc_direct_method.cont:
157  // CHECK-NEXT: [[CMD1:%.*]] = load ptr, ptr @OBJC_SELECTOR_REFERENCES_
158  // CHECK-NEXT: store ptr [[CMD1]], ptr [[CMDVAL]],
159  SEL sel = _cmd;
160}
161
162@end
163// CHECK-LABEL: define hidden i32 @"\01-[Root intProperty]"
164
165// Check the synthesized objectProperty calls objc_getProperty(); this also
166// checks that the synthesized method passes undef for the `cmd` argument.
167// CHECK-LABEL: define hidden ptr @"\01-[Root objectProperty]"(
168// CHECK-LABEL: objc_direct_method.cont:
169// CHECK-NEXT: [[SELFVAL:%.*]] = load {{.*}} %self.addr,
170// CHECK-NEXT: [[IVAR:%.*]] = load {{.*}} @"OBJC_IVAR_$_Root._objectProperty",
171// CHECK-NEXT: call ptr @objc_getProperty(ptr noundef [[SELFVAL]], ptr noundef poison, i64 noundef [[IVAR]], {{.*}})
172
173@interface Foo : Root {
174  id __strong _cause_cxx_destruct;
175}
176@property(nonatomic, readonly, direct) int getDirect_setDynamic;
177@property(nonatomic, readonly) int getDynamic_setDirect;
178@end
179
180@interface Foo ()
181@property(nonatomic, readwrite) int getDirect_setDynamic;
182@property(nonatomic, readwrite, direct) int getDynamic_setDirect;
183- (int)directMethodInExtension __attribute__((objc_direct));
184@end
185
186@interface Foo (Cat)
187- (int)directMethodInCategory __attribute__((objc_direct));
188@end
189
190__attribute__((objc_direct_members))
191@implementation Foo
192// CHECK-LABEL: define hidden i32 @"\01-[Foo directMethodInExtension]"(
193- (int)directMethodInExtension {
194  return 42;
195}
196// CHECK-LABEL: define hidden i32 @"\01-[Foo getDirect_setDynamic]"(
197// CHECK-LABEL: define internal void @"\01-[Foo setGetDirect_setDynamic:]"(
198// CHECK-LABEL: define internal i32 @"\01-[Foo getDynamic_setDirect]"(
199// CHECK-LABEL: define hidden void @"\01-[Foo setGetDynamic_setDirect:]"(
200// CHECK-LABEL: define internal void @"\01-[Foo .cxx_destruct]"(
201@end
202
203@implementation Foo (Cat)
204// CHECK-LABEL: define hidden i32 @"\01-[Foo directMethodInCategory]"(
205- (int)directMethodInCategory {
206  return 42;
207}
208// CHECK-LABEL: define hidden i32 @"\01-[Foo directMethodInCategoryNoDecl]"(
209- (int)directMethodInCategoryNoDecl __attribute__((objc_direct)) {
210  return 42;
211}
212@end
213
214int useRoot(Root *r) {
215  // CHECK-LABEL: define{{.*}} i32 @useRoot
216  // CHECK: %{{[^ ]*}} = call i32  @"\01-[Root getInt]"
217  // CHECK: %{{[^ ]*}} = call i32  @"\01-[Root intProperty]"
218  // CHECK: %{{[^ ]*}} = call i32  @"\01-[Root intProperty2]"
219  return [r getInt] + [r intProperty] + [r intProperty2];
220}
221
222int useFoo(Foo *f) {
223  // CHECK-LABEL: define{{.*}} i32 @useFoo
224  // CHECK: call void @"\01-[Foo setGetDynamic_setDirect:]"
225  // CHECK: %{{[^ ]*}} = call i32 @"\01-[Foo getDirect_setDynamic]"
226  // CHECK: %{{[^ ]*}} = call i32 @"\01-[Foo directMethodInExtension]"
227  // CHECK: %{{[^ ]*}} = call i32 @"\01-[Foo directMethodInCategory]"
228  // CHECK: %{{[^ ]*}} = call i32 @"\01-[Foo directMethodInCategoryNoDecl]"
229  [f setGetDynamic_setDirect:1];
230  return [f getDirect_setDynamic] +
231         [f directMethodInExtension] +
232         [f directMethodInCategory] +
233         [f directMethodInCategoryNoDecl];
234}
235
236__attribute__((objc_root_class))
237@interface RootDeclOnly
238@property(direct, readonly) int intProperty;
239@end
240
241int useRootDeclOnly(RootDeclOnly *r) {
242  // CHECK-LABEL: define{{.*}} i32 @useRootDeclOnly
243  // CHECK: %{{[^ ]*}} = call i32 @"\01-[RootDeclOnly intProperty]"
244  return [r intProperty];
245}
246