gem5  [DEVELOP-FOR-23.0]
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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 namespace 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.
106 template <>
107 struct Argument<TestABI_1D, int>
108 {
109  static int
111  {
112  return tc->ints[state++];
113  }
114 };
115 
116 template <typename Arg>
117 struct Argument<TestABI_1D, 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 
127 template <>
128 struct Result<TestABI_1D, int>
129 {
130  static void
131  store(ThreadContext *tc, const int &ret)
132  {
133  tc->intResult = ret + 1;
134  }
135 };
136 
137 template <typename Ret>
138 struct 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.
151 template <>
153 {
154  static int
156  {
157  return tc->ints[--state];
158  }
159 
160  static void
162  {
163  state++;
164  }
165 };
166 
167 template <typename Ret>
169 {
170  static void store(ThreadContext *tc, const Ret &ret) {}
171  static void
173  {
174  state++;
175  }
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 
181 template <>
182 struct Argument<TestABI_2D, int>
183 {
184  static int
186  {
187  return tc->ints[state.first++];
188  }
189 };
190 
191 template <typename Arg>
192 struct Argument<TestABI_2D, 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 
202 template <>
203 struct Result<TestABI_2D, int>
204 {
205  static void
206  store(ThreadContext *tc, const int &ret)
207  {
208  tc->intResult = ret + 2;
209  }
210 };
211 
212 template <typename Ret>
213 struct 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.
224 template <>
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.
239 void
240 testIntVoid(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.
255 void
257 {
258  EXPECT_EQ(a, tc->ints[1]);
259  EXPECT_EQ(b, tc->ints[0]);
260 }
261 
262 int
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.
272 void
273 test2DVoid(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 
286 void
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.
294 const int IntRetValue = 50;
295 const float FloatRetValue = 3.14;
296 const double DoubleRetValue = 12.34;
297 
301 
302 
303 // The actual test bodies.
304 TEST(GuestABITest, ABI_1D_args)
305 {
306  ThreadContext tc;
307  invokeSimcall<TestABI_1D>(&tc, testIntVoid);
308  EXPECT_EQ(tc.intResult, tc.DefaultIntResult);
309  EXPECT_EQ(tc.floatResult, tc.DefaultFloatResult);
310 }
311 
312 TEST(GuestABITest, ABI_Prepare)
313 {
314  ThreadContext tc;
315  invokeSimcall<TestABI_Prepare>(&tc, testPrepareVoid);
316  invokeSimcall<TestABI_Prepare>(&tc, testPrepareInt);
317 }
318 
319 TEST(GuestABITest, ABI_2D_args)
320 {
321  ThreadContext tc;
322  invokeSimcall<TestABI_2D>(&tc, test2DVoid);
323  EXPECT_EQ(tc.intResult, tc.DefaultIntResult);
324  EXPECT_EQ(tc.floatResult, tc.DefaultFloatResult);
325 }
326 
327 TEST(GuestABITest, ABI_TC_init)
328 {
329  ThreadContext tc;
330  tc.intOffset = 2;
331  invokeSimcall<TestABI_TcInit>(&tc, testTcInit);
332 }
333 
334 TEST(GuestABITest, ABI_returns)
335 {
336  // 1D returns.
337  {
338  ThreadContext tc;
339  int ret = invokeSimcall<TestABI_1D>(&tc, testIntRet);
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;
361  int ret = invokeSimcall<TestABI_1D, false>(&tc, testIntRet);
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;
371  int ret = invokeSimcall<TestABI_2D>(&tc, testIntRet);
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 
392 TEST(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 
399 TEST(GuestABITest, isVarArgs)
400 {
402  EXPECT_FALSE(guest_abi::IsVarArgsV<int>);
403  EXPECT_FALSE(guest_abi::IsVarArgsV<double>);
404  struct FooStruct {};
405  EXPECT_FALSE(guest_abi::IsVarArgsV<FooStruct>);
406  union FooUnion {};
407  EXPECT_FALSE(guest_abi::IsVarArgsV<FooUnion>);
408 }
TestABI_2D
Definition: guest_abi.test.cc:84
testIntVoid
void testIntVoid(ThreadContext *tc, int a, float b, int c, double d, guest_abi::VarArgs< int, float, double > varargs)
Definition: guest_abi.test.cc:240
TestABI_TcInit
Definition: guest_abi.test.cc:89
gem5::ThreadContext::ints
static const int ints[]
Definition: guest_abi.test.cc:43
TestABI_TcInit::State::pos
int pos
Definition: guest_abi.test.cc:93
gem5::guest_abi::Result< TestABI_Prepare, Ret >::prepare
static void prepare(ThreadContext *tc, TestABI_Prepare::State &state)
Definition: guest_abi.test.cc:172
IntRetValue
const int IntRetValue
Definition: guest_abi.test.cc:294
gem5::ThreadContext::DefaultIntResult
static const int DefaultIntResult
Definition: guest_abi.test.cc:46
gem5::guest_abi::VarArgs::get
Arg get()
Definition: varargs.hh:164
gem5::ArmISA::a
Bitfield< 8 > a
Definition: misc_types.hh:66
gem5::ThreadContext::floats
static const double floats[]
Definition: guest_abi.test.cc:44
testFloatRet
float testFloatRet(ThreadContext *tc)
Definition: guest_abi.test.cc:299
gem5::ThreadContext::intOffset
int intOffset
Definition: guest_abi.test.cc:52
gem5::guest_abi::Argument< TestABI_Prepare, int >::get
static int get(ThreadContext *tc, TestABI_Prepare::State &state)
Definition: guest_abi.test.cc:155
TestABI_TcInit::State
Definition: guest_abi.test.cc:91
gem5::guest_abi::Result< TestABI_2D, int >::store
static void store(ThreadContext *tc, const int &ret)
Definition: guest_abi.test.cc:206
gem5::VegaISA::c
Bitfield< 2 > c
Definition: pagetable.hh:63
gem5::ThreadContext::floatResult
double floatResult
Definition: guest_abi.test.cc:50
testDoubleRet
double testDoubleRet(ThreadContext *tc)
Definition: guest_abi.test.cc:300
TestABI_Prepare::State
int State
Definition: guest_abi.test.cc:78
gem5::ArmISA::b
Bitfield< 7 > b
Definition: misc_types.hh:438
gem5::ThreadContext::DefaultFloatResult
static const double DefaultFloatResult
Definition: guest_abi.test.cc:47
gem5::ThreadContext
ThreadContext is the external interface to all thread state for anything outside of the CPU.
Definition: thread_context.hh:88
testPrepareVoid
void testPrepareVoid(ThreadContext *tc, int a, int b)
Definition: guest_abi.test.cc:256
testTcInit
void testTcInit(ThreadContext *tc, int a)
Definition: guest_abi.test.cc:287
gem5::ArmISA::d
Bitfield< 9 > d
Definition: misc_types.hh:64
TEST
TEST(GuestABITest, ABI_1D_args)
Definition: guest_abi.test.cc:304
testIntRet
int testIntRet(ThreadContext *tc)
Definition: guest_abi.test.cc:298
gem5::dumpSimcall
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::statistics::dump
void dump()
Dump all statistics data to the registered outputs.
Definition: statistics.cc:300
gem5::guest_abi::IsVarArgsV
constexpr bool IsVarArgsV
Definition: varargs.hh:179
gem5::guest_abi::Argument< TestABI_2D, Arg, typename std::enable_if_t< std::is_floating_point_v< Arg > > >::get
static Arg get(ThreadContext *tc, TestABI_2D::State &state)
Definition: guest_abi.test.cc:196
gem5::guest_abi::Result< TestABI_1D, int >::store
static void store(ThreadContext *tc, const int &ret)
Definition: guest_abi.test.cc:131
TestABI_1D
Definition: guest_abi.test.cc:70
std::pair< int, int >
gem5::guest_abi::Result< TestABI_1D, Ret, typename std::enable_if_t< std::is_floating_point_v< Ret > > >::store
static void store(ThreadContext *tc, const Ret &ret)
Definition: guest_abi.test.cc:142
FloatRetValue
const float FloatRetValue
Definition: guest_abi.test.cc:295
gem5::guest_abi::Argument< TestABI_2D, int >::get
static int get(ThreadContext *tc, TestABI_2D::State &state)
Definition: guest_abi.test.cc:185
state
atomic_var_t state
Definition: helpers.cc:188
TestABI_1D::State
int State
Definition: guest_abi.test.cc:72
std
Overload hash function for BasicBlockRange type.
Definition: misc.hh:2909
gem5::guest_abi::Argument< TestABI_Prepare, int >::prepare
static void prepare(ThreadContext *tc, TestABI_Prepare::State &state)
Definition: guest_abi.test.cc:161
guest_abi.hh
TestABI_TcInit::State::State
State(const ThreadContext *tc)
Definition: guest_abi.test.cc:94
gem5::ThreadContext::intResult
int intResult
Definition: guest_abi.test.cc:49
gem5::guest_abi::Result< TestABI_Prepare, Ret >::store
static void store(ThreadContext *tc, const Ret &ret)
Definition: guest_abi.test.cc:170
gem5::guest_abi::Argument
Definition: definition.hh:98
gem5::guest_abi::VarArgs
Definition: varargs.hh:149
gem5::guest_abi::Result
Definition: definition.hh:63
gem5
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
Definition: gpu_translation_state.hh:37
testPrepareInt
int testPrepareInt(ThreadContext *tc, int a, int b)
Definition: guest_abi.test.cc:263
test2DVoid
void test2DVoid(ThreadContext *tc, int a, float b, int c, double d, guest_abi::VarArgs< int, float, double > varargs)
Definition: guest_abi.test.cc:273
DoubleRetValue
const double DoubleRetValue
Definition: guest_abi.test.cc:296
gem5::guest_abi::Argument< TestABI_1D, Arg, typename std::enable_if_t< std::is_floating_point_v< Arg > > >::get
static Arg get(ThreadContext *tc, TestABI_1D::State &state)
Definition: guest_abi.test.cc:121
TestABI_Prepare
Definition: guest_abi.test.cc:76
gem5::guest_abi::Argument< TestABI_TcInit, int >::get
static int get(ThreadContext *tc, TestABI_TcInit::State &state)
Definition: guest_abi.test.cc:228
gem5::guest_abi::Argument< TestABI_1D, int >::get
static int get(ThreadContext *tc, TestABI_1D::State &state)
Definition: guest_abi.test.cc:110
gem5::guest_abi::Result< TestABI_2D, Ret, typename std::enable_if_t< std::is_floating_point_v< Ret > > >::store
static void store(ThreadContext *tc, const Ret &ret)
Definition: guest_abi.test.cc:217

Generated on Sun Jul 30 2023 01:56:59 for gem5 by doxygen 1.8.17