abi_aapcs64.c (3739B)
1 /* AAPCS64 (AArch64 SysV) ABI dispatch. 2 * 3 * v1 covers the cases the cg test harness exercises: 4 * void -> IGNORE 5 * integer ≤ 8B -> DIRECT, one INT part in a register 6 * integer 16B -> DIRECT, two INT parts (X0+X1) 7 * pointer -> DIRECT, one INT part in a register 8 * float/double -> DIRECT, one FP part in a register 9 * small struct -> DIRECT, INT parts (HFA/HVA refinement: TODO) 10 * large struct -> INDIRECT (sret for return; passed by reference) 11 * Variadics, HFA classification, and split GPR+stack tail still 12 * land with the parser. */ 13 14 #include <string.h> 15 16 #include "abi/abi_internal.h" 17 #include "cg/type.h" 18 #include "core/arena.h" 19 #include "core/core.h" 20 21 static void classify_scalar(TargetABI* a, KitCgTypeId t, ABIArgInfo* out) { 22 ABITypeInfo ti = abi_cg_type_info(a, t); 23 if (ti.scalar_kind == ABI_SC_INT && ti.size == 16) { 24 abi_classify_int128_pair(a, out); 25 return; 26 } 27 abi_classify_scalar_reg_part(a, out, ti, ti.scalar_kind == ABI_SC_FLOAT); 28 } 29 30 static void classify_aggregate(TargetABI* a, KitCgTypeId t, ABIArgInfo* out, 31 int is_return) { 32 ABITypeInfo ti = abi_cg_type_info(a, t); 33 if (ti.size == 0) { 34 abi_classify_void(out); 35 return; 36 } 37 /* AAPCS64: aggregates ≤ 16 bytes pass in up to 2 GPRs (or HFA in FP regs; 38 * v1 ignores HFA). Larger aggregates pass by reference (caller copy for 39 * args, sret pointer for return). */ 40 if (ti.size <= 16) { 41 u32 nparts = (ti.size + 7) / 8; 42 ABIArgPart* parts = arena_array(a->c->tu, ABIArgPart, nparts); 43 memset(parts, 0, sizeof(ABIArgPart) * nparts); 44 u32 off = 0; 45 for (u32 i = 0; i < nparts; ++i) { 46 u32 chunk = (ti.size - off > 8) ? 8 : (ti.size - off); 47 parts[i].cls = ABI_CLASS_INT; 48 parts[i].loc = ABI_LOC_REG; 49 parts[i].size = chunk; 50 parts[i].align = 8; 51 parts[i].src_offset = off; 52 off += chunk; 53 } 54 out->kind = ABI_ARG_DIRECT; 55 out->flags = ABI_AF_NONE; 56 out->parts = parts; 57 out->nparts = nparts; 58 out->indirect_align = 0; 59 } else { 60 out->kind = ABI_ARG_INDIRECT; 61 out->flags = is_return ? ABI_AF_SRET : ABI_AF_BYVAL; 62 out->indirect_align = ti.align; 63 out->parts = NULL; 64 out->nparts = 0; 65 } 66 } 67 68 static void classify_one(TargetABI* a, KitCgTypeId t, ABIArgInfo* out, 69 int is_return) { 70 const CgType* ty = cg_type_get(a->c, t); 71 if (!ty || ty->kind == KIT_CG_TYPE_VOID) { 72 abi_classify_void(out); 73 return; 74 } 75 switch (ty->kind) { 76 case KIT_CG_TYPE_RECORD: 77 classify_aggregate(a, t, out, is_return); 78 return; 79 default: 80 classify_scalar(a, t, out); 81 return; 82 } 83 } 84 85 /* Non-static so apple_arm64_compute_func_info can delegate to it during 86 * the Phase 1 alias period — see abi_apple_arm64.c. */ 87 ABIFuncInfo* aapcs64_compute_func_info(TargetABI* a, KitCgTypeId fn) { 88 /* AArch64 returns the sret pointer in the dedicated x8 register, so it never 89 * consumes an x0..x7 argument slot: sret_consumes_int_arg stays 0. */ 90 return abi_compute_func_info_generic(a, fn, classify_one, 91 /*sret_consumes_int_arg=*/0); 92 } 93 94 const ABIVtable aapcs64_vtable = { 95 .compute_func_info = aapcs64_compute_func_info, 96 .va_list_info = {32, 8, ABI_SC_VOID, 0, 0, 0}, 97 .va_list_layout = {.kind = ABI_VA_LIST_AAPCS64, 98 .stack_offset = 0, 99 .gr_top_offset = 8, 100 .vr_top_offset = 16, 101 .gr_offs_offset = 24, 102 .vr_offs_offset = 28, 103 .gp_reg_count = 8, 104 .fp_reg_count = 8, 105 .gp_slot_size = 8, 106 .fp_slot_size = 16}, 107 };