commit 7484601482123847d836cc711d250f7cbef65d46
parent e16a6ff438645bc74c6d4945681f8874801fc981
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Tue, 26 May 2026 15:41:07 -0700
abi: add va_list layout details per target
Add ABIVaListInfo/ABIVaListKind and abi_va_list_layout() to describe the
in-memory layout of __builtin_va_list for each ABI. AAPCS64 gets the full
struct layout (stack/gr_top/vr_top/gr_offs/vr_offs fields and register
counts); SysV x64 and Apple x64 get their register-save-area layout; pointer
and Windows ABIs get the POINTER kind.
Auto-upgrade OPAQUE to POINTER when the underlying type is a scalar pointer,
so targets that don't need the detailed layout can stay OPAQUE and still
provide a useful fallback.
Diffstat:
10 files changed, 76 insertions(+), 0 deletions(-)
diff --git a/src/abi/abi.c b/src/abi/abi.c
@@ -168,6 +168,16 @@ const ABIFuncInfo* abi_cg_func_info(TargetABI* a, CfreeCgTypeId fn_type) {
ABITypeInfo abi_va_list_info(TargetABI* a) { return a->vt->va_list_info; }
+ABIVaListInfo abi_va_list_layout(TargetABI* a) {
+ ABIVaListInfo out = a->vt->va_list_layout;
+ if (out.kind == ABI_VA_LIST_OPAQUE) {
+ out.type = a->vt->va_list_info;
+ if (out.type.scalar_kind == ABI_SC_PTR && out.type.size == 8u)
+ out.kind = ABI_VA_LIST_POINTER;
+ }
+ return out;
+}
+
/* ---- lifecycle ---- */
static const ABIVtable* select_vtable(Compiler* c) {
diff --git a/src/abi/abi.h b/src/abi/abi.h
@@ -27,6 +27,28 @@ typedef struct ABITypeInfo {
u8 pad;
} ABITypeInfo;
+typedef enum ABIVaListKind {
+ ABI_VA_LIST_OPAQUE,
+ ABI_VA_LIST_POINTER,
+ ABI_VA_LIST_AAPCS64,
+ ABI_VA_LIST_SYSV_X64,
+} ABIVaListKind;
+
+typedef struct ABIVaListInfo {
+ ABITypeInfo type;
+ u8 kind; /* ABIVaListKind */
+ u8 pad[3];
+ u32 stack_offset;
+ u32 gr_top_offset;
+ u32 vr_top_offset;
+ u32 gr_offs_offset;
+ u32 vr_offs_offset;
+ u32 gp_reg_count;
+ u32 fp_reg_count;
+ u32 gp_slot_size;
+ u32 fp_slot_size;
+} ABIVaListInfo;
+
typedef struct ABIFieldLayout {
u32 offset; /* byte offset from record base */
u16 bit_offset; /* bit offset within storage unit for bitfields */
@@ -122,5 +144,6 @@ u32 abi_cg_alignof(TargetABI*, CfreeCgTypeId);
const ABIRecordLayout* abi_cg_record_layout(TargetABI*, CfreeCgTypeId);
const ABIFuncInfo* abi_cg_func_info(TargetABI*, CfreeCgTypeId fn_type);
ABITypeInfo abi_va_list_info(TargetABI*);
+ABIVaListInfo abi_va_list_layout(TargetABI*);
#endif
diff --git a/src/abi/abi_aapcs64.c b/src/abi/abi_aapcs64.c
@@ -144,4 +144,16 @@ ABIFuncInfo* aapcs64_compute_func_info(TargetABI* a, CfreeCgTypeId fn) {
const ABIVtable aapcs64_vtable = {
.compute_func_info = aapcs64_compute_func_info,
.va_list_info = {32, 8, ABI_SC_VOID, 0, 0, 0},
+ .va_list_layout =
+ {.type = {32, 8, ABI_SC_VOID, 0, 0, 0},
+ .kind = ABI_VA_LIST_AAPCS64,
+ .stack_offset = 0,
+ .gr_top_offset = 8,
+ .vr_top_offset = 16,
+ .gr_offs_offset = 24,
+ .vr_offs_offset = 28,
+ .gp_reg_count = 8,
+ .fp_reg_count = 8,
+ .gp_slot_size = 8,
+ .fp_slot_size = 16},
};
diff --git a/src/abi/abi_aapcs64_windows.c b/src/abi/abi_aapcs64_windows.c
@@ -63,4 +63,6 @@ static ABIFuncInfo* aapcs64_windows_compute_func_info(TargetABI* a,
const ABIVtable aapcs64_windows_vtable = {
.compute_func_info = aapcs64_windows_compute_func_info,
.va_list_info = {8, 8, ABI_SC_PTR, 0, 0, 0},
+ .va_list_layout =
+ {.type = {8, 8, ABI_SC_PTR, 0, 0, 0}, .kind = ABI_VA_LIST_POINTER},
};
diff --git a/src/abi/abi_apple_arm64.c b/src/abi/abi_apple_arm64.c
@@ -45,4 +45,6 @@ static ABIFuncInfo* apple_arm64_compute_func_info(TargetABI* a,
const ABIVtable apple_arm64_vtable = {
.compute_func_info = apple_arm64_compute_func_info,
.va_list_info = {8, 8, ABI_SC_PTR, 0, 0, 0},
+ .va_list_layout =
+ {.type = {8, 8, ABI_SC_PTR, 0, 0, 0}, .kind = ABI_VA_LIST_POINTER},
};
diff --git a/src/abi/abi_apple_x64.c b/src/abi/abi_apple_x64.c
@@ -18,4 +18,15 @@ static ABIFuncInfo* apple_x64_compute_func_info(TargetABI* a,
const ABIVtable apple_x64_vtable = {
.compute_func_info = apple_x64_compute_func_info,
.va_list_info = {24, 8, ABI_SC_VOID, 0, 0, 0},
+ .va_list_layout =
+ {.type = {24, 8, ABI_SC_VOID, 0, 0, 0},
+ .kind = ABI_VA_LIST_SYSV_X64,
+ .stack_offset = 8,
+ .gr_top_offset = 16,
+ .gr_offs_offset = 0,
+ .vr_offs_offset = 4,
+ .gp_reg_count = 6,
+ .fp_reg_count = 8,
+ .gp_slot_size = 8,
+ .fp_slot_size = 16},
};
diff --git a/src/abi/abi_internal.h b/src/abi/abi_internal.h
@@ -14,6 +14,7 @@ typedef struct ABIVtable {
* abi.c calls this once per CgTypeId and memoizes the result. */
ABIFuncInfo* (*compute_func_info)(TargetABI*, CfreeCgTypeId fn);
ABITypeInfo va_list_info;
+ ABIVaListInfo va_list_layout;
} ABIVtable;
/* Per-ABI vtables exposed by their TUs. */
diff --git a/src/abi/abi_rv64.c b/src/abi/abi_rv64.c
@@ -246,4 +246,6 @@ static ABIFuncInfo* rv64_compute_func_info(TargetABI* a, CfreeCgTypeId fn) {
const ABIVtable rv64_vtable = {
.compute_func_info = rv64_compute_func_info,
.va_list_info = {8, 8, ABI_SC_PTR, 0, 0, 0},
+ .va_list_layout =
+ {.type = {8, 8, ABI_SC_PTR, 0, 0, 0}, .kind = ABI_VA_LIST_POINTER},
};
diff --git a/src/abi/abi_sysv_x64.c b/src/abi/abi_sysv_x64.c
@@ -296,4 +296,15 @@ static ABIFuncInfo* sysv_x64_compute_func_info(TargetABI* a, CfreeCgTypeId fn) {
const ABIVtable sysv_x64_vtable = {
.compute_func_info = sysv_x64_compute_func_info,
.va_list_info = {24, 8, ABI_SC_VOID, 0, 0, 0},
+ .va_list_layout =
+ {.type = {24, 8, ABI_SC_VOID, 0, 0, 0},
+ .kind = ABI_VA_LIST_SYSV_X64,
+ .stack_offset = 8,
+ .gr_top_offset = 16,
+ .gr_offs_offset = 0,
+ .vr_offs_offset = 4,
+ .gp_reg_count = SYSV_X64_GP_REG_COUNT,
+ .fp_reg_count = SYSV_X64_FP_REG_COUNT,
+ .gp_slot_size = SYSV_X64_GP_SLOT_SIZE,
+ .fp_slot_size = SYSV_X64_FP_SLOT_SIZE},
};
diff --git a/src/abi/abi_win64_x64.c b/src/abi/abi_win64_x64.c
@@ -175,4 +175,6 @@ static ABIFuncInfo* win64_x64_compute_func_info(TargetABI* a,
const ABIVtable win64_x64_vtable = {
.compute_func_info = win64_x64_compute_func_info,
.va_list_info = {8, 8, ABI_SC_PTR, 0, 0, 0},
+ .va_list_layout =
+ {.type = {8, 8, ABI_SC_PTR, 0, 0, 0}, .kind = ABI_VA_LIST_POINTER},
};