gem5  v22.1.0.0
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 
35 using namespace gem5;
36 
37 namespace gem5
38 {
39 // Fake ThreadContext which holds data and captures results.
40 class ThreadContext
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 
55 const int ThreadContext::ints[] = {
56  0, 1, 2, 3, 4, 5, 6, 7
57 };
58 const double ThreadContext::floats[] = {
59  10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0
60 };
61 
63 const 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.
70 struct TestABI_1D
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.
84 struct TestABI_2D
85 {
87 };
88 
90 {
91  struct State
92  {
93  int pos;
94  State(const ThreadContext *tc) : pos(tc->intOffset) {}
95  };
96 };
97 
98 namespace gem5
99 {
100 
101 GEM5_DEPRECATED_NAMESPACE(GuestABI, guest_abi);
102 namespace guest_abi
103 {
104 
105 // Hooks for the 1D ABI arguments and return value. Add 1 or 1.0 to return
106 // values so we can tell they went through the right set of hooks.
107 template <>
108 struct Argument<TestABI_1D, int>
109 {
110  static int
112  {
113  return tc->ints[state++];
114  }
115 };
116 
117 template <typename Arg>
118 struct Argument<TestABI_1D, Arg,
119  typename std::enable_if_t<std::is_floating_point_v<Arg>>>
120 {
121  static Arg
123  {
124  return tc->floats[state++];
125  }
126 };
127 
128 template <>
129 struct Result<TestABI_1D, int>
130 {
131  static void
132  store(ThreadContext *tc, const int &ret)
133  {
134  tc->intResult = ret + 1;
135  }
136 };
137 
138 template <typename Ret>
139 struct Result<TestABI_1D, Ret,
140  typename std::enable_if_t<std::is_floating_point_v<Ret>>>
141 {
142  static void
143  store(ThreadContext *tc, const Ret &ret)
144  {
145  tc->floatResult = ret + 1.0;
146  }
147 };
148 
149 // Hooks for the ABI which uses prepare(). It uses the same rules as the
150 // 1D ABI for arguments, but allocates space for and discards return values
151 // and returns integer arguments in reverse order.
152 template <>
154 {
155  static int
157  {
158  return tc->ints[--state];
159  }
160 
161  static void
163  {
164  state++;
165  }
166 };
167 
168 template <typename Ret>
170 {
171  static void store(ThreadContext *tc, const Ret &ret) {}
172  static void
174  {
175  state++;
176  }
177 };
178 
179 // Hooks for the 2D ABI arguments and return value. Add 2 or 2.0 to return
180 // values so we can tell they went through the right set of hooks.
181 
182 template <>
183 struct Argument<TestABI_2D, int>
184 {
185  static int
187  {
188  return tc->ints[state.first++];
189  }
190 };
191 
192 template <typename Arg>
193 struct Argument<TestABI_2D, Arg,
194  typename std::enable_if_t<std::is_floating_point_v<Arg>>>
195 {
196  static Arg
198  {
199  return tc->floats[state.second++];
200  }
201 };
202 
203 template <>
204 struct Result<TestABI_2D, int>
205 {
206  static void
207  store(ThreadContext *tc, const int &ret)
208  {
209  tc->intResult = ret + 2;
210  }
211 };
212 
213 template <typename Ret>
214 struct Result<TestABI_2D, Ret,
215  typename std::enable_if_t<std::is_floating_point_v<Ret>>>
216 {
217  static void
218  store(ThreadContext *tc, const Ret &ret)
219  {
220  tc->floatResult = ret + 2.0;
221  }
222 };
223 
224 // Hooks for the TcInit ABI arguments.
225 template <>
227 {
228  static int
230  {
231  return tc->ints[state.pos++];
232  }
233 };
234 
235 } // namespace guest_abi
236 } // namespace gem5
237 
238 // Test function which verifies that its arguments reflect the 1D ABI and
239 // which doesn't return anything.
240 void
241 testIntVoid(ThreadContext *tc, int a, float b, int c, double d,
243 {
244  EXPECT_EQ(a, tc->ints[0]);
245  EXPECT_EQ(b, tc->floats[1]);
246  EXPECT_EQ(c, tc->ints[2]);
247  EXPECT_EQ(d, tc->floats[3]);
248 
249  EXPECT_EQ(varargs.get<int>(), tc->ints[4]);
250  EXPECT_EQ(varargs.get<float>(), tc->floats[5]);
251  EXPECT_EQ(varargs.get<double>(), tc->floats[6]);
252 }
253 
254 // Test functions which verify that the return allocating ABI allocates space
255 // for its return value successfully.
256 void
258 {
259  EXPECT_EQ(a, tc->ints[1]);
260  EXPECT_EQ(b, tc->ints[0]);
261 }
262 
263 int
265 {
266  EXPECT_EQ(a, tc->ints[2]);
267  EXPECT_EQ(b, tc->ints[1]);
268  return 0;
269 }
270 
271 // Test function which verifies that its arguments reflect the 2D ABI and
272 // which doesn't return anything.
273 void
274 test2DVoid(ThreadContext *tc, int a, float b, int c, double d,
276 {
277  EXPECT_EQ(a, tc->ints[0]);
278  EXPECT_EQ(b, tc->floats[0]);
279  EXPECT_EQ(c, tc->ints[1]);
280  EXPECT_EQ(d, tc->floats[1]);
281 
282  EXPECT_EQ(varargs.get<int>(), tc->ints[2]);
283  EXPECT_EQ(varargs.get<float>(), tc->floats[2]);
284  EXPECT_EQ(varargs.get<double>(), tc->floats[3]);
285 }
286 
287 void
289 {
290  EXPECT_EQ(tc->intOffset, 2);
291  EXPECT_EQ(a, tc->ints[2]);
292 }
293 
294 // Test functions which returns various types of values.
295 const int IntRetValue = 50;
296 const float FloatRetValue = 3.14;
297 const double DoubleRetValue = 12.34;
298 
302 
303 
304 // The actual test bodies.
305 TEST(GuestABITest, ABI_1D_args)
306 {
307  ThreadContext tc;
308  invokeSimcall<TestABI_1D>(&tc, testIntVoid);
309  EXPECT_EQ(tc.intResult, tc.DefaultIntResult);
310  EXPECT_EQ(tc.floatResult, tc.DefaultFloatResult);
311 }
312 
313 TEST(GuestABITest, ABI_Prepare)
314 {
315  ThreadContext tc;
316  invokeSimcall<TestABI_Prepare>(&tc, testPrepareVoid);
317  invokeSimcall<TestABI_Prepare>(&tc, testPrepareInt);
318 }
319 
320 TEST(GuestABITest, ABI_2D_args)
321 {
322  ThreadContext tc;
323  invokeSimcall<TestABI_2D>(&tc, test2DVoid);
324  EXPECT_EQ(tc.intResult, tc.DefaultIntResult);
325  EXPECT_EQ(tc.floatResult, tc.DefaultFloatResult);
326 }
327 
328 TEST(GuestABITest, ABI_TC_init)
329 {
330  ThreadContext tc;
331  tc.intOffset = 2;
332  invokeSimcall<TestABI_TcInit>(&tc, testTcInit);
333 }
334 
335 TEST(GuestABITest, ABI_returns)
336 {
337  // 1D returns.
338  {
339  ThreadContext tc;
340  int ret = invokeSimcall<TestABI_1D>(&tc, testIntRet);
341  EXPECT_EQ(ret, IntRetValue);
342  EXPECT_EQ(tc.intResult, IntRetValue + 1);
343  EXPECT_EQ(tc.floatResult, tc.DefaultFloatResult);
344  }
345  {
346  ThreadContext tc;
347  float ret = invokeSimcall<TestABI_1D>(&tc, testFloatRet);
348  EXPECT_EQ(ret, FloatRetValue);
349  EXPECT_EQ(tc.intResult, tc.DefaultIntResult);
350  EXPECT_EQ(tc.floatResult, FloatRetValue + 1.0);
351  }
352  {
353  ThreadContext tc;
354  double ret = invokeSimcall<TestABI_1D>(&tc, testDoubleRet);
355  EXPECT_EQ(ret, DoubleRetValue);
356  EXPECT_EQ(tc.intResult, tc.DefaultIntResult);
357  EXPECT_EQ(tc.floatResult, DoubleRetValue + 1.0);
358  }
359  {
360  // Disable storing the return value in the ThreadContext.
361  ThreadContext tc;
362  int ret = invokeSimcall<TestABI_1D, false>(&tc, testIntRet);
363  EXPECT_EQ(ret, IntRetValue);
364  EXPECT_EQ(tc.intResult, tc.DefaultIntResult);
365  EXPECT_EQ(tc.floatResult, tc.DefaultFloatResult);
366  }
367 
368 
369  // 2D returns.
370  {
371  ThreadContext tc;
372  int ret = invokeSimcall<TestABI_2D>(&tc, testIntRet);
373  EXPECT_EQ(ret, IntRetValue);
374  EXPECT_EQ(tc.intResult, IntRetValue + 2);
375  EXPECT_EQ(tc.floatResult, tc.DefaultFloatResult);
376  }
377  {
378  ThreadContext tc;
379  float ret = invokeSimcall<TestABI_2D>(&tc, testFloatRet);
380  EXPECT_EQ(ret, FloatRetValue);
381  EXPECT_EQ(tc.intResult, tc.DefaultIntResult);
382  EXPECT_EQ(tc.floatResult, FloatRetValue + 2.0);
383  }
384  {
385  ThreadContext tc;
386  double ret = invokeSimcall<TestABI_2D>(&tc, testDoubleRet);
387  EXPECT_EQ(ret, DoubleRetValue);
388  EXPECT_EQ(tc.intResult, tc.DefaultIntResult);
389  EXPECT_EQ(tc.floatResult, DoubleRetValue + 2.0);
390  }
391 }
392 
393 TEST(GuestABITest, dumpSimcall)
394 {
395  ThreadContext tc;
396  std::string dump = dumpSimcall<TestABI_1D>("test", &tc, testIntVoid);
397  EXPECT_EQ(dump, "test(0, 11, 2, 13, ...)");
398 }
399 
400 TEST(GuestABITest, isVarArgs)
401 {
403  EXPECT_FALSE(guest_abi::IsVarArgsV<int>);
404  EXPECT_FALSE(guest_abi::IsVarArgsV<double>);
405  struct FooStruct {};
406  EXPECT_FALSE(guest_abi::IsVarArgsV<FooStruct>);
407  union FooUnion {};
408  EXPECT_FALSE(guest_abi::IsVarArgsV<FooUnion>);
409 }
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[]
STL pair class.
Definition: stl.hh:58
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:188
Bitfield< 7 > b
Definition: misc_types.hh:388
Bitfield< 8 > a
Definition: misc_types.hh:66
Bitfield< 9 > d
Definition: misc_types.hh:64
Bitfield< 2 > c
Definition: pagetable.hh:63
constexpr bool IsVarArgsV
Definition: varargs.hh:180
void dump()
Dump all statistics data to the registered outputs.
Definition: statistics.cc:301
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
std::string dumpSimcall(std::string name, ThreadContext *tc, std::function< Ret(ThreadContext *, Args...)> target=std::function< Ret(ThreadContext *, Args...)>())
Definition: guest_abi.hh:111
GEM5_DEPRECATED_NAMESPACE(GuestABI, guest_abi)
Overload hash function for BasicBlockRange type.
Definition: misc.hh:2826
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 Wed Dec 21 2022 10:22:39 for gem5 by doxygen 1.9.1