kit

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

native_frame.c (5827B)


      1 #include "cg/native_frame.h"
      2 
      3 #include <string.h>
      4 
      5 #include "core/arena.h"
      6 
      7 static u32 nf_align_up(u32 v, u32 align) {
      8   u32 mask = align ? align - 1u : 0u;
      9   return (v + mask) & ~mask;
     10 }
     11 
     12 static void nf_panic(NativeFrame* f, const char* msg) {
     13   compiler_panic(f->c, (SrcLoc){0, 0, 0}, "native frame: %s", msg);
     14 }
     15 
     16 void native_frame_init(NativeFrame* f, Compiler* c) {
     17   memset(f, 0, sizeof *f);
     18   f->c = c;
     19 }
     20 
     21 void native_frame_reset(NativeFrame* f) {
     22   /* Keep the slots buffer (slots/slots_cap) for reuse across functions in the
     23    * translation unit; nslots = 0 logically clears it. The transient free list is
     24    * per-function: dropping nfree_bins discards any stale buckets, and each fresh
     25    * slot_alloc reinitializes its entry's free_next/in_free, so no stale handle
     26    * from the previous function can be served. */
     27   f->nslots = 0;
     28   f->cum_off = 0;
     29   f->max_outgoing = 0;
     30   f->ncallee_saves = 0;
     31   f->nfree_bins = 0;
     32   f->frame_final = 0;
     33   f->known_frame = 0;
     34   f->has_alloca = 0;
     35 }
     36 
     37 /* Find the free bucket for (size,align), or NULL. */
     38 static u32* nf_free_bin_find(NativeFrame* f, u32 size, u32 align) {
     39   for (u32 i = 0; i < f->nfree_bins; ++i)
     40     if (f->free_bins[i].size == size && f->free_bins[i].align == align)
     41       return &f->free_bins[i].head;
     42   return NULL;
     43 }
     44 
     45 NativeFrameSlot native_frame_slot_alloc(NativeFrame* f,
     46                                         const NativeFrameSlotDesc* d) {
     47   NativeFrameSlotEntry* s;
     48   u32 size = d->size ? d->size : 8u;
     49   u32 align = d->align ? d->align : 1u;
     50   if (f->frame_final) nf_panic(f, "frame slot requested after prologue");
     51   /* A transient temp first tries to reuse a dead slot of the exact same
     52    * (size,align): its home offset already satisfies the alignment, so handing
     53    * the same handle back is safe and leaves cum_off (the frame high-water mark)
     54    * unchanged. */
     55   if (d->flags & NATIVE_FRAME_SLOT_TRANSIENT) {
     56     u32* head = nf_free_bin_find(f, size, align);
     57     if (head && *head != NATIVE_FRAME_SLOT_NONE) {
     58       NativeFrameSlot slot = *head;
     59       s = &f->slots[slot - 1u];
     60       *head = s->free_next;
     61       s->free_next = NATIVE_FRAME_SLOT_NONE;
     62       s->in_free = 0;
     63       s->kind = d->kind;
     64       return slot;
     65     }
     66   }
     67   if (f->nslots == f->slots_cap) {
     68     u32 cap = f->slots_cap ? f->slots_cap * 2u : 16u;
     69     NativeFrameSlotEntry* nb =
     70         arena_zarray(f->c->tu, NativeFrameSlotEntry, cap);
     71     if (f->slots) memcpy(nb, f->slots, sizeof(*nb) * f->nslots);
     72     f->slots = nb;
     73     f->slots_cap = cap;
     74   }
     75   f->cum_off = nf_align_up(f->cum_off + size, align);
     76   s = &f->slots[f->nslots++];
     77   s->off = f->cum_off;
     78   s->size = size;
     79   s->align = align;
     80   s->free_next = NATIVE_FRAME_SLOT_NONE;
     81   s->kind = d->kind;
     82   s->in_free = 0;
     83   return (NativeFrameSlot)f->nslots;
     84 }
     85 
     86 void native_frame_release_slot(NativeFrame* f, NativeFrameSlot slot) {
     87   NativeFrameSlotEntry* s;
     88   u32* head;
     89   if (slot == NATIVE_FRAME_SLOT_NONE || slot > f->nslots) return;
     90   s = &f->slots[slot - 1u];
     91   if (s->in_free) return; /* already released */
     92   head = nf_free_bin_find(f, s->size, s->align);
     93   if (!head) {
     94     if (f->nfree_bins >= (u32)(sizeof f->free_bins / sizeof f->free_bins[0]))
     95       return; /* bucket table full: don't recycle this shape (still correct) */
     96     f->free_bins[f->nfree_bins].size = s->size;
     97     f->free_bins[f->nfree_bins].align = s->align;
     98     f->free_bins[f->nfree_bins].head = NATIVE_FRAME_SLOT_NONE;
     99     head = &f->free_bins[f->nfree_bins].head;
    100     f->nfree_bins++;
    101   }
    102   s->free_next = *head;
    103   *head = slot;
    104   s->in_free = 1;
    105 }
    106 
    107 NativeFrameSlotEntry* native_frame_slot_at(NativeFrame* f,
    108                                            NativeFrameSlot slot) {
    109   if (slot == NATIVE_FRAME_SLOT_NONE || slot > f->nslots)
    110     nf_panic(f, "bad frame slot");
    111   return &f->slots[slot - 1u];
    112 }
    113 
    114 void native_frame_note_outgoing(NativeFrame* f, u32 bytes) {
    115   if (bytes > f->max_outgoing) f->max_outgoing = bytes;
    116 }
    117 
    118 void native_frame_set_final(NativeFrame* f) { f->frame_final = 1; }
    119 
    120 void native_frame_set_callee_saves(NativeFrame* f, const u32* used_by_class,
    121                                    u32 nclasses,
    122                                    const NativeFrameSaveSpec* spec_by_class,
    123                                    u32 nspec, int alloc_slots) {
    124   f->ncallee_saves = 0;
    125   if (!used_by_class) return;
    126   for (u32 cls = 0; cls < nclasses; ++cls) {
    127     u32 mask = used_by_class[cls];
    128     for (Reg r = 0; r < 32u && mask; ++r) {
    129       NativeFrameCalleeSave* cs;
    130       if ((mask & (1u << r)) == 0) continue;
    131       mask &= ~(1u << r);
    132       if (f->ncallee_saves >= NATIVE_FRAME_MAX_CALLEE_SAVES)
    133         nf_panic(f, "too many callee-saved registers");
    134       cs = &f->callee_saves[f->ncallee_saves++];
    135       cs->cls = (u8)cls;
    136       cs->reg = r;
    137       cs->slot = NATIVE_FRAME_SLOT_NONE;
    138       cs->type = 0;
    139       if (cls < nspec && spec_by_class) cs->type = spec_by_class[cls].type;
    140       if (alloc_slots) {
    141         NativeFrameSlotDesc sd;
    142         const NativeFrameSaveSpec* sp =
    143             (cls < nspec && spec_by_class) ? &spec_by_class[cls] : NULL;
    144         memset(&sd, 0, sizeof sd);
    145         sd.type = cs->type;
    146         sd.size = sp && sp->size ? sp->size : 8u;
    147         sd.align = sp && sp->align ? sp->align : 8u;
    148         sd.kind = NATIVE_FRAME_SLOT_SAVE;
    149         cs->slot = native_frame_slot_alloc(f, &sd);
    150       }
    151     }
    152   }
    153 }
    154 
    155 u32 native_frame_collect_saves(const NativeFrame* f, NativeAllocClass cls,
    156                                Reg* out, u32 cap) {
    157   u32 n = 0;
    158   for (u32 i = 0; i < f->ncallee_saves; ++i) {
    159     if (f->callee_saves[i].cls != (u8)cls) continue;
    160     if (n >= cap) break;
    161     out[n++] = f->callee_saves[i].reg;
    162   }
    163   return n;
    164 }
    165 
    166 u32 native_frame_va_save_bytes(TargetABI* abi) {
    167   ABIVaListInfo va = abi_va_list_layout(abi);
    168   return va.gp_reg_count * va.gp_slot_size + va.fp_reg_count * va.fp_slot_size;
    169 }