sim: Make it possible for a GuestABI to init its Position based on a TC.
authorGabe Black <gabeblack@google.com>
Tue, 17 Dec 2019 05:28:40 +0000 (21:28 -0800)
committerGabe Black <gabeblack@google.com>
Thu, 6 Feb 2020 04:47:03 +0000 (04:47 +0000)
It may be necessary to initialize the GuestABI Position type based on
the current state of the thread, for instance by reading the current
stack pointer.

This change makes it possible (but not mandantory) for an ABI to supply
a constructor for Position which accepts a ThreadContext * which it can
use to intiialize itself.

Change-Id: I5609b185f746368c5f9eb2a04074dcafa088f925
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/23749
Reviewed-by: Jason Lowe-Power <jason@lowepower.com>
Maintainer: Gabe Black <gabeblack@google.com>
Tested-by: kokoro <noreply+kokoro@google.com>
src/sim/guest_abi.hh
src/sim/guest_abi.test.cc

index 2dd27c424efb50e977b91acbe52ab42c0b4f5984..5432af3f9219d86aba5c001a03d1656a2857eb37 100644 (file)
@@ -61,6 +61,32 @@ namespace GuestABI
  * std::enable_if style conditional specializations.
  */
 
+/*
+ * Position may need to be initialized based on the ThreadContext, for instance
+ * to find out where the stack pointer is initially.
+ */
+template <typename ABI, typename Enabled=void>
+struct PositionInitializer
+{
+    static typename ABI::Position
+    init(const ThreadContext *tc)
+    {
+        return typename ABI::Position();
+    }
+};
+
+template <typename ABI>
+struct PositionInitializer<ABI, typename std::enable_if<
+    std::is_constructible<typename ABI::Position, const ThreadContext *>::value
+    >::type>
+{
+    static typename ABI::Position
+    init(const ThreadContext *tc)
+    {
+        return typename ABI::Position(tc);
+    }
+};
+
 template <typename ABI, typename Ret, typename Enabled=void>
 struct Result
 {
@@ -407,7 +433,7 @@ invokeSimcall(ThreadContext *tc,
 {
     // Default construct a Position to track consumed resources. Built in
     // types will be zero initialized.
-    auto position = typename ABI::Position();
+    auto position = GuestABI::PositionInitializer<ABI>::init(tc);
     GuestABI::ResultAllocator<ABI, Ret>::allocate(tc, position);
     return GuestABI::callFrom<ABI, Ret, Args...>(tc, position, target);
 }
@@ -427,7 +453,7 @@ invokeSimcall(ThreadContext *tc,
 {
     // Default construct a Position to track consumed resources. Built in
     // types will be zero initialized.
-    auto position = typename ABI::Position();
+    auto position = GuestABI::PositionInitializer<ABI>::init(tc);
     GuestABI::callFrom<ABI, Args...>(tc, position, target);
 }
 
@@ -450,7 +476,7 @@ dumpSimcall(std::string name, ThreadContext *tc,
             std::function<Ret(ThreadContext *, Args...)> target=
             std::function<Ret(ThreadContext *, Args...)>())
 {
-    auto position = typename ABI::Position();
+    auto position = GuestABI::PositionInitializer<ABI>::init(tc);
     std::ostringstream ss;
 
     GuestABI::ResultAllocator<ABI, Ret>::allocate(tc, position);
index 2f896f9b3e5ce721060aa31f70dc8f20f9e7236f..506163ee65625af69632883e127df9538d2740de 100644 (file)
@@ -46,6 +46,8 @@ class ThreadContext
 
     int intResult = DefaultIntResult;
     double floatResult = DefaultFloatResult;
+
+    int intOffset = 0;
 };
 
 const int ThreadContext::ints[] = {
@@ -80,6 +82,15 @@ struct TestABI_2D
     using Position = std::pair<int, int>;
 };
 
+struct TestABI_TcInit
+{
+    struct Position
+    {
+        int pos;
+        Position(const ThreadContext *tc) : pos(tc->intOffset) {}
+    };
+};
+
 namespace GuestABI
 {
 
@@ -188,6 +199,17 @@ struct Result<TestABI_2D, Ret,
     }
 };
 
+// Hooks for the TcInit ABI arguments.
+template <>
+struct Argument<TestABI_TcInit, int>
+{
+    static int
+    get(ThreadContext *tc, TestABI_TcInit::Position &position)
+    {
+        return tc->ints[position.pos++];
+    }
+};
+
 } // namespace GuestABI
 
 // Test function which verifies that its arguments reflect the 1D ABI and
@@ -237,6 +259,13 @@ test2DVoid(ThreadContext *tc, int a, float b, int c, double d,
     EXPECT_EQ(varargs.get<double>(), tc->floats[3]);
 }
 
+void
+testTcInit(ThreadContext *tc, int a)
+{
+    EXPECT_EQ(tc->intOffset, 2);
+    EXPECT_EQ(a, tc->ints[2]);
+}
+
 // Test functions which returns various types of values.
 const int IntRetValue = 50;
 const float FloatRetValue = 3.14;
@@ -271,6 +300,13 @@ TEST(GuestABI, ABI_2D_args)
     EXPECT_EQ(tc.floatResult, tc.DefaultFloatResult);
 }
 
+TEST(GuestABI, ABI_TC_init)
+{
+    ThreadContext tc;
+    tc.intOffset = 2;
+    invokeSimcall<TestABI_TcInit>(&tc, testTcInit);
+}
+
 TEST(GuestABI, ABI_returns)
 {
     // 1D returns.