kit

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

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 }