| // RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -o - %s | FileCheck %s |
| |
| // TODO: actually test most of this instead of just emitting it |
| |
| int printf(const char *, ...); |
| |
| @interface Root |
| -(id) alloc; |
| -(id) init; |
| @end |
| |
| @interface A : Root { |
| int x; |
| int y, ro, z; |
| id ob0, ob1, ob2, ob3, ob4; |
| } |
| @property int x; |
| @property int y; |
| @property int z; |
| @property(readonly) int ro; |
| @property(assign) id ob0; |
| @property(retain) id ob1; |
| @property(copy) id ob2; |
| @property(retain, nonatomic) id ob3; |
| @property(copy, nonatomic) id ob4; |
| @end |
| |
| @implementation A |
| @dynamic x; |
| @synthesize y; |
| @synthesize z = z; |
| @synthesize ro; |
| @synthesize ob0; |
| @synthesize ob1; |
| @synthesize ob2; |
| @synthesize ob3; |
| @synthesize ob4; |
| -(int) y { |
| return x + 1; |
| } |
| -(void) setZ: (int) arg { |
| x = arg - 1; |
| } |
| @end |
| |
| @interface A (Cat) |
| @property int dyn; |
| @end |
| |
| @implementation A (Cat) |
| -(int) dyn { |
| return 10; |
| } |
| @end |
| |
| // Test that compound operations only compute the base once. |
| // CHECK-LABEL: define void @test2 |
| A *test2_helper(void); |
| void test2() { |
| // CHECK: [[BASE:%.*]] = call [[A:%.*]]* @test2_helper() |
| // CHECK-NEXT: [[SEL:%.*]] = load i8*, i8** |
| // CHECK-NEXT: [[BASETMP:%.*]] = bitcast [[A]]* [[BASE]] to i8* |
| // CHECK-NEXT: [[LD:%.*]] = call i32 bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i32 (i8*, i8*)*)(i8* [[BASETMP]], i8* [[SEL]]) |
| // CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[LD]], 1 |
| // CHECK-NEXT: [[SEL:%.*]] = load i8*, i8** |
| // CHECK-NEXT: [[BASETMP:%.*]] = bitcast [[A]]* [[BASE]] to i8* |
| // CHECK-NEXT: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i32)*)(i8* [[BASETMP]], i8* [[SEL]], i32 [[ADD]]) |
| test2_helper().dyn++; |
| |
| // CHECK: [[BASE:%.*]] = call [[A]]* @test2_helper() |
| // CHECK-NEXT: [[SEL:%.*]] = load i8*, i8** |
| // CHECK-NEXT: [[BASETMP:%.*]] = bitcast [[A]]* [[BASE]] to i8* |
| // CHECK-NEXT: [[LD:%.*]] = call i32 bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i32 (i8*, i8*)*)(i8* [[BASETMP]], i8* [[SEL]]) |
| // CHECK-NEXT: [[ADD:%.*]] = mul nsw i32 [[LD]], 10 |
| // CHECK-NEXT: [[SEL:%.*]] = load i8*, i8** |
| // CHECK-NEXT: [[BASETMP:%.*]] = bitcast [[A]]* [[BASE]] to i8* |
| // CHECK-NEXT: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i32)*)(i8* [[BASETMP]], i8* [[SEL]], i32 [[ADD]]) |
| test2_helper().dyn *= 10; |
| } |
| |
| // Test aggregate initialization from property reads. |
| // Not crashing is good enough for the property-specific test. |
| struct test3_struct { int x,y,z; }; |
| struct test3_nested { struct test3_struct t; }; |
| @interface test3_object |
| @property struct test3_struct s; |
| @end |
| void test3(test3_object *p) { |
| struct test3_struct array[1] = { p.s }; |
| struct test3_nested agg = { p.s }; |
| } |
| |
| // PR8742 |
| @interface Test4 {} |
| @property float f; |
| @end |
| // CHECK-LABEL: define void @test4 |
| void test4(Test4 *t) { |
| extern int test4_printf(const char *, ...); |
| // CHECK: [[TMP:%.*]] = call float {{.*}} @objc_msgSend |
| // CHECK-NEXT: [[EXT:%.*]] = fpext float [[TMP]] to double |
| // CHECK-NEXT: call i32 (i8*, ...) @test4_printf(i8* {{.*}}, double [[EXT]]) |
| // CHECK-NEXT: ret void |
| test4_printf("%.2f", t.f); |
| } |
| |
| @interface Test5 { |
| unsigned _x : 5; |
| } |
| @property unsigned x; |
| @end |
| @implementation Test5 |
| @synthesize x = _x; |
| @end |
| |
| // rdar://problem/10410531 |
| @interface Test6 |
| @property void (*prop)(void); |
| @end |
| |
| void test6_func(void); |
| void test6(Test6 *a) { |
| a.prop = test6_func; |
| } |
| |
| // rdar://problem/10507455 |
| @interface Test7 |
| @property unsigned char x; |
| @end |
| void test7(Test7 *t) { |
| t.x &= 2; |
| t.x |= 5; |
| t.x ^= 8; |
| } |
| // CHECK: define void @test7([[TEST7:%.*]]* |
| // CHECK: [[T:%.*]] = alloca [[TEST7]]*, |
| // CHECK-NEXT: store |
| // CHECK-NEXT: [[T0:%.*]] = load [[TEST7]]*, [[TEST7]]** [[T]], align |
| // CHECK-NEXT: load i8*, i8** @OBJC_SELECTOR_REFERENCES |
| // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST7]]* [[T0]] to i8* |
| // CHECK-NEXT: [[T2:%.*]] = call zeroext i8 bitcast |
| // CHECK-NEXT: [[T3:%.*]] = zext i8 [[T2]] to i32 |
| // CHECK-NEXT: [[T4:%.*]] = and i32 [[T3]], 2 |
| // CHECK-NEXT: [[T5:%.*]] = trunc i32 [[T4]] to i8 |
| // CHECK-NEXT: load i8*, i8** @OBJC_SELECTOR_REFERENCES |
| // CHECK-NEXT: [[T6:%.*]] = bitcast [[TEST7]]* [[T0]] to i8* |
| // CHECK-NEXT: call void bitcast |
| // CHECK-NEXT: [[T0:%.*]] = load [[TEST7]]*, [[TEST7]]** [[T]], align |
| // CHECK-NEXT: load i8*, i8** @OBJC_SELECTOR_REFERENCES |
| // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST7]]* [[T0]] to i8* |
| // CHECK-NEXT: [[T2:%.*]] = call zeroext i8 bitcast |
| // CHECK-NEXT: [[T3:%.*]] = zext i8 [[T2]] to i32 |
| // CHECK-NEXT: [[T4:%.*]] = or i32 [[T3]], 5 |
| // CHECK-NEXT: [[T5:%.*]] = trunc i32 [[T4]] to i8 |
| // CHECK-NEXT: load i8*, i8** @OBJC_SELECTOR_REFERENCES |
| // CHECK-NEXT: [[T6:%.*]] = bitcast [[TEST7]]* [[T0]] to i8* |
| // CHECK-NEXT: call void bitcast |
| // CHECK-NEXT: [[T0:%.*]] = load [[TEST7]]*, [[TEST7]]** [[T]], align |
| // CHECK-NEXT: load i8*, i8** @OBJC_SELECTOR_REFERENCES |
| // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST7]]* [[T0]] to i8* |
| // CHECK-NEXT: [[T2:%.*]] = call zeroext i8 bitcast |
| // CHECK-NEXT: [[T3:%.*]] = zext i8 [[T2]] to i32 |
| // CHECK-NEXT: [[T4:%.*]] = xor i32 [[T3]], 8 |
| // CHECK-NEXT: [[T5:%.*]] = trunc i32 [[T4]] to i8 |
| // CHECK-NEXT: load i8*, i8** @OBJC_SELECTOR_REFERENCES |
| // CHECK-NEXT: [[T6:%.*]] = bitcast [[TEST7]]* [[T0]] to i8* |
| // CHECK-NEXT: call void bitcast |
| // CHECK-NEXT: ret void |