kit

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

ir.h (7778B)


      1 #ifndef KIT_CG_IR_H
      2 #define KIT_CG_IR_H
      3 
      4 #include "cg/cgtarget.h"
      5 #include "core/arena.h"
      6 #include "core/hashmap.h"
      7 
      8 HASHMAP_DEFINE(ObjSymSet, ObjSymId, u8, hash_u32);
      9 
     10 typedef enum CgIrOp {
     11   CG_IR_NOP,
     12   CG_IR_LABEL,
     13 
     14   CG_IR_LOAD_IMM,
     15   CG_IR_LOAD_CONST,
     16   CG_IR_COPY,
     17   CG_IR_LOAD,
     18   CG_IR_STORE,
     19   CG_IR_ADDR_OF,
     20   CG_IR_TLS_ADDR_OF,
     21   CG_IR_AGG_COPY,
     22   CG_IR_AGG_SET,
     23   CG_IR_BITFIELD_LOAD,
     24   CG_IR_BITFIELD_STORE,
     25 
     26   CG_IR_BINOP,
     27   CG_IR_UNOP,
     28   CG_IR_CMP,
     29   CG_IR_CONVERT,
     30 
     31   CG_IR_CALL,
     32   CG_IR_RET,
     33   CG_IR_UNREACHABLE,
     34 
     35   CG_IR_BR,
     36   CG_IR_CMP_BRANCH,
     37   CG_IR_SWITCH,
     38   CG_IR_INDIRECT_BRANCH,
     39   CG_IR_LOAD_LABEL_ADDR,
     40   CG_IR_LOCAL_STATIC_DATA_BEGIN,
     41   CG_IR_LOCAL_STATIC_DATA_WRITE,
     42   CG_IR_LOCAL_STATIC_DATA_LABEL_ADDR,
     43   CG_IR_LOCAL_STATIC_DATA_END,
     44   CG_IR_SCOPE_BEGIN,
     45   CG_IR_SCOPE_END,
     46   CG_IR_BREAK_TO,
     47   CG_IR_CONTINUE_TO,
     48 
     49   CG_IR_ALLOCA,
     50   CG_IR_VA_START,
     51   CG_IR_VA_ARG,
     52   CG_IR_VA_END,
     53   CG_IR_VA_COPY,
     54 
     55   CG_IR_ATOMIC_LOAD,
     56   CG_IR_ATOMIC_STORE,
     57   CG_IR_ATOMIC_RMW,
     58   CG_IR_ATOMIC_CAS,
     59   CG_IR_FENCE,
     60 
     61   CG_IR_INTRINSIC,
     62   CG_IR_ASM_BLOCK,
     63 } CgIrOp;
     64 
     65 typedef struct CgIrLocal {
     66   CGLocal id;
     67   CGLocalDesc desc;
     68   u32 param_index;
     69   u8 is_param;
     70   u8 address_taken;
     71   u8 pad[2];
     72 } CgIrLocal;
     73 
     74 typedef struct CgIrParam {
     75   CGLocal local;
     76   CGParamDesc desc;
     77 } CgIrParam;
     78 
     79 typedef struct CgIrLabel {
     80   Label id;
     81   SrcLoc first_place_loc;
     82   u32 nplaces;
     83 } CgIrLabel;
     84 
     85 typedef struct CgIrScope {
     86   CGScope id;
     87   CGScopeDesc desc;
     88 } CgIrScope;
     89 
     90 typedef struct CgIrTlsAux {
     91   ObjSymId sym;
     92   i64 addend;
     93 } CgIrTlsAux;
     94 
     95 typedef struct CgIrAggAux {
     96   AggregateAccess access;
     97 } CgIrAggAux;
     98 
     99 typedef struct CgIrBitFieldAux {
    100   BitFieldAccess access;
    101 } CgIrBitFieldAux;
    102 
    103 typedef struct CgIrCallAux {
    104   CGCallDesc desc;
    105 } CgIrCallAux;
    106 
    107 typedef struct CgIrRetAux {
    108   CGLocal value; /* CG_LOCAL_NONE when present == 0 (void return) */
    109   u8 present;
    110 } CgIrRetAux;
    111 
    112 typedef struct CgIrCmpBranchAux {
    113   CmpOp op;
    114   Label target;
    115 } CgIrCmpBranchAux;
    116 
    117 typedef struct CgIrSwitchAux {
    118   KitCgTypeId selector_type;
    119   Label default_label;
    120   CGSwitchCase* cases;
    121   u32 ncases;
    122   u8 hint;
    123   u8 opt_level;
    124   u8 pad[2];
    125 } CgIrSwitchAux;
    126 
    127 typedef struct CgIrIndirectAux {
    128   Label* targets;
    129   u32 ntargets;
    130 } CgIrIndirectAux;
    131 
    132 typedef struct CgIrLocalStaticBeginAux {
    133   CGLocalStaticDataDesc desc;
    134 } CgIrLocalStaticBeginAux;
    135 
    136 typedef struct CgIrLocalStaticWriteAux {
    137   u8* data;
    138   u64 len;
    139   u8 has_data;
    140   u8 pad[7];
    141 } CgIrLocalStaticWriteAux;
    142 
    143 typedef struct CgIrLocalStaticLabelAux {
    144   Label target;
    145   i64 addend;
    146   u32 width;
    147   u32 address_space;
    148 } CgIrLocalStaticLabelAux;
    149 
    150 typedef struct CgIrScopeAux {
    151   CGScope scope;
    152   CGScopeDesc desc;
    153 } CgIrScopeAux;
    154 
    155 typedef struct CgIrAtomicAux {
    156   MemAccess mem;
    157   KitCgMemOrder order;
    158   KitCgAtomicOp op;
    159   KitCgMemOrder failure;
    160 } CgIrAtomicAux;
    161 
    162 typedef struct CgIrAsmAux {
    163   char* tmpl;
    164   AsmConstraint* outs;
    165   Operand* out_ops;
    166   AsmConstraint* ins;
    167   Operand* in_ops;
    168   Sym* clobbers;
    169   u32 nout;
    170   u32 nin;
    171   u32 nclob;
    172   u32 clobber_abi_sets; /* KitCgAsmClobberAbiSet bits */
    173 } CgIrAsmAux;
    174 
    175 typedef struct CgIrIntrinsicAux {
    176   IntrinKind kind;
    177   Operand* dsts;
    178   Operand* args;
    179   u32 ndst;
    180   u32 narg;
    181 } CgIrIntrinsicAux;
    182 
    183 /* Per-instruction semantic-mode flags carried in CgIrInst.flags. They select,
    184  * per op, between the IR's portable edge-case semantics (default, bit clear)
    185  * and the target's native-instruction semantics (bit set). Both modes are fully
    186  * defined — the IR has no undefined behavior in either; the target-defined
    187  * choice trades cross-target portability for the cheapest lowering when the
    188  * source language already declares the edge undefined. See the "Semantic modes"
    189  * and "Well-definedness" sections of doc/IR.md. Honoring these bits is per
    190  * consumer; a consumer that does not understand a bit must implement the
    191  * portable semantics, which is always a safe refinement. */
    192 typedef enum CgIrInstFlag {
    193   CG_IR_INST_FLAG_NONE = 0,
    194   /* BINOP sdiv/udiv/srem/urem: a zero divisor and INT_MIN/-1 follow the target
    195    * divide instruction instead of the portable trap (zero) / wrap (INT_MIN/-1).
    196    */
    197   CG_IR_INST_TARGET_DIV_EDGES = 1u << 0,
    198   /* BINOP shl/shr_s/shr_u: an out-of-range shift count follows the target shift
    199    * instruction instead of the portable reduce-modulo-width. */
    200   CG_IR_INST_TARGET_SHIFT_EDGES = 1u << 1,
    201   /* CONVERT ftoi_s/ftoi_u: out-of-range / NaN / inf inputs follow the target
    202    * convert instruction instead of the portable saturate (NaN -> 0). */
    203   CG_IR_INST_TARGET_FPTOINT_EDGES = 1u << 2,
    204 } CgIrInstFlag;
    205 
    206 typedef struct CgIrInst {
    207   u32 id;
    208   u16 op;
    209   u16 flags; /* CgIrInstFlag: per-op portable-vs-target-defined edge semantics
    210               */
    211   SrcLoc loc;
    212   u32 nopnds;
    213   Operand* opnds;
    214   union {
    215     i64 imm;
    216     ConstBytes cbytes;
    217     MemAccess mem;
    218     void* aux;
    219   } extra;
    220 } CgIrInst;
    221 
    222 typedef struct CgIrFunc {
    223   Arena* arena;
    224   Compiler* c;
    225   CGFuncDesc desc;
    226 
    227   CgIrInst* insts;
    228   u32 ninsts;
    229   u32 insts_cap;
    230 
    231   CgIrLocal* locals;
    232   u32 nlocals;
    233   u32 locals_cap;
    234 
    235   CgIrParam* params;
    236   u32 nparams;
    237   u32 params_cap;
    238 
    239   CgIrLabel* labels;
    240   u32 nlabels;
    241   u32 labels_cap;
    242 
    243   CgIrScope* scopes;
    244   u32 nscopes;
    245   u32 scopes_cap;
    246 
    247   ObjSymSet call_refs;
    248   ObjSymSet global_refs;
    249 
    250   u32 next_inst_id;
    251   u8 complete;
    252   u8 removed;
    253   u8 pad[2];
    254 } CgIrFunc;
    255 
    256 typedef struct CgIrAlias {
    257   ObjSymId alias_sym;
    258   ObjSymId target_sym;
    259   KitCgTypeId type;
    260 } CgIrAlias;
    261 
    262 /* A file-scope `__asm__(...)` block, captured verbatim for replay. The
    263  * single-pass target emits it inline during recording; the optimizer path has
    264  * no live target then, so the module retains it for opt_on_finalize to replay
    265  * (see cg_ir_module_add_file_scope_asm). */
    266 typedef struct CgIrFileScopeAsm {
    267   const char* src;
    268   size_t len;
    269 } CgIrFileScopeAsm;
    270 
    271 typedef struct CgIrModule {
    272   Arena* arena;
    273   Compiler* c;
    274   CgIrFunc** funcs;
    275   u32 nfuncs;
    276   u32 funcs_cap;
    277   CgIrAlias* aliases;
    278   u32 naliases;
    279   u32 aliases_cap;
    280   CgIrFileScopeAsm* file_scope_asms;
    281   u32 nfile_scope_asms;
    282   u32 file_scope_asms_cap;
    283 } CgIrModule;
    284 
    285 CgIrModule* cg_ir_module_new(Compiler*);
    286 CgIrFunc* cg_ir_func_new(Compiler*, const CGFuncDesc*);
    287 void cg_ir_module_add_func(CgIrModule*, CgIrFunc*);
    288 void cg_ir_module_add_alias(CgIrModule*, ObjSymId alias_sym,
    289                             ObjSymId target_sym, KitCgTypeId type);
    290 void cg_ir_module_add_file_scope_asm(CgIrModule*, const char* src, size_t len);
    291 void cg_ir_module_refsets_fini(CgIrModule*);
    292 
    293 void cg_ir_symset_init_lazy(Compiler*, ObjSymSet*);
    294 void cg_ir_symset_add(Compiler*, ObjSymSet*, ObjSymId);
    295 int cg_ir_symset_contains(const ObjSymSet*, ObjSymId);
    296 void cg_ir_symset_fini(ObjSymSet*);
    297 
    298 CGLocal cg_ir_func_add_local(CgIrFunc*, const CGLocalDesc*, int is_param,
    299                              u32 param_index);
    300 void cg_ir_func_mark_local_address_taken(CgIrFunc*, CGLocal);
    301 void cg_ir_func_add_param(CgIrFunc*, CGLocal, const CGParamDesc*);
    302 Label cg_ir_func_add_label(CgIrFunc*);
    303 void cg_ir_func_note_label_place(CgIrFunc*, Label, SrcLoc);
    304 CGScope cg_ir_func_add_scope(CgIrFunc*, const CGScopeDesc*);
    305 
    306 CgIrInst* cg_ir_emit(CgIrFunc*, CgIrOp, SrcLoc);
    307 
    308 /* Render the semantic CG IR tape to `w` as line-oriented text. Stable enough
    309  * for golden-file diffs; symbols appear by numeric id (sym#N). */
    310 void cg_ir_func_dump(const CgIrFunc*, Writer*);
    311 
    312 Operand* cg_ir_dup_operands(Arena*, const Operand*, u32 n);
    313 CGLocal* cg_ir_dup_locals(Arena*, const CGLocal*, u32 n);
    314 Label* cg_ir_dup_labels(Arena*, const Label*, u32 n);
    315 CGSwitchCase* cg_ir_dup_switch_cases(Arena*, const CGSwitchCase*, u32 n);
    316 ConstBytes cg_ir_dup_const_bytes(Arena*, ConstBytes);
    317 CGCallDesc cg_ir_dup_call_desc(Arena*, const CGCallDesc*);
    318 AsmConstraint* cg_ir_dup_asm_constraints(Arena*, const AsmConstraint*, u32 n);
    319 char* cg_ir_dup_cstr(Arena*, const char*);
    320 
    321 #endif