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