// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once #include #include "common/types.h" #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, ... #define VA_CTX(ctx) \ alignas(16)::Common::VaCtx 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(::Common::VaRegSave, gp); \ (ctx).va_list.fp_offset = offsetof(::Common::VaRegSave, fp); \ (ctx).va_list.overflow_arg_area = &overflow_arg_area; namespace Common { // https://stackoverflow.com/questions/4958384/what-is-the-format-of-the-x86-64-va-list-structure struct VaList { u32 gp_offset; u32 fp_offset; void* overflow_arg_area; void* reg_save_area; }; struct VaRegSave { u64 gp[6]; __m128 fp[8]; }; struct VaCtx { VaRegSave reg_save_area; VaList va_list; }; template T vaArgRegSaveAreaGp(VaList* l) { auto* addr = reinterpret_cast(static_cast(l->reg_save_area) + l->gp_offset); l->gp_offset += Size; return *addr; } template T vaArgOverflowArgArea(VaList* l) { auto ptr = ((reinterpret_cast(l->overflow_arg_area) + (Align - 1)) & ~(Align - 1)); auto* addr = reinterpret_cast(ptr); l->overflow_arg_area = reinterpret_cast(ptr + Size); return *addr; } template T vaArgRegSaveAreaFp(VaList* l) { auto* addr = reinterpret_cast(static_cast(l->reg_save_area) + l->fp_offset); l->fp_offset += Size; return *addr; } inline int vaArgInteger(VaList* l) { if (l->gp_offset <= 40) { return vaArgRegSaveAreaGp(l); } return vaArgOverflowArgArea(l); } inline long long vaArgLongLong(VaList* l) { if (l->gp_offset <= 40) { return vaArgRegSaveAreaGp(l); } return vaArgOverflowArgArea(l); } inline long vaArgLong(VaList* l) { if (l->gp_offset <= 40) { return vaArgRegSaveAreaGp(l); } return vaArgOverflowArgArea(l); } inline double vaArgDouble(VaList* l) { if (l->fp_offset <= 160) { return vaArgRegSaveAreaFp(l); } return vaArgOverflowArgArea(l); } template T* vaArgPtr(VaList* l) { if (l->gp_offset <= 40) { return vaArgRegSaveAreaGp(l); } return vaArgOverflowArgArea(l); } } // namespace Common