abi.c (11344B)
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 static ABITypeInfo abi_cg_type_info_compute(TargetABI* a, KitCgTypeId id) { 28 ABITypeInfo r = {0, 0, ABI_SC_VOID, 0, 0, 0}; 29 const CgType* t; 30 t = cg_type_get(a->c, id); 31 if (!t) return r; 32 switch (t->kind) { 33 case KIT_CG_TYPE_PTR: 34 r.size = a->c->target.ptr_size ? a->c->target.ptr_size : 8; 35 r.align = a->c->target.ptr_align ? a->c->target.ptr_align : 8; 36 r.scalar_kind = ABI_SC_PTR; 37 return r; 38 case KIT_CG_TYPE_ARRAY: { 39 ABITypeInfo e = abi_cg_type_info(a, t->array.elem); 40 r.size = e.size * t->array.count; 41 r.align = e.align; 42 return r; 43 } 44 case KIT_CG_TYPE_RECORD: { 45 const ABIRecordLayout* L = abi_cg_record_layout(a, id); 46 if (L) { 47 r.size = L->size; 48 r.align = L->align; 49 } 50 return r; 51 } 52 case KIT_CG_TYPE_ENUM: 53 return abi_cg_type_info(a, t->enum_.base); 54 case KIT_CG_TYPE_FUNC: 55 /* sizeof(function) is undefined in C; use 1 for arithmetic. */ 56 r.size = 1; 57 r.align = 1; 58 return r; 59 case KIT_CG_TYPE_VOID: 60 r.align = 1; 61 r.scalar_kind = ABI_SC_VOID; 62 return r; 63 case KIT_CG_TYPE_BOOL: 64 r.size = t->size; 65 r.align = t->align; 66 r.scalar_kind = ABI_SC_BOOL; 67 return r; 68 case KIT_CG_TYPE_INT: 69 r.size = t->size; 70 r.align = t->align; 71 r.scalar_kind = ABI_SC_INT; 72 return r; 73 case KIT_CG_TYPE_FLOAT: 74 r.size = t->size; 75 r.align = t->align; 76 r.scalar_kind = ABI_SC_FLOAT; 77 return r; 78 case KIT_CG_TYPE_VARARG_STATE: 79 r.size = t->size; 80 r.align = t->align; 81 return r; 82 default: 83 return r; 84 } 85 } 86 87 ABITypeInfo abi_cg_type_info(TargetABI* a, KitCgTypeId id) { 88 const ABITypeInfo* p; 89 ABITypeInfo r; 90 if (!id) { 91 ABITypeInfo z = {0, 0, ABI_SC_VOID, 0, 0, 0}; 92 return z; 93 } 94 /* Builtins are the overwhelming majority of type queries: index the 95 * per-compiler layout table inline (one load, no cross-TU call) once cg_api 96 * has published it. Before that, fall through to the general path, which 97 * lazily creates the table. */ 98 if (id <= KIT_CG_BUILTIN_COUNT && a->c->cg_builtin_layout) 99 return ((const ABITypeInfo*)a->c->cg_builtin_layout)[id - 1u]; 100 /* User types: a borrowed pointer to the cached layout (no field-by-field 101 * copy) collapses the alias/enum/array recursion to one load; a miss computes 102 * once and caches. */ 103 p = api_type_layout_ref(a->c, id); 104 if (p) return *p; 105 r = abi_cg_type_info_compute(a, id); 106 api_type_layout_put(a->c, id, r); 107 return r; 108 } 109 110 u32 abi_cg_sizeof(TargetABI* a, KitCgTypeId id) { 111 return abi_cg_type_info(a, id).size; 112 } 113 u32 abi_cg_alignof(TargetABI* a, KitCgTypeId id) { 114 return abi_cg_type_info(a, id).align; 115 } 116 117 u32 abi_cg_scalar_split_lane_size(TargetABI* a, KitCgTypeId id) { 118 if (!a || !a->vt || !a->vt->scalar_split_lane_size) return 0; 119 return a->vt->scalar_split_lane_size(a, id); 120 } 121 122 /* ---- record layout (struct/union) ---- 123 * 124 * The CG type constructor computes the shared source-facing record layout. 125 * The ABI cache exposes that immutable layout to codegen passes. When an ABI 126 * with different source bit-field rules lands, record construction should be 127 * routed through an ABI-specific layout hook before the type is committed. */ 128 129 static ABIRecordLayout* compute_record_layout(TargetABI* a, KitCgTypeId id) { 130 ABIRecordLayout* L = arena_new(a->c->tu, ABIRecordLayout); 131 const CgType* t = cg_type_get(a->c, id); 132 if (!L) return NULL; 133 if (!t || t->kind != KIT_CG_TYPE_RECORD || 134 !(t->record.flags & CG_TYPE_RECORD_COMPLETE)) 135 return NULL; 136 memset(L, 0, sizeof *L); 137 ABIFieldLayout* fl = NULL; 138 if (t->record.nfields) { 139 fl = arena_array(a->c->tu, ABIFieldLayout, t->record.nfields); 140 memset(fl, 0, sizeof(ABIFieldLayout) * t->record.nfields); 141 } 142 143 for (u32 i = 0; i < t->record.nfields; ++i) { 144 const CgTypeField* f = &t->record.fields[i]; 145 fl[i].offset = (u32)f->offset; 146 fl[i].bit_offset = f->bit_offset; 147 fl[i].bit_width = (f->flags & KIT_CG_FIELD_BITFIELD) ? f->bit_width : 0; 148 fl[i].storage_size = f->bit_storage_size ? f->bit_storage_size 149 : (u32)abi_cg_sizeof(a, f->type); 150 } 151 L->size = (u32)t->size; 152 L->align = t->align; 153 L->nfields = t->record.nfields; 154 L->fields = fl; 155 return L; 156 } 157 158 const ABIRecordLayout* abi_cg_record_layout(TargetABI* a, KitCgTypeId id) { 159 const CgType* t = cg_type_get(a->c, id); 160 ABIRecordLayout** hit; 161 ABIRecordLayout* L; 162 if (!t || t->kind != KIT_CG_TYPE_RECORD || 163 !(t->record.flags & CG_TYPE_RECORD_COMPLETE)) 164 return NULL; 165 hit = AbiRecLayoutMap_get(&a->rec_cache, id); 166 if (hit) return *hit; 167 L = compute_record_layout(a, id); 168 if (!L) return NULL; 169 AbiRecLayoutMap_set(&a->rec_cache, id, L); 170 return L; 171 } 172 173 /* ---- shared classifier primitives ---- 174 * 175 * The per-ABI classifiers (abi_sysv_x64.c, abi_win64_x64.c, abi_aapcs64.c, 176 * abi_rv64.c) share these byte-identical building blocks; the ABI-specific 177 * scalar/aggregate rules stay in their own TUs. */ 178 179 /* A void / zero-size argument is ignored (no parts, no register/stack slot). */ 180 void abi_classify_void(ABIArgInfo* out) { 181 memset(out, 0, sizeof *out); 182 out->kind = ABI_ARG_IGNORE; 183 } 184 185 /* A 16-byte integer scalar (__int128 / __uint128) passed/returned as two 186 * INTEGER eightbytes: low half in the lower-numbered register, high in the 187 * next. Used by the SysV-x64, Win64 (mingw), and AAPCS64 classifiers, which 188 * all agree on this shape. */ 189 void abi_classify_int128_pair(TargetABI* a, ABIArgInfo* out) { 190 ABIArgPart* parts = arena_array(a->c->tu, ABIArgPart, 2); 191 memset(parts, 0, sizeof(ABIArgPart) * 2); 192 for (u32 i = 0; i < 2; ++i) { 193 parts[i].cls = ABI_CLASS_INT; 194 parts[i].loc = ABI_LOC_REG; 195 parts[i].size = 8; 196 parts[i].align = 8; 197 parts[i].src_offset = i * 8; 198 } 199 out->kind = ABI_ARG_DIRECT; 200 out->flags = ABI_AF_NONE; 201 out->parts = parts; 202 out->nparts = 2; 203 out->indirect_align = 0; 204 } 205 206 /* The single-register scalar tail shared by every per-ABI classify_scalar: a 207 * DIRECT argument with exactly one register part carrying the whole scalar. 208 * `is_fp` selects the part class; the caller owns the FP-eligibility decision. 209 */ 210 void abi_classify_scalar_reg_part(TargetABI* a, ABIArgInfo* out, ABITypeInfo ti, 211 int is_fp) { 212 out->kind = ABI_ARG_DIRECT; 213 out->flags = ABI_AF_NONE; 214 out->indirect_align = 0; 215 216 ABIArgPart* parts = arena_new(a->c->tu, ABIArgPart); 217 memset(parts, 0, sizeof *parts); 218 parts->cls = is_fp ? ABI_CLASS_FP : ABI_CLASS_INT; 219 parts->loc = ABI_LOC_REG; 220 parts->size = ti.size; 221 parts->align = ti.align; 222 parts->src_offset = 0; 223 224 out->parts = parts; 225 out->nparts = 1; 226 } 227 228 /* Generic compute_func_info scaffold shared by the per-ABI vtables. Classifies 229 * the result then every parameter through `classify_one`, filling the shared 230 * has_sret / sret_consumes_int_arg / variadic / nparams fields. The per-ABI 231 * vararg metadata pass (SysV-x64 gp/fp offsets) runs in the caller on the 232 * returned info; all vararg_* fields are left zero here. */ 233 ABIFuncInfo* abi_compute_func_info_generic(TargetABI* a, KitCgTypeId fn, 234 ABIClassifyOneFn classify_one, 235 int sret_consumes_int_arg) { 236 ABIFuncInfo* info = arena_new(a->c->tu, ABIFuncInfo); 237 const CgType* fnty = cg_type_get(a->c, fn); 238 memset(info, 0, sizeof *info); 239 240 classify_one(a, cg_func_ret_type(fnty), &info->ret, /*is_return=*/1); 241 info->has_sret = (info->ret.kind == ABI_ARG_INDIRECT) ? 1 : 0; 242 info->sret_consumes_int_arg = 243 (sret_consumes_int_arg && info->has_sret) ? 1 : 0; 244 info->variadic = fnty->func.abi_variadic; 245 246 info->nparams = (u16)fnty->func.nparams; 247 if (fnty->func.nparams) { 248 ABIArgInfo* arr = arena_array(a->c->tu, ABIArgInfo, fnty->func.nparams); 249 memset(arr, 0, sizeof(ABIArgInfo) * fnty->func.nparams); 250 for (u32 i = 0; i < fnty->func.nparams; ++i) { 251 classify_one(a, fnty->func.params[i].type, &arr[i], /*is_return=*/0); 252 } 253 info->params = arr; 254 } else { 255 info->params = NULL; 256 } 257 return info; 258 } 259 260 /* ---- function classification (vtabled) ---- */ 261 262 const ABIFuncInfo* abi_cg_func_info(TargetABI* a, KitCgTypeId fn_type) { 263 const CgType* fn = cg_type_get(a->c, fn_type); 264 ABIFuncInfo** hit; 265 ABIFuncInfo* info; 266 if (!fn || fn->kind != KIT_CG_TYPE_FUNC) return NULL; 267 hit = AbiFnInfoMap_get(&a->fn_cache, fn_type); 268 if (hit) return *hit; 269 info = a->vt->compute_func_info(a, fn_type); 270 if (!info) return NULL; 271 AbiFnInfoMap_set(&a->fn_cache, fn_type, info); 272 return info; 273 } 274 275 u32 abi_stack_probe_interval(TargetABI* a) { 276 return a->vt->stack_probe_interval; 277 } 278 279 ABITypeInfo abi_va_list_info(TargetABI* a) { return a->vt->va_list_info; } 280 281 ABIVaListInfo abi_va_list_layout(TargetABI* a) { 282 /* va_list_info is the single source of truth for the va_list ABITypeInfo; 283 * the layout's .type is always derived from it so the two cannot drift. */ 284 ABIVaListInfo out = a->vt->va_list_layout; 285 out.type = a->vt->va_list_info; 286 if (out.kind == ABI_VA_LIST_OPAQUE && out.type.scalar_kind == ABI_SC_PTR && 287 out.type.size == 8u) 288 out.kind = ABI_VA_LIST_POINTER; 289 return out; 290 } 291 292 /* ---- lifecycle ---- */ 293 294 static const ABIVtable* select_vtable(Compiler* c) { 295 const ABIVtable* vt = abi_vtable_lookup(c->target.arch, c->target.obj); 296 if (vt) return vt; 297 { 298 SrcLoc loc = {0, 0, 0}; 299 compiler_panic(c, loc, "abi_init: unsupported target arch/obj %d/%d", 300 (int)c->target.arch, (int)c->target.obj); 301 } 302 } 303 304 void abi_init(TargetABI* a, Compiler* c) { 305 memset(a, 0, sizeof *a); 306 a->c = c; 307 a->vt = select_vtable(c); 308 /* The cached values stay on c->tu (per-TU arena); only the index lives on the 309 * compiler heap, freed in abi_fini. */ 310 AbiFnInfoMap_init(&a->fn_cache, (Heap*)c->ctx->heap); 311 AbiRecLayoutMap_init(&a->rec_cache, (Heap*)c->ctx->heap); 312 } 313 314 void abi_fini(TargetABI* a) { 315 if (!a) return; 316 AbiFnInfoMap_fini(&a->fn_cache); 317 AbiRecLayoutMap_fini(&a->rec_cache); 318 a->vt = NULL; 319 a->c = NULL; 320 } 321 322 TargetABI* abi_new(Compiler* c) { 323 Heap* h = (Heap*)c->ctx->heap; 324 TargetABI* a = 325 (TargetABI*)h->alloc(h, sizeof(TargetABI), _Alignof(TargetABI)); 326 if (!a) return NULL; 327 abi_init(a, c); 328 return a; 329 } 330 331 void abi_free(TargetABI* a) { 332 if (!a) return; 333 Heap* h = (Heap*)a->c->ctx->heap; 334 abi_fini(a); 335 h->free(h, a, sizeof(TargetABI)); 336 } 337 338 Compiler* abi_compiler(TargetABI* a) { return a ? a->c : NULL; }