| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| // RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify=both,expected %s | ||
| // RUN: %clang_cc1 -verify=both,ref %s | ||
|
|
||
| /// FIXME: Copied from test/Sema/atomic-expr.c. | ||
| /// this expression seems to be rejected for weird reasons, | ||
| /// but we imitate the current interpreter's behavior. | ||
| _Atomic int ai = 0; | ||
| // FIXME: &ai is an address constant, so this should be accepted as an | ||
| // initializer, but the bit-cast inserted due to the pointer conversion is | ||
| // tripping up the test for whether the initializer is a constant expression. | ||
| // The warning is correct but the error is not. | ||
| _Atomic(int *) aip3 = &ai; // both-warning {{incompatible pointer types initializing '_Atomic(int *)' with an expression of type '_Atomic(int) *'}} \ | ||
| // both-error {{initializer element is not a compile-time constant}} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| // RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify=both,expected -std=c++11 %s | ||
| // RUN: %clang_cc1 -verify=both,ref -std=c++11 %s | ||
| // RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify=both,expected -std=c++98 %s | ||
| // RUN: %clang_cc1 -verify=both,ref -std=c++98 %s | ||
|
|
||
|
|
||
|
|
||
| // expected-no-diagnostics | ||
| // ref-no-diagnostics | ||
|
|
||
|
|
||
| /// Rejected in c++98 | ||
| #if __cplusplus >= 201103L | ||
| constexpr _Atomic(bool) B = true; | ||
| static_assert(B, ""); | ||
| #endif | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| // RUN: not %clang_cc1 -std=c++2c -ast-dump %s | FileCheck %s | ||
|
|
||
| namespace InvalidPacksShouldNotCrash { | ||
|
|
||
| struct NotAPack; | ||
| template <typename T, auto V, template<typename> typename Tp> | ||
| void not_pack() { | ||
| int i = 0; | ||
| i...[0]; // expected-error {{i does not refer to the name of a parameter pack}} | ||
| V...[0]; // expected-error {{V does not refer to the name of a parameter pack}} | ||
| NotAPack...[0] a; // expected-error{{'NotAPack' does not refer to the name of a parameter pack}} | ||
| T...[0] b; // expected-error{{'T' does not refer to the name of a parameter pack}} | ||
| Tp...[0] c; // expected-error{{'Tp' does not refer to the name of a parameter pack}} | ||
| } | ||
|
|
||
| // CHECK: FunctionDecl {{.*}} not_pack 'void ()' | ||
| // CHECK: DeclStmt {{.*}} | ||
| // CHECK: DeclStmt {{.*}} | ||
| // CHECK-NEXT: VarDecl {{.*}} a 'NotAPack...{{.*}}' | ||
| // CHECK-NEXT: DeclStmt {{.*}} | ||
| // CHECK-NEXT: VarDecl {{.*}} 'T...{{.*}}' | ||
| // CHECK-NEXT: DeclStmt {{.*}} | ||
| // CHECK-NEXT: VarDecl {{.*}} c 'Tp...{{.*}}' | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,199 @@ | ||
| // RUN: %clang_analyze_cc1 -Wno-array-bounds -analyzer-output=text \ | ||
| // RUN: -analyzer-checker=core,alpha.security.ArrayBoundV2,unix.Malloc,alpha.security.taint -verify %s | ||
|
|
||
| int TenElements[10]; | ||
|
|
||
| int irrelevantAssumptions(int arg) { | ||
| int a = TenElements[arg]; | ||
| // Here the analyzer assumes that `arg` is in bounds, but doesn't report this | ||
| // because `arg` is not interesting for the bug. | ||
| int b = TenElements[13]; | ||
| // expected-warning@-1 {{Out of bound access to memory after the end of 'TenElements'}} | ||
| // expected-note@-2 {{Access of 'TenElements' at index 13, while it holds only 10 'int' elements}} | ||
| return a + b; | ||
| } | ||
|
|
||
|
|
||
| int assumingBoth(int arg) { | ||
| int a = TenElements[arg]; | ||
| // expected-note@-1 {{Assuming index is non-negative and less than 10, the number of 'int' elements in 'TenElements'}} | ||
| int b = TenElements[arg]; // no additional note, we already assumed that 'arg' is in bounds | ||
| int c = TenElements[arg + 10]; | ||
| // expected-warning@-1 {{Out of bound access to memory after the end of 'TenElements'}} | ||
| // expected-note@-2 {{Access of 'TenElements' at an overflowing index, while it holds only 10 'int' elements}} | ||
| return a + b + c; | ||
| } | ||
|
|
||
| int assumingBothPointerToMiddle(int arg) { | ||
| // If we're accessing an TenElements through a pointer pointing to its middle, the checker | ||
| // will speak about the "byte offset" measured from the beginning of the TenElements. | ||
| int *p = TenElements + 2; | ||
| int a = p[arg]; | ||
| // FIXME: The following note does not appear: | ||
| // {{Assuming byte offset is non-negative and less than 40, the extent of 'TenElements'}} | ||
| // It seems that the analyzer "gives up" modeling this pointer arithmetics | ||
| // and says that `p[arg]` is just an UnknownVal (instead of calculating that | ||
| // it's equivalent to `TenElements[2+arg]`). | ||
|
|
||
| int b = TenElements[arg]; // This is normal access, and only the lower bound is new. | ||
| // expected-note@-1 {{Assuming index is non-negative}} | ||
| int c = TenElements[arg + 10]; | ||
| // expected-warning@-1 {{Out of bound access to memory after the end of 'TenElements'}} | ||
| // expected-note@-2 {{Access of 'TenElements' at an overflowing index, while it holds only 10 'int' elements}} | ||
| return a + b + c; | ||
| } | ||
|
|
||
| int assumingLower(int arg) { | ||
| // expected-note@+2 {{Assuming 'arg' is < 10}} | ||
| // expected-note@+1 {{Taking false branch}} | ||
| if (arg >= 10) | ||
| return 0; | ||
| int a = TenElements[arg]; | ||
| // expected-note@-1 {{Assuming index is non-negative}} | ||
| int b = TenElements[arg + 10]; | ||
| // expected-warning@-1 {{Out of bound access to memory after the end of 'TenElements'}} | ||
| // expected-note@-2 {{Access of 'TenElements' at an overflowing index, while it holds only 10 'int' elements}} | ||
| return a + b; | ||
| } | ||
|
|
||
| int assumingUpper(int arg) { | ||
| // expected-note@+2 {{Assuming 'arg' is >= 0}} | ||
| // expected-note@+1 {{Taking false branch}} | ||
| if (arg < 0) | ||
| return 0; | ||
| int a = TenElements[arg]; | ||
| // expected-note@-1 {{Assuming index is less than 10, the number of 'int' elements in 'TenElements'}} | ||
| int b = TenElements[arg - 10]; | ||
| // expected-warning@-1 {{Out of bound access to memory preceding 'TenElements'}} | ||
| // expected-note@-2 {{Access of 'TenElements' at negative byte offset}} | ||
| return a + b; | ||
| } | ||
|
|
||
| int assumingUpperIrrelevant(int arg) { | ||
| // FIXME: The assumption "assuming index is less than 10" is printed because | ||
| // it's assuming something about the interesting variable `arg`; however, | ||
| // it's irrelevant because in this testcase the out of bound access is | ||
| // deduced from the _lower_ bound on `arg`. Currently the analyzer cannot | ||
| // filter out assumptions that are logically irrelevant but "touch" | ||
| // interesting symbols; eventually it would be good to add support for this. | ||
|
|
||
| // expected-note@+2 {{Assuming 'arg' is >= 0}} | ||
| // expected-note@+1 {{Taking false branch}} | ||
| if (arg < 0) | ||
| return 0; | ||
| int a = TenElements[arg]; | ||
| // expected-note@-1 {{Assuming index is less than 10, the number of 'int' elements in 'TenElements'}} | ||
| int b = TenElements[arg + 10]; | ||
| // expected-warning@-1 {{Out of bound access to memory after the end of 'TenElements'}} | ||
| // expected-note@-2 {{Access of 'TenElements' at an overflowing index, while it holds only 10 'int' elements}} | ||
| return a + b; | ||
| } | ||
|
|
||
| int assumingUpperUnsigned(unsigned arg) { | ||
| int a = TenElements[arg]; | ||
| // expected-note@-1 {{Assuming index is less than 10, the number of 'int' elements in 'TenElements'}} | ||
| int b = TenElements[(int)arg - 10]; | ||
| // expected-warning@-1 {{Out of bound access to memory preceding 'TenElements'}} | ||
| // expected-note@-2 {{Access of 'TenElements' at negative byte offset}} | ||
| return a + b; | ||
| } | ||
|
|
||
| int assumingNothing(unsigned arg) { | ||
| // expected-note@+2 {{Assuming 'arg' is < 10}} | ||
| // expected-note@+1 {{Taking false branch}} | ||
| if (arg >= 10) | ||
| return 0; | ||
| int a = TenElements[arg]; // no note here, we already know that 'arg' is in bounds | ||
| int b = TenElements[(int)arg - 10]; | ||
| // expected-warning@-1 {{Out of bound access to memory preceding 'TenElements'}} | ||
| // expected-note@-2 {{Access of 'TenElements' at negative byte offset}} | ||
| return a + b; | ||
| } | ||
|
|
||
| short assumingConvertedToCharP(int arg) { | ||
| // When indices are reported, the note will use the element type that's the | ||
| // result type of the subscript operator. | ||
| char *cp = (char*)TenElements; | ||
| char a = cp[arg]; | ||
| // expected-note@-1 {{Assuming index is non-negative and less than 40, the number of 'char' elements in 'TenElements'}} | ||
| char b = cp[arg]; // no additional note, we already assumed that 'arg' is in bounds | ||
| char c = cp[arg + 40]; | ||
| // expected-warning@-1 {{Out of bound access to memory after the end of 'TenElements'}} | ||
| // expected-note@-2 {{Access of 'TenElements' at an overflowing index, while it holds only 40 'char' elements}} | ||
| return a + b + c; | ||
| } | ||
|
|
||
| struct foo { | ||
| int num; | ||
| char a[8]; | ||
| char b[5]; | ||
| }; | ||
|
|
||
| int assumingConvertedToIntP(struct foo f, int arg) { | ||
| // When indices are reported, the note will use the element type that's the | ||
| // result type of the subscript operator. | ||
| int a = ((int*)(f.a))[arg]; | ||
| // expected-note@-1 {{Assuming index is non-negative and less than 2, the number of 'int' elements in 'f.a'}} | ||
| // However, if the extent of the memory region is not divisible by the | ||
| // element size, the checker measures the offset and extent in bytes. | ||
| int b = ((int*)(f.b))[arg]; | ||
| // expected-note@-1 {{Assuming byte offset is less than 5, the extent of 'f.b'}} | ||
| int c = TenElements[arg-2]; | ||
| // expected-warning@-1 {{Out of bound access to memory preceding 'TenElements'}} | ||
| // expected-note@-2 {{Access of 'TenElements' at negative byte offset}} | ||
| return a + b + c; | ||
| } | ||
|
|
||
| int assumingPlainOffset(struct foo f, int arg) { | ||
| // This TC is intended to check the corner case that the checker prints the | ||
| // shorter "offset" instead of "byte offset" when it's irrelevant that the | ||
| // offset is measured in bytes. | ||
|
|
||
| // expected-note@+2 {{Assuming 'arg' is < 2}} | ||
| // expected-note@+1 {{Taking false branch}} | ||
| if (arg >= 2) | ||
| return 0; | ||
|
|
||
| int b = ((int*)(f.b))[arg]; | ||
| // expected-note@-1 {{Assuming byte offset is non-negative and less than 5, the extent of 'f.b'}} | ||
| // FIXME: this should be {{Assuming offset is non-negative}} | ||
| // but the current simplification algorithm doesn't realize that arg <= 1 | ||
| // implies that the byte offset arg*4 will be less than 5. | ||
|
|
||
| int c = TenElements[arg+10]; | ||
| // expected-warning@-1 {{Out of bound access to memory after the end of 'TenElements'}} | ||
| // expected-note@-2 {{Access of 'TenElements' at an overflowing index, while it holds only 10 'int' elements}} | ||
| return b + c; | ||
| } | ||
|
|
||
| typedef __typeof(sizeof(int)) size_t; | ||
| void *malloc(size_t size); | ||
| void free(void *ptr); | ||
|
|
||
| int assumingExtent(int arg) { | ||
| // Verify that the assumption note is printed when the extent is interesting | ||
| // (even if the index isn't interesting). | ||
| int *mem = (int*)malloc(arg); | ||
|
|
||
| mem[12] = 123; | ||
| // expected-note@-1 {{Assuming index '12' is less than the number of 'int' elements in the heap area}} | ||
|
|
||
| free(mem); | ||
|
|
||
| return TenElements[arg]; | ||
| // expected-warning@-1 {{Out of bound access to memory after the end of 'TenElements'}} | ||
| // expected-note@-2 {{Access of 'TenElements' at an overflowing index, while it holds only 10 'int' elements}} | ||
| } | ||
|
|
||
| int *extentInterestingness(int arg) { | ||
| // Verify that in an out-of-bounds access issue the extent is marked as | ||
| // interesting (so assumptions about its value are printed). | ||
| int *mem = (int*)malloc(arg); | ||
|
|
||
| TenElements[arg] = 123; | ||
| // expected-note@-1 {{Assuming index is non-negative and less than 10, the number of 'int' elements in 'TenElements'}} | ||
|
|
||
| return &mem[12]; | ||
| // expected-warning@-1 {{Out of bound access to memory after the end of the heap area}} | ||
| // expected-note@-2 {{Access of 'int' element in the heap area at index 12}} | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,112 @@ | ||
| // RUN: %clang_cc1 -fsyntax-only -verify %s | ||
|
|
||
| namespace N0 { | ||
| template<typename T> | ||
| void f0(); | ||
|
|
||
| template<typename T> | ||
| int x0 = 0; | ||
|
|
||
| template<typename T> | ||
| class C0; | ||
| } | ||
| using namespace N0; | ||
|
|
||
| template<> | ||
| void f0<int>(); // expected-error {{no function template matches}} | ||
|
|
||
| template<> | ||
| int x0<int>; | ||
|
|
||
| template<> | ||
| class C0<int>; | ||
|
|
||
| namespace N1 { | ||
| namespace N2 { | ||
| template<typename T> | ||
| void f2(); | ||
|
|
||
| template<typename T> | ||
| int x2 = 0; | ||
|
|
||
| template<typename T> | ||
| class C2; | ||
| } | ||
| using namespace N2; | ||
| } | ||
|
|
||
| template<> | ||
| void N1::f2<int>(); // expected-error {{no function template matches}} | ||
|
|
||
| template<> | ||
| int N1::x2<int>; | ||
|
|
||
| template<> | ||
| class N1::C2<int>; | ||
|
|
||
| namespace N3 { | ||
| namespace N4 { | ||
| template<typename T> | ||
| void f4(); | ||
|
|
||
| template<typename T> | ||
| int x4 = 0; | ||
|
|
||
| template<typename T> | ||
| class C4; | ||
| } | ||
| using N4::f4; | ||
| using N4::x4; | ||
| using N4::C4; | ||
| } | ||
|
|
||
| template<> | ||
| void N3::f4<int>(); // expected-error {{no function template matches}} | ||
|
|
||
| template<> | ||
| int N3::x4<int>; | ||
|
|
||
| template<> | ||
| class N3::C4<int>; | ||
|
|
||
| inline namespace N5 { | ||
| template<typename T> | ||
| void f5(); | ||
|
|
||
| template<typename T> | ||
| int x5 = 0; | ||
|
|
||
| template<typename T> | ||
| class C5; | ||
| } | ||
|
|
||
| template<> | ||
| void f5<int>(); | ||
|
|
||
| template<> | ||
| int x5<int>; | ||
|
|
||
| template<> | ||
| class C5<int>; | ||
|
|
||
| namespace N6 { | ||
| inline namespace N7 { | ||
| template<typename T> | ||
| void f7(); | ||
|
|
||
| template<typename T> | ||
| int x7 = 0; | ||
|
|
||
| template<typename T> | ||
| class C7; | ||
| } | ||
| } | ||
|
|
||
| template<> | ||
| void N6::f7<int>(); | ||
|
|
||
| template<> | ||
| int N6::x7<int>; | ||
|
|
||
| template<> | ||
| class N6::C7<int>; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,206 @@ | ||
| // RUN: %clang_cc1 -fsyntax-only -pedantic-errors -verify %s | ||
|
|
||
| template<typename T> struct A { | ||
| template<typename U> struct B { | ||
| // FIXME: The standard does not seem to consider non-friend elaborated-type-specifiers that | ||
| // declare partial specializations/explicit specializations/explicit instantiations to be | ||
| // declarative, see https://lists.isocpp.org/core/2024/01/15325.php | ||
| struct C; | ||
| template<typename V> struct D; | ||
|
|
||
| void f(); | ||
| template<typename V> void g(); | ||
|
|
||
| static int x; | ||
| template<typename V> static int y; | ||
|
|
||
| enum class E; | ||
| }; | ||
| }; | ||
|
|
||
| template<typename T> | ||
| template<typename U> | ||
| struct A<T>::template B<U>::C { }; // expected-error{{'template' cannot be used after a declarative}} | ||
|
|
||
| template<> | ||
| template<> | ||
| struct A<int>::template B<bool>::C; // expected-error{{'template' cannot be used after a declarative}} | ||
|
|
||
| template<> | ||
| template<> | ||
| struct A<int>::template B<bool>::C { }; // expected-error{{'template' cannot be used after a declarative}} | ||
|
|
||
| template<typename T> | ||
| template<typename U> | ||
| template<typename V> | ||
| struct A<T>::template B<U>::D<V*>; // expected-error{{'template' cannot be used after a declarative}} | ||
|
|
||
| template<typename T> | ||
| template<typename U> | ||
| template<typename V> | ||
| struct A<T>::B<U>::template D<V**>; // expected-error{{'template' cannot be used after a declarative}} | ||
|
|
||
| template<typename T> | ||
| template<typename U> | ||
| template<typename V> | ||
| struct A<T>::template B<U>::D { }; // expected-error{{'template' cannot be used after a declarative}} | ||
|
|
||
| template<typename T> | ||
| template<typename U> | ||
| template<typename V> | ||
| struct A<T>::template B<U>::D<V*> { }; // expected-error{{'template' cannot be used after a declarative}} | ||
|
|
||
| template<typename T> | ||
| template<typename U> | ||
| template<typename V> | ||
| struct A<T>::B<U>::template D<V**> { }; // expected-error{{'template' cannot be used after a declarative}} | ||
|
|
||
| template<> | ||
| template<> | ||
| template<typename V> | ||
| struct A<int>::template B<bool>::D; // expected-error{{'template' cannot be used after a declarative}} | ||
|
|
||
| template<> | ||
| template<> | ||
| template<> | ||
| struct A<int>::template B<bool>::D<short>; // expected-error{{'template' cannot be used after a declarative}} | ||
|
|
||
| template<> | ||
| template<> | ||
| template<> | ||
| struct A<int>::B<bool>::template D<long>; // expected-error{{'template' cannot be used after a declarative}} | ||
|
|
||
| template<> | ||
| template<> | ||
| template<typename V> | ||
| struct A<int>::template B<bool>::D<V*>; // expected-error{{'template' cannot be used after a declarative}} | ||
|
|
||
| template<> | ||
| template<> | ||
| template<typename V> | ||
| struct A<int>::B<bool>::template D<V**>; // expected-error{{'template' cannot be used after a declarative}} | ||
|
|
||
| template<> | ||
| template<> | ||
| template<typename V> | ||
| struct A<int>::template B<bool>::D { }; // expected-error{{'template' cannot be used after a declarative}} | ||
|
|
||
| template<> | ||
| template<> | ||
| template<> | ||
| struct A<int>::template B<bool>::D<short> { }; // expected-error{{'template' cannot be used after a declarative}} | ||
|
|
||
| template<> | ||
| template<> | ||
| template<> | ||
| struct A<int>::B<bool>::template D<long> { }; // expected-error{{'template' cannot be used after a declarative}} | ||
|
|
||
| template<> | ||
| template<> | ||
| template<typename V> | ||
| struct A<int>::template B<bool>::D<V*> { }; // expected-error{{'template' cannot be used after a declarative}} | ||
|
|
||
| template<> | ||
| template<> | ||
| template<typename V> | ||
| struct A<int>::B<bool>::template D<V**> { }; // expected-error{{'template' cannot be used after a declarative}} | ||
|
|
||
| template<typename T> | ||
| template<typename U> | ||
| void A<T>::template B<U>::f() { } // expected-error{{'template' cannot be used after a declarative}} | ||
|
|
||
| template<> | ||
| template<> | ||
| void A<int>::template B<bool>::f() { } // expected-error{{'template' cannot be used after a declarative}} | ||
|
|
||
| template<typename T> | ||
| template<typename U> | ||
| template<typename V> | ||
| void A<T>::template B<U>::g() { } // expected-error{{'template' cannot be used after a declarative}} | ||
|
|
||
| template<> | ||
| template<> | ||
| template<> | ||
| void A<int>::B<bool>::template g<short>() { } // expected-error{{'template' cannot be used after a declarative}} | ||
|
|
||
| template<> | ||
| template<> | ||
| template<> | ||
| void A<int>::template B<bool>::g<long>() { } // expected-error{{'template' cannot be used after a declarative}} | ||
|
|
||
| template<> | ||
| template<> | ||
| template<typename V> | ||
| void A<int>::template B<bool>::g() { } // expected-error{{'template' cannot be used after a declarative}} | ||
|
|
||
| template<typename T> | ||
| template<typename U> | ||
| int A<T>::template B<U>::x = 0; // expected-error{{'template' cannot be used after a declarative}} | ||
|
|
||
| template<typename T> | ||
| template<typename U> | ||
| template<typename V> | ||
| int A<T>::template B<U>::y = 0; // expected-error{{'template' cannot be used after a declarative}} | ||
|
|
||
| template<typename T> | ||
| template<typename U> | ||
| template<typename V> | ||
| int A<T>::template B<U>::y<V*> = 0; // expected-error{{'template' cannot be used after a declarative}} | ||
|
|
||
| template<typename T> | ||
| template<typename U> | ||
| template<typename V> | ||
| int A<T>::B<U>::template y<V**> = 0; // expected-error{{'template' cannot be used after a declarative}} | ||
|
|
||
| template<> | ||
| template<> | ||
| template<typename V> | ||
| int A<int>::template B<bool>::y = 0; // expected-error{{'template' cannot be used after a declarative}} | ||
|
|
||
| template<> | ||
| template<> | ||
| template<> | ||
| int A<int>::template B<bool>::y<short> = 0; // expected-error{{'template' cannot be used after a declarative}} | ||
|
|
||
| template<> | ||
| template<> | ||
| template<> | ||
| int A<int>::B<bool>::template y<long> = 0; // expected-error{{'template' cannot be used after a declarative}} | ||
|
|
||
| template<> | ||
| template<> | ||
| template<typename V> | ||
| int A<int>::template B<bool>::y<V*> = 0; // expected-error{{'template' cannot be used after a declarative}} | ||
|
|
||
| template<> | ||
| template<> | ||
| template<typename V> | ||
| int A<int>::B<bool>::template y<V**> = 0; // expected-error{{'template' cannot be used after a declarative}} | ||
| template<typename T> | ||
| template<typename U> | ||
| enum class A<T>::template B<U>::E { a }; // expected-error{{'template' cannot be used after a declarative}} | ||
|
|
||
| template<> | ||
| template<> | ||
| enum class A<int>::template B<bool>::E; // expected-error{{'template' cannot be used after a declarative}} | ||
|
|
||
| template<> | ||
| template<> | ||
| enum class A<int>::template B<bool>::E { a }; // expected-error{{'template' cannot be used after a declarative}} | ||
|
|
||
| // FIXME: We don't call Sema::diagnoseQualifiedDeclaration for friend declarations right now | ||
| template<typename T> | ||
| struct F { | ||
| // FIXME: f should be assumed to name a template per [temp.names] p3.4 | ||
| friend void T::f<int>(); | ||
| // expected-error@-1{{use 'template' keyword to treat 'f' as a dependent template name}} | ||
| // expected-error@-2{{no candidate function template was found for}} | ||
|
|
||
| // FIXME: We should diagnose the presence of 'template' here | ||
| friend void T::template f<int>(); // expected-error{{no candidate function template was found for}} | ||
| friend void T::template U<int>::f(); | ||
|
|
||
| // These should be allowed | ||
| friend class T::template U<int>; | ||
| friend class T::template U<int>::V; | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,218 @@ | ||
| // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 4 | ||
| // REQUIRES: riscv-registered-target | ||
| // RUN: %clang_cc1 -triple riscv64 -target-feature +v \ | ||
| // RUN: -target-feature +experimental-zvfbfmin -disable-O0-optnone \ | ||
| // RUN: -emit-llvm %s -o - | opt -S -passes=mem2reg | \ | ||
| // RUN: FileCheck --check-prefix=CHECK-RV64 %s | ||
|
|
||
| #include <riscv_vector.h> | ||
|
|
||
| // CHECK-RV64-LABEL: define dso_local <vscale x 1 x bfloat> @test_vfncvtbf16_f_f_w_bf16mf4( | ||
| // CHECK-RV64-SAME: <vscale x 1 x float> [[VS2:%.*]], i64 noundef [[VL:%.*]]) #[[ATTR0:[0-9]+]] { | ||
| // CHECK-RV64-NEXT: entry: | ||
| // CHECK-RV64-NEXT: [[TMP0:%.*]] = call <vscale x 1 x bfloat> @llvm.riscv.vfncvtbf16.f.f.w.nxv1bf16.nxv1f32.i64(<vscale x 1 x bfloat> poison, <vscale x 1 x float> [[VS2]], i64 7, i64 [[VL]]) | ||
| // CHECK-RV64-NEXT: ret <vscale x 1 x bfloat> [[TMP0]] | ||
| // | ||
| vbfloat16mf4_t test_vfncvtbf16_f_f_w_bf16mf4(vfloat32mf2_t vs2, size_t vl) { | ||
| return __riscv_vfncvtbf16_f_f_w_bf16mf4(vs2, vl); | ||
| } | ||
|
|
||
| // CHECK-RV64-LABEL: define dso_local <vscale x 2 x bfloat> @test_vfncvtbf16_f_f_w_bf16mf2( | ||
| // CHECK-RV64-SAME: <vscale x 2 x float> [[VS2:%.*]], i64 noundef [[VL:%.*]]) #[[ATTR0]] { | ||
| // CHECK-RV64-NEXT: entry: | ||
| // CHECK-RV64-NEXT: [[TMP0:%.*]] = call <vscale x 2 x bfloat> @llvm.riscv.vfncvtbf16.f.f.w.nxv2bf16.nxv2f32.i64(<vscale x 2 x bfloat> poison, <vscale x 2 x float> [[VS2]], i64 7, i64 [[VL]]) | ||
| // CHECK-RV64-NEXT: ret <vscale x 2 x bfloat> [[TMP0]] | ||
| // | ||
| vbfloat16mf2_t test_vfncvtbf16_f_f_w_bf16mf2(vfloat32m1_t vs2, size_t vl) { | ||
| return __riscv_vfncvtbf16_f_f_w_bf16mf2(vs2, vl); | ||
| } | ||
|
|
||
| // CHECK-RV64-LABEL: define dso_local <vscale x 4 x bfloat> @test_vfncvtbf16_f_f_w_bf16m1( | ||
| // CHECK-RV64-SAME: <vscale x 4 x float> [[VS2:%.*]], i64 noundef [[VL:%.*]]) #[[ATTR0]] { | ||
| // CHECK-RV64-NEXT: entry: | ||
| // CHECK-RV64-NEXT: [[TMP0:%.*]] = call <vscale x 4 x bfloat> @llvm.riscv.vfncvtbf16.f.f.w.nxv4bf16.nxv4f32.i64(<vscale x 4 x bfloat> poison, <vscale x 4 x float> [[VS2]], i64 7, i64 [[VL]]) | ||
| // CHECK-RV64-NEXT: ret <vscale x 4 x bfloat> [[TMP0]] | ||
| // | ||
| vbfloat16m1_t test_vfncvtbf16_f_f_w_bf16m1(vfloat32m2_t vs2, size_t vl) { | ||
| return __riscv_vfncvtbf16_f_f_w_bf16m1(vs2, vl); | ||
| } | ||
|
|
||
| // CHECK-RV64-LABEL: define dso_local <vscale x 8 x bfloat> @test_vfncvtbf16_f_f_w_bf16m2( | ||
| // CHECK-RV64-SAME: <vscale x 8 x float> [[VS2:%.*]], i64 noundef [[VL:%.*]]) #[[ATTR0]] { | ||
| // CHECK-RV64-NEXT: entry: | ||
| // CHECK-RV64-NEXT: [[TMP0:%.*]] = call <vscale x 8 x bfloat> @llvm.riscv.vfncvtbf16.f.f.w.nxv8bf16.nxv8f32.i64(<vscale x 8 x bfloat> poison, <vscale x 8 x float> [[VS2]], i64 7, i64 [[VL]]) | ||
| // CHECK-RV64-NEXT: ret <vscale x 8 x bfloat> [[TMP0]] | ||
| // | ||
| vbfloat16m2_t test_vfncvtbf16_f_f_w_bf16m2(vfloat32m4_t vs2, size_t vl) { | ||
| return __riscv_vfncvtbf16_f_f_w_bf16m2(vs2, vl); | ||
| } | ||
|
|
||
| // CHECK-RV64-LABEL: define dso_local <vscale x 16 x bfloat> @test_vfncvtbf16_f_f_w_bf16m4( | ||
| // CHECK-RV64-SAME: <vscale x 16 x float> [[VS2:%.*]], i64 noundef [[VL:%.*]]) #[[ATTR0]] { | ||
| // CHECK-RV64-NEXT: entry: | ||
| // CHECK-RV64-NEXT: [[TMP0:%.*]] = call <vscale x 16 x bfloat> @llvm.riscv.vfncvtbf16.f.f.w.nxv16bf16.nxv16f32.i64(<vscale x 16 x bfloat> poison, <vscale x 16 x float> [[VS2]], i64 7, i64 [[VL]]) | ||
| // CHECK-RV64-NEXT: ret <vscale x 16 x bfloat> [[TMP0]] | ||
| // | ||
| vbfloat16m4_t test_vfncvtbf16_f_f_w_bf16m4(vfloat32m8_t vs2, size_t vl) { | ||
| return __riscv_vfncvtbf16_f_f_w_bf16m4(vs2, vl); | ||
| } | ||
|
|
||
| // CHECK-RV64-LABEL: define dso_local <vscale x 1 x bfloat> @test_vfncvtbf16_f_f_w_bf16mf4_m( | ||
| // CHECK-RV64-SAME: <vscale x 1 x i1> [[VM:%.*]], <vscale x 1 x float> [[VS2:%.*]], i64 noundef [[VL:%.*]]) #[[ATTR0]] { | ||
| // CHECK-RV64-NEXT: entry: | ||
| // CHECK-RV64-NEXT: [[TMP0:%.*]] = call <vscale x 1 x bfloat> @llvm.riscv.vfncvtbf16.f.f.w.mask.nxv1bf16.nxv1f32.i64(<vscale x 1 x bfloat> poison, <vscale x 1 x float> [[VS2]], <vscale x 1 x i1> [[VM]], i64 7, i64 [[VL]], i64 3) | ||
| // CHECK-RV64-NEXT: ret <vscale x 1 x bfloat> [[TMP0]] | ||
| // | ||
| vbfloat16mf4_t test_vfncvtbf16_f_f_w_bf16mf4_m(vbool64_t vm, vfloat32mf2_t vs2, | ||
| size_t vl) { | ||
| return __riscv_vfncvtbf16_f_f_w_bf16mf4_m(vm, vs2, vl); | ||
| } | ||
|
|
||
| // CHECK-RV64-LABEL: define dso_local <vscale x 2 x bfloat> @test_vfncvtbf16_f_f_w_bf16mf2_m( | ||
| // CHECK-RV64-SAME: <vscale x 2 x i1> [[VM:%.*]], <vscale x 2 x float> [[VS2:%.*]], i64 noundef [[VL:%.*]]) #[[ATTR0]] { | ||
| // CHECK-RV64-NEXT: entry: | ||
| // CHECK-RV64-NEXT: [[TMP0:%.*]] = call <vscale x 2 x bfloat> @llvm.riscv.vfncvtbf16.f.f.w.mask.nxv2bf16.nxv2f32.i64(<vscale x 2 x bfloat> poison, <vscale x 2 x float> [[VS2]], <vscale x 2 x i1> [[VM]], i64 7, i64 [[VL]], i64 3) | ||
| // CHECK-RV64-NEXT: ret <vscale x 2 x bfloat> [[TMP0]] | ||
| // | ||
| vbfloat16mf2_t test_vfncvtbf16_f_f_w_bf16mf2_m(vbool32_t vm, vfloat32m1_t vs2, | ||
| size_t vl) { | ||
| return __riscv_vfncvtbf16_f_f_w_bf16mf2_m(vm, vs2, vl); | ||
| } | ||
|
|
||
| // CHECK-RV64-LABEL: define dso_local <vscale x 4 x bfloat> @test_vfncvtbf16_f_f_w_bf16m1_m( | ||
| // CHECK-RV64-SAME: <vscale x 4 x i1> [[VM:%.*]], <vscale x 4 x float> [[VS2:%.*]], i64 noundef [[VL:%.*]]) #[[ATTR0]] { | ||
| // CHECK-RV64-NEXT: entry: | ||
| // CHECK-RV64-NEXT: [[TMP0:%.*]] = call <vscale x 4 x bfloat> @llvm.riscv.vfncvtbf16.f.f.w.mask.nxv4bf16.nxv4f32.i64(<vscale x 4 x bfloat> poison, <vscale x 4 x float> [[VS2]], <vscale x 4 x i1> [[VM]], i64 7, i64 [[VL]], i64 3) | ||
| // CHECK-RV64-NEXT: ret <vscale x 4 x bfloat> [[TMP0]] | ||
| // | ||
| vbfloat16m1_t test_vfncvtbf16_f_f_w_bf16m1_m(vbool16_t vm, vfloat32m2_t vs2, | ||
| size_t vl) { | ||
| return __riscv_vfncvtbf16_f_f_w_bf16m1_m(vm, vs2, vl); | ||
| } | ||
|
|
||
| // CHECK-RV64-LABEL: define dso_local <vscale x 8 x bfloat> @test_vfncvtbf16_f_f_w_bf16m2_m( | ||
| // CHECK-RV64-SAME: <vscale x 8 x i1> [[VM:%.*]], <vscale x 8 x float> [[VS2:%.*]], i64 noundef [[VL:%.*]]) #[[ATTR0]] { | ||
| // CHECK-RV64-NEXT: entry: | ||
| // CHECK-RV64-NEXT: [[TMP0:%.*]] = call <vscale x 8 x bfloat> @llvm.riscv.vfncvtbf16.f.f.w.mask.nxv8bf16.nxv8f32.i64(<vscale x 8 x bfloat> poison, <vscale x 8 x float> [[VS2]], <vscale x 8 x i1> [[VM]], i64 7, i64 [[VL]], i64 3) | ||
| // CHECK-RV64-NEXT: ret <vscale x 8 x bfloat> [[TMP0]] | ||
| // | ||
| vbfloat16m2_t test_vfncvtbf16_f_f_w_bf16m2_m(vbool8_t vm, vfloat32m4_t vs2, | ||
| size_t vl) { | ||
| return __riscv_vfncvtbf16_f_f_w_bf16m2_m(vm, vs2, vl); | ||
| } | ||
|
|
||
| // CHECK-RV64-LABEL: define dso_local <vscale x 16 x bfloat> @test_vfncvtbf16_f_f_w_bf16m4_m( | ||
| // CHECK-RV64-SAME: <vscale x 16 x i1> [[VM:%.*]], <vscale x 16 x float> [[VS2:%.*]], i64 noundef [[VL:%.*]]) #[[ATTR0]] { | ||
| // CHECK-RV64-NEXT: entry: | ||
| // CHECK-RV64-NEXT: [[TMP0:%.*]] = call <vscale x 16 x bfloat> @llvm.riscv.vfncvtbf16.f.f.w.mask.nxv16bf16.nxv16f32.i64(<vscale x 16 x bfloat> poison, <vscale x 16 x float> [[VS2]], <vscale x 16 x i1> [[VM]], i64 7, i64 [[VL]], i64 3) | ||
| // CHECK-RV64-NEXT: ret <vscale x 16 x bfloat> [[TMP0]] | ||
| // | ||
| vbfloat16m4_t test_vfncvtbf16_f_f_w_bf16m4_m(vbool4_t vm, vfloat32m8_t vs2, | ||
| size_t vl) { | ||
| return __riscv_vfncvtbf16_f_f_w_bf16m4_m(vm, vs2, vl); | ||
| } | ||
|
|
||
| // CHECK-RV64-LABEL: define dso_local <vscale x 1 x bfloat> @test_vfncvtbf16_f_f_w_bf16mf4_rm( | ||
| // CHECK-RV64-SAME: <vscale x 1 x float> [[VS2:%.*]], i64 noundef [[VL:%.*]]) #[[ATTR0]] { | ||
| // CHECK-RV64-NEXT: entry: | ||
| // CHECK-RV64-NEXT: [[TMP0:%.*]] = call <vscale x 1 x bfloat> @llvm.riscv.vfncvtbf16.f.f.w.nxv1bf16.nxv1f32.i64(<vscale x 1 x bfloat> poison, <vscale x 1 x float> [[VS2]], i64 0, i64 [[VL]]) | ||
| // CHECK-RV64-NEXT: ret <vscale x 1 x bfloat> [[TMP0]] | ||
| // | ||
| vbfloat16mf4_t test_vfncvtbf16_f_f_w_bf16mf4_rm(vfloat32mf2_t vs2, size_t vl) { | ||
| return __riscv_vfncvtbf16_f_f_w_bf16mf4_rm(vs2, __RISCV_FRM_RNE, vl); | ||
| } | ||
|
|
||
| // CHECK-RV64-LABEL: define dso_local <vscale x 2 x bfloat> @test_vfncvtbf16_f_f_w_bf16mf2_rm( | ||
| // CHECK-RV64-SAME: <vscale x 2 x float> [[VS2:%.*]], i64 noundef [[VL:%.*]]) #[[ATTR0]] { | ||
| // CHECK-RV64-NEXT: entry: | ||
| // CHECK-RV64-NEXT: [[TMP0:%.*]] = call <vscale x 2 x bfloat> @llvm.riscv.vfncvtbf16.f.f.w.nxv2bf16.nxv2f32.i64(<vscale x 2 x bfloat> poison, <vscale x 2 x float> [[VS2]], i64 0, i64 [[VL]]) | ||
| // CHECK-RV64-NEXT: ret <vscale x 2 x bfloat> [[TMP0]] | ||
| // | ||
| vbfloat16mf2_t test_vfncvtbf16_f_f_w_bf16mf2_rm(vfloat32m1_t vs2, size_t vl) { | ||
| return __riscv_vfncvtbf16_f_f_w_bf16mf2_rm(vs2, __RISCV_FRM_RNE, vl); | ||
| } | ||
|
|
||
| // CHECK-RV64-LABEL: define dso_local <vscale x 4 x bfloat> @test_vfncvtbf16_f_f_w_bf16m1_rm( | ||
| // CHECK-RV64-SAME: <vscale x 4 x float> [[VS2:%.*]], i64 noundef [[VL:%.*]]) #[[ATTR0]] { | ||
| // CHECK-RV64-NEXT: entry: | ||
| // CHECK-RV64-NEXT: [[TMP0:%.*]] = call <vscale x 4 x bfloat> @llvm.riscv.vfncvtbf16.f.f.w.nxv4bf16.nxv4f32.i64(<vscale x 4 x bfloat> poison, <vscale x 4 x float> [[VS2]], i64 0, i64 [[VL]]) | ||
| // CHECK-RV64-NEXT: ret <vscale x 4 x bfloat> [[TMP0]] | ||
| // | ||
| vbfloat16m1_t test_vfncvtbf16_f_f_w_bf16m1_rm(vfloat32m2_t vs2, size_t vl) { | ||
| return __riscv_vfncvtbf16_f_f_w_bf16m1_rm(vs2, __RISCV_FRM_RNE, vl); | ||
| } | ||
|
|
||
| // CHECK-RV64-LABEL: define dso_local <vscale x 8 x bfloat> @test_vfncvtbf16_f_f_w_bf16m2_rm( | ||
| // CHECK-RV64-SAME: <vscale x 8 x float> [[VS2:%.*]], i64 noundef [[VL:%.*]]) #[[ATTR0]] { | ||
| // CHECK-RV64-NEXT: entry: | ||
| // CHECK-RV64-NEXT: [[TMP0:%.*]] = call <vscale x 8 x bfloat> @llvm.riscv.vfncvtbf16.f.f.w.nxv8bf16.nxv8f32.i64(<vscale x 8 x bfloat> poison, <vscale x 8 x float> [[VS2]], i64 0, i64 [[VL]]) | ||
| // CHECK-RV64-NEXT: ret <vscale x 8 x bfloat> [[TMP0]] | ||
| // | ||
| vbfloat16m2_t test_vfncvtbf16_f_f_w_bf16m2_rm(vfloat32m4_t vs2, size_t vl) { | ||
| return __riscv_vfncvtbf16_f_f_w_bf16m2_rm(vs2, __RISCV_FRM_RNE, vl); | ||
| } | ||
|
|
||
| // CHECK-RV64-LABEL: define dso_local <vscale x 16 x bfloat> @test_vfncvtbf16_f_f_w_bf16m4_rm( | ||
| // CHECK-RV64-SAME: <vscale x 16 x float> [[VS2:%.*]], i64 noundef [[VL:%.*]]) #[[ATTR0]] { | ||
| // CHECK-RV64-NEXT: entry: | ||
| // CHECK-RV64-NEXT: [[TMP0:%.*]] = call <vscale x 16 x bfloat> @llvm.riscv.vfncvtbf16.f.f.w.nxv16bf16.nxv16f32.i64(<vscale x 16 x bfloat> poison, <vscale x 16 x float> [[VS2]], i64 0, i64 [[VL]]) | ||
| // CHECK-RV64-NEXT: ret <vscale x 16 x bfloat> [[TMP0]] | ||
| // | ||
| vbfloat16m4_t test_vfncvtbf16_f_f_w_bf16m4_rm(vfloat32m8_t vs2, size_t vl) { | ||
| return __riscv_vfncvtbf16_f_f_w_bf16m4_rm(vs2, __RISCV_FRM_RNE, vl); | ||
| } | ||
|
|
||
| vbfloat16mf4_t | ||
| // CHECK-RV64-LABEL: define dso_local <vscale x 1 x bfloat> @test_vfncvtbf16_f_f_w_bf16mf4_rm_m( | ||
| // CHECK-RV64-SAME: <vscale x 1 x i1> [[VM:%.*]], <vscale x 1 x float> [[VS2:%.*]], i64 noundef [[VL:%.*]]) #[[ATTR0]] { | ||
| // CHECK-RV64-NEXT: entry: | ||
| // CHECK-RV64-NEXT: [[TMP0:%.*]] = call <vscale x 1 x bfloat> @llvm.riscv.vfncvtbf16.f.f.w.mask.nxv1bf16.nxv1f32.i64(<vscale x 1 x bfloat> poison, <vscale x 1 x float> [[VS2]], <vscale x 1 x i1> [[VM]], i64 0, i64 [[VL]], i64 3) | ||
| // CHECK-RV64-NEXT: ret <vscale x 1 x bfloat> [[TMP0]] | ||
| // | ||
| test_vfncvtbf16_f_f_w_bf16mf4_rm_m(vbool64_t vm, vfloat32mf2_t vs2, size_t vl) { | ||
| return __riscv_vfncvtbf16_f_f_w_bf16mf4_rm_m(vm, vs2, __RISCV_FRM_RNE, vl); | ||
| } | ||
|
|
||
| // CHECK-RV64-LABEL: define dso_local <vscale x 2 x bfloat> @test_vfncvtbf16_f_f_w_bf16mf2_rm_m( | ||
| // CHECK-RV64-SAME: <vscale x 2 x i1> [[VM:%.*]], <vscale x 2 x float> [[VS2:%.*]], i64 noundef [[VL:%.*]]) #[[ATTR0]] { | ||
| // CHECK-RV64-NEXT: entry: | ||
| // CHECK-RV64-NEXT: [[TMP0:%.*]] = call <vscale x 2 x bfloat> @llvm.riscv.vfncvtbf16.f.f.w.mask.nxv2bf16.nxv2f32.i64(<vscale x 2 x bfloat> poison, <vscale x 2 x float> [[VS2]], <vscale x 2 x i1> [[VM]], i64 0, i64 [[VL]], i64 3) | ||
| // CHECK-RV64-NEXT: ret <vscale x 2 x bfloat> [[TMP0]] | ||
| // | ||
| vbfloat16mf2_t test_vfncvtbf16_f_f_w_bf16mf2_rm_m(vbool32_t vm, | ||
| vfloat32m1_t vs2, size_t vl) { | ||
| return __riscv_vfncvtbf16_f_f_w_bf16mf2_rm_m(vm, vs2, __RISCV_FRM_RNE, vl); | ||
| } | ||
|
|
||
| // CHECK-RV64-LABEL: define dso_local <vscale x 4 x bfloat> @test_vfncvtbf16_f_f_w_bf16m1_rm_m( | ||
| // CHECK-RV64-SAME: <vscale x 4 x i1> [[VM:%.*]], <vscale x 4 x float> [[VS2:%.*]], i64 noundef [[VL:%.*]]) #[[ATTR0]] { | ||
| // CHECK-RV64-NEXT: entry: | ||
| // CHECK-RV64-NEXT: [[TMP0:%.*]] = call <vscale x 4 x bfloat> @llvm.riscv.vfncvtbf16.f.f.w.mask.nxv4bf16.nxv4f32.i64(<vscale x 4 x bfloat> poison, <vscale x 4 x float> [[VS2]], <vscale x 4 x i1> [[VM]], i64 0, i64 [[VL]], i64 3) | ||
| // CHECK-RV64-NEXT: ret <vscale x 4 x bfloat> [[TMP0]] | ||
| // | ||
| vbfloat16m1_t test_vfncvtbf16_f_f_w_bf16m1_rm_m(vbool16_t vm, vfloat32m2_t vs2, | ||
| size_t vl) { | ||
| return __riscv_vfncvtbf16_f_f_w_bf16m1_rm_m(vm, vs2, __RISCV_FRM_RNE, vl); | ||
| } | ||
|
|
||
| // CHECK-RV64-LABEL: define dso_local <vscale x 8 x bfloat> @test_vfncvtbf16_f_f_w_bf16m2_rm_m( | ||
| // CHECK-RV64-SAME: <vscale x 8 x i1> [[VM:%.*]], <vscale x 8 x float> [[VS2:%.*]], i64 noundef [[VL:%.*]]) #[[ATTR0]] { | ||
| // CHECK-RV64-NEXT: entry: | ||
| // CHECK-RV64-NEXT: [[TMP0:%.*]] = call <vscale x 8 x bfloat> @llvm.riscv.vfncvtbf16.f.f.w.mask.nxv8bf16.nxv8f32.i64(<vscale x 8 x bfloat> poison, <vscale x 8 x float> [[VS2]], <vscale x 8 x i1> [[VM]], i64 0, i64 [[VL]], i64 3) | ||
| // CHECK-RV64-NEXT: ret <vscale x 8 x bfloat> [[TMP0]] | ||
| // | ||
| vbfloat16m2_t test_vfncvtbf16_f_f_w_bf16m2_rm_m(vbool8_t vm, vfloat32m4_t vs2, | ||
| size_t vl) { | ||
| return __riscv_vfncvtbf16_f_f_w_bf16m2_rm_m(vm, vs2, __RISCV_FRM_RNE, vl); | ||
| } | ||
|
|
||
| // CHECK-RV64-LABEL: define dso_local <vscale x 16 x bfloat> @test_vfncvtbf16_f_f_w_bf16m4_rm_m( | ||
| // CHECK-RV64-SAME: <vscale x 16 x i1> [[VM:%.*]], <vscale x 16 x float> [[VS2:%.*]], i64 noundef [[VL:%.*]]) #[[ATTR0]] { | ||
| // CHECK-RV64-NEXT: entry: | ||
| // CHECK-RV64-NEXT: [[TMP0:%.*]] = call <vscale x 16 x bfloat> @llvm.riscv.vfncvtbf16.f.f.w.mask.nxv16bf16.nxv16f32.i64(<vscale x 16 x bfloat> poison, <vscale x 16 x float> [[VS2]], <vscale x 16 x i1> [[VM]], i64 0, i64 [[VL]], i64 3) | ||
| // CHECK-RV64-NEXT: ret <vscale x 16 x bfloat> [[TMP0]] | ||
| // | ||
| vbfloat16m4_t test_vfncvtbf16_f_f_w_bf16m4_rm_m(vbool4_t vm, vfloat32m8_t vs2, | ||
| size_t vl) { | ||
| return __riscv_vfncvtbf16_f_f_w_bf16m4_rm_m(vm, vs2, __RISCV_FRM_RNE, vl); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,113 @@ | ||
| // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 4 | ||
| // REQUIRES: riscv-registered-target | ||
| // RUN: %clang_cc1 -triple riscv64 -target-feature +v \ | ||
| // RUN: -target-feature +experimental-zvfbfmin -disable-O0-optnone \ | ||
| // RUN: -emit-llvm %s -o - | opt -S -passes=mem2reg | \ | ||
| // RUN: FileCheck --check-prefix=CHECK-RV64 %s | ||
|
|
||
| #include <riscv_vector.h> | ||
|
|
||
| // CHECK-RV64-LABEL: define dso_local <vscale x 1 x float> @test_vfwcvtbf16_f_f_v_f32mf2( | ||
| // CHECK-RV64-SAME: <vscale x 1 x bfloat> [[VS2:%.*]], i64 noundef [[VL:%.*]]) #[[ATTR0:[0-9]+]] { | ||
| // CHECK-RV64-NEXT: entry: | ||
| // CHECK-RV64-NEXT: [[TMP0:%.*]] = call <vscale x 1 x float> @llvm.riscv.vfwcvtbf16.f.f.v.nxv1f32.nxv1bf16.i64(<vscale x 1 x float> poison, <vscale x 1 x bfloat> [[VS2]], i64 [[VL]]) | ||
| // CHECK-RV64-NEXT: ret <vscale x 1 x float> [[TMP0]] | ||
| // | ||
| vfloat32mf2_t test_vfwcvtbf16_f_f_v_f32mf2(vbfloat16mf4_t vs2, size_t vl) { | ||
| return __riscv_vfwcvtbf16_f_f_v_f32mf2(vs2, vl); | ||
| } | ||
|
|
||
| // CHECK-RV64-LABEL: define dso_local <vscale x 2 x float> @test_vfwcvtbf16_f_f_v_f32m1( | ||
| // CHECK-RV64-SAME: <vscale x 2 x bfloat> [[VS2:%.*]], i64 noundef [[VL:%.*]]) #[[ATTR0]] { | ||
| // CHECK-RV64-NEXT: entry: | ||
| // CHECK-RV64-NEXT: [[TMP0:%.*]] = call <vscale x 2 x float> @llvm.riscv.vfwcvtbf16.f.f.v.nxv2f32.nxv2bf16.i64(<vscale x 2 x float> poison, <vscale x 2 x bfloat> [[VS2]], i64 [[VL]]) | ||
| // CHECK-RV64-NEXT: ret <vscale x 2 x float> [[TMP0]] | ||
| // | ||
| vfloat32m1_t test_vfwcvtbf16_f_f_v_f32m1(vbfloat16mf2_t vs2, size_t vl) { | ||
| return __riscv_vfwcvtbf16_f_f_v_f32m1(vs2, vl); | ||
| } | ||
|
|
||
| // CHECK-RV64-LABEL: define dso_local <vscale x 4 x float> @test_vfwcvtbf16_f_f_v_f32m2( | ||
| // CHECK-RV64-SAME: <vscale x 4 x bfloat> [[VS2:%.*]], i64 noundef [[VL:%.*]]) #[[ATTR0]] { | ||
| // CHECK-RV64-NEXT: entry: | ||
| // CHECK-RV64-NEXT: [[TMP0:%.*]] = call <vscale x 4 x float> @llvm.riscv.vfwcvtbf16.f.f.v.nxv4f32.nxv4bf16.i64(<vscale x 4 x float> poison, <vscale x 4 x bfloat> [[VS2]], i64 [[VL]]) | ||
| // CHECK-RV64-NEXT: ret <vscale x 4 x float> [[TMP0]] | ||
| // | ||
| vfloat32m2_t test_vfwcvtbf16_f_f_v_f32m2(vbfloat16m1_t vs2, size_t vl) { | ||
| return __riscv_vfwcvtbf16_f_f_v_f32m2(vs2, vl); | ||
| } | ||
|
|
||
| // CHECK-RV64-LABEL: define dso_local <vscale x 8 x float> @test_vfwcvtbf16_f_f_v_f32m4( | ||
| // CHECK-RV64-SAME: <vscale x 8 x bfloat> [[VS2:%.*]], i64 noundef [[VL:%.*]]) #[[ATTR0]] { | ||
| // CHECK-RV64-NEXT: entry: | ||
| // CHECK-RV64-NEXT: [[TMP0:%.*]] = call <vscale x 8 x float> @llvm.riscv.vfwcvtbf16.f.f.v.nxv8f32.nxv8bf16.i64(<vscale x 8 x float> poison, <vscale x 8 x bfloat> [[VS2]], i64 [[VL]]) | ||
| // CHECK-RV64-NEXT: ret <vscale x 8 x float> [[TMP0]] | ||
| // | ||
| vfloat32m4_t test_vfwcvtbf16_f_f_v_f32m4(vbfloat16m2_t vs2, size_t vl) { | ||
| return __riscv_vfwcvtbf16_f_f_v_f32m4(vs2, vl); | ||
| } | ||
|
|
||
| // CHECK-RV64-LABEL: define dso_local <vscale x 16 x float> @test_vfwcvtbf16_f_f_v_f32m8( | ||
| // CHECK-RV64-SAME: <vscale x 16 x bfloat> [[VS2:%.*]], i64 noundef [[VL:%.*]]) #[[ATTR0]] { | ||
| // CHECK-RV64-NEXT: entry: | ||
| // CHECK-RV64-NEXT: [[TMP0:%.*]] = call <vscale x 16 x float> @llvm.riscv.vfwcvtbf16.f.f.v.nxv16f32.nxv16bf16.i64(<vscale x 16 x float> poison, <vscale x 16 x bfloat> [[VS2]], i64 [[VL]]) | ||
| // CHECK-RV64-NEXT: ret <vscale x 16 x float> [[TMP0]] | ||
| // | ||
| vfloat32m8_t test_vfwcvtbf16_f_f_v_f32m8(vbfloat16m4_t vs2, size_t vl) { | ||
| return __riscv_vfwcvtbf16_f_f_v_f32m8(vs2, vl); | ||
| } | ||
|
|
||
| // CHECK-RV64-LABEL: define dso_local <vscale x 1 x float> @test_vfwcvtbf16_f_f_v_f32mf2_m( | ||
| // CHECK-RV64-SAME: <vscale x 1 x i1> [[VM:%.*]], <vscale x 1 x bfloat> [[VS2:%.*]], i64 noundef [[VL:%.*]]) #[[ATTR0]] { | ||
| // CHECK-RV64-NEXT: entry: | ||
| // CHECK-RV64-NEXT: [[TMP0:%.*]] = call <vscale x 1 x float> @llvm.riscv.vfwcvtbf16.f.f.v.mask.nxv1f32.nxv1bf16.i64(<vscale x 1 x float> poison, <vscale x 1 x bfloat> [[VS2]], <vscale x 1 x i1> [[VM]], i64 [[VL]], i64 3) | ||
| // CHECK-RV64-NEXT: ret <vscale x 1 x float> [[TMP0]] | ||
| // | ||
| vfloat32mf2_t test_vfwcvtbf16_f_f_v_f32mf2_m(vbool64_t vm, vbfloat16mf4_t vs2, | ||
| size_t vl) { | ||
| return __riscv_vfwcvtbf16_f_f_v_f32mf2_m(vm, vs2, vl); | ||
| } | ||
|
|
||
| // CHECK-RV64-LABEL: define dso_local <vscale x 2 x float> @test_vfwcvtbf16_f_f_v_f32m1_m( | ||
| // CHECK-RV64-SAME: <vscale x 2 x i1> [[VM:%.*]], <vscale x 2 x bfloat> [[VS2:%.*]], i64 noundef [[VL:%.*]]) #[[ATTR0]] { | ||
| // CHECK-RV64-NEXT: entry: | ||
| // CHECK-RV64-NEXT: [[TMP0:%.*]] = call <vscale x 2 x float> @llvm.riscv.vfwcvtbf16.f.f.v.mask.nxv2f32.nxv2bf16.i64(<vscale x 2 x float> poison, <vscale x 2 x bfloat> [[VS2]], <vscale x 2 x i1> [[VM]], i64 [[VL]], i64 3) | ||
| // CHECK-RV64-NEXT: ret <vscale x 2 x float> [[TMP0]] | ||
| // | ||
| vfloat32m1_t test_vfwcvtbf16_f_f_v_f32m1_m(vbool32_t vm, vbfloat16mf2_t vs2, | ||
| size_t vl) { | ||
| return __riscv_vfwcvtbf16_f_f_v_f32m1_m(vm, vs2, vl); | ||
| } | ||
|
|
||
| // CHECK-RV64-LABEL: define dso_local <vscale x 4 x float> @test_vfwcvtbf16_f_f_v_f32m2_m( | ||
| // CHECK-RV64-SAME: <vscale x 4 x i1> [[VM:%.*]], <vscale x 4 x bfloat> [[VS2:%.*]], i64 noundef [[VL:%.*]]) #[[ATTR0]] { | ||
| // CHECK-RV64-NEXT: entry: | ||
| // CHECK-RV64-NEXT: [[TMP0:%.*]] = call <vscale x 4 x float> @llvm.riscv.vfwcvtbf16.f.f.v.mask.nxv4f32.nxv4bf16.i64(<vscale x 4 x float> poison, <vscale x 4 x bfloat> [[VS2]], <vscale x 4 x i1> [[VM]], i64 [[VL]], i64 3) | ||
| // CHECK-RV64-NEXT: ret <vscale x 4 x float> [[TMP0]] | ||
| // | ||
| vfloat32m2_t test_vfwcvtbf16_f_f_v_f32m2_m(vbool16_t vm, vbfloat16m1_t vs2, | ||
| size_t vl) { | ||
| return __riscv_vfwcvtbf16_f_f_v_f32m2_m(vm, vs2, vl); | ||
| } | ||
|
|
||
| // CHECK-RV64-LABEL: define dso_local <vscale x 8 x float> @test_vfwcvtbf16_f_f_v_f32m4_m( | ||
| // CHECK-RV64-SAME: <vscale x 8 x i1> [[VM:%.*]], <vscale x 8 x bfloat> [[VS2:%.*]], i64 noundef [[VL:%.*]]) #[[ATTR0]] { | ||
| // CHECK-RV64-NEXT: entry: | ||
| // CHECK-RV64-NEXT: [[TMP0:%.*]] = call <vscale x 8 x float> @llvm.riscv.vfwcvtbf16.f.f.v.mask.nxv8f32.nxv8bf16.i64(<vscale x 8 x float> poison, <vscale x 8 x bfloat> [[VS2]], <vscale x 8 x i1> [[VM]], i64 [[VL]], i64 3) | ||
| // CHECK-RV64-NEXT: ret <vscale x 8 x float> [[TMP0]] | ||
| // | ||
| vfloat32m4_t test_vfwcvtbf16_f_f_v_f32m4_m(vbool8_t vm, vbfloat16m2_t vs2, | ||
| size_t vl) { | ||
| return __riscv_vfwcvtbf16_f_f_v_f32m4_m(vm, vs2, vl); | ||
| } | ||
|
|
||
| // CHECK-RV64-LABEL: define dso_local <vscale x 16 x float> @test_vfwcvtbf16_f_f_v_f32m8_m( | ||
| // CHECK-RV64-SAME: <vscale x 16 x i1> [[VM:%.*]], <vscale x 16 x bfloat> [[VS2:%.*]], i64 noundef [[VL:%.*]]) #[[ATTR0]] { | ||
| // CHECK-RV64-NEXT: entry: | ||
| // CHECK-RV64-NEXT: [[TMP0:%.*]] = call <vscale x 16 x float> @llvm.riscv.vfwcvtbf16.f.f.v.mask.nxv16f32.nxv16bf16.i64(<vscale x 16 x float> poison, <vscale x 16 x bfloat> [[VS2]], <vscale x 16 x i1> [[VM]], i64 [[VL]], i64 3) | ||
| // CHECK-RV64-NEXT: ret <vscale x 16 x float> [[TMP0]] | ||
| // | ||
| vfloat32m8_t test_vfwcvtbf16_f_f_v_f32m8_m(vbool4_t vm, vbfloat16m4_t vs2, | ||
| size_t vl) { | ||
| return __riscv_vfwcvtbf16_f_f_v_f32m8_m(vm, vs2, vl); | ||
| } |