1 /*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "gtest/gtest.h"
18
19 #include <cstdint>
20 #include <tuple>
21
22 #include "berberis/intrinsics/guest_cpu_flags.h"
23 #include "berberis/intrinsics/intrinsics.h"
24
25 namespace berberis::intrinsics {
26
27 namespace {
28
29 using VXRMFlags::RDN;
30 using VXRMFlags::RNE;
31 using VXRMFlags::RNU;
32 using VXRMFlags::ROD;
33
TEST(Intrinsics,Aadd)34 TEST(Intrinsics, Aadd) {
35 auto Verify = []<typename T>(int8_t vxrm) {
36 for (int x = std::numeric_limits<T>::min(); x <= std::numeric_limits<T>::max(); ++x) {
37 for (int y = std::numeric_limits<T>::min(); y <= std::numeric_limits<T>::max(); ++y) {
38 ASSERT_EQ(Aadd<T>(vxrm, x, y), Roundoff(vxrm, x + y, 1));
39 }
40 }
41 };
42 Verify.operator()<int8_t>(RDN);
43 Verify.operator()<int8_t>(RNE);
44 Verify.operator()<int8_t>(RNU);
45 Verify.operator()<int8_t>(ROD);
46 Verify.operator()<uint8_t>(RDN);
47 Verify.operator()<uint8_t>(RNE);
48 Verify.operator()<uint8_t>(RNU);
49 Verify.operator()<uint8_t>(ROD);
50 }
51
TEST(Intrinsics,Asub)52 TEST(Intrinsics, Asub) {
53 auto Verify = []<typename T>(int8_t vxrm) {
54 for (int x = std::numeric_limits<T>::min(); x <= std::numeric_limits<T>::max(); ++x) {
55 for (int y = std::numeric_limits<T>::min(); y <= std::numeric_limits<T>::max(); ++y) {
56 // Note: with Aadd we never overflow thus it's enough to compare value of Asub with
57 // Roundoff-produced integer. But with Asub we have to force the result of Roundoff
58 // into smaller type to ensure that we are producing what we are supposed to produce:
59 // for vasub and vasubu, overflow is ignored and the result wraps around.
60 ASSERT_EQ(std::get<0>(Asub<T>(vxrm, x, y)),
61 static_cast<T>(std::get<0>(Roundoff(vxrm, x - y, 1))));
62 }
63 }
64 };
65 Verify.operator()<int8_t>(RDN);
66 Verify.operator()<int8_t>(RNE);
67 Verify.operator()<int8_t>(RNU);
68 Verify.operator()<int8_t>(ROD);
69 Verify.operator()<uint8_t>(RDN);
70 Verify.operator()<uint8_t>(RNE);
71 Verify.operator()<uint8_t>(RNU);
72 Verify.operator()<uint8_t>(ROD);
73 }
74
TEST(Intrinsics,Div)75 TEST(Intrinsics, Div) {
76 ASSERT_EQ(std::get<0>(Div<int8_t>(int8_t{-128}, int8_t{0})), int8_t{-1});
77 ASSERT_EQ(std::get<0>(Div<int8_t>(int8_t{-128}, int8_t{-1})), int8_t{-128});
78 ASSERT_EQ(std::get<0>(Div<int8_t>(int8_t{-128}, int8_t{-2})), int8_t{64});
79 ASSERT_EQ(std::get<0>(Div<uint8_t>(uint8_t{128}, uint8_t{0})), uint8_t{255});
80 ASSERT_EQ(std::get<0>(Div<uint8_t>(uint8_t{128}, uint8_t{1})), uint8_t{128});
81 ASSERT_EQ(std::get<0>(Div<uint8_t>(uint8_t{128}, uint8_t{2})), uint8_t{64});
82 ASSERT_EQ(std::get<0>(Div<int16_t>(int16_t{-32768}, int16_t{0})), int16_t{-1});
83 ASSERT_EQ(std::get<0>(Div<int16_t>(int16_t{-32768}, int16_t{-1})), int16_t{-32768});
84 ASSERT_EQ(std::get<0>(Div<int16_t>(int16_t{-32768}, int16_t{-2})), int16_t{16384});
85 ASSERT_EQ(std::get<0>(Div<uint16_t>(uint16_t{32768}, uint16_t{0})), uint16_t{65535});
86 ASSERT_EQ(std::get<0>(Div<uint16_t>(uint16_t{32768}, uint16_t{1})), uint16_t{32768});
87 ASSERT_EQ(std::get<0>(Div<uint16_t>(uint16_t{32768}, uint16_t{2})), uint16_t{16384});
88 ASSERT_EQ(std::get<0>(Div<int32_t>(int32_t{-2147483648}, int32_t{0})), int32_t{-1});
89 ASSERT_EQ(std::get<0>(Div<int32_t>(int32_t{-2147483648}, int32_t{-1})), int32_t{-2147483648});
90 ASSERT_EQ(std::get<0>(Div<int32_t>(int32_t{-2147483648}, int32_t{-2})), int32_t{1073741824});
91 ASSERT_EQ(std::get<0>(Div<uint32_t>(uint32_t{2147483648}, uint32_t{0})), uint32_t{4294967295});
92 ASSERT_EQ(std::get<0>(Div<uint32_t>(uint32_t{2147483648}, uint32_t{1})), uint32_t{2147483648});
93 ASSERT_EQ(std::get<0>(Div<uint32_t>(uint32_t{2147483648}, uint32_t{2})), uint32_t{1073741824});
94 ASSERT_EQ(std::get<0>(Div<int64_t>(int64_t{-9223372036854775807 - 1}, int64_t{0})), int64_t{-1});
95 ASSERT_EQ(std::get<0>(Div<int64_t>(int64_t{-9223372036854775807 - 1}, int64_t{-1})),
96 int64_t{-9223372036854775807 - 1});
97 ASSERT_EQ(std::get<0>(Div<int64_t>(int64_t{-9223372036854775807 - 1}, int64_t{-2})),
98 int64_t{4611686018427387904});
99 ASSERT_EQ(std::get<0>(Div<uint64_t>(uint64_t{9223372036854775808U}, uint64_t{0})),
100 uint64_t{18446744073709551615U});
101 ASSERT_EQ(std::get<0>(Div<uint64_t>(uint64_t{9223372036854775808U}, uint64_t{1})),
102 uint64_t{9223372036854775808U});
103 ASSERT_EQ(std::get<0>(Div<uint64_t>(uint64_t{9223372036854775808U}, uint64_t{2})),
104 uint64_t{4611686018427387904});
105 }
106
TEST(Intrinsics,RoundOff)107 TEST(Intrinsics, RoundOff) {
108 ASSERT_EQ(std::get<0>(Roundoff<int8_t>(RNE, int8_t{8}, uint8_t{0})), int8_t{8});
109 ASSERT_EQ(std::get<0>(Roundoff<int8_t>(RNE, int8_t{-8}, uint8_t{0})), int8_t{-8});
110 ASSERT_EQ(std::get<0>(Roundoff<int8_t>(RNU, int8_t{65}, uint8_t{2})), int8_t{16});
111 ASSERT_EQ(std::get<0>(Roundoff<int8_t>(RNU, int8_t{-125}, uint8_t{2})), int8_t{-31});
112 ASSERT_EQ(std::get<0>(Roundoff<uint8_t>(RNU, uint8_t{125}, uint8_t{2})), uint8_t{31});
113 ASSERT_EQ(std::get<0>(Roundoff<int8_t>(RNU, int8_t{-125}, uint8_t{2})), int8_t{-31});
114 ASSERT_EQ(std::get<0>(Roundoff<uint8_t>(RNE, uint8_t{125}, uint8_t{2})), uint8_t{31});
115 ASSERT_EQ(std::get<0>(Roundoff<int8_t>(RNE, int8_t{-125}, uint8_t{2})), int8_t{-31});
116 ASSERT_EQ(std::get<0>(Roundoff<uint8_t>(RDN, uint8_t{125}, uint8_t{2})), uint8_t{31});
117 ASSERT_EQ(std::get<0>(Roundoff<int8_t>(RDN, int8_t{-125}, uint8_t{2})), int8_t{-32});
118 ASSERT_EQ(std::get<0>(Roundoff<uint8_t>(ROD, uint8_t{125}, uint8_t{2})), uint8_t{31});
119 ASSERT_EQ(std::get<0>(Roundoff<int8_t>(ROD, int8_t{-125}, uint8_t{2})), int8_t{-31});
120
121 ASSERT_EQ(std::get<0>(Roundoff<int16_t>(RNU, int16_t{-250}, uint16_t{2})), int16_t{-62});
122 ASSERT_EQ(std::get<0>(Roundoff<uint16_t>(RNU, uint16_t{242}, uint16_t{2})), uint16_t{61});
123 ASSERT_EQ(std::get<0>(Roundoff<uint16_t>(RNE, uint16_t{242}, uint16_t{2})), uint16_t{60});
124 ASSERT_EQ(std::get<0>(Roundoff<uint16_t>(RDN, uint16_t{242}, uint16_t{2})), uint16_t{60});
125 ASSERT_EQ(std::get<0>(Roundoff<uint16_t>(ROD, uint16_t{242}, uint16_t{2})), uint16_t{61});
126 ASSERT_EQ(std::get<0>(Roundoff<uint16_t>(RNU, uint16_t{191}, uint16_t{2})), uint16_t{48});
127 ASSERT_EQ(std::get<0>(Roundoff<uint16_t>(RNE, uint16_t{191}, uint16_t{2})), uint16_t{48});
128 ASSERT_EQ(std::get<0>(Roundoff<uint16_t>(RDN, uint16_t{191}, uint16_t{2})), uint16_t{47});
129 ASSERT_EQ(std::get<0>(Roundoff<uint16_t>(ROD, uint16_t{191}, uint16_t{2})), uint16_t{47});
130
131 ASSERT_EQ(std::get<0>(Roundoff<int32_t>(RDN, int32_t{-2147483648}, uint32_t{3})),
132 int32_t{-268435456});
133 ASSERT_EQ(std::get<0>(Roundoff<uint32_t>(ROD, uint32_t{2147483648}, uint32_t{3})),
134 uint32_t{268435456});
135
136 ASSERT_EQ(std::get<0>(Roundoff<int64_t>(RNU, int64_t{-9223372036854775807 - 1}, uint64_t{3})),
137 int64_t{-1152921504606846976});
138 ASSERT_EQ(std::get<0>(Roundoff<uint64_t>(ROD, uint64_t{9223372036854775808U}, uint64_t{4})),
139 uint64_t{576460752303423488});
140 }
141
TEST(Intrinsics,Rsqrt)142 TEST(Intrinsics, Rsqrt) {
143 ASSERT_EQ(RSqrtEstimate<Float64>(Float64{255}), Float64{0.0625});
144 ASSERT_EQ(RSqrtEstimate<Float32>(Float32{255}), Float32{0.0625});
145 ASSERT_EQ(RSqrtEstimate<Float64>(Float64{2000.123}),
146 bit_cast<Float64>(uint64_t(0x3F96E00000000000)));
147 ASSERT_EQ(RSqrtEstimate<Float32>(Float32{2000.123}), bit_cast<Float32>(uint32_t(0x3CB70000)));
148
149 ASSERT_EQ(RSqrtEstimate<Float64>(Float64{0.1123}), Float64{2.984375});
150 ASSERT_EQ(RSqrtEstimate<Float32>(Float32{0.1123}), Float32{2.984375});
151
152 ASSERT_EQ(RSqrtEstimate<Float64>(Float64{0}), std::numeric_limits<Float64>::infinity());
153 ASSERT_EQ(RSqrtEstimate<Float32>(Float32{0}), std::numeric_limits<Float32>::infinity());
154
155 ASSERT_EQ(bit_cast<uint64_t>(RSqrtEstimate<Float64>(Float64{-2.1})),
156 bit_cast<uint64_t>(std::numeric_limits<Float64>::quiet_NaN()));
157 ASSERT_EQ(bit_cast<uint32_t>(RSqrtEstimate<Float32>(Float32{-2.1})),
158 bit_cast<uint32_t>(std::numeric_limits<Float32>::quiet_NaN()));
159 }
160
161 } // namespace
162
163 } // namespace berberis::intrinsics
164