| 1 | //===-- Unittests for ArgList ---------------------------------------------===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | |
| 9 | #include "src/__support/arg_list.h" |
| 10 | #include "src/__support/macros/properties/os.h" |
| 11 | |
| 12 | #include "test/UnitTest/Test.h" |
| 13 | |
| 14 | int get_nth_int(int n, ...) { |
| 15 | va_list vlist; |
| 16 | va_start(vlist, n); |
| 17 | LIBC_NAMESPACE::internal::ArgList v(vlist); |
| 18 | va_end(vlist); |
| 19 | |
| 20 | for (int i = 0; i < n; ++i) { |
| 21 | v.next_var<int>(); |
| 22 | } |
| 23 | return v.next_var<int>(); |
| 24 | } |
| 25 | |
| 26 | TEST(LlvmLibcArgListTest, BasicUsage) { |
| 27 | ASSERT_EQ(get_nth_int(n: 5, 0, 10, 20, 30, 40, 50, 60, 70, 80, 90), 50); |
| 28 | } |
| 29 | |
| 30 | int sum_two_nums(int first, int second, ...) { |
| 31 | va_list vlist; |
| 32 | va_start(vlist, second); |
| 33 | LIBC_NAMESPACE::internal::ArgList v1(vlist); |
| 34 | va_end(vlist); |
| 35 | |
| 36 | LIBC_NAMESPACE::internal::ArgList v2 = v1; |
| 37 | |
| 38 | int first_val; |
| 39 | for (int i = 0; i < first; ++i) { |
| 40 | v1.next_var<int>(); |
| 41 | } |
| 42 | first_val = v1.next_var<int>(); |
| 43 | |
| 44 | int second_val; |
| 45 | for (int i = 0; i < second; ++i) { |
| 46 | v2.next_var<int>(); |
| 47 | } |
| 48 | second_val = v2.next_var<int>(); |
| 49 | |
| 50 | return first_val + second_val; |
| 51 | } |
| 52 | |
| 53 | TEST(LlvmLibcArgListTest, CopyConstructor) { |
| 54 | ASSERT_EQ(sum_two_nums(first: 3, second: 1, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024), |
| 55 | 10); |
| 56 | |
| 57 | ASSERT_EQ(sum_two_nums(first: 3, second: 5, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024), |
| 58 | 40); |
| 59 | } |
| 60 | |
| 61 | long int check_primitives(int first, ...) { |
| 62 | va_list vlist; |
| 63 | va_start(vlist, first); |
| 64 | LIBC_NAMESPACE::internal::ArgList args(vlist); |
| 65 | va_end(vlist); |
| 66 | |
| 67 | long int count = 0; |
| 68 | count += args.next_var<int>(); |
| 69 | count += args.next_var<int>(); |
| 70 | count += args.next_var<int>(); |
| 71 | count += args.next_var<long>(); |
| 72 | count += args.next_var<unsigned long>(); |
| 73 | count += args.next_var<long long>(); |
| 74 | count += args.next_var<unsigned long long>(); |
| 75 | count += static_cast<long int>(args.next_var<double>()); |
| 76 | count += static_cast<long int>(args.next_var<double>()); |
| 77 | count += static_cast<long int>(args.next_var<long double>()); |
| 78 | count += *args.next_var<int *>(); |
| 79 | return count; |
| 80 | } |
| 81 | |
| 82 | TEST(LlvmLibcArgListTest, TestPrimitiveTypes) { |
| 83 | char c = '\x01'; |
| 84 | short s = 2; |
| 85 | int i = 3; |
| 86 | long l = 4l; |
| 87 | unsigned long ul = 5ul; |
| 88 | long long ll = 6ll; |
| 89 | unsigned long long ull = 7ull; |
| 90 | float f = 8.0f; |
| 91 | double d = 9.0; |
| 92 | long double ld = 10.0L; |
| 93 | long v = 11; |
| 94 | void *p = &v; |
| 95 | ASSERT_EQ(check_primitives(first: 0, c, s, i, l, ul, ll, ull, f, d, ld, p), 66l); |
| 96 | } |
| 97 | |
| 98 | struct S { |
| 99 | char c; |
| 100 | short s; |
| 101 | int i; |
| 102 | long l; |
| 103 | float f; |
| 104 | double d; |
| 105 | }; |
| 106 | |
| 107 | long int check_struct_type(int first, ...) { |
| 108 | va_list vlist; |
| 109 | va_start(vlist, first); |
| 110 | LIBC_NAMESPACE::internal::ArgList args(vlist); |
| 111 | va_end(vlist); |
| 112 | |
| 113 | S s = args.next_var<S>(); |
| 114 | int last = args.next_var<int>(); |
| 115 | return s.c + s.s + s.i + s.l + static_cast<long>(s.f + s.d) + last; |
| 116 | } |
| 117 | |
| 118 | TEST(LlvmLibcArgListTest, TestStructTypes) { |
| 119 | S s{.c: '\x1', .s: 2, .i: 3, .l: 4l, .f: 5.0f, .d: 6.0}; |
| 120 | ASSERT_EQ(check_struct_type(first: 0, s, 1), 22l); |
| 121 | } |
| 122 | |
| 123 | // Test vector extensions from clang. |
| 124 | #if !defined(LIBC_TARGET_OS_IS_WINDOWS) && __has_attribute(ext_vector_type) |
| 125 | |
| 126 | using int1 = int __attribute__((ext_vector_type(1))); |
| 127 | using int2 = int __attribute__((ext_vector_type(2))); |
| 128 | using int3 = int __attribute__((ext_vector_type(3))); |
| 129 | using int4 = int __attribute__((ext_vector_type(4))); |
| 130 | |
| 131 | int check_vector_type(int first, ...) { |
| 132 | va_list vlist; |
| 133 | va_start(vlist, first); |
| 134 | LIBC_NAMESPACE::internal::ArgList args(vlist); |
| 135 | va_end(vlist); |
| 136 | |
| 137 | int1 v1 = args.next_var<int1>(); |
| 138 | int2 v2 = args.next_var<int2>(); |
| 139 | int3 v3 = args.next_var<int3>(); |
| 140 | int4 v4 = args.next_var<int4>(); |
| 141 | |
| 142 | return v1.x + v2.x + v2.y + v3.x + v3.y + v3.z + v4.x + v4.y + v4.z + v4.w; |
| 143 | } |
| 144 | |
| 145 | TEST(LlvmLibcArgListTest, TestVectorTypes) { |
| 146 | int1 v1 = {1}; |
| 147 | int2 v2 = {1, 2}; |
| 148 | int3 v3 = {1, 2, 3}; |
| 149 | int4 v4 = {1, 2, 3, 4}; |
| 150 | ASSERT_EQ(check_vector_type(first: 0, v1, v2, v3, v4), 20); |
| 151 | } |
| 152 | |
| 153 | #endif |
| 154 | |