abi.c (7024B)
1 /* TargetABI dispatch and shared codegen type layout. 2 * 3 * The single authority for target-dependent storage layout and calling 4 * convention decisions. Frontends lower source-language types to CgType 5 * before calling into this layer. 6 * 7 * Per-ABI bits (function classification, __va_list shape) live in 8 * abi_aapcs64.c, abi_sysv_x64.c, ... The ABI registry selects the vtable 9 * for (target.arch, target.obj). The C-standard-driven scalar profile and 10 * record layout stay here so all ABIs share one impl. */ 11 12 #include "abi/abi.h" 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 /* ---- scalar profile ---- 22 * 23 * Shared by all currently supported ABIs (LP64 on Linux for both 24 * aarch64 and x86_64). When a Windows-x64 (LLP64) or 32-bit ABI lands, 25 * promote prim_info into the vtable. */ 26 27 ABITypeInfo abi_cg_type_info(TargetABI* a, KitCgTypeId id) { 28 ABITypeInfo r = {0, 0, ABI_SC_VOID, 0, 0, 0}; 29 const CgType* t; 30 if (!id) return r; 31 t = cg_type_get(a->c, id); 32 if (!t) return r; 33 switch (t->kind) { 34 case KIT_CG_TYPE_ALIAS: 35 return abi_cg_type_info(a, t->alias.base); 36 case KIT_CG_TYPE_PTR: 37 r.size = a->c->target.ptr_size ? a->c->target.ptr_size : 8; 38 r.align = a->c->target.ptr_align ? a->c->target.ptr_align : 8; 39 r.scalar_kind = ABI_SC_PTR; 40 return r; 41 case KIT_CG_TYPE_ARRAY: { 42 ABITypeInfo e = abi_cg_type_info(a, t->array.elem); 43 r.size = e.size * t->array.count; 44 r.align = e.align; 45 return r; 46 } 47 case KIT_CG_TYPE_RECORD: { 48 const ABIRecordLayout* L = abi_cg_record_layout(a, id); 49 if (L) { 50 r.size = L->size; 51 r.align = L->align; 52 } 53 return r; 54 } 55 case KIT_CG_TYPE_ENUM: 56 return abi_cg_type_info(a, t->enum_.base); 57 case KIT_CG_TYPE_FUNC: 58 /* sizeof(function) is undefined in C; use 1 for arithmetic. */ 59 r.size = 1; 60 r.align = 1; 61 return r; 62 case KIT_CG_TYPE_VOID: 63 r.align = 1; 64 r.scalar_kind = ABI_SC_VOID; 65 return r; 66 case KIT_CG_TYPE_BOOL: 67 r.size = t->size; 68 r.align = t->align; 69 r.scalar_kind = ABI_SC_BOOL; 70 return r; 71 case KIT_CG_TYPE_INT: 72 r.size = t->size; 73 r.align = t->align; 74 r.scalar_kind = ABI_SC_INT; 75 return r; 76 case KIT_CG_TYPE_FLOAT: 77 r.size = t->size; 78 r.align = t->align; 79 r.scalar_kind = ABI_SC_FLOAT; 80 return r; 81 case KIT_CG_TYPE_VARARG_STATE: 82 r.size = t->size; 83 r.align = t->align; 84 return r; 85 default: 86 return r; 87 } 88 } 89 90 ABITypeInfo abi_internal_type_info(TargetABI* a, KitCgTypeId id) { 91 return abi_cg_type_info(a, id); 92 } 93 94 u32 abi_cg_sizeof(TargetABI* a, KitCgTypeId id) { 95 return abi_cg_type_info(a, id).size; 96 } 97 u32 abi_cg_alignof(TargetABI* a, KitCgTypeId id) { 98 return abi_cg_type_info(a, id).align; 99 } 100 101 u32 abi_cg_scalar_split_lane_size(TargetABI* a, KitCgTypeId id) { 102 if (!a || !a->vt || !a->vt->scalar_split_lane_size) return 0; 103 return a->vt->scalar_split_lane_size(a, id); 104 } 105 106 /* ---- record layout (struct/union) ---- 107 * 108 * The CG type constructor computes the shared source-facing record layout. 109 * The ABI cache exposes that immutable layout to codegen passes. When an ABI 110 * with different source bit-field rules lands, record construction should be 111 * routed through an ABI-specific layout hook before the type is committed. */ 112 113 static ABIRecordLayout* compute_record_layout(TargetABI* a, KitCgTypeId id) { 114 ABIRecordLayout* L = arena_new(a->c->tu, ABIRecordLayout); 115 const CgType* t = cg_type_get(a->c, id); 116 if (!L) return NULL; 117 if (!t || t->kind != KIT_CG_TYPE_RECORD) return NULL; 118 memset(L, 0, sizeof *L); 119 ABIFieldLayout* fl = NULL; 120 if (t->record.nfields) { 121 fl = arena_array(a->c->tu, ABIFieldLayout, t->record.nfields); 122 memset(fl, 0, sizeof(ABIFieldLayout) * t->record.nfields); 123 } 124 125 for (u32 i = 0; i < t->record.nfields; ++i) { 126 const CgTypeField* f = &t->record.fields[i]; 127 fl[i].offset = (u32)f->offset; 128 fl[i].bit_offset = f->bit_offset; 129 fl[i].bit_width = (f->flags & KIT_CG_FIELD_BITFIELD) ? f->bit_width : 0; 130 fl[i].storage_size = f->bit_storage_size ? f->bit_storage_size 131 : (u32)abi_cg_sizeof(a, f->type); 132 } 133 L->size = (u32)t->size; 134 L->align = t->align; 135 L->nfields = t->record.nfields; 136 L->fields = fl; 137 return L; 138 } 139 140 const ABIRecordLayout* abi_cg_record_layout(TargetABI* a, KitCgTypeId id) { 141 const CgType* t = cg_type_get(a->c, id); 142 if (!t || t->kind != KIT_CG_TYPE_RECORD) return NULL; 143 for (RecordLayoutCacheEntry* e = a->rec_cache; e; e = e->next) { 144 if (e->ty == id) return e->layout; 145 } 146 ABIRecordLayout* L = compute_record_layout(a, id); 147 if (!L) return NULL; 148 RecordLayoutCacheEntry* e = arena_new(a->c->tu, RecordLayoutCacheEntry); 149 e->ty = id; 150 e->layout = L; 151 e->next = a->rec_cache; 152 a->rec_cache = e; 153 return L; 154 } 155 156 /* ---- function classification (vtabled) ---- */ 157 158 const ABIFuncInfo* abi_cg_func_info(TargetABI* a, KitCgTypeId fn_type) { 159 const CgType* fn = cg_type_get(a->c, fn_type); 160 if (!fn || fn->kind != KIT_CG_TYPE_FUNC) return NULL; 161 for (FuncInfoCacheEntry* e = a->fn_cache; e; e = e->next) { 162 if (e->fn == fn_type) return e->info; 163 } 164 ABIFuncInfo* info = a->vt->compute_func_info(a, fn_type); 165 if (!info) return NULL; 166 FuncInfoCacheEntry* e = arena_new(a->c->tu, FuncInfoCacheEntry); 167 e->fn = fn_type; 168 e->info = info; 169 e->next = a->fn_cache; 170 a->fn_cache = e; 171 return info; 172 } 173 174 u32 abi_stack_probe_interval(TargetABI* a) { 175 return a->vt->stack_probe_interval; 176 } 177 178 ABITypeInfo abi_va_list_info(TargetABI* a) { return a->vt->va_list_info; } 179 180 ABIVaListInfo abi_va_list_layout(TargetABI* a) { 181 ABIVaListInfo out = a->vt->va_list_layout; 182 if (out.kind == ABI_VA_LIST_OPAQUE) { 183 out.type = a->vt->va_list_info; 184 if (out.type.scalar_kind == ABI_SC_PTR && out.type.size == 8u) 185 out.kind = ABI_VA_LIST_POINTER; 186 } 187 return out; 188 } 189 190 /* ---- lifecycle ---- */ 191 192 static const ABIVtable* select_vtable(Compiler* c) { 193 const ABIVtable* vt = abi_vtable_lookup(c->target.arch, c->target.obj); 194 if (vt) return vt; 195 { 196 SrcLoc loc = {0, 0, 0}; 197 compiler_panic(c, loc, "abi_init: unsupported target arch/obj %d/%d", 198 (int)c->target.arch, (int)c->target.obj); 199 } 200 } 201 202 void abi_init(TargetABI* a, Compiler* c) { 203 memset(a, 0, sizeof *a); 204 a->c = c; 205 a->vt = select_vtable(c); 206 } 207 208 void abi_fini(TargetABI* a) { 209 /* Arena-backed; nothing to release. */ 210 if (!a) return; 211 a->fn_cache = NULL; 212 a->rec_cache = NULL; 213 a->vt = NULL; 214 a->c = NULL; 215 } 216 217 TargetABI* abi_new(Compiler* c) { 218 Heap* h = (Heap*)c->ctx->heap; 219 TargetABI* a = 220 (TargetABI*)h->alloc(h, sizeof(TargetABI), _Alignof(TargetABI)); 221 if (!a) return NULL; 222 abi_init(a, c); 223 return a; 224 } 225 226 void abi_free(TargetABI* a) { 227 if (!a) return; 228 Heap* h = (Heap*)a->c->ctx->heap; 229 abi_fini(a); 230 h->free(h, a, sizeof(TargetABI)); 231 } 232 233 Compiler* abi_compiler(TargetABI* a) { return a ? a->c : NULL; }