kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

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; }