kit

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

cg_adapter.h (10695B)


      1 #ifndef KIT_PARSE_CG_ADAPTER_H
      2 #define KIT_PARSE_CG_ADAPTER_H
      3 
      4 /* cg_adapter.h — the C parser <-> codegen seam.
      5  *
      6  * Declares the `pcg_*` helpers (implemented in cg_adapter.c) plus the
      7  * C-frontend types they operate on. Every `pcg_*` call keeps the parser's
      8  * typed shadow stack (cg_type_stack / cg_value_flags / cg_lv_aux in struct
      9  * Parser) in lockstep with the public CG stack and folds C lvalue chains into
     10  * single effective-address memops; the parser never calls stack-affecting
     11  * `kit_cg_*` ops directly. See doc/FRONTENDS.md for the design. */
     12 
     13 #include <kit/cg.h>
     14 
     15 #include "c_support.h"
     16 #include "type/type.h"
     17 
     18 typedef KitCg CG;
     19 typedef KitCgLabel CGLabel;
     20 typedef KitCgLocal FrameSlot;
     21 
     22 #define FRAME_SLOT_NONE KIT_CG_LOCAL_NONE
     23 #define OBJ_GROUP_NONE 0u
     24 
     25 /* Lvalue auxiliary state, carried parallel to cg_type_stack / cg_value_flags.
     26  *
     27  * The C parser tracks one logical "C-language value" per stack slot. When that
     28  * slot is a C-language lvalue (PCG_VALUE_LVALUE), the aux below records the
     29  * pending effective-address modifiers and bit-field metadata that the next
     30  * load / store / addr will fold onto the CG memop.
     31  *
     32  * Lvalue chains (`s.f`, `a[i].g`, etc.) accumulate into this aux instead of
     33  * emitting per-step CG ops: there is no CG-level `field` / `index` /
     34  * `addr_offset` op anymore. Field offsets bump `offset`; subscripts set
     35  * `scale` and leave the evaluated index value on the CG stack just above the
     36  * lvalue base. Bit-field selections fill `bit_*`. The aux is consumed by the
     37  * very next pcg_load / pcg_store / pcg_addr that crosses the slot.
     38  *
     39  * `base_kind` records what the CG-stack base under this lvalue actually is —
     40  * either an OPK_LOCAL produced by push_local (PCG_LV_BASE_LOCAL) or a
     41  * pointer rvalue from push_symbol_addr, push_local_addr, dereference, or
     42  * pointer arithmetic (PCG_LV_BASE_POINTER_RV). Stream A's CG-side memops
     43  * accept either shape uniformly; pcg_addr uses the distinction to decide
     44  * whether to emit kit_cg_addr or treat the base as already-a-pointer. */
     45 typedef enum PcgLvBaseKind {
     46   PCG_LV_BASE_LOCAL = 0,
     47   PCG_LV_BASE_POINTER_RV = 1,
     48 } PcgLvBaseKind;
     49 
     50 typedef struct PcgLvAux {
     51   i64 offset;
     52   u32 scale;
     53   u16 bit_offset;
     54   u16 bit_width;
     55   u32 storage_size;
     56   u8 bit_signed;
     57   u8 base_kind;    /* PcgLvBaseKind */
     58   u8 is_subobject; /* lvalue is a member/element of a larger CG object */
     59   u8 pad[5];
     60 } PcgLvAux;
     61 
     62 typedef enum BinOp {
     63   BO_IADD,
     64   BO_ISUB,
     65   BO_IMUL,
     66   BO_SDIV,
     67   BO_UDIV,
     68   BO_SREM,
     69   BO_UREM,
     70   BO_FADD,
     71   BO_FSUB,
     72   BO_FMUL,
     73   BO_FDIV,
     74   BO_AND,
     75   BO_OR,
     76   BO_XOR,
     77   BO_SHL,
     78   BO_SHR_S,
     79   BO_SHR_U,
     80 } BinOp;
     81 
     82 typedef enum UnOp {
     83   UO_NEG,
     84   UO_NOT,
     85   UO_BNOT,
     86 } UnOp;
     87 
     88 /* Compare markers used by the C parser. The integer block plus the four
     89  * relational FP markers (CMP_LT_F..CMP_GE_F) cover the bare C operators; the
     90  * latter map to the *ordered* FP predicates in pcg_fp_cmp. The trailing
     91  * ordered/unordered block mirrors the global CmpOp / public KitCgFpCmpOp so
     92  * the C99 comparison builtins (islessgreater -> CMP_ONE_F) and any
     93  * negation-driven unordered duals are reachable from the frontend 1:1. */
     94 typedef enum CmpOp {
     95   CMP_EQ,
     96   CMP_NE,
     97   CMP_LT_S,
     98   CMP_LE_S,
     99   CMP_GT_S,
    100   CMP_GE_S,
    101   CMP_LT_U,
    102   CMP_LE_U,
    103   CMP_GT_U,
    104   CMP_GE_U,
    105   /* Relational FP operator markers (bare `< <= > >=` on floats) -> ordered. */
    106   CMP_LT_F,
    107   CMP_LE_F,
    108   CMP_GT_F,
    109   CMP_GE_F,
    110   /* Ordered FP relationals (NaN -> false). */
    111   CMP_OEQ_F,
    112   CMP_ONE_F,
    113   CMP_OLT_F,
    114   CMP_OLE_F,
    115   CMP_OGT_F,
    116   CMP_OGE_F,
    117   /* Unordered FP relationals (NaN -> true). */
    118   CMP_UEQ_F,
    119   CMP_UNE_F,
    120   CMP_ULT_F,
    121   CMP_ULE_F,
    122   CMP_UGT_F,
    123   CMP_UGE_F,
    124 } CmpOp;
    125 
    126 typedef enum AtomicOp {
    127   AO_XCHG,
    128   AO_ADD,
    129   AO_SUB,
    130   AO_AND,
    131   AO_OR,
    132   AO_XOR,
    133   AO_NAND,
    134 } AtomicOp;
    135 
    136 typedef enum MemOrder {
    137   MO_RELAXED,
    138   MO_CONSUME,
    139   MO_ACQUIRE,
    140   MO_RELEASE,
    141   MO_ACQ_REL,
    142   MO_SEQ_CST,
    143 } MemOrder;
    144 
    145 typedef enum IntrinKind {
    146   INTRIN_NONE = 0,
    147   INTRIN_POPCOUNT,
    148   INTRIN_CTZ,
    149   INTRIN_CLZ,
    150   INTRIN_MEMCPY,
    151   INTRIN_MEMMOVE,
    152   INTRIN_MEMSET,
    153   INTRIN_PREFETCH,
    154   INTRIN_ASSUME_ALIGNED,
    155   INTRIN_EXPECT,
    156   INTRIN_UNREACHABLE,
    157   INTRIN_TRAP,
    158   INTRIN_SETJMP,
    159   INTRIN_LONGJMP,
    160   INTRIN_SADD_OVERFLOW,
    161   INTRIN_UADD_OVERFLOW,
    162   INTRIN_SSUB_OVERFLOW,
    163   INTRIN_USUB_OVERFLOW,
    164   INTRIN_SMUL_OVERFLOW,
    165   INTRIN_UMUL_OVERFLOW,
    166 } IntrinKind;
    167 
    168 typedef enum AsmDir { ASM_IN, ASM_OUT, ASM_INOUT } AsmDir;
    169 
    170 typedef struct AsmConstraint {
    171   const char* str;
    172   Sym name;
    173   const Type* type;
    174   Sym reg; /* hard-register name for a GNU local register variable; 0 = none */
    175   u8 dir;
    176   u8 pad[3];
    177 } AsmConstraint;
    178 
    179 typedef enum FrameSlotKind {
    180   FS_LOCAL,
    181   FS_PARAM,
    182   FS_SPILL,
    183   FS_SRET,
    184   FS_ALLOCA,
    185 } FrameSlotKind;
    186 
    187 typedef enum FrameSlotFlag {
    188   FSF_NONE = 0,
    189   FSF_ADDR_TAKEN = 1u << 0,
    190   FSF_VOLATILE = 1u << 1,
    191 } FrameSlotFlag;
    192 
    193 typedef struct FrameSlotDesc {
    194   const Type* type;
    195   Sym name;
    196   SrcLoc loc;
    197   u32 size;
    198   u32 align;
    199   u8 kind;
    200   u8 pad;
    201   u16 flags;
    202 } FrameSlotDesc;
    203 
    204 typedef struct CGParamDesc {
    205   u32 index;
    206   Sym name;
    207   const Type* type;
    208   FrameSlot slot;
    209   const void* abi;
    210   const void* incoming;
    211   u32 nincoming;
    212   SrcLoc loc;
    213 } CGParamDesc;
    214 
    215 typedef enum CGFuncDescFlag {
    216   CGFD_NONE = 0,
    217   CGFD_NORETURN = 1u << 0,
    218 } CGFuncDescFlag;
    219 
    220 typedef struct CGFuncDesc {
    221   ObjSymId sym;
    222   ObjSecId text_section_id;
    223   u32 group_id;
    224   const Type* fn_type;
    225   const void* abi;
    226   const CGParamDesc* params;
    227   u32 nparams;
    228   SrcLoc loc;
    229   u32 flags;
    230   KitCgInlinePolicy inline_policy;
    231 } CGFuncDesc;
    232 
    233 typedef struct Parser Parser;
    234 
    235 KitCgTypeId pcg_tid(Parser*, const Type*);
    236 KitCgMemAccess pcg_mem(Parser*, const Type*);
    237 const Type* pcg_top_type(Parser*);
    238 const Type* pcg_top2_type(Parser*);
    239 void pcg_retag_top(Parser*, const Type*);
    240 void pcg_push_type(Parser*, const Type*);
    241 void pcg_drop_type(Parser*);
    242 void pcg_dup_type(Parser*);
    243 void pcg_swap_type(Parser*);
    244 /* Structural CG ops that also mirror onto the typed shadow stack. */
    245 void pcg_dup(Parser*);
    246 void pcg_swap(Parser*);
    247 void pcg_drop(Parser*);
    248 int pcg_top_is_bitfield(Parser*);
    249 void pcg_set_top_bitfield(Parser*);
    250 int pcg_top_is_register(Parser*);
    251 void pcg_set_top_register(Parser*);
    252 int pcg_top_is_lvalue(Parser*);
    253 int pcg_top_is_modifiable_lvalue(Parser*);
    254 int pcg_top_is_null_ptr_const(Parser*);
    255 void pcg_set_top_lvalue(Parser*);
    256 void pcg_rot3_type(Parser*);
    257 int pcg_emit_enabled(Parser*);
    258 void pcg_codegen_suppress_push(Parser*);
    259 void pcg_codegen_suppress_pop(Parser*);
    260 
    261 KitCgIntBinOp pcg_int_binop(BinOp);
    262 KitCgFpBinOp pcg_fp_binop(BinOp);
    263 KitCgIntCmpOp pcg_int_cmp(CmpOp);
    264 KitCgFpCmpOp pcg_fp_cmp(CmpOp);
    265 KitCgAtomicOp pcg_atomic_op(AtomicOp);
    266 KitCgMemOrder pcg_mem_order(MemOrder);
    267 int pcg_type_is_fp(const Type*);
    268 int pcg_type_is_signed(const Type*);
    269 
    270 FrameSlot pcg_local(Parser*, const FrameSlotDesc*);
    271 FrameSlot pcg_param_slot(Parser*, u32, const FrameSlotDesc*);
    272 void pcg_param(Parser*, const CGParamDesc*);
    273 void pcg_func_begin(Parser*, const CGFuncDesc*);
    274 void pcg_func_end(Parser*);
    275 void pcg_set_loc(Parser*, SrcLoc);
    276 void pcg_push_int(Parser*, i64, const Type*);
    277 void pcg_push_float(Parser*, double, const Type*);
    278 void pcg_push_local_typed(Parser*, FrameSlot, const Type*);
    279 void pcg_push_global(Parser*, ObjSymId, const Type*);
    280 void pcg_load(Parser*);
    281 void pcg_addr(Parser*);
    282 void pcg_push_label_addr(Parser*, CGLabel);
    283 void pcg_computed_goto(Parser*, const CGLabel*, u32);
    284 CGLabel pcg_label_new(Parser*);
    285 void pcg_label_place(Parser*, CGLabel);
    286 void pcg_jump(Parser*, CGLabel);
    287 void pcg_branch_true(Parser*, CGLabel);
    288 void pcg_branch_false(Parser*, CGLabel);
    289 void pcg_store(Parser*);
    290 void pcg_deref(Parser*, const Type*);
    291 
    292 /* ---- Lvalue auxiliary access ----
    293  *
    294  * pcg_top_lv_aux returns a mutable pointer to TOS's lvalue aux, used by
    295  * parse_postfix and the initializer / compound-assignment paths to fold
    296  * field offsets and bit-field metadata inline. Returns NULL if the parser
    297  * stack is empty; behavior on a non-lvalue TOS is the caller's responsibility
    298  * (parse_postfix has already validated lvalueness before calling). */
    299 PcgLvAux* pcg_top_lv_aux(Parser*);
    300 PcgLvAux* pcg_lv_aux_at(Parser*, u32 depth);
    301 
    302 /* ---- Lvalue chain helpers ----
    303  *
    304  * Each maps directly to the canonical encodings in doc/INDIRECT.md without
    305  * emitting any intermediate field / index / addr_offset CG op. Field offsets
    306  * and array scales are accumulated on the TOS lvalue's aux; the next
    307  * pcg_load / pcg_store / pcg_addr consumes them. */
    308 
    309 /* Fold `s.f` (or any path-resolved field selection) into the TOS lvalue.
    310  * byte_offset is the cumulative offset within the record; ty is the field
    311  * type; bf_* are bit-field metadata (bf_width == 0 for non-bitfields). The
    312  * caller is responsible for verifying TOS is an lvalue of a record type. */
    313 void pcg_lv_member(Parser*, i64 byte_offset, const Type* field_ty,
    314                    u16 bf_offset, u16 bf_width, u32 bf_storage_size);
    315 
    316 /* Attach `[index]` to the TOS lvalue. PRECONDITION: the index value has just
    317  * been pushed onto the CG stack (and parser stack) above the lvalue base;
    318  * the parser stack therefore has [base_lv, index] at depth [1, 0]. This call
    319  * records `scale = elem_size` on the base's aux, drops the index parser
    320  * slot (leaving the index value on the CG stack for the eventual memop),
    321  * and retags the surviving slot as elem_ty (lvalue). */
    322 void pcg_lv_subscript(Parser*, u32 elem_size, const Type* elem_ty);
    323 
    324 /* Decay an array lvalue at TOS into a pointer-to-element rvalue. Emits
    325  * kit_cg_addr (or a no-op for pointer-rvalue bases) and folds any pending
    326  * EA modifiers into the resulting pointer via ptr arithmetic. After return,
    327  * TOS is a pointer rvalue of type `*arr_ty->elem`. */
    328 void pcg_decay_array(Parser*, const Type* arr_ty);
    329 
    330 void pcg_binop(Parser*, BinOp);
    331 void pcg_unop(Parser*, UnOp);
    332 void pcg_cmp(Parser*, CmpOp);
    333 void pcg_convert(Parser*, const Type*);
    334 void pcg_inc_dec(Parser*, BinOp, int);
    335 void pcg_call(Parser*, u32, const Type*);
    336 void pcg_call_symbol(Parser*, KitCgSym, u32, const Type*);
    337 void pcg_ret(Parser*, int);
    338 void pcg_alloca(Parser*);
    339 void pcg_va_arg(Parser*, const Type*);
    340 void pcg_va_start(Parser*);
    341 void pcg_va_end(Parser*);
    342 void pcg_va_copy(Parser*);
    343 void pcg_atomic_load(Parser*, MemOrder);
    344 void pcg_atomic_store(Parser*, MemOrder);
    345 void pcg_atomic_rmw(Parser*, AtomicOp, MemOrder);
    346 void pcg_atomic_cas(Parser*, MemOrder, MemOrder);
    347 void pcg_fence(Parser*, MemOrder);
    348 void pcg_intrinsic_unary_to_int(Parser*, IntrinKind);
    349 void pcg_intrinsic_void(Parser*, IntrinKind);
    350 void pcg_syscall(Parser*, u32 nargs, const Type* long_ty);
    351 void pcg_frame_or_return_address(Parser*, int is_return, u32 level);
    352 void pcg_inline_asm(Parser*, const char*, const AsmConstraint*, u32,
    353                     const AsmConstraint*, u32, const Sym*, u32);
    354 
    355 #endif