303 lines
12 KiB
C++
303 lines
12 KiB
C++
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme \
|
|
// RUN: -S -disable-O0-optnone -Werror -emit-llvm -o - %s \
|
|
// RUN: | opt -S -passes=mem2reg \
|
|
// RUN: | opt -S -passes=inline \
|
|
// RUN: | FileCheck %s
|
|
|
|
extern "C" {
|
|
|
|
extern int normal_callee();
|
|
|
|
// == FUNCTION DECLARATIONS ==
|
|
|
|
int streaming_decl(void) __arm_streaming;
|
|
int streaming_compatible_decl(void) __arm_streaming_compatible;
|
|
int shared_za_decl(void) __arm_inout("za");
|
|
int preserves_za_decl(void) __arm_preserves("za");
|
|
int private_za_decl(void);
|
|
|
|
// == FUNCTION DEFINITIONS ==
|
|
|
|
// CHECK-LABEL: @streaming_caller()
|
|
// CHECK-SAME: #[[SM_ENABLED:[0-9]+]]
|
|
// CHECK: call i32 @normal_callee()
|
|
//
|
|
int streaming_caller() __arm_streaming {
|
|
return normal_callee();
|
|
}
|
|
|
|
// CHECK: declare i32 @normal_callee() #[[NORMAL_DECL:[0-9]+]]
|
|
|
|
|
|
// CHECK-LABEL: @streaming_callee()
|
|
// CHECK-SAME: #[[SM_ENABLED]]
|
|
// CHECK: call i32 @streaming_decl() #[[SM_ENABLED_CALL:[0-9]+]]
|
|
//
|
|
int streaming_callee() __arm_streaming {
|
|
return streaming_decl();
|
|
}
|
|
|
|
// CHECK: declare i32 @streaming_decl() #[[SM_ENABLED_DECL:[0-9]+]]
|
|
|
|
// CHECK-LABEL: @streaming_compatible_caller()
|
|
// CHECK-SAME: #[[SM_COMPATIBLE:[0-9]+]]
|
|
// CHECK: call i32 @normal_callee()
|
|
//
|
|
int streaming_compatible_caller() __arm_streaming_compatible {
|
|
return normal_callee();
|
|
}
|
|
|
|
// CHECK-LABEL: @streaming_compatible_callee()
|
|
// CHECK-SAME: #[[SM_COMPATIBLE]]
|
|
// CHECK: call i32 @streaming_compatible_decl() #[[SM_COMPATIBLE_CALL:[0-9]+]]
|
|
//
|
|
int streaming_compatible_callee() __arm_streaming_compatible {
|
|
return streaming_compatible_decl();
|
|
}
|
|
|
|
// CHECK: declare i32 @streaming_compatible_decl() #[[SM_COMPATIBLE_DECL:[0-9]+]]
|
|
|
|
// CHECK-LABEL: @locally_streaming_caller()
|
|
// CHECK-SAME: #[[SM_BODY:[0-9]+]]
|
|
// CHECK: call i32 @normal_callee()
|
|
//
|
|
__arm_locally_streaming int locally_streaming_caller() {
|
|
return normal_callee();
|
|
}
|
|
|
|
// CHECK-LABEL: @locally_streaming_callee()
|
|
// CHECK-SAME: #[[SM_BODY]]
|
|
// CHECK: call i32 @locally_streaming_caller() #[[SM_BODY_CALL:[0-9]+]]
|
|
//
|
|
__arm_locally_streaming int locally_streaming_callee() {
|
|
return locally_streaming_caller();
|
|
}
|
|
|
|
|
|
// CHECK-LABEL: @shared_za_caller()
|
|
// CHECK-SAME: #[[ZA_SHARED:[0-9]+]]
|
|
// CHECK: call i32 @normal_callee()
|
|
//
|
|
int shared_za_caller() __arm_inout("za") {
|
|
return normal_callee();
|
|
}
|
|
|
|
// CHECK-LABEL: @shared_za_callee()
|
|
// CHECK-SAME: #[[ZA_SHARED]]
|
|
// CHECK: call i32 @shared_za_decl() #[[ZA_SHARED_CALL:[0-9]+]]
|
|
//
|
|
int shared_za_callee() __arm_inout("za") {
|
|
return shared_za_decl();
|
|
}
|
|
|
|
// CHECK: declare i32 @shared_za_decl() #[[ZA_SHARED_DECL:[0-9]+]]
|
|
|
|
|
|
// CHECK-LABEL: @preserves_za_caller()
|
|
// CHECK-SAME: #[[ZA_PRESERVED:[0-9]+]]
|
|
// CHECK: call i32 @normal_callee()
|
|
//
|
|
int preserves_za_caller() __arm_preserves("za") {
|
|
return normal_callee();
|
|
}
|
|
|
|
// CHECK-LABEL: @preserves_za_callee()
|
|
// CHECK-SAME: #[[ZA_PRESERVED]]
|
|
// CHECK: call i32 @preserves_za_decl() #[[ZA_PRESERVED_CALL:[0-9]+]]
|
|
//
|
|
int preserves_za_callee() __arm_preserves("za") {
|
|
return preserves_za_decl();
|
|
}
|
|
|
|
// CHECK: declare i32 @preserves_za_decl() #[[ZA_PRESERVED_DECL:[0-9]+]]
|
|
|
|
|
|
// CHECK-LABEL: @new_za_caller()
|
|
// CHECK-SAME: #[[ZA_NEW:[0-9]+]]
|
|
// CHECK: call i32 @normal_callee()
|
|
//
|
|
__arm_new("za") int new_za_caller() {
|
|
return normal_callee();
|
|
}
|
|
|
|
// CHECK-LABEL: @new_za_callee()
|
|
// CHECK-SAME: #[[ZA_NEW]]
|
|
// CHECK: call i32 @private_za_decl()
|
|
//
|
|
__arm_new("za") int new_za_callee() {
|
|
return private_za_decl();
|
|
}
|
|
|
|
// CHECK: declare i32 @private_za_decl()
|
|
|
|
|
|
// Ensure that the attributes are correctly propagated to function types
|
|
// and also to callsites.
|
|
typedef void (*s_ptrty) (int, int) __arm_streaming;
|
|
typedef void (*sc_ptrty) (int, int) __arm_streaming_compatible;
|
|
typedef void (*sz_ptrty) (int, int) __arm_inout("za");
|
|
typedef void (*pz_ptrty) (int, int) __arm_preserves("za");
|
|
|
|
// CHECK-LABEL: @test_streaming_ptrty(
|
|
// CHECK-SAME: #[[NORMAL_DEF:[0-9]+]]
|
|
// CHECK: call void [[F:%.*]](i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) #[[SM_ENABLED_CALL]]
|
|
//
|
|
void test_streaming_ptrty(s_ptrty f, int x, int y) { return f(x, y); }
|
|
// CHECK-LABEL: @test_streaming_compatible_ptrty(
|
|
// CHECK-SAME: #[[NORMAL_DEF]]
|
|
// CHECK: call void [[F:%.*]](i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) #[[SM_COMPATIBLE_CALL]]
|
|
//
|
|
void test_streaming_compatible_ptrty(sc_ptrty f, int x, int y) { return f(x, y); }
|
|
// CHECK-LABEL: @test_shared_za(
|
|
// CHECK-SAME: #[[ZA_SHARED]]
|
|
// CHECK: call void [[F:%.*]](i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) #[[ZA_SHARED_CALL]]
|
|
//
|
|
void test_shared_za(sz_ptrty f, int x, int y) __arm_inout("za") { return f(x, y); }
|
|
// CHECK-LABEL: @test_preserved_za(
|
|
// CHECK-SAME: #[[ZA_SHARED]]
|
|
// CHECK: call void [[F:%.*]](i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) #[[ZA_PRESERVED_CALL]]
|
|
//
|
|
void test_preserved_za(pz_ptrty f, int x, int y) __arm_inout("za") { return f(x, y); }
|
|
|
|
// CHECK-LABEL: @test_indirect_streaming_ptrty(
|
|
// CHECK-SAME: #[[NORMAL_DEF:[0-9]+]]
|
|
// CHECK: call void [[F:%.*]](i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) #[[SM_ENABLED_CALL]]
|
|
//
|
|
typedef s_ptrty **indirect_s_ptrty;
|
|
void test_indirect_streaming_ptrty(indirect_s_ptrty fptr, int x, int y) { return (**fptr)(x, y); }
|
|
} // extern "C"
|
|
|
|
//
|
|
// Test that having the attribute in different places (on declaration and on type)
|
|
// both results in the attribute being applied to the type.
|
|
//
|
|
|
|
// CHECK-LABEL: @_Z24test_same_type_streamingv(
|
|
// CHECK: call void @_Z10streaming1v() #[[SM_ENABLED_CALL]]
|
|
// CHECK: call void @_Z10streaming2v() #[[SM_ENABLED_CALL]]
|
|
// CHECK: call void @_Z20same_type_streaming1v() #[[SM_ENABLED_CALL]]
|
|
// CHECK: call void @_Z20same_type_streaming2v() #[[SM_ENABLED_CALL]]
|
|
// CHECK: ret void
|
|
// CHECK: }
|
|
// CHECK: declare void @_Z10streaming1v() #[[SM_ENABLED_DECL]]
|
|
// CHECK: declare void @_Z10streaming2v() #[[SM_ENABLED_DECL]]
|
|
// CHECK: declare void @_Z20same_type_streaming1v() #[[SM_ENABLED_DECL]]
|
|
// CHECK: declare void @_Z20same_type_streaming2v() #[[SM_ENABLED_DECL]]
|
|
void streaming1(void) __arm_streaming;
|
|
void streaming2() __arm_streaming;
|
|
decltype(streaming1) same_type_streaming1;
|
|
decltype(streaming2) same_type_streaming2;
|
|
void test_same_type_streaming() {
|
|
streaming1();
|
|
streaming2();
|
|
same_type_streaming1();
|
|
same_type_streaming2();
|
|
}
|
|
|
|
//
|
|
// Test overloading; the attribute is not required for overloaded types and
|
|
// does not apply if not specified.
|
|
//
|
|
|
|
// CHECK-LABEL: @_Z12overloadedfni(
|
|
// CHECK-SAME: #[[SM_ENABLED]]
|
|
int overloadedfn(int x) __arm_streaming { return x; }
|
|
// CHECK-LABEL: @_Z12overloadedfnf(
|
|
// CHECK-SAME: #[[NORMAL_DEF]]
|
|
//
|
|
float overloadedfn(float x) { return x; }
|
|
// CHECK-LABEL: @_Z13test_overloadi(
|
|
// CHECK-SAME: #[[NORMAL_DEF]]
|
|
//
|
|
int test_overload(int x) { return overloadedfn(x); }
|
|
// CHECK-LABEL: @_Z13test_overloadf(
|
|
// CHECK-SAME: #[[NORMAL_DEF]]
|
|
//
|
|
float test_overload(float x) { return overloadedfn(x); }
|
|
|
|
// CHECK-LABEL: @_Z11test_lambdai(
|
|
// CHECK-SAME: #[[NORMAL_DEF]]
|
|
// CHECK: call noundef i32 @"_ZZ11test_lambdaiENK3$_0clEi"({{.*}}) #[[SM_ENABLED_CALL]]
|
|
//
|
|
// CHECK: @"_ZZ11test_lambdaiENK3$_0clEi"(
|
|
// CHECK-SAME: #[[SM_ENABLED]]
|
|
int test_lambda(int x) {
|
|
auto F = [](int x) __arm_streaming { return x; };
|
|
return F(x);
|
|
}
|
|
|
|
// CHECK-LABEL: @_Z27test_template_instantiationv(
|
|
// CHECK-SAME: #[[NORMAL_DEF]]
|
|
// CHECK: call noundef i32 @_Z15template_functyIiET_S0_(i32 noundef 12) #[[SM_ENABLED_CALL]]
|
|
//
|
|
// CHECK: @_Z15template_functyIiET_S0_(
|
|
// CHECK-SAME: #[[SM_ENABLED]]
|
|
template <typename Ty>
|
|
Ty template_functy(Ty x) __arm_streaming { return x; }
|
|
int test_template_instantiation() { return template_functy(12); }
|
|
|
|
//
|
|
// Test that arm_locally_streaming is inherited by future redeclarations,
|
|
// even when they don't specify the attribute.
|
|
//
|
|
|
|
// CHECK: define {{.*}} @_Z25locally_streaming_inheritv(
|
|
// CHECK-SAME: #[[SM_BODY]]
|
|
__arm_locally_streaming void locally_streaming_inherit();
|
|
void locally_streaming_inherit() {
|
|
streaming_decl();
|
|
}
|
|
|
|
// Test that the attributes are propagated properly to calls
|
|
// when using a variadic template as indirection.
|
|
__attribute__((always_inline))
|
|
int call() { return 0; }
|
|
|
|
template <typename T, typename... Other>
|
|
__attribute__((always_inline))
|
|
int call(T f, Other... other) __arm_inout("za") {
|
|
return f() + call(other...);
|
|
}
|
|
|
|
// CHECK: {{.*}} @_Z22test_variadic_templatev(
|
|
// CHECK: call {{.*}} i32 @normal_callee() #[[NOUNWIND_CALL:[0-9]+]]
|
|
// CHECK-NEXT: call {{.*}} i32 @streaming_decl() #[[NOUNWIND_SM_ENABLED_CALL:[0-9]+]]
|
|
// CHECK-NEXT: call {{.*}} i32 @streaming_compatible_decl() #[[NOUNWIND_SM_COMPATIBLE_CALL:[0-9]+]]
|
|
// CHECK-NEXT: call {{.*}} i32 @shared_za_decl() #[[NOUNWIND_ZA_SHARED_CALL:[0-9]+]]
|
|
// CHECK-NEXT: call {{.*}} i32 @preserves_za_decl() #[[NOUNWIND_ZA_PRESERVED_CALL:[0-9]+]]
|
|
// CHECK-NEXT: add nsw
|
|
// CHECK-NEXT: add nsw
|
|
// CHECK-NEXT: add nsw
|
|
// CHECK-NEXT: add nsw
|
|
// CHECK-NEXT: ret
|
|
int test_variadic_template() __arm_inout("za") {
|
|
return call(normal_callee,
|
|
streaming_decl,
|
|
streaming_compatible_decl,
|
|
shared_za_decl,
|
|
preserves_za_decl);
|
|
}
|
|
|
|
// CHECK: attributes #[[SM_ENABLED]] = { mustprogress noinline nounwind "aarch64_pstate_sm_enabled" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+bf16,+sme" }
|
|
// CHECK: attributes #[[NORMAL_DECL]] = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+bf16,+sme" }
|
|
// CHECK: attributes #[[SM_ENABLED_DECL]] = { "aarch64_pstate_sm_enabled" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+bf16,+sme" }
|
|
// CHECK: attributes #[[SM_COMPATIBLE]] = { mustprogress noinline nounwind "aarch64_pstate_sm_compatible" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+bf16,+sme" }
|
|
// CHECK: attributes #[[SM_COMPATIBLE_DECL]] = { "aarch64_pstate_sm_compatible" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+bf16,+sme" }
|
|
// CHECK: attributes #[[SM_BODY]] = { mustprogress noinline nounwind "aarch64_pstate_sm_body" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+bf16,+sme" }
|
|
// CHECK: attributes #[[ZA_SHARED]] = { mustprogress noinline nounwind "aarch64_pstate_za_shared" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+bf16,+sme" }
|
|
// CHECK: attributes #[[ZA_SHARED_DECL]] = { "aarch64_pstate_za_shared" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+bf16,+sme" }
|
|
// CHECK: attributes #[[ZA_PRESERVED]] = { mustprogress noinline nounwind "aarch64_pstate_za_preserved" "aarch64_pstate_za_shared" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+bf16,+sme" }
|
|
// CHECK: attributes #[[ZA_PRESERVED_DECL]] = { "aarch64_pstate_za_preserved" "aarch64_pstate_za_shared" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+bf16,+sme" }
|
|
// CHECK: attributes #[[ZA_NEW]] = { mustprogress noinline nounwind "aarch64_pstate_za_new" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+bf16,+sme" }
|
|
// CHECK: attributes #[[NORMAL_DEF]] = { mustprogress noinline nounwind "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+bf16,+sme" }
|
|
// CHECK: attributes #[[SM_ENABLED_CALL]] = { "aarch64_pstate_sm_enabled" }
|
|
// CHECK: attributes #[[SM_COMPATIBLE_CALL]] = { "aarch64_pstate_sm_compatible" }
|
|
// CHECK: attributes #[[SM_BODY_CALL]] = { "aarch64_pstate_sm_body" }
|
|
// CHECK: attributes #[[ZA_SHARED_CALL]] = { "aarch64_pstate_za_shared" }
|
|
// CHECK: attributes #[[ZA_PRESERVED_CALL]] = { "aarch64_pstate_za_preserved" "aarch64_pstate_za_shared" }
|
|
// CHECK: attributes #[[NOUNWIND_CALL]] = { nounwind }
|
|
// CHECK: attributes #[[NOUNWIND_SM_ENABLED_CALL]] = { nounwind "aarch64_pstate_sm_enabled" }
|
|
// CHECK: attributes #[[NOUNWIND_SM_COMPATIBLE_CALL]] = { nounwind "aarch64_pstate_sm_compatible" }
|
|
// CHECK: attributes #[[NOUNWIND_ZA_SHARED_CALL]] = { nounwind "aarch64_pstate_za_shared" }
|
|
// CHECK: attributes #[[NOUNWIND_ZA_PRESERVED_CALL]] = { nounwind "aarch64_pstate_za_preserved" "aarch64_pstate_za_shared" }
|
|
|