kit

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

native_frame.h (6192B)


      1 /* see also: cg/native_argmove.h (shared parallel-copy register shuffle) */
      2 #ifndef KIT_CG_NATIVE_FRAME_H
      3 #define KIT_CG_NATIVE_FRAME_H
      4 
      5 /* Shared native-frame bookkeeping for the aa64/rv64/x64 NativeTarget backends.
      6  *
      7  * Every native backend lays out a stack frame the same way at the bookkeeping
      8  * level: a table of frame slots (locals, spills, sret/variadic homes, and — on
      9  * aa64 — callee-save homes) accumulated below the frame anchor, a running
     10  * max-outgoing-arg size, and a set of callee-saved registers the allocator
     11  * touched. The *arithmetic* of assigning each slot a cumulative offset, the
     12  * frame-final gate that forbids growing the frame after the prologue is
     13  * emitted, and the derivation of the used-callee-save set from the optimizer's
     14  * per-class masks are identical across all three. They live here.
     15  *
     16  * What stays in each backend is everything ISA/ABI-specific: the coordinate
     17  * transform from a slot's cumulative `off` to an anchor-relative displacement
     18  * (fp/s0/rbp-relative, and aa64's top- vs bottom-record choice), the
     19  * prologue/epilogue instruction encoding, callee-save placement (aa64 reserves
     20  * slots here; rv64/x64 compute offsets below the locals), the slim-prologue
     21  * variants, deferred-patch application, and the variadic register-save stores.
     22  *
     23  * The frame-relevant ABI facts are consulted through this module too:
     24  * native_frame_va_save_bytes derives the vararg register-save-area size from
     25  * the target ABI's va_list layout, so the per-arch magic numbers (rv64 64, x64
     26  * 176, aa64 64+128) all come from one ABI-driven query. */
     27 
     28 #include "abi/abi.h"
     29 #include "arch/native_target.h"
     30 #include "core/core.h"
     31 
     32 /* One allocated frame slot. `off` is the cumulative byte offset below the frame
     33  * anchor (positive); the backend converts it to an anchor-relative
     34  * displacement. Layout matches the per-arch slot structs it replaces. */
     35 typedef struct NativeFrameSlotEntry {
     36   u32 off;
     37   u32 size;
     38   u32 align;
     39   u8 kind; /* NativeFrameSlotKind */
     40   u8 pad[3];
     41 } NativeFrameSlotEntry;
     42 
     43 /* A callee-saved register the function body used and must preserve. `slot` is
     44  * the reserved save slot when the backend asked native_frame to allocate one
     45  * (aa64), else NATIVE_FRAME_SLOT_NONE (rv64/x64 compute the save offset). */
     46 typedef struct NativeFrameCalleeSave {
     47   NativeFrameSlot slot;
     48   KitCgTypeId type;
     49   u8 cls; /* NativeAllocClass */
     50   Reg reg;
     51 } NativeFrameCalleeSave;
     52 
     53 /* Per-class save-slot shape, used only when native_frame_set_callee_saves is
     54  * asked to allocate save slots (alloc_slots != 0). Indexed by NativeAllocClass.
     55  */
     56 typedef struct NativeFrameSaveSpec {
     57   u32 size;
     58   u32 align;
     59   KitCgTypeId type;
     60 } NativeFrameSaveSpec;
     61 
     62 /* x19..x28 (10) + v8..v15 (8) on aa64; s0..s11 + fs0..fs11 on rv64; the Win64
     63  * GPR + XMM callee-saved set on x64. 48 covers every target with headroom. */
     64 #define NATIVE_FRAME_MAX_CALLEE_SAVES 48u
     65 
     66 typedef struct NativeFrame {
     67   Compiler* c;
     68 
     69   NativeFrameSlotEntry* slots; /* arena-grown; 1-indexed handles */
     70   u32 nslots;
     71   u32 slots_cap;
     72   u32 cum_off; /* running below-anchor slot bytes (sum of reservations) */
     73 
     74   u32 max_outgoing; /* max outgoing-arg bytes across all calls */
     75 
     76   NativeFrameCalleeSave callee_saves[NATIVE_FRAME_MAX_CALLEE_SAVES];
     77   u32 ncallee_saves;
     78 
     79   u8 frame_final; /* set once the prologue is emitted; bars further slots */
     80   u8 known_frame; /* optimizer (known-frame) path vs single-pass path */
     81   u8 has_alloca;  /* body contains a dynamic alloca */
     82   u8 pad;
     83 } NativeFrame;
     84 
     85 /* One-time setup (call from <arch>_native_target_new). */
     86 void native_frame_init(NativeFrame* f, Compiler* c);
     87 
     88 /* Per-function reset: clears the slot table, outgoing size, callee-save set and
     89  * the frame flags. Keeps the slots buffer for reuse across functions. */
     90 void native_frame_reset(NativeFrame* f);
     91 
     92 /* Allocate a frame slot, advancing the cumulative offset by `size` aligned to
     93  * `align` (defaults: size 8, align 1). Returns a 1-indexed handle. Panics if
     94  * the frame is already final. Identical arithmetic to the per-arch allocators.
     95  */
     96 NativeFrameSlot native_frame_slot_alloc(NativeFrame* f,
     97                                         const NativeFrameSlotDesc* d);
     98 
     99 /* Resolve a 1-indexed handle to its entry. Panics on an out-of-range handle. */
    100 NativeFrameSlotEntry* native_frame_slot_at(NativeFrame* f,
    101                                            NativeFrameSlot slot);
    102 
    103 /* Grow max_outgoing to at least `bytes`. */
    104 void native_frame_note_outgoing(NativeFrame* f, u32 bytes);
    105 
    106 /* Mark the frame final (no further native_frame_slot_alloc allowed). */
    107 void native_frame_set_final(NativeFrame* f);
    108 
    109 static inline u32 native_frame_slot_bytes(const NativeFrame* f) {
    110   return f->cum_off;
    111 }
    112 
    113 /* Derive the used-callee-save set from the optimizer's per-class masks (one
    114  * bitmask of hard registers per NativeAllocClass, already restricted to the
    115  * callee-saved set by the caller). Appends one NativeFrameCalleeSave per set
    116  * bit. When alloc_slots is non-zero, also reserves an 8/size-byte save slot per
    117  * register (aa64); otherwise slot is left NONE and the backend computes the
    118  * save offset itself (rv64/x64). `spec_by_class` (indexed by NativeAllocClass)
    119  * gives the save-slot shape per class and may be NULL when alloc_slots == 0.
    120  * Resets the set first; panics if it would exceed
    121  * NATIVE_FRAME_MAX_CALLEE_SAVES. */
    122 void native_frame_set_callee_saves(NativeFrame* f, const u32* used_by_class,
    123                                    u32 nclasses,
    124                                    const NativeFrameSaveSpec* spec_by_class,
    125                                    u32 nspec, int alloc_slots);
    126 
    127 /* Fill `out` with the registers in the callee-save set belonging to `cls`, in
    128  * the order they were derived. Returns the count written (capped at `cap`). */
    129 u32 native_frame_collect_saves(const NativeFrame* f, NativeAllocClass cls,
    130                                Reg* out, u32 cap);
    131 
    132 /* Bytes of the vararg register-save area for `abi`, derived from its va_list
    133  * layout: gp_reg_count*gp_slot_size + fp_reg_count*fp_slot_size. 0 for ABIs
    134  * with no register-save area (e.g. Win64). The one ABI-consulting frame query.
    135  */
    136 u32 native_frame_va_save_bytes(TargetABI* abi);
    137 
    138 #endif