sim: Rename allocate in GuestABI to prepare.

This method can be used for allocating resources for registers and/or
arguments, but it can also be used for generic preparation for them
as well. For instance, it can be used to detect some sort of property
of the function signature as a whole (if it's variadic for instance)
which can be stored in position and used to change ABI behavior.

Change-Id: I8a090be65dc4987e35cd115562114cd1b748155f
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/24106
Reviewed-by: Gabe Black <gabeblack@google.com>
Maintainer: Gabe Black <gabeblack@google.com>
Tested-by: kokoro <noreply+kokoro@google.com>
This commit is contained in:
Gabe Black
2019-12-22 22:00:46 -08:00
parent 10c46f0996
commit 4e894d8673
4 changed files with 39 additions and 38 deletions

View File

@@ -50,7 +50,7 @@ invokeSimcall(ThreadContext *tc,
// Default construct a Position to track consumed resources. Built in
// types will be zero initialized.
auto position = GuestABI::initializePosition<ABI>(tc);
GuestABI::allocateSignature<ABI, Ret, Args...>(tc, position);
GuestABI::prepareForFunction<ABI, Ret, Args...>(tc, position);
return GuestABI::callFrom<ABI, Ret, Args...>(tc, position, target);
}
@@ -70,7 +70,7 @@ invokeSimcall(ThreadContext *tc,
// Default construct a Position to track consumed resources. Built in
// types will be zero initialized.
auto position = GuestABI::initializePosition<ABI>(tc);
GuestABI::allocateArguments<ABI, Args...>(tc, position);
GuestABI::prepareForArguments<ABI, Args...>(tc, position);
GuestABI::callFrom<ABI, Args...>(tc, position, target);
}
@@ -96,7 +96,7 @@ dumpSimcall(std::string name, ThreadContext *tc,
auto position = GuestABI::initializePosition<ABI>(tc);
std::ostringstream ss;
GuestABI::allocateSignature<ABI, Ret, Args...>(tc, position);
GuestABI::prepareForFunction<ABI, Ret, Args...>(tc, position);
ss << name;
GuestABI::dumpArgsFrom<ABI, Ret, Args...>(0, ss, tc, position);
return ss.str();

View File

@@ -66,8 +66,8 @@ struct TestABI_1D
using Position = int;
};
// ABI anchor for an ABI which uses the allocate() hook.
struct TestABI_Allocate
// ABI anchor for an ABI which uses the prepare() hook.
struct TestABI_Prepare
{
using Position = int;
};
@@ -136,31 +136,31 @@ struct Result<TestABI_1D, Ret,
}
};
// Hooks for the ABI which uses allocate(). It uses the same rules as the
// Hooks for the ABI which uses prepare(). It uses the same rules as the
// 1D ABI for arguments, but allocates space for and discards return values
// and returns integer arguments in reverse order.
template <>
struct Argument<TestABI_Allocate, int>
struct Argument<TestABI_Prepare, int>
{
static int
get(ThreadContext *tc, TestABI_Allocate::Position &position)
get(ThreadContext *tc, TestABI_Prepare::Position &position)
{
return tc->ints[--position];
}
static void
allocate(ThreadContext *tc, TestABI_Allocate::Position &position)
prepare(ThreadContext *tc, TestABI_Prepare::Position &position)
{
position++;
}
};
template <typename Ret>
struct Result<TestABI_Allocate, Ret>
struct Result<TestABI_Prepare, Ret>
{
static void store(ThreadContext *tc, const Ret &ret) {}
static void
allocate(ThreadContext *tc, TestABI_Allocate::Position &position)
prepare(ThreadContext *tc, TestABI_Prepare::Position &position)
{
position++;
}
@@ -243,14 +243,14 @@ testIntVoid(ThreadContext *tc, int a, float b, int c, double d,
// Test functions which verify that the return allocating ABI allocates space
// for its return value successfully.
void
testAllocateVoid(ThreadContext *tc, int a, int b)
testPrepareVoid(ThreadContext *tc, int a, int b)
{
EXPECT_EQ(a, tc->ints[1]);
EXPECT_EQ(b, tc->ints[0]);
}
int
testAllocateInt(ThreadContext *tc, int a, int b)
testPrepareInt(ThreadContext *tc, int a, int b)
{
EXPECT_EQ(a, tc->ints[2]);
EXPECT_EQ(b, tc->ints[1]);
@@ -299,11 +299,11 @@ TEST(GuestABI, ABI_1D_args)
EXPECT_EQ(tc.floatResult, tc.DefaultFloatResult);
}
TEST(GuestABI, ABI_Allocate)
TEST(GuestABI, ABI_Prepare)
{
ThreadContext tc;
invokeSimcall<TestABI_Allocate>(&tc, testAllocateVoid);
invokeSimcall<TestABI_Allocate>(&tc, testAllocateInt);
invokeSimcall<TestABI_Prepare>(&tc, testPrepareVoid);
invokeSimcall<TestABI_Prepare>(&tc, testPrepareInt);
}
TEST(GuestABI, ABI_2D_args)

View File

@@ -72,11 +72,12 @@ struct Result
typename ABI::Position &position);
/*
* Adjust the position of arguments based on the return type, if necessary.
* Prepare for a result of type Ret. This might mean, for instance,
* allocating an argument register for a result pointer.
*
* This method can be excluded if no adjustment is necessary.
* This method can be excluded if no preparation is necessary.
*/
static void allocate(ThreadContext *tc, typename ABI::Position &position);
static void prepare(ThreadContext *tc, typename ABI::Position &position);
};
/*
@@ -101,10 +102,10 @@ struct Argument
static Arg get(ThreadContext *tc, typename ABI::Position &position);
/*
* Adjust the position of arguments based on the argument type, if
* necessary.
* Prepare for an argument of type Arg. This might mean, for instance,
* allocating an argument register for a result pointer.
*
* This method can be excluded if no adjustment is necessary.
* This method can be excluded if no preparation is necessary.
*/
static void allocate(ThreadContext *tc, typename ABI::Position &position);
};

View File

@@ -71,63 +71,63 @@ initializePosition(const ThreadContext *tc)
}
/*
* This struct template provides a default allocate() method in case the
* This struct template provides a default prepare() method in case the
* Result or Argument template doesn't provide one. This is the default in
* cases where the return or argument type doesn't affect where things are
* stored.
*/
template <typename ABI, template <class ...> class Role,
typename Type, typename Enabled=void>
struct Allocator
struct Preparer
{
static void
allocate(ThreadContext *tc, typename ABI::Position &position)
prepare(ThreadContext *tc, typename ABI::Position &position)
{}
};
/*
* If the return or argument type isn't void and does affect where things
* are stored, the ABI can implement an allocate() method for the various
* are stored, the ABI can implement a prepare() method for the various
* argument and/or return types, and this specialization will call into it.
*/
template <typename ABI, template <class ...> class Role, typename Type>
struct Allocator<ABI, Role, Type, decltype((void)&Role<ABI, Type>::allocate)>
struct Preparer<ABI, Role, Type, decltype((void)&Role<ABI, Type>::prepare)>
{
static void
allocate(ThreadContext *tc, typename ABI::Position &position)
prepare(ThreadContext *tc, typename ABI::Position &position)
{
Role<ABI, Type>::allocate(tc, position);
Role<ABI, Type>::prepare(tc, position);
}
};
template <typename ABI, typename Ret, typename Enabled=void>
static void
allocateResult(ThreadContext *tc, typename ABI::Position &position)
prepareForResult(ThreadContext *tc, typename ABI::Position &position)
{
Allocator<ABI, Result, Ret>::allocate(tc, position);
Preparer<ABI, Result, Ret>::prepare(tc, position);
}
template <typename ABI>
static void
allocateArguments(ThreadContext *tc, typename ABI::Position &position)
prepareForArguments(ThreadContext *tc, typename ABI::Position &position)
{
return;
}
template <typename ABI, typename NextArg, typename ...Args>
static void
allocateArguments(ThreadContext *tc, typename ABI::Position &position)
prepareForArguments(ThreadContext *tc, typename ABI::Position &position)
{
Allocator<ABI, Argument, NextArg>::allocate(tc, position);
allocateArguments<ABI, Args...>(tc, position);
Preparer<ABI, Argument, NextArg>::prepare(tc, position);
prepareForArguments<ABI, Args...>(tc, position);
}
template <typename ABI, typename Ret, typename ...Args>
static void
allocateSignature(ThreadContext *tc, typename ABI::Position &position)
prepareForFunction(ThreadContext *tc, typename ABI::Position &position)
{
allocateResult<ABI, Ret>(tc, position);
allocateArguments<ABI, Args...>(tc, position);
prepareForResult<ABI, Ret>(tc, position);
prepareForArguments<ABI, Args...>(tc, position);
}
/*