2 * Copyright 2019 Google, Inc.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met: redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer;
8 * redistributions in binary form must reproduce the above copyright
9 * notice, this list of conditions and the following disclaimer in the
10 * documentation and/or other materials provided with the distribution;
11 * neither the name of the copyright holders nor the names of its
12 * contributors may be used to endorse or promote products derived from
13 * this software without specific prior written permission.
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include <gtest/gtest.h>
30 #include <type_traits>
33 #include "sim/guest_abi.hh"
35 // Fake ThreadContext which holds data and captures results.
39 static const int ints
[];
40 static const double floats
[];
42 static const int DefaultIntResult
;
43 static const double DefaultFloatResult
;
45 int intResult
= DefaultIntResult
;
46 double floatResult
= DefaultFloatResult
;
51 const int ThreadContext::ints
[] = {
52 0, 1, 2, 3, 4, 5, 6, 7
54 const double ThreadContext::floats
[] = {
55 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0
58 const int ThreadContext::DefaultIntResult
= 0;
59 const double ThreadContext::DefaultFloatResult
= 0.0;
61 // ABI anchor for an ABI which has 1D progress. Conceptually, this could be
62 // because integer and floating point arguments are stored in the same
69 // ABI anchor for an ABI which uses the prepare() hook.
70 struct TestABI_Prepare
75 // ABI anchor for an ABI which has 2D progress. Conceptually, this could be
76 // because integer and floating point arguments are stored in separate
80 using State
= std::pair
<int, int>;
88 State(const ThreadContext
*tc
) : pos(tc
->intOffset
) {}
95 // Hooks for the 1D ABI arguments and return value. Add 1 or 1.0 to return
96 // values so we can tell they went through the right set of hooks.
98 struct Argument
<TestABI_1D
, int>
101 get(ThreadContext
*tc
, TestABI_1D::State
&state
)
103 return tc
->ints
[state
++];
107 template <typename Arg
>
108 struct Argument
<TestABI_1D
, Arg
,
109 typename
std::enable_if_t
<std::is_floating_point
<Arg
>::value
>>
112 get(ThreadContext
*tc
, TestABI_1D::State
&state
)
114 return tc
->floats
[state
++];
119 struct Result
<TestABI_1D
, int>
122 store(ThreadContext
*tc
, const int &ret
)
124 tc
->intResult
= ret
+ 1;
128 template <typename Ret
>
129 struct Result
<TestABI_1D
, Ret
,
130 typename
std::enable_if_t
<std::is_floating_point
<Ret
>::value
>>
133 store(ThreadContext
*tc
, const Ret
&ret
)
135 tc
->floatResult
= ret
+ 1.0;
139 // Hooks for the ABI which uses prepare(). It uses the same rules as the
140 // 1D ABI for arguments, but allocates space for and discards return values
141 // and returns integer arguments in reverse order.
143 struct Argument
<TestABI_Prepare
, int>
146 get(ThreadContext
*tc
, TestABI_Prepare::State
&state
)
148 return tc
->ints
[--state
];
152 prepare(ThreadContext
*tc
, TestABI_Prepare::State
&state
)
158 template <typename Ret
>
159 struct Result
<TestABI_Prepare
, Ret
>
161 static void store(ThreadContext
*tc
, const Ret
&ret
) {}
163 prepare(ThreadContext
*tc
, TestABI_Prepare::State
&state
)
169 // Hooks for the 2D ABI arguments and return value. Add 2 or 2.0 to return
170 // values so we can tell they went through the right set of hooks.
173 struct Argument
<TestABI_2D
, int>
176 get(ThreadContext
*tc
, TestABI_2D::State
&state
)
178 return tc
->ints
[state
.first
++];
182 template <typename Arg
>
183 struct Argument
<TestABI_2D
, Arg
,
184 typename
std::enable_if_t
<std::is_floating_point
<Arg
>::value
>>
187 get(ThreadContext
*tc
, TestABI_2D::State
&state
)
189 return tc
->floats
[state
.second
++];
194 struct Result
<TestABI_2D
, int>
197 store(ThreadContext
*tc
, const int &ret
)
199 tc
->intResult
= ret
+ 2;
203 template <typename Ret
>
204 struct Result
<TestABI_2D
, Ret
,
205 typename
std::enable_if_t
<std::is_floating_point
<Ret
>::value
>>
208 store(ThreadContext
*tc
, const Ret
&ret
)
210 tc
->floatResult
= ret
+ 2.0;
214 // Hooks for the TcInit ABI arguments.
216 struct Argument
<TestABI_TcInit
, int>
219 get(ThreadContext
*tc
, TestABI_TcInit::State
&state
)
221 return tc
->ints
[state
.pos
++];
225 } // namespace GuestABI
227 // Test function which verifies that its arguments reflect the 1D ABI and
228 // which doesn't return anything.
230 testIntVoid(ThreadContext
*tc
, int a
, float b
, int c
, double d
,
231 GuestABI::VarArgs
<int,float,double> varargs
)
233 EXPECT_EQ(a
, tc
->ints
[0]);
234 EXPECT_EQ(b
, tc
->floats
[1]);
235 EXPECT_EQ(c
, tc
->ints
[2]);
236 EXPECT_EQ(d
, tc
->floats
[3]);
238 EXPECT_EQ(varargs
.get
<int>(), tc
->ints
[4]);
239 EXPECT_EQ(varargs
.get
<float>(), tc
->floats
[5]);
240 EXPECT_EQ(varargs
.get
<double>(), tc
->floats
[6]);
243 // Test functions which verify that the return allocating ABI allocates space
244 // for its return value successfully.
246 testPrepareVoid(ThreadContext
*tc
, int a
, int b
)
248 EXPECT_EQ(a
, tc
->ints
[1]);
249 EXPECT_EQ(b
, tc
->ints
[0]);
253 testPrepareInt(ThreadContext
*tc
, int a
, int b
)
255 EXPECT_EQ(a
, tc
->ints
[2]);
256 EXPECT_EQ(b
, tc
->ints
[1]);
260 // Test function which verifies that its arguments reflect the 2D ABI and
261 // which doesn't return anything.
263 test2DVoid(ThreadContext
*tc
, int a
, float b
, int c
, double d
,
264 GuestABI::VarArgs
<int,float,double> varargs
)
266 EXPECT_EQ(a
, tc
->ints
[0]);
267 EXPECT_EQ(b
, tc
->floats
[0]);
268 EXPECT_EQ(c
, tc
->ints
[1]);
269 EXPECT_EQ(d
, tc
->floats
[1]);
271 EXPECT_EQ(varargs
.get
<int>(), tc
->ints
[2]);
272 EXPECT_EQ(varargs
.get
<float>(), tc
->floats
[2]);
273 EXPECT_EQ(varargs
.get
<double>(), tc
->floats
[3]);
277 testTcInit(ThreadContext
*tc
, int a
)
279 EXPECT_EQ(tc
->intOffset
, 2);
280 EXPECT_EQ(a
, tc
->ints
[2]);
283 // Test functions which returns various types of values.
284 const int IntRetValue
= 50;
285 const float FloatRetValue
= 3.14;
286 const double DoubleRetValue
= 12.34;
288 int testIntRet(ThreadContext
*tc
) { return IntRetValue
; }
289 float testFloatRet(ThreadContext
*tc
) { return FloatRetValue
; }
290 double testDoubleRet(ThreadContext
*tc
) { return DoubleRetValue
; }
293 // The actual test bodies.
294 TEST(GuestABI
, ABI_1D_args
)
297 invokeSimcall
<TestABI_1D
>(&tc
, testIntVoid
);
298 EXPECT_EQ(tc
.intResult
, tc
.DefaultIntResult
);
299 EXPECT_EQ(tc
.floatResult
, tc
.DefaultFloatResult
);
302 TEST(GuestABI
, ABI_Prepare
)
305 invokeSimcall
<TestABI_Prepare
>(&tc
, testPrepareVoid
);
306 invokeSimcall
<TestABI_Prepare
>(&tc
, testPrepareInt
);
309 TEST(GuestABI
, ABI_2D_args
)
312 invokeSimcall
<TestABI_2D
>(&tc
, test2DVoid
);
313 EXPECT_EQ(tc
.intResult
, tc
.DefaultIntResult
);
314 EXPECT_EQ(tc
.floatResult
, tc
.DefaultFloatResult
);
317 TEST(GuestABI
, ABI_TC_init
)
321 invokeSimcall
<TestABI_TcInit
>(&tc
, testTcInit
);
324 TEST(GuestABI
, ABI_returns
)
329 int ret
= invokeSimcall
<TestABI_1D
>(&tc
, testIntRet
);
330 EXPECT_EQ(ret
, IntRetValue
);
331 EXPECT_EQ(tc
.intResult
, IntRetValue
+ 1);
332 EXPECT_EQ(tc
.floatResult
, tc
.DefaultFloatResult
);
336 float ret
= invokeSimcall
<TestABI_1D
>(&tc
, testFloatRet
);
337 EXPECT_EQ(ret
, FloatRetValue
);
338 EXPECT_EQ(tc
.intResult
, tc
.DefaultIntResult
);
339 EXPECT_EQ(tc
.floatResult
, FloatRetValue
+ 1.0);
343 double ret
= invokeSimcall
<TestABI_1D
>(&tc
, testDoubleRet
);
344 EXPECT_EQ(ret
, DoubleRetValue
);
345 EXPECT_EQ(tc
.intResult
, tc
.DefaultIntResult
);
346 EXPECT_EQ(tc
.floatResult
, DoubleRetValue
+ 1.0);
349 // Disable storing the return value in the ThreadContext.
351 int ret
= invokeSimcall
<TestABI_1D
, false>(&tc
, testIntRet
);
352 EXPECT_EQ(ret
, IntRetValue
);
353 EXPECT_EQ(tc
.intResult
, tc
.DefaultIntResult
);
354 EXPECT_EQ(tc
.floatResult
, tc
.DefaultFloatResult
);
361 int ret
= invokeSimcall
<TestABI_2D
>(&tc
, testIntRet
);
362 EXPECT_EQ(ret
, IntRetValue
);
363 EXPECT_EQ(tc
.intResult
, IntRetValue
+ 2);
364 EXPECT_EQ(tc
.floatResult
, tc
.DefaultFloatResult
);
368 float ret
= invokeSimcall
<TestABI_2D
>(&tc
, testFloatRet
);
369 EXPECT_EQ(ret
, FloatRetValue
);
370 EXPECT_EQ(tc
.intResult
, tc
.DefaultIntResult
);
371 EXPECT_EQ(tc
.floatResult
, FloatRetValue
+ 2.0);
375 double ret
= invokeSimcall
<TestABI_2D
>(&tc
, testDoubleRet
);
376 EXPECT_EQ(ret
, DoubleRetValue
);
377 EXPECT_EQ(tc
.intResult
, tc
.DefaultIntResult
);
378 EXPECT_EQ(tc
.floatResult
, DoubleRetValue
+ 2.0);
382 TEST(GuestABI
, dumpSimcall
)
385 std::string dump
= dumpSimcall
<TestABI_1D
>("test", &tc
, testIntVoid
);
386 EXPECT_EQ(dump
, "test(0, 11, 2, 13, ...)");
389 TEST(GuestABI
, isVarArgs
)
391 EXPECT_TRUE(GuestABI::IsVarArgs
<GuestABI::VarArgs
<int>>::value
);
392 EXPECT_FALSE(GuestABI::IsVarArgs
<int>::value
);
393 EXPECT_FALSE(GuestABI::IsVarArgs
<double>::value
);
395 EXPECT_FALSE(GuestABI::IsVarArgs
<FooStruct
>::value
);
397 EXPECT_FALSE(GuestABI::IsVarArgs
<FooUnion
>::value
);