c_abi.c (7336B)
1 #include "abi/c_abi.h" 2 3 #include <string.h> 4 5 /* Size/align of a C type are a pure function of the type + the fixed target. 6 * Both ride the per-id api_type_layout memo (and the cg_id cached on the Type 7 * node by type_cg_id_in_pool), so a direct kit_cg_type_size/align off the 8 * lowered id is already memoized — no second Type*-keyed cache is needed. 9 * Record layouts (the O(M accesses x N fields) cost) are still memoized on the 10 * Type node by c_abi_record_layout below. */ 11 static int abi_info_cacheable(const Type* t) { 12 /* Incomplete records have no stable layout yet; everything else (scalars, 13 * pointers, arrays, functions, enums, complete records) is fixed. */ 14 return !((t->kind == TY_STRUCT || t->kind == TY_UNION) && t->rec.incomplete); 15 } 16 17 u32 c_abi_sizeof(KitCompiler* a, Pool* p, const Type* t) { 18 return (u32)kit_cg_type_size(a, type_cg_id_in_pool(a, p, t)); 19 } 20 21 u32 c_abi_alignof(KitCompiler* a, Pool* p, const Type* t) { 22 return kit_cg_type_align(a, type_cg_id_in_pool(a, p, t)); 23 } 24 25 const ABIRecordLayout* c_abi_record_layout(KitCompiler* a, Pool* p, 26 const Type* t) { 27 KitCgTypeId id; 28 const KitCgRecordLayout* view; 29 ABIRecordLayout* L; 30 ABIFieldLayout* fl = NULL; 31 u32 nfields; 32 /* Memoized on the Type node (mirrors cg_id). The layout is a pure function of 33 * the complete record + the fixed target, so once built it never changes; an 34 * incomplete record (no stable layout) is never cached. Collapses the former 35 * O(M member-accesses x N fields) rebuild to one build per distinct record. 36 */ 37 if (abi_info_cacheable(t) && t->abi_layout) return t->abi_layout; 38 id = type_cg_id_in_pool(a, p, t); 39 if (kit_cg_type_kind(a, id) != KIT_CG_TYPE_RECORD) return NULL; 40 /* Borrow the CG-owned layout view once; every offset/bit value below is 41 * sourced from it instead of N per-field queries. */ 42 view = kit_cg_type_record_layout(a, id); 43 if (!view) return NULL; 44 nfields = view->nfields; 45 L = arena_znew(p->arena, ABIRecordLayout); 46 if (!L) return NULL; 47 if (nfields) { 48 fl = arena_zarray(p->arena, ABIFieldLayout, nfields); 49 if (!fl) return NULL; 50 for (u32 i = 0; i < nfields; ++i) { 51 const KitCgFieldLayout* f = &view->fields[i]; 52 fl[i].offset = (u32)f->offset; 53 fl[i].storage_size = f->bit_storage_size 54 ? f->bit_storage_size 55 : (u32)kit_cg_type_size(a, f->type); 56 if (t->rec.fields[i].flags & FIELD_BITFIELD) { 57 fl[i].bit_width = t->rec.fields[i].bitfield_width; 58 fl[i].bit_offset = f->bit_offset; 59 } 60 } 61 } 62 L->size = (u32)view->size; 63 L->align = view->align; 64 L->nfields = nfields; 65 L->fields = fl; 66 /* Cache for subsequent accesses. Only a complete record is cacheable; the 67 * RECORD-kind check above already implies the id lowered, but guard anyway so 68 * an incomplete record (which can't reach here via a RECORD id) never sticks. 69 */ 70 if (abi_info_cacheable(t)) ((Type*)t)->abi_layout = L; 71 return L; 72 } 73 74 const ABIFuncInfo* c_abi_func_info(KitCompiler* a, Pool* p, 75 const Type* fn_type) { 76 KitCgTypeId id = type_cg_id_in_pool(a, p, fn_type); 77 ABIFuncInfo* info; 78 uint32_t nparams; 79 if (kit_cg_type_kind(a, id) != KIT_CG_TYPE_FUNC) return NULL; 80 nparams = kit_cg_type_func_nparams(a, id); 81 info = arena_znew(p->arena, ABIFuncInfo); 82 if (!info) return NULL; 83 info->nparams = (u16)nparams; 84 if (nparams) { 85 info->params = arena_zarray(p->arena, ABIArgInfo, nparams); 86 if (!info->params) return NULL; 87 } 88 return info; 89 } 90 91 static const Type* c_size_or_uintptr(KitCompiler* a, Pool* p) { 92 KitTargetSpec target = kit_compiler_target_spec(a); 93 if (kit_target_uses_lp64(target)) return type_prim(p, TY_ULONG); 94 return target.ptr_size == 8 ? type_prim(p, TY_ULLONG) : type_prim(p, TY_UINT); 95 } 96 97 const Type* c_abi_size_type(KitCompiler* a, Pool* p) { 98 return c_size_or_uintptr(a, p); 99 } 100 101 const Type* c_abi_ptrdiff_type(KitCompiler* a, Pool* p) { 102 KitTargetSpec target = kit_compiler_target_spec(a); 103 if (kit_target_uses_lp64(target)) return type_prim(p, TY_LONG); 104 return target.ptr_size == 8 ? type_prim(p, TY_LLONG) : type_prim(p, TY_INT); 105 } 106 107 const Type* c_abi_intptr_type(KitCompiler* a, Pool* p) { 108 return c_abi_ptrdiff_type(a, p); 109 } 110 111 const Type* c_abi_uintptr_type(KitCompiler* a, Pool* p) { 112 return c_size_or_uintptr(a, p); 113 } 114 115 const Type* c_abi_va_list_type(KitCompiler* a, Pool* p) { 116 /* Key the frontend `__builtin_va_list` spelling on the abstract va_list 117 * shape the target ABI reports, not on a re-derived arch/os ladder. The 118 * record field definitions are unchanged; only the dispatch is abstract: 119 * SYSV_X64 -> the System V __va_list_tag register-save record; 120 * AAPCS64 -> the AArch64 __va_list register-save record; 121 * POINTER / OPAQUE -> a single pointer that walks the arg area. 122 * The old Apple-vs-AAPCS64 arm64 split disappears (Apple is POINTER), as 123 * does the x86_64/rv64 split (both follow the abstract kind). */ 124 switch (kit_cg_target_va_list_kind(a)) { 125 case KIT_CG_VALIST_SYSV_X64: { 126 const Type* vp = type_ptr(p, type_void(p)); 127 const Type* uit = type_prim(p, TY_UINT); 128 Sym name = kit_sym_intern(p->c, KIT_SLICE_LIT("__va_list_tag")); 129 SrcLoc nl = {0, 0, 0}; 130 TagId tg = type_tag_new(p, TAG_STRUCT, name, nl); 131 TypeRecordBuilder* b = type_record_begin(p, TY_STRUCT, tg, name); 132 type_record_field( 133 b, (Field){.name = kit_sym_intern(p->c, KIT_SLICE_LIT("gp_offset")), 134 .type = uit}); 135 type_record_field( 136 b, (Field){.name = kit_sym_intern(p->c, KIT_SLICE_LIT("fp_offset")), 137 .type = uit}); 138 type_record_field( 139 b, (Field){.name = kit_sym_intern(p->c, 140 KIT_SLICE_LIT("overflow_arg_area")), 141 .type = vp}); 142 type_record_field(b, (Field){.name = kit_sym_intern( 143 p->c, KIT_SLICE_LIT("reg_save_area")), 144 .type = vp}); 145 return type_record_end(p, b); 146 } 147 case KIT_CG_VALIST_AAPCS64: { 148 const Type* vp = type_ptr(p, type_void(p)); 149 const Type* it = type_prim(p, TY_INT); 150 Sym name = kit_sym_intern(p->c, KIT_SLICE_LIT("__va_list")); 151 SrcLoc nl = {0, 0, 0}; 152 TagId tg = type_tag_new(p, TAG_STRUCT, name, nl); 153 TypeRecordBuilder* b = type_record_begin(p, TY_STRUCT, tg, name); 154 type_record_field( 155 b, (Field){.name = kit_sym_intern(p->c, KIT_SLICE_LIT("__stack")), 156 .type = vp}); 157 type_record_field( 158 b, (Field){.name = kit_sym_intern(p->c, KIT_SLICE_LIT("__gr_top")), 159 .type = vp}); 160 type_record_field( 161 b, (Field){.name = kit_sym_intern(p->c, KIT_SLICE_LIT("__vr_top")), 162 .type = vp}); 163 type_record_field( 164 b, (Field){.name = kit_sym_intern(p->c, KIT_SLICE_LIT("__gr_offs")), 165 .type = it}); 166 type_record_field( 167 b, (Field){.name = kit_sym_intern(p->c, KIT_SLICE_LIT("__vr_offs")), 168 .type = it}); 169 return type_record_end(p, b); 170 } 171 case KIT_CG_VALIST_POINTER: 172 case KIT_CG_VALIST_OPAQUE: 173 break; 174 } 175 return type_ptr(p, type_void(p)); 176 }