sim: Make it possible for a GuestABI to init its Position based on a TC.

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>
This commit is contained in:
Gabe Black
2019-12-16 21:28:40 -08:00
parent 992454e0f2
commit 24be0cc1ce
2 changed files with 65 additions and 3 deletions

View 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);

View 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.