1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
|
// 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
|