CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
331 lines
13 KiB
Objective-C
331 lines
13 KiB
Objective-C
// RUN: %clang_cc1 -emit-llvm -fobjc-arc -triple arm64-apple-darwin10 \
|
|
// RUN: -fobjc-direct-precondition-thunk %s -o - | FileCheck %s
|
|
|
|
struct my_complex_struct {
|
|
int a, b;
|
|
};
|
|
|
|
struct my_aggregate_struct {
|
|
int a, b;
|
|
char buf[128];
|
|
};
|
|
|
|
__attribute__((objc_root_class))
|
|
@interface Root
|
|
- (int)getInt __attribute__((objc_direct));
|
|
@property(direct, readonly) int intProperty;
|
|
@property(direct, readonly) int intProperty2;
|
|
@property(direct, readonly) id objectProperty;
|
|
@end
|
|
|
|
@implementation Root
|
|
// CHECK-LABEL: define hidden i32 @"-[Root intProperty2]D"(ptr noundef %self)
|
|
- (int)intProperty2 {
|
|
return 42;
|
|
}
|
|
|
|
// CHECK-LABEL: define hidden i32 @"-[Root getInt]D"(ptr noundef %self)
|
|
- (int)getInt __attribute__((objc_direct)) {
|
|
return 42;
|
|
}
|
|
|
|
// CHECK-LABEL: define hidden i32 @"+[Root classGetInt]D"(ptr noundef %self)
|
|
+ (int)classGetInt __attribute__((objc_direct)) {
|
|
return 42;
|
|
}
|
|
|
|
// CHECK-LABEL: define hidden i64 @"-[Root getComplex]D"(ptr noundef %self)
|
|
- (struct my_complex_struct)getComplex __attribute__((objc_direct)) {
|
|
struct my_complex_struct st = {.a = 42};
|
|
return st;
|
|
}
|
|
|
|
// CHECK-LABEL: define hidden i64 @"+[Root classGetComplex]D"(ptr noundef %self)
|
|
+ (struct my_complex_struct)classGetComplex __attribute__((objc_direct)) {
|
|
struct my_complex_struct st = {.a = 42};
|
|
return st;
|
|
}
|
|
|
|
// CHECK-LABEL: define hidden void @"-[Root getAggregate]D"(ptr {{.*}} sret(%struct.my_aggregate_struct) {{.*}} %agg.result, ptr noundef %self)
|
|
- (struct my_aggregate_struct)getAggregate __attribute__((objc_direct)) {
|
|
struct my_aggregate_struct st = {.a = 42};
|
|
return st;
|
|
}
|
|
|
|
// CHECK-LABEL: define hidden void @"+[Root classGetAggregate]D"(ptr {{.*}} sret(%struct.my_aggregate_struct) {{.*}} %agg.result, ptr noundef %self)
|
|
+ (struct my_aggregate_struct)classGetAggregate __attribute__((objc_direct)) {
|
|
struct my_aggregate_struct st = {.a = 42};
|
|
return st;
|
|
}
|
|
|
|
// CHECK-LABEL: define hidden void @"-[Root accessCmd]D"(ptr noundef %self)
|
|
- (void)accessCmd __attribute__((objc_direct)) {
|
|
// loading the _cmd selector
|
|
SEL sel = _cmd;
|
|
}
|
|
|
|
@end
|
|
|
|
// CHECK-LABEL: define hidden i32 @"-[Root intProperty]D"(ptr noundef %self)
|
|
// CHECK-LABEL: define hidden ptr @"-[Root objectProperty]D"(ptr noundef %self)
|
|
|
|
@interface Foo : Root {
|
|
id __strong _cause_cxx_destruct;
|
|
}
|
|
@property(nonatomic, readonly, direct) int getDirect_setDynamic;
|
|
@property(nonatomic, readonly) int getDynamic_setDirect;
|
|
@end
|
|
|
|
@interface Foo ()
|
|
@property(nonatomic, readwrite) int getDirect_setDynamic;
|
|
@property(nonatomic, readwrite, direct) int getDynamic_setDirect;
|
|
- (int)directMethodInExtension __attribute__((objc_direct));
|
|
@end
|
|
|
|
@interface Foo (Cat)
|
|
- (int)directMethodInCategory __attribute__((objc_direct));
|
|
@end
|
|
|
|
__attribute__((objc_direct_members))
|
|
@implementation Foo
|
|
// CHECK-LABEL: define hidden i32 @"-[Foo directMethodInExtension]D"(ptr noundef %self)
|
|
- (int)directMethodInExtension {
|
|
return 42;
|
|
}
|
|
|
|
// CHECK-LABEL: define hidden i32 @"-[Foo getDirect_setDynamic]D"(ptr noundef %self)
|
|
// CHECK-LABEL: define internal void @"\01-[Foo setGetDirect_setDynamic:]"(ptr noundef %self, ptr noundef %_cmd, i32 noundef %getDirect_setDynamic)
|
|
// CHECK-LABEL: define internal i32 @"\01-[Foo getDynamic_setDirect]"(ptr noundef %self, ptr noundef %_cmd)
|
|
// CHECK-LABEL: define hidden void @"-[Foo setGetDynamic_setDirect:]D"(ptr noundef %self, i32 noundef %getDynamic_setDirect)
|
|
|
|
@end
|
|
|
|
@implementation Foo (Cat)
|
|
// CHECK-LABEL: define hidden i32 @"-[Foo directMethodInCategory]D"(ptr noundef %self)
|
|
- (int)directMethodInCategory {
|
|
return 42;
|
|
}
|
|
|
|
// CHECK-LABEL: define hidden i32 @"-[Foo directMethodInCategoryNoDecl]D"(ptr noundef %self)
|
|
- (int)directMethodInCategoryNoDecl __attribute__((objc_direct)) {
|
|
return 42;
|
|
}
|
|
|
|
@end
|
|
|
|
// CHECK-LABEL: define{{.*}} i32 @useRoot(ptr noundef %r)
|
|
int useRoot(Root *r) {
|
|
// CHECK: call i32 @"-[Root getInt]D_thunk"(ptr noundef %{{[0-9]+}})
|
|
// CHECK: call i32 @"-[Root intProperty]D_thunk"(ptr noundef %{{[0-9]+}})
|
|
// CHECK: call i32 @"-[Root intProperty2]D_thunk"(ptr noundef %{{[0-9]+}})
|
|
return [r getInt] + [r intProperty] + [r intProperty2];
|
|
}
|
|
|
|
// Thunks are emitted after the first function that uses them
|
|
// CHECK-LABEL: define linkonce_odr hidden i32 @"-[Root getInt]D_thunk"(ptr noundef %self)
|
|
// CHECK: entry:
|
|
// CHECK: %[[IS_NIL:.*]] = icmp eq ptr {{.*}}, null
|
|
// CHECK: br i1 %[[IS_NIL]], label %objc_direct_method.self_is_nil, label %objc_direct_method.cont
|
|
// CHECK: objc_direct_method.self_is_nil:
|
|
// CHECK: call void @llvm.memset
|
|
// CHECK: br label %dummy_ret_block
|
|
// CHECK: objc_direct_method.cont:
|
|
// CHECK: %[[RET:.*]] = musttail call i32 @"-[Root getInt]D"(ptr noundef %self)
|
|
// CHECK: ret i32 %[[RET]]
|
|
// CHECK: dummy_ret_block:
|
|
|
|
// CHECK-LABEL: define linkonce_odr hidden i32 @"-[Root intProperty]D_thunk"(ptr noundef %self)
|
|
// CHECK: entry:
|
|
// CHECK: %[[IS_NIL:.*]] = icmp eq ptr {{.*}}, null
|
|
// CHECK: br i1 %[[IS_NIL]], label %objc_direct_method.self_is_nil, label %objc_direct_method.cont
|
|
// CHECK: objc_direct_method.self_is_nil:
|
|
// CHECK: call void @llvm.memset
|
|
// CHECK: br label %dummy_ret_block
|
|
// CHECK: objc_direct_method.cont:
|
|
// CHECK: %[[RET:.*]] = musttail call i32 @"-[Root intProperty]D"(ptr noundef %self)
|
|
// CHECK: ret i32 %[[RET]]
|
|
// CHECK: dummy_ret_block:
|
|
|
|
// CHECK-LABEL: define linkonce_odr hidden i32 @"-[Root intProperty2]D_thunk"(ptr noundef %self)
|
|
// CHECK: entry:
|
|
// CHECK: %[[IS_NIL:.*]] = icmp eq ptr {{.*}}, null
|
|
// CHECK: br i1 %[[IS_NIL]], label %objc_direct_method.self_is_nil, label %objc_direct_method.cont
|
|
// CHECK: objc_direct_method.self_is_nil:
|
|
// CHECK: call void @llvm.memset
|
|
// CHECK: br label %dummy_ret_block
|
|
// CHECK: objc_direct_method.cont:
|
|
// CHECK: %[[RET:.*]] = musttail call i32 @"-[Root intProperty2]D"(ptr noundef %self)
|
|
// CHECK: ret i32 %[[RET]]
|
|
// CHECK: dummy_ret_block:
|
|
|
|
// CHECK-LABEL: define{{.*}} i32 @useFoo(ptr noundef %f)
|
|
int useFoo(Foo *f) {
|
|
// CHECK: call void @"-[Foo setGetDynamic_setDirect:]D_thunk"(ptr noundef %{{[0-9]+}}, i32 noundef 1)
|
|
// CHECK: call i32 @"-[Foo getDirect_setDynamic]D_thunk"(ptr noundef %{{[0-9]+}})
|
|
// CHECK: call i32 @"-[Foo directMethodInExtension]D_thunk"(ptr noundef %{{[0-9]+}})
|
|
// CHECK: call i32 @"-[Foo directMethodInCategory]D_thunk"(ptr noundef %{{[0-9]+}})
|
|
// CHECK: call i32 @"-[Foo directMethodInCategoryNoDecl]D_thunk"(ptr noundef %{{[0-9]+}})
|
|
[f setGetDynamic_setDirect:1];
|
|
return [f getDirect_setDynamic] +
|
|
[f directMethodInExtension] +
|
|
[f directMethodInCategory] +
|
|
[f directMethodInCategoryNoDecl];
|
|
}
|
|
|
|
// CHECK-LABEL: define linkonce_odr hidden void @"-[Foo setGetDynamic_setDirect:]D_thunk"(ptr noundef %self, i32 noundef
|
|
// CHECK: entry:
|
|
// CHECK: %[[IS_NIL:.*]] = icmp eq ptr {{.*}}, null
|
|
// CHECK: br i1 %[[IS_NIL]], label %objc_direct_method.self_is_nil, label %objc_direct_method.cont
|
|
// CHECK: objc_direct_method.self_is_nil:
|
|
// CHECK: br label %dummy_ret_block
|
|
// CHECK: objc_direct_method.cont:
|
|
// CHECK: musttail call void @"-[Foo setGetDynamic_setDirect:]D"(ptr noundef %self, i32 noundef
|
|
// CHECK: ret void
|
|
// CHECK: dummy_ret_block:
|
|
// CHECK: ret void
|
|
|
|
// CHECK-LABEL: define linkonce_odr hidden i32 @"-[Foo getDirect_setDynamic]D_thunk"(ptr noundef %self)
|
|
// CHECK: entry:
|
|
// CHECK: %[[IS_NIL:.*]] = icmp eq ptr {{.*}}, null
|
|
// CHECK: br i1 %[[IS_NIL]], label %objc_direct_method.self_is_nil, label %objc_direct_method.cont
|
|
// CHECK: objc_direct_method.self_is_nil:
|
|
// CHECK: call void @llvm.memset
|
|
// CHECK: br label %dummy_ret_block
|
|
// CHECK: objc_direct_method.cont:
|
|
// CHECK: %[[RET:.*]] = musttail call i32 @"-[Foo getDirect_setDynamic]D"(ptr noundef %self)
|
|
// CHECK: ret i32 %[[RET]]
|
|
// CHECK: dummy_ret_block:
|
|
|
|
// CHECK-LABEL: define linkonce_odr hidden i32 @"-[Foo directMethodInExtension]D_thunk"(ptr noundef %self)
|
|
// CHECK: entry:
|
|
// CHECK: %[[IS_NIL:.*]] = icmp eq ptr {{.*}}, null
|
|
// CHECK: br i1 %[[IS_NIL]], label %objc_direct_method.self_is_nil, label %objc_direct_method.cont
|
|
// CHECK: objc_direct_method.self_is_nil:
|
|
// CHECK: call void @llvm.memset
|
|
// CHECK: br label %dummy_ret_block
|
|
// CHECK: objc_direct_method.cont:
|
|
// CHECK: %[[RET:.*]] = musttail call i32 @"-[Foo directMethodInExtension]D"(ptr noundef %self)
|
|
// CHECK: ret i32 %[[RET]]
|
|
// CHECK: dummy_ret_block:
|
|
|
|
// CHECK-LABEL: define linkonce_odr hidden i32 @"-[Foo directMethodInCategory]D_thunk"(ptr noundef %self)
|
|
// CHECK: entry:
|
|
// CHECK: %[[IS_NIL:.*]] = icmp eq ptr {{.*}}, null
|
|
// CHECK: br i1 %[[IS_NIL]], label %objc_direct_method.self_is_nil, label %objc_direct_method.cont
|
|
// CHECK: objc_direct_method.self_is_nil:
|
|
// CHECK: call void @llvm.memset
|
|
// CHECK: br label %dummy_ret_block
|
|
// CHECK: objc_direct_method.cont:
|
|
// CHECK: %[[RET:.*]] = musttail call i32 @"-[Foo directMethodInCategory]D"(ptr noundef %self)
|
|
// CHECK: ret i32 %[[RET]]
|
|
// CHECK: dummy_ret_block:
|
|
|
|
// CHECK-LABEL: define linkonce_odr hidden i32 @"-[Foo directMethodInCategoryNoDecl]D_thunk"(ptr noundef %self)
|
|
// CHECK: entry:
|
|
// CHECK: %[[IS_NIL:.*]] = icmp eq ptr {{.*}}, null
|
|
// CHECK: br i1 %[[IS_NIL]], label %objc_direct_method.self_is_nil, label %objc_direct_method.cont
|
|
// CHECK: objc_direct_method.self_is_nil:
|
|
// CHECK: call void @llvm.memset
|
|
// CHECK: br label %dummy_ret_block
|
|
// CHECK: objc_direct_method.cont:
|
|
// CHECK: %[[RET:.*]] = musttail call i32 @"-[Foo directMethodInCategoryNoDecl]D"(ptr noundef %self)
|
|
// CHECK: ret i32 %[[RET]]
|
|
// CHECK: dummy_ret_block:
|
|
|
|
__attribute__((objc_root_class))
|
|
@interface RootDeclOnly
|
|
@property(direct, readonly) int intProperty;
|
|
@end
|
|
|
|
__attribute__((objc_root_class, weak_import))
|
|
@interface WeakRoot
|
|
+ (int)classGetInt __attribute__((objc_direct, weak_import));
|
|
@end
|
|
|
|
// CHECK-LABEL: define{{.*}} i32 @useRootDeclOnly(ptr noundef %r)
|
|
int useRootDeclOnly(RootDeclOnly *r) {
|
|
// CHECK: call i32 @"-[RootDeclOnly intProperty]D_thunk"(ptr noundef %{{[0-9]+}})
|
|
return [r intProperty];
|
|
}
|
|
|
|
// Verify thunk is generated for external direct method
|
|
// CHECK: declare{{.*}} i32 @"-[RootDeclOnly intProperty]D"(ptr)
|
|
// CHECK-LABEL: define linkonce_odr hidden i32 @"-[RootDeclOnly intProperty]D_thunk"(ptr noundef %self)
|
|
// CHECK: entry:
|
|
// CHECK: %[[IS_NIL:.*]] = icmp eq ptr {{.*}}, null
|
|
// CHECK: br i1 %[[IS_NIL]], label %objc_direct_method.self_is_nil, label %objc_direct_method.cont
|
|
// CHECK: objc_direct_method.self_is_nil:
|
|
// CHECK: call void @llvm.memset
|
|
// CHECK: br label %dummy_ret_block
|
|
// CHECK: objc_direct_method.cont:
|
|
// CHECK: %[[RET:.*]] = musttail call i32 @"-[RootDeclOnly intProperty]D"(ptr noundef %self)
|
|
// CHECK: ret i32 %[[RET]]
|
|
// CHECK: dummy_ret_block:
|
|
|
|
int useSRet(Root *r) {
|
|
return (
|
|
// First call is to instance method - uses thunk
|
|
// CHECK: call i64 @"-[Root getComplex]D_thunk"
|
|
[r getComplex].a +
|
|
// TODO: we should know that this instance is non nil.
|
|
// CHECK: call void @"-[Root getAggregate]D_thunk"
|
|
[r getAggregate].a +
|
|
// TODO: The compiler is not smart enough to know the class object must be realized yet.
|
|
// CHECK: call i64 @"+[Root classGetComplex]D_thunk"(ptr noundef
|
|
[Root classGetComplex].a +
|
|
// CHECK: call void @"+[Root classGetAggregate]D_thunk"(ptr {{.*}}sret
|
|
[Root classGetAggregate].a
|
|
);
|
|
}
|
|
|
|
// CHECK-LABEL: define linkonce_odr hidden i64 @"-[Root getComplex]D_thunk"
|
|
// CHECK-LABEL: define linkonce_odr hidden void @"-[Root getAggregate]D_thunk"(ptr dead_on_unwind writable sret(%struct.my_aggregate_struct) {{.*}} %agg.result, ptr noundef %self)
|
|
// CHECK: entry:
|
|
// CHECK: %[[IS_NIL:.*]] = icmp eq ptr {{.*}}, null
|
|
// CHECK: br i1 %[[IS_NIL]], label %objc_direct_method.self_is_nil, label %objc_direct_method.cont
|
|
// CHECK: objc_direct_method.self_is_nil:
|
|
// CHECK: call void @llvm.memset
|
|
// CHECK: br label %dummy_ret_block
|
|
// CHECK: objc_direct_method.cont:
|
|
// CHECK: musttail call void @"-[Root getAggregate]D"(ptr dead_on_unwind writable sret(%struct.my_aggregate_struct) {{.*}} %agg.result, ptr noundef %self)
|
|
// CHECK: ret void
|
|
// CHECK: dummy_ret_block:
|
|
// CHECK: ret void
|
|
|
|
// Class method thunks should have class realization (objc_msgSend)
|
|
// instead of a nil check.
|
|
// CHECK-LABEL: define linkonce_odr hidden i64 @"+[Root classGetComplex]D_thunk"(ptr noundef %self)
|
|
// CHECK: entry:
|
|
// CHECK-NOT: icmp eq ptr
|
|
// CHECK: call ptr @objc_msgSend
|
|
// CHECK: musttail call i64 @"+[Root classGetComplex]D"(ptr noundef %self)
|
|
// CHECK: ret i64
|
|
|
|
// CHECK-LABEL: define linkonce_odr hidden void @"+[Root classGetAggregate]D_thunk"(ptr {{.*}} sret(%struct.my_aggregate_struct) {{.*}} %agg.result, ptr noundef %self)
|
|
// CHECK: entry:
|
|
// CHECK-NOT: icmp eq ptr
|
|
// CHECK: call ptr @objc_msgSend
|
|
// CHECK: musttail call void @"+[Root classGetAggregate]D"(ptr {{.*}} sret(%struct.my_aggregate_struct) {{.*}} %agg.result, ptr noundef %self)
|
|
// CHECK: ret void
|
|
|
|
// CHECK-LABEL: define{{.*}} i32 @useWeakRoot()
|
|
int useWeakRoot() {
|
|
// CHECK: call i32 @"+[WeakRoot classGetInt]D_thunk"
|
|
return [WeakRoot classGetInt];
|
|
}
|
|
|
|
// Weakly linked class method thunks should have class realization
|
|
// AND a nil check (the weak class may not exist at runtime).
|
|
// CHECK-LABEL: define linkonce_odr hidden i32 @"+[WeakRoot classGetInt]D_thunk"(ptr noundef %self)
|
|
// CHECK: entry:
|
|
// CHECK: call ptr @objc_msgSend
|
|
// CHECK: %[[IS_NIL:.*]] = icmp eq ptr {{.*}}, null
|
|
// CHECK: br i1 %[[IS_NIL]], label %objc_direct_method.self_is_nil, label %objc_direct_method.cont
|
|
// CHECK: objc_direct_method.self_is_nil:
|
|
// CHECK: call void @llvm.memset
|
|
// CHECK: br label %dummy_ret_block
|
|
// CHECK: objc_direct_method.cont:
|
|
// CHECK: %[[RET:.*]] = musttail call i32 @"+[WeakRoot classGetInt]D"(ptr noundef %self)
|
|
// CHECK: ret i32 %[[RET]]
|
|
// CHECK: dummy_ret_block:
|