gem5 v24.0.0.0
Loading...
Searching...
No Matches
guest_abi.test.cc
Go to the documentation of this file.
1/*
2 * Copyright 2019 Google, Inc.
3 *
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.
14 *
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.
26 */
27
28#include <gtest/gtest.h>
29
30#include <type_traits>
31#include <utility>
32
33#include "sim/guest_abi.hh"
34
35using namespace gem5;
36
37namespace gem5
38{
39// Fake ThreadContext which holds data and captures results.
41{
42 public:
43 static const int ints[];
44 static const double floats[];
45
46 static const int DefaultIntResult;
47 static const double DefaultFloatResult;
48
51
52 int intOffset = 0;
53};
54
55const int ThreadContext::ints[] = {
56 0, 1, 2, 3, 4, 5, 6, 7
57};
58const double ThreadContext::floats[] = {
59 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0
60};
61
63const double ThreadContext::DefaultFloatResult = 0.0;
64
65} // namespace gem5
66
67// ABI anchor for an ABI which has 1D progress. Conceptually, this could be
68// because integer and floating point arguments are stored in the same
69// registers.
71{
72 using State = int;
73};
74
75// ABI anchor for an ABI which uses the prepare() hook.
77{
78 using State = int;
79};
80
81// ABI anchor for an ABI which has 2D progress. Conceptually, this could be
82// because integer and floating point arguments are stored in separate
83// registers.
85{
87};
88
90{
91 struct State
92 {
93 int pos;
94 State(const ThreadContext *tc) : pos(tc->intOffset) {}
95 };
96};
97
98namespace gem5
99{
100
101namespace guest_abi
102{
103
104// Hooks for the 1D ABI arguments and return value. Add 1 or 1.0 to return
105// values so we can tell they went through the right set of hooks.
106template <>
108{
109 static int
111 {
112 return tc->ints[state++];
113 }
114};
115
116template <typename Arg>
118 typename std::enable_if_t<std::is_floating_point_v<Arg>>>
119{
120 static Arg
122 {
123 return tc->floats[state++];
124 }
125};
126
127template <>
128struct Result<TestABI_1D, int>
129{
130 static void
131 store(ThreadContext *tc, const int &ret)
132 {
133 tc->intResult = ret + 1;
134 }
135};
136
137template <typename Ret>
138struct Result<TestABI_1D, Ret,
139 typename std::enable_if_t<std::is_floating_point_v<Ret>>>
140{
141 static void
142 store(ThreadContext *tc, const Ret &ret)
143 {
144 tc->floatResult = ret + 1.0;
145 }
146};
147
148// Hooks for the ABI which uses prepare(). It uses the same rules as the
149// 1D ABI for arguments, but allocates space for and discards return values
150// and returns integer arguments in reverse order.
151template <>
153{
154 static int
156 {
157 return tc->ints[--state];
158 }
159
160 static void
165};
166
167template <typename Ret>
169{
170 static void store(ThreadContext *tc, const Ret &ret) {}
171 static void
176};
177
178// Hooks for the 2D ABI arguments and return value. Add 2 or 2.0 to return
179// values so we can tell they went through the right set of hooks.
180
181template <>
183{
184 static int
186 {
187 return tc->ints[state.first++];
188 }
189};
190
191template <typename Arg>
193 typename std::enable_if_t<std::is_floating_point_v<Arg>>>
194{
195 static Arg
197 {
198 return tc->floats[state.second++];
199 }
200};
201
202template <>
203struct Result<TestABI_2D, int>
204{
205 static void
206 store(ThreadContext *tc, const int &ret)
207 {
208 tc->intResult = ret + 2;
209 }
210};
211
212template <typename Ret>
213struct Result<TestABI_2D, Ret,
214 typename std::enable_if_t<std::is_floating_point_v<Ret>>>
215{
216 static void
217 store(ThreadContext *tc, const Ret &ret)
218 {
219 tc->floatResult = ret + 2.0;
220 }
221};
222
223// Hooks for the TcInit ABI arguments.
224template <>
226{
227 static int
229 {
230 return tc->ints[state.pos++];
231 }
232};
233
234} // namespace guest_abi
235} // namespace gem5
236
237// Test function which verifies that its arguments reflect the 1D ABI and
238// which doesn't return anything.
239void
240testIntVoid(ThreadContext *tc, int a, float b, int c, double d,
242{
243 EXPECT_EQ(a, tc->ints[0]);
244 EXPECT_EQ(b, tc->floats[1]);
245 EXPECT_EQ(c, tc->ints[2]);
246 EXPECT_EQ(d, tc->floats[3]);
247
248 EXPECT_EQ(varargs.get<int>(), tc->ints[4]);
249 EXPECT_EQ(varargs.get<float>(), tc->floats[5]);
250 EXPECT_EQ(varargs.get<double>(), tc->floats[6]);
251}
252
253// Test functions which verify that the return allocating ABI allocates space
254// for its return value successfully.
255void
257{
258 EXPECT_EQ(a, tc->ints[1]);
259 EXPECT_EQ(b, tc->ints[0]);
260}
261
262int
264{
265 EXPECT_EQ(a, tc->ints[2]);
266 EXPECT_EQ(b, tc->ints[1]);
267 return 0;
268}
269
270// Test function which verifies that its arguments reflect the 2D ABI and
271// which doesn't return anything.
272void
273test2DVoid(ThreadContext *tc, int a, float b, int c, double d,
275{
276 EXPECT_EQ(a, tc->ints[0]);
277 EXPECT_EQ(b, tc->floats[0]);
278 EXPECT_EQ(c, tc->ints[1]);
279 EXPECT_EQ(d, tc->floats[1]);
280
281 EXPECT_EQ(varargs.get<int>(), tc->ints[2]);
282 EXPECT_EQ(varargs.get<float>(), tc->floats[2]);
283 EXPECT_EQ(varargs.get<double>(), tc->floats[3]);
284}
285
286void
288{
289 EXPECT_EQ(tc->intOffset, 2);
290 EXPECT_EQ(a, tc->ints[2]);
291}
292
293// Test functions which returns various types of values.
294const int IntRetValue = 50;
295const float FloatRetValue = 3.14;
296const double DoubleRetValue = 12.34;
297
301
302
303// The actual test bodies.
304TEST(GuestABITest, ABI_1D_args)
305{
306 ThreadContext tc;
308 EXPECT_EQ(tc.intResult, tc.DefaultIntResult);
309 EXPECT_EQ(tc.floatResult, tc.DefaultFloatResult);
310}
311
318
319TEST(GuestABITest, ABI_2D_args)
320{
321 ThreadContext tc;
323 EXPECT_EQ(tc.intResult, tc.DefaultIntResult);
324 EXPECT_EQ(tc.floatResult, tc.DefaultFloatResult);
325}
326
327TEST(GuestABITest, ABI_TC_init)
328{
329 ThreadContext tc;
330 tc.intOffset = 2;
332}
333
334TEST(GuestABITest, ABI_returns)
335{
336 // 1D returns.
337 {
338 ThreadContext tc;
340 EXPECT_EQ(ret, IntRetValue);
341 EXPECT_EQ(tc.intResult, IntRetValue + 1);
342 EXPECT_EQ(tc.floatResult, tc.DefaultFloatResult);
343 }
344 {
345 ThreadContext tc;
346 float ret = invokeSimcall<TestABI_1D>(&tc, testFloatRet);
347 EXPECT_EQ(ret, FloatRetValue);
348 EXPECT_EQ(tc.intResult, tc.DefaultIntResult);
349 EXPECT_EQ(tc.floatResult, FloatRetValue + 1.0);
350 }
351 {
352 ThreadContext tc;
353 double ret = invokeSimcall<TestABI_1D>(&tc, testDoubleRet);
354 EXPECT_EQ(ret, DoubleRetValue);
355 EXPECT_EQ(tc.intResult, tc.DefaultIntResult);
356 EXPECT_EQ(tc.floatResult, DoubleRetValue + 1.0);
357 }
358 {
359 // Disable storing the return value in the ThreadContext.
360 ThreadContext tc;
362 EXPECT_EQ(ret, IntRetValue);
363 EXPECT_EQ(tc.intResult, tc.DefaultIntResult);
364 EXPECT_EQ(tc.floatResult, tc.DefaultFloatResult);
365 }
366
367
368 // 2D returns.
369 {
370 ThreadContext tc;
372 EXPECT_EQ(ret, IntRetValue);
373 EXPECT_EQ(tc.intResult, IntRetValue + 2);
374 EXPECT_EQ(tc.floatResult, tc.DefaultFloatResult);
375 }
376 {
377 ThreadContext tc;
378 float ret = invokeSimcall<TestABI_2D>(&tc, testFloatRet);
379 EXPECT_EQ(ret, FloatRetValue);
380 EXPECT_EQ(tc.intResult, tc.DefaultIntResult);
381 EXPECT_EQ(tc.floatResult, FloatRetValue + 2.0);
382 }
383 {
384 ThreadContext tc;
385 double ret = invokeSimcall<TestABI_2D>(&tc, testDoubleRet);
386 EXPECT_EQ(ret, DoubleRetValue);
387 EXPECT_EQ(tc.intResult, tc.DefaultIntResult);
388 EXPECT_EQ(tc.floatResult, DoubleRetValue + 2.0);
389 }
390}
391
392TEST(GuestABITest, dumpSimcall)
393{
394 ThreadContext tc;
395 std::string dump = dumpSimcall<TestABI_1D>("test", &tc, testIntVoid);
396 EXPECT_EQ(dump, "test(0, 11, 2, 13, ...)");
397}
398
399TEST(GuestABITest, isVarArgs)
400{
402 EXPECT_FALSE(guest_abi::IsVarArgsV<int>);
403 EXPECT_FALSE(guest_abi::IsVarArgsV<double>);
404 struct FooStruct {};
406 union FooUnion {};
408}
ThreadContext is the external interface to all thread state for anything outside of the CPU.
static const int ints[]
static const double DefaultFloatResult
static const int DefaultIntResult
static const double floats[]
const float FloatRetValue
void testTcInit(ThreadContext *tc, int a)
const int IntRetValue
void test2DVoid(ThreadContext *tc, int a, float b, int c, double d, guest_abi::VarArgs< int, float, double > varargs)
void testIntVoid(ThreadContext *tc, int a, float b, int c, double d, guest_abi::VarArgs< int, float, double > varargs)
void testPrepareVoid(ThreadContext *tc, int a, int b)
int testPrepareInt(ThreadContext *tc, int a, int b)
const double DoubleRetValue
TEST(GuestABITest, ABI_1D_args)
double testDoubleRet(ThreadContext *tc)
int testIntRet(ThreadContext *tc)
float testFloatRet(ThreadContext *tc)
atomic_var_t state
Definition helpers.cc:211
Bitfield< 7 > b
Bitfield< 29 > c
Definition misc_types.hh:53
Bitfield< 8 > a
Definition misc_types.hh:66
Bitfield< 9 > d
Definition misc_types.hh:64
constexpr bool IsVarArgsV
Definition varargs.hh:179
void dump()
Dump all statistics data to the registered outputs.
Copyright (c) 2024 - Pranith Kumar Copyright (c) 2020 Inria All rights reserved.
Definition binary32.hh:36
std::string dumpSimcall(std::string name, ThreadContext *tc, std::function< Ret(ThreadContext *, Args...)> target=std::function< Ret(ThreadContext *, Args...)>())
Definition guest_abi.hh:111
Ret invokeSimcall(ThreadContext *tc, std::function< Ret(ThreadContext *, Args...)> target)
Definition guest_abi.hh:50
Overload hash function for BasicBlockRange type.
Definition binary32.hh:81
State(const ThreadContext *tc)
static int get(ThreadContext *tc, TestABI_1D::State &state)
static int get(ThreadContext *tc, TestABI_2D::State &state)
static int get(ThreadContext *tc, TestABI_Prepare::State &state)
static void prepare(ThreadContext *tc, TestABI_Prepare::State &state)
static int get(ThreadContext *tc, TestABI_TcInit::State &state)
static void store(ThreadContext *tc, const int &ret)
static void store(ThreadContext *tc, const int &ret)
static void store(ThreadContext *tc, const Ret &ret)
static void prepare(ThreadContext *tc, TestABI_Prepare::State &state)

Generated on Tue Jun 18 2024 16:24:06 for gem5 by doxygen 1.11.0