Current (old) function call signature:
long vmcall(const std::string& function_name,
std::vector<address_t> args);
Now since I can only call into the guest using (address-sized) integers, this is quite a limited interface, and I want to expand it to at least also handle floating point values, and possibly others, like so:
template <typename... Args>
long vmcall(const std::string& function_name,
Args&&... args);
That will be the new function signature, replacing the old one.
To show how the args vector is currently used:
template <int W>
inline void Machine<W>::setup_call(
address_t call_addr, address_t retn_addr,
std::vector<address_t> args)
{
assert(args.size() <= 8);
cpu.reg(RISCV::REG_RA) = retn_addr;
for (size_t arg = 0; arg < args.size(); arg++) {
cpu.reg(RISCV::REG_ARG0 + arg) = args[arg];
}
cpu.jump(call_addr);
}
This function is called from vmcall with std::move(args), and all it does is copy the integer arguments in the args vector into the integral CPU registers, incrementally. This works fine when I want to call a function that only takes integral arguments. So, if I wanted to call a function that, say, takes one floating-point argument, then there is no way to do that. This is because FP registers are completely separate, and need to be handled differently.
Also, 32-bit and 64-bit floats are handled differently through NaN-boxing. So, it would be nice if it was possible to differentiate between float and double as well.
I'm not so strong on template magic to begin with. How do I branch on the type of each element in the parameter pack?
In C++17, the way to iterate over a parameter pack is to use a comma fold:
(<expr>, ...); // expr contains Args and/or args
If a single expression is insufficient, you can use an immediately-invoked lambda:
([&] {
<statements> // statements contains Args and/or args
}(), ...);
Combine this with if constexpr
on the types of your arguments:
std::vector<address_t> addr_args;
std::vector<fp_t> fp_args;
([&] {
if constexpr (std::is_integral_v<Args>)
addr_args.push_back(args);
else
fp_args.push_back(args);
}(), ...);