Kyty/source/emulator/include/Emulator/Libs/VaContext.h

242 lines
7.4 KiB
C++

#ifndef EMULATOR_INCLUDE_EMULATOR_LIBS_VACONTEXT_H_
#define EMULATOR_INCLUDE_EMULATOR_LIBS_VACONTEXT_H_
#include <cstddef>
#include <xmmintrin.h>
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define VA_ARGS \
uint64_t rdi, uint64_t rsi, uint64_t rdx, uint64_t rcx, uint64_t r8, uint64_t r9, uint64_t overflow_arg_area, __m128 xmm0, \
__m128 xmm1, __m128 xmm2, __m128 xmm3, __m128 xmm4, __m128 xmm5, __m128 xmm6, __m128 xmm7, ...
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define VA_CONTEXT(ctx) \
alignas(16) VaContext ctx; \
(ctx).reg_save_area.gp[0] = rdi; \
(ctx).reg_save_area.gp[1] = rsi; \
(ctx).reg_save_area.gp[2] = rdx; \
(ctx).reg_save_area.gp[3] = rcx; \
(ctx).reg_save_area.gp[4] = r8; \
(ctx).reg_save_area.gp[5] = r9; \
(ctx).reg_save_area.fp[0] = xmm0; \
(ctx).reg_save_area.fp[1] = xmm1; \
(ctx).reg_save_area.fp[2] = xmm2; \
(ctx).reg_save_area.fp[3] = xmm3; \
(ctx).reg_save_area.fp[4] = xmm4; \
(ctx).reg_save_area.fp[5] = xmm5; \
(ctx).reg_save_area.fp[6] = xmm6; \
(ctx).reg_save_area.fp[7] = xmm7; \
(ctx).va_list.reg_save_area = &(ctx).reg_save_area; \
(ctx).va_list.gp_offset = offsetof(VaRegSave, gp); \
(ctx).va_list.fp_offset = offsetof(VaRegSave, fp); \
(ctx).va_list.overflow_arg_area = &overflow_arg_area;
namespace Kyty::Libs {
#pragma pack(1)
struct VaList
{
uint32_t gp_offset;
uint32_t fp_offset;
void* overflow_arg_area;
void* reg_save_area;
};
// typedef float __m128 __attribute__((__vector_size__(16), __aligned__(16)));
struct VaRegSave
{
uint64_t gp[6];
__m128 fp[8];
};
struct VaContext
{
VaRegSave reg_save_area;
VaList va_list;
};
struct VaCharX16
{
char x[16];
};
struct VaShortX8
{
short x[8]; // NOLINT(google-runtime-int)
};
struct VaIntX4
{
int x[4];
};
struct VaFloatX4
{
float x[4];
};
#pragma pack()
template <class T, uint64_t Align, uint64_t Size>
T VaArg_overflow_arg_area(VaList* l)
{
auto ptr = ((reinterpret_cast<uint64_t>(l->overflow_arg_area) + (Align - 1)) & ~(Align - 1));
auto* addr = reinterpret_cast<T*>(ptr);
l->overflow_arg_area = reinterpret_cast<void*>(ptr + Size);
return *addr;
}
template <class T, uint32_t Size>
T VaArg_reg_save_area_gp(VaList* l)
{
auto* addr = reinterpret_cast<T*>(static_cast<uint8_t*>(l->reg_save_area) + l->gp_offset);
l->gp_offset += Size;
return *addr;
}
template <class T, uint32_t Size>
T VaArg_reg_save_area_fp(VaList* l)
{
auto* addr = reinterpret_cast<T*>(static_cast<uint8_t*>(l->reg_save_area) + l->fp_offset);
l->fp_offset += Size;
return *addr;
}
template <>
inline VaFloatX4 VaArg_reg_save_area_fp<VaFloatX4, 32>(VaList* l)
{
auto* addr = reinterpret_cast<VaFloatX4*>(static_cast<uint8_t*>(l->reg_save_area) + l->fp_offset);
l->fp_offset += 32;
VaFloatX4 ret = {{addr[0].x[0], addr[0].x[1], addr[1].x[0], addr[1].x[1]}};
return ret;
}
inline int VaArg_int(VaList* l)
{
if (l->gp_offset <= 40)
{
return VaArg_reg_save_area_gp<int, 8>(l);
}
return VaArg_overflow_arg_area<int, 1, 8>(l);
}
inline double VaArg_double(VaList* l)
{
if (l->fp_offset <= 160)
{
return VaArg_reg_save_area_fp<double, 16>(l);
}
return VaArg_overflow_arg_area<double, 1, 8>(l);
}
inline long double VaArg_long_double(VaList* l)
{
return VaArg_overflow_arg_area<long double, 16, 16>(l);
}
inline wint_t VaArg_wint_t(VaList* l)
{
if (l->gp_offset <= 40)
{
return VaArg_reg_save_area_gp<wint_t, 8>(l);
}
return VaArg_overflow_arg_area<wint_t, 1, 8>(l);
}
inline VaCharX16 VaArg_char_x16(VaList* l)
{
if (l->gp_offset <= 32)
{
return VaArg_reg_save_area_gp<VaCharX16, 16>(l);
}
return VaArg_overflow_arg_area<VaCharX16, 1, 16>(l);
}
inline long VaArg_long(VaList* l) // NOLINT(google-runtime-int)
{
if (l->gp_offset <= 40)
{
return VaArg_reg_save_area_gp<long, 8>(l); // NOLINT(google-runtime-int)
}
return VaArg_overflow_arg_area<long, 1, 8>(l); // NOLINT(google-runtime-int)
}
inline intmax_t VaArg_intmax_t(VaList* l)
{
if (l->gp_offset <= 40)
{
return VaArg_reg_save_area_gp<intmax_t, 8>(l);
}
return VaArg_overflow_arg_area<intmax_t, 1, 8>(l);
}
inline long long VaArg_long_long(VaList* l) // NOLINT(google-runtime-int)
{
if (l->gp_offset <= 40)
{
return VaArg_reg_save_area_gp<long long, 8>(l); // NOLINT(google-runtime-int)
}
return VaArg_overflow_arg_area<long long, 1, 8>(l); // NOLINT(google-runtime-int)
}
inline ptrdiff_t VaArg_ptrdiff_t(VaList* l)
{
if (l->gp_offset <= 40)
{
return VaArg_reg_save_area_gp<ptrdiff_t, 8>(l);
}
return VaArg_overflow_arg_area<ptrdiff_t, 1, 8>(l);
}
inline size_t VaArg_size_t(VaList* l)
{
if (l->gp_offset <= 40)
{
return VaArg_reg_save_area_gp<size_t, 8>(l);
}
return VaArg_overflow_arg_area<size_t, 1, 8>(l);
}
inline VaShortX8 VaArg_ShortX8(VaList* l)
{
if (l->gp_offset <= 32)
{
return VaArg_reg_save_area_gp<VaShortX8, 16>(l);
}
return VaArg_overflow_arg_area<VaShortX8, 1, 16>(l);
}
inline VaIntX4 VaArg_IntX4(VaList* l)
{
if (l->gp_offset <= 32)
{
return VaArg_reg_save_area_gp<VaIntX4, 16>(l);
}
return VaArg_overflow_arg_area<VaIntX4, 1, 16>(l);
}
inline VaFloatX4 VaArg_FloatX4(VaList* l)
{
if (l->fp_offset <= 144)
{
return VaArg_reg_save_area_fp<VaFloatX4, 32>(l);
}
return VaArg_overflow_arg_area<VaFloatX4, 1, 16>(l);
}
template <class T>
T* VaArg_ptr(VaList* l)
{
if (l->gp_offset <= 40)
{
return VaArg_reg_save_area_gp<T*, 8>(l);
}
return VaArg_overflow_arg_area<T*, 1, 8>(l);
}
} // namespace Kyty::Libs
#endif /* EMULATOR_INCLUDE_EMULATOR_LIBS_VACONTEXT_H_ */