kit

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

ir_recorder.c (23716B)


      1 #include "cg/ir_recorder.h"
      2 
      3 #include <string.h>
      4 
      5 struct CgIrRecorder {
      6   CgTarget base;
      7   u32 magic;
      8   CgIrModule* module;
      9   CgIrFunc* cur;
     10   SrcLoc loc;
     11   void (*func_recorded)(void*, CgIrFunc*);
     12   void (*finalize_recorded)(void*, const CgIrModule*);
     13   void (*destroy_user)(void*);
     14   int (*local_static_data_begin)(void*, const CGLocalStaticDataDesc*);
     15   const char* (*data_label_addr_unsupported_msg)(void*);
     16   const char* (*tail_call_unrealizable_reason)(void*, const CGFuncDesc*,
     17                                                const CGCallDesc*);
     18   int (*asm_is_reg_constraint)(void*, const char*);
     19   void* user;
     20 };
     21 
     22 #define CG_IR_RECORDER_MAGIC 0x43524952u
     23 
     24 static CgIrRecorder* rec_of(CgTarget* t) { return (CgIrRecorder*)t; }
     25 
     26 static void rec_panic(CgIrRecorder* r, const char* what) {
     27   compiler_panic(r->base.c, r->loc, "cg ir recorder: %s", what);
     28 }
     29 
     30 static CgIrFunc* require_func(CgIrRecorder* r) {
     31   if (!r->cur) rec_panic(r, "operation outside function");
     32   return r->cur;
     33 }
     34 
     35 static void* aux_alloc(CgIrRecorder* r, size_t size, size_t align) {
     36   void* p = arena_zalloc(require_func(r)->arena, size, align);
     37   if (!p) rec_panic(r, "out of memory");
     38   return p;
     39 }
     40 
     41 #define AUX_NEW(r, T) ((T*)aux_alloc((r), sizeof(T), _Alignof(T)))
     42 
     43 static CgIrInst* emit(CgIrRecorder* r, CgIrOp op) {
     44   return cg_ir_emit(require_func(r), op, r->loc);
     45 }
     46 
     47 static void note_global_ref(CgIrRecorder* r, Operand op) {
     48   if (op.kind == OPK_GLOBAL)
     49     cg_ir_symset_add(r->base.c, &require_func(r)->global_refs, op.v.global.sym);
     50 }
     51 
     52 static void note_global_refs(CgIrRecorder* r, const Operand* ops, u32 n) {
     53   if (!ops) return;
     54   for (u32 i = 0; i < n; ++i) note_global_ref(r, ops[i]);
     55 }
     56 
     57 static void set_ops(CgIrRecorder* r, CgIrInst* in, const Operand* ops, u32 n) {
     58   in->opnds = cg_ir_dup_operands(require_func(r)->arena, ops, n);
     59   in->nopnds = n;
     60   note_global_refs(r, ops, n);
     61 }
     62 
     63 static void rec_func_begin(CgTarget* t, const CGFuncDesc* desc) {
     64   CgIrRecorder* r = rec_of(t);
     65   if (r->cur) rec_panic(r, "nested function begin");
     66   r->cur = cg_ir_func_new(t->c, desc);
     67   if (!r->cur) rec_panic(r, "out of memory");
     68   cg_ir_module_add_func(r->module, r->cur);
     69   r->loc = desc ? desc->loc : (SrcLoc){0, 0, 0};
     70 }
     71 
     72 static void rec_func_end(CgTarget* t) {
     73   CgIrRecorder* r = rec_of(t);
     74   CgIrFunc* f = require_func(r);
     75   f->complete = 1;
     76   if (r->func_recorded) r->func_recorded(r->user, f);
     77   r->cur = NULL;
     78 }
     79 
     80 static void rec_alias(CgTarget* t, ObjSymId alias_sym, ObjSymId target_sym,
     81                       KitCgTypeId type) {
     82   CgIrRecorder* r = rec_of(t);
     83   cg_ir_module_add_alias(r->module, alias_sym, target_sym, type);
     84 }
     85 
     86 static CGLocal rec_local(CgTarget* t, const CGLocalDesc* desc) {
     87   CgIrRecorder* r = rec_of(t);
     88   return cg_ir_func_add_local(require_func(r), desc, 0, 0);
     89 }
     90 
     91 static void rec_local_addr(CgTarget* t, Operand dst, const CGLocalDesc* desc,
     92                            CGLocal local) {
     93   CgIrRecorder* r = rec_of(t);
     94   CgIrInst* in = emit(r, CG_IR_ADDR_OF);
     95   Operand ops[2];
     96   (void)desc;
     97   cg_ir_func_mark_local_address_taken(require_func(r), local);
     98   memset(ops, 0, sizeof ops);
     99   ops[0] = dst;
    100   ops[1].kind = OPK_LOCAL;
    101   ops[1].type = desc ? desc->type : dst.type;
    102   ops[1].v.local = local;
    103   set_ops(r, in, ops, 2);
    104 }
    105 
    106 static CGLocal rec_param(CgTarget* t, const CGParamDesc* desc) {
    107   CgIrRecorder* r = rec_of(t);
    108   CgIrFunc* f = require_func(r);
    109   CGLocalDesc ld;
    110   CGLocal local;
    111   memset(&ld, 0, sizeof ld);
    112   ld.type = desc->type;
    113   ld.name = desc->name;
    114   ld.loc = desc->loc;
    115   ld.size = desc->size;
    116   ld.align = desc->align;
    117   ld.flags = desc->flags;
    118   local = cg_ir_func_add_local(f, &ld, 1, desc->index);
    119   cg_ir_func_add_param(f, local, desc);
    120   return local;
    121 }
    122 
    123 static Label rec_label_new(CgTarget* t) {
    124   return cg_ir_func_add_label(require_func(rec_of(t)));
    125 }
    126 
    127 static void rec_label_place(CgTarget* t, Label label) {
    128   CgIrRecorder* r = rec_of(t);
    129   CgIrInst* in = emit(r, CG_IR_LABEL);
    130   in->extra.imm = (i64)label;
    131   cg_ir_func_note_label_place(require_func(r), label, r->loc);
    132 }
    133 
    134 static void rec_jump(CgTarget* t, Label label) {
    135   CgIrInst* in = emit(rec_of(t), CG_IR_BR);
    136   in->extra.imm = (i64)label;
    137 }
    138 
    139 static void rec_cmp_branch(CgTarget* t, CmpOp op, Operand a, Operand b,
    140                            Label label) {
    141   CgIrRecorder* r = rec_of(t);
    142   CgIrInst* in = emit(r, CG_IR_CMP_BRANCH);
    143   CgIrCmpBranchAux* aux = AUX_NEW(r, CgIrCmpBranchAux);
    144   Operand ops[2] = {a, b};
    145   aux->op = op;
    146   aux->target = label;
    147   set_ops(r, in, ops, 2);
    148   in->extra.aux = aux;
    149 }
    150 
    151 static void rec_switch(CgTarget* t, const CGSwitchDesc* desc) {
    152   CgIrRecorder* r = rec_of(t);
    153   CgIrInst* in = emit(r, CG_IR_SWITCH);
    154   CgIrSwitchAux* aux = AUX_NEW(r, CgIrSwitchAux);
    155   Operand op = desc->selector;
    156   aux->selector_type = desc->selector_type;
    157   aux->default_label = desc->default_label;
    158   aux->cases =
    159       cg_ir_dup_switch_cases(require_func(r)->arena, desc->cases, desc->ncases);
    160   aux->ncases = desc->ncases;
    161   aux->hint = desc->hint;
    162   aux->opt_level = desc->opt_level;
    163   set_ops(r, in, &op, 1);
    164   in->extra.aux = aux;
    165 }
    166 
    167 static void rec_indirect_branch(CgTarget* t, Operand addr,
    168                                 const Label* valid_targets, u32 ntargets) {
    169   CgIrRecorder* r = rec_of(t);
    170   CgIrInst* in = emit(r, CG_IR_INDIRECT_BRANCH);
    171   CgIrIndirectAux* aux = AUX_NEW(r, CgIrIndirectAux);
    172   aux->targets =
    173       cg_ir_dup_labels(require_func(r)->arena, valid_targets, ntargets);
    174   aux->ntargets = ntargets;
    175   set_ops(r, in, &addr, 1);
    176   in->extra.aux = aux;
    177 }
    178 
    179 static void rec_load_label_addr(CgTarget* t, Operand dst, Label label) {
    180   CgIrInst* in = emit(rec_of(t), CG_IR_LOAD_LABEL_ADDR);
    181   set_ops(rec_of(t), in, &dst, 1);
    182   in->extra.imm = (i64)label;
    183 }
    184 
    185 static int rec_local_static_data_begin(CgTarget* t,
    186                                        const CGLocalStaticDataDesc* desc) {
    187   CgIrRecorder* r = rec_of(t);
    188   if (r->local_static_data_begin &&
    189       !r->local_static_data_begin(r->user, desc)) {
    190     return 0;
    191   }
    192   CgIrInst* in = emit(r, CG_IR_LOCAL_STATIC_DATA_BEGIN);
    193   CgIrLocalStaticBeginAux* aux = AUX_NEW(r, CgIrLocalStaticBeginAux);
    194   aux->desc = *desc;
    195   in->extra.aux = aux;
    196   return 1;
    197 }
    198 
    199 static void rec_local_static_data_write(CgTarget* t, const u8* data, u64 len) {
    200   CgIrRecorder* r = rec_of(t);
    201   CgIrFunc* f = require_func(r);
    202   CgIrInst* in = emit(r, CG_IR_LOCAL_STATIC_DATA_WRITE);
    203   CgIrLocalStaticWriteAux* aux = AUX_NEW(r, CgIrLocalStaticWriteAux);
    204   aux->len = len;
    205   if (data && len) {
    206     if (len > UINT32_MAX) rec_panic(r, "local static data chunk too large");
    207     aux->data = arena_array(f->arena, u8, (u32)len);
    208     memcpy(aux->data, data, (size_t)len);
    209     aux->has_data = 1;
    210   }
    211   in->extra.aux = aux;
    212 }
    213 
    214 static void rec_local_static_data_label_addr(CgTarget* t, Label target,
    215                                              i64 addend, u32 width,
    216                                              u32 address_space) {
    217   CgIrRecorder* r = rec_of(t);
    218   CgIrInst* in = emit(r, CG_IR_LOCAL_STATIC_DATA_LABEL_ADDR);
    219   CgIrLocalStaticLabelAux* aux = AUX_NEW(r, CgIrLocalStaticLabelAux);
    220   aux->target = target;
    221   aux->addend = addend;
    222   aux->width = width;
    223   aux->address_space = address_space;
    224   in->extra.aux = aux;
    225 }
    226 
    227 static void rec_local_static_data_end(CgTarget* t) {
    228   (void)emit(rec_of(t), CG_IR_LOCAL_STATIC_DATA_END);
    229 }
    230 
    231 static const char* rec_data_label_addr_unsupported_msg(CgTarget* t) {
    232   CgIrRecorder* r = rec_of(t);
    233   if (r->data_label_addr_unsupported_msg)
    234     return r->data_label_addr_unsupported_msg(r->user);
    235   return "IR recorder supports function-local label address data";
    236 }
    237 
    238 /* A target that cannot resolve code-label addresses in static data (it set
    239  * data_label_addr_unsupported_msg) likewise cannot build a label-address jump
    240  * table; report that so kit_cg_switch routes table plans through switch_. */
    241 static int rec_supports_label_table(CgTarget* t) {
    242   CgIrRecorder* r = rec_of(t);
    243   return r->data_label_addr_unsupported_msg ? 0 : 1;
    244 }
    245 
    246 static CGScope rec_scope_begin(CgTarget* t, const CGScopeDesc* desc) {
    247   CgIrRecorder* r = rec_of(t);
    248   CgIrInst* in = emit(r, CG_IR_SCOPE_BEGIN);
    249   CgIrScopeAux* aux = AUX_NEW(r, CgIrScopeAux);
    250   CGScope scope = cg_ir_func_add_scope(require_func(r), desc);
    251   aux->scope = scope;
    252   aux->desc = *desc;
    253   in->extra.aux = aux;
    254   return scope;
    255 }
    256 
    257 static void rec_scope_id_op(CgTarget* t, CgIrOp op, CGScope scope) {
    258   CgIrInst* in = emit(rec_of(t), op);
    259   in->extra.imm = (i64)scope;
    260 }
    261 
    262 static void rec_scope_end(CgTarget* t, CGScope scope) {
    263   rec_scope_id_op(t, CG_IR_SCOPE_END, scope);
    264 }
    265 
    266 static void rec_break_to(CgTarget* t, CGScope scope) {
    267   rec_scope_id_op(t, CG_IR_BREAK_TO, scope);
    268 }
    269 
    270 static void rec_continue_to(CgTarget* t, CGScope scope) {
    271   rec_scope_id_op(t, CG_IR_CONTINUE_TO, scope);
    272 }
    273 
    274 static void rec_load_imm(CgTarget* t, Operand dst, i64 imm) {
    275   CgIrInst* in = emit(rec_of(t), CG_IR_LOAD_IMM);
    276   set_ops(rec_of(t), in, &dst, 1);
    277   in->extra.imm = imm;
    278 }
    279 
    280 static void rec_load_const(CgTarget* t, Operand dst, ConstBytes cbytes) {
    281   CgIrRecorder* r = rec_of(t);
    282   CgIrInst* in = emit(r, CG_IR_LOAD_CONST);
    283   set_ops(r, in, &dst, 1);
    284   in->extra.cbytes = cg_ir_dup_const_bytes(require_func(r)->arena, cbytes);
    285 }
    286 
    287 static void rec_copy(CgTarget* t, Operand dst, Operand src) {
    288   CgIrInst* in = emit(rec_of(t), CG_IR_COPY);
    289   Operand ops[2] = {dst, src};
    290   set_ops(rec_of(t), in, ops, 2);
    291 }
    292 
    293 /* Bit-fields ride the generic load/store (mem.bf_width != 0); this impl
    294  * translates them to the dedicated CG_IR_BITFIELD_LOAD/STORE opcodes. */
    295 static void rec_bitfield_load(CgTarget* t, Operand dst, Operand record_addr,
    296                               BitFieldAccess access);
    297 static void rec_bitfield_store(CgTarget* t, Operand record_addr, Operand src,
    298                                BitFieldAccess access);
    299 
    300 static void rec_load(CgTarget* t, Operand dst, Operand addr, MemAccess mem) {
    301   CgIrInst* in;
    302   if (mem.bf_width != 0) {
    303     rec_bitfield_load(t, dst, addr, bf_from_mem(mem));
    304     return;
    305   }
    306   in = emit(rec_of(t), CG_IR_LOAD);
    307   Operand ops[2] = {dst, addr};
    308   set_ops(rec_of(t), in, ops, 2);
    309   in->extra.mem = mem;
    310 }
    311 
    312 static void rec_store(CgTarget* t, Operand addr, Operand src, MemAccess mem) {
    313   CgIrInst* in;
    314   if (mem.bf_width != 0) {
    315     rec_bitfield_store(t, addr, src, bf_from_mem(mem));
    316     return;
    317   }
    318   in = emit(rec_of(t), CG_IR_STORE);
    319   Operand ops[2] = {addr, src};
    320   set_ops(rec_of(t), in, ops, 2);
    321   in->extra.mem = mem;
    322 }
    323 
    324 static void rec_addr_of(CgTarget* t, Operand dst, Operand lv) {
    325   CgIrInst* in = emit(rec_of(t), CG_IR_ADDR_OF);
    326   Operand ops[2] = {dst, lv};
    327   set_ops(rec_of(t), in, ops, 2);
    328   if (lv.kind == OPK_LOCAL)
    329     cg_ir_func_mark_local_address_taken(require_func(rec_of(t)), lv.v.local);
    330 }
    331 
    332 static void rec_tls_addr_of(CgTarget* t, Operand dst, ObjSymId sym,
    333                             i64 addend) {
    334   CgIrRecorder* r = rec_of(t);
    335   CgIrInst* in = emit(r, CG_IR_TLS_ADDR_OF);
    336   CgIrTlsAux* aux = AUX_NEW(r, CgIrTlsAux);
    337   aux->sym = sym;
    338   aux->addend = addend;
    339   set_ops(r, in, &dst, 1);
    340   cg_ir_symset_add(r->base.c, &require_func(r)->global_refs, sym);
    341   in->extra.aux = aux;
    342 }
    343 
    344 static void rec_copy_bytes(CgTarget* t, Operand dst_addr, Operand src_addr,
    345                            AggregateAccess access) {
    346   CgIrRecorder* r = rec_of(t);
    347   CgIrInst* in = emit(r, CG_IR_AGG_COPY);
    348   CgIrAggAux* aux = AUX_NEW(r, CgIrAggAux);
    349   Operand ops[2] = {dst_addr, src_addr};
    350   aux->access = access;
    351   set_ops(r, in, ops, 2);
    352   in->extra.aux = aux;
    353 }
    354 
    355 static void rec_set_bytes(CgTarget* t, Operand dst_addr, Operand byte_value,
    356                           AggregateAccess access) {
    357   CgIrRecorder* r = rec_of(t);
    358   CgIrInst* in = emit(r, CG_IR_AGG_SET);
    359   CgIrAggAux* aux = AUX_NEW(r, CgIrAggAux);
    360   Operand ops[2] = {dst_addr, byte_value};
    361   aux->access = access;
    362   set_ops(r, in, ops, 2);
    363   in->extra.aux = aux;
    364 }
    365 
    366 static void rec_bitfield_load(CgTarget* t, Operand dst, Operand record_addr,
    367                               BitFieldAccess access) {
    368   CgIrRecorder* r = rec_of(t);
    369   CgIrInst* in = emit(r, CG_IR_BITFIELD_LOAD);
    370   CgIrBitFieldAux* aux = AUX_NEW(r, CgIrBitFieldAux);
    371   Operand ops[2] = {dst, record_addr};
    372   aux->access = access;
    373   set_ops(r, in, ops, 2);
    374   in->extra.aux = aux;
    375 }
    376 
    377 static void rec_bitfield_store(CgTarget* t, Operand record_addr, Operand src,
    378                                BitFieldAccess access) {
    379   CgIrRecorder* r = rec_of(t);
    380   CgIrInst* in = emit(r, CG_IR_BITFIELD_STORE);
    381   CgIrBitFieldAux* aux = AUX_NEW(r, CgIrBitFieldAux);
    382   Operand ops[2] = {record_addr, src};
    383   aux->access = access;
    384   set_ops(r, in, ops, 2);
    385   in->extra.aux = aux;
    386 }
    387 
    388 static void rec_binop(CgTarget* t, BinOp op, Operand dst, Operand a,
    389                       Operand b) {
    390   CgIrInst* in = emit(rec_of(t), CG_IR_BINOP);
    391   Operand ops[3] = {dst, a, b};
    392   set_ops(rec_of(t), in, ops, 3);
    393   in->extra.imm = (i64)op;
    394 }
    395 
    396 static void rec_unop(CgTarget* t, UnOp op, Operand dst, Operand a) {
    397   CgIrInst* in = emit(rec_of(t), CG_IR_UNOP);
    398   Operand ops[2] = {dst, a};
    399   set_ops(rec_of(t), in, ops, 2);
    400   in->extra.imm = (i64)op;
    401 }
    402 
    403 static void rec_cmp(CgTarget* t, CmpOp op, Operand dst, Operand a, Operand b) {
    404   CgIrInst* in = emit(rec_of(t), CG_IR_CMP);
    405   Operand ops[3] = {dst, a, b};
    406   set_ops(rec_of(t), in, ops, 3);
    407   in->extra.imm = (i64)op;
    408 }
    409 
    410 static void rec_convert(CgTarget* t, ConvKind op, Operand dst, Operand src) {
    411   CgIrInst* in = emit(rec_of(t), CG_IR_CONVERT);
    412   Operand ops[2] = {dst, src};
    413   set_ops(rec_of(t), in, ops, 2);
    414   in->extra.imm = (i64)op;
    415 }
    416 
    417 static void rec_call(CgTarget* t, const CGCallDesc* desc) {
    418   CgIrRecorder* r = rec_of(t);
    419   CgIrInst* in = emit(r, CG_IR_CALL);
    420   CgIrCallAux* aux = AUX_NEW(r, CgIrCallAux);
    421   aux->desc = cg_ir_dup_call_desc(require_func(r)->arena, desc);
    422   note_global_ref(r, desc->callee);
    423   if (desc->callee.kind == OPK_GLOBAL && desc->callee.v.global.addend == 0) {
    424     cg_ir_symset_add(r->base.c, &require_func(r)->call_refs,
    425                      desc->callee.v.global.sym);
    426   }
    427   in->extra.aux = aux;
    428 }
    429 
    430 static const char* rec_tail_call_unrealizable_reason(CgTarget* t,
    431                                                      const CGCallDesc* desc) {
    432   CgIrRecorder* r = rec_of(t);
    433   if (r->tail_call_unrealizable_reason) {
    434     CgIrFunc* f = require_func(r);
    435     return r->tail_call_unrealizable_reason(r->user, &f->desc, desc);
    436   }
    437   return NULL;
    438 }
    439 
    440 static void rec_ret(CgTarget* t, CGLocal value) {
    441   CgIrRecorder* r = rec_of(t);
    442   CgIrInst* in = emit(r, CG_IR_RET);
    443   CgIrRetAux* aux = AUX_NEW(r, CgIrRetAux);
    444   aux->value = value;
    445   aux->present = value != CG_LOCAL_NONE;
    446   in->extra.aux = aux;
    447 }
    448 
    449 static void rec_unreachable(CgTarget* t) {
    450   (void)emit(rec_of(t), CG_IR_UNREACHABLE);
    451 }
    452 
    453 static void rec_alloca(CgTarget* t, Operand dst, Operand size, u32 align) {
    454   CgIrInst* in = emit(rec_of(t), CG_IR_ALLOCA);
    455   Operand ops[2] = {dst, size};
    456   set_ops(rec_of(t), in, ops, 2);
    457   in->extra.imm = (i64)align;
    458 }
    459 
    460 static void rec_va_start(CgTarget* t, Operand ap_addr) {
    461   CgIrInst* in = emit(rec_of(t), CG_IR_VA_START);
    462   set_ops(rec_of(t), in, &ap_addr, 1);
    463 }
    464 
    465 static void rec_va_arg(CgTarget* t, Operand dst, Operand ap_addr,
    466                        KitCgTypeId type) {
    467   CgIrInst* in = emit(rec_of(t), CG_IR_VA_ARG);
    468   Operand ops[2] = {dst, ap_addr};
    469   set_ops(rec_of(t), in, ops, 2);
    470   in->extra.imm = (i64)type;
    471 }
    472 
    473 static void rec_va_end(CgTarget* t, Operand ap_addr) {
    474   CgIrInst* in = emit(rec_of(t), CG_IR_VA_END);
    475   set_ops(rec_of(t), in, &ap_addr, 1);
    476 }
    477 
    478 static void rec_va_copy(CgTarget* t, Operand dst_ap_addr, Operand src_ap_addr) {
    479   CgIrInst* in = emit(rec_of(t), CG_IR_VA_COPY);
    480   Operand ops[2] = {dst_ap_addr, src_ap_addr};
    481   set_ops(rec_of(t), in, ops, 2);
    482 }
    483 
    484 static void rec_atomic_load(CgTarget* t, Operand dst, Operand addr,
    485                             MemAccess mem, KitCgMemOrder order) {
    486   CgIrRecorder* r = rec_of(t);
    487   CgIrInst* in = emit(r, CG_IR_ATOMIC_LOAD);
    488   CgIrAtomicAux* aux = AUX_NEW(r, CgIrAtomicAux);
    489   Operand ops[2] = {dst, addr};
    490   aux->mem = mem;
    491   aux->order = order;
    492   set_ops(r, in, ops, 2);
    493   in->extra.aux = aux;
    494 }
    495 
    496 static void rec_atomic_store(CgTarget* t, Operand addr, Operand src,
    497                              MemAccess mem, KitCgMemOrder order) {
    498   CgIrRecorder* r = rec_of(t);
    499   CgIrInst* in = emit(r, CG_IR_ATOMIC_STORE);
    500   CgIrAtomicAux* aux = AUX_NEW(r, CgIrAtomicAux);
    501   Operand ops[2] = {addr, src};
    502   aux->mem = mem;
    503   aux->order = order;
    504   set_ops(r, in, ops, 2);
    505   in->extra.aux = aux;
    506 }
    507 
    508 static void rec_atomic_rmw(CgTarget* t, KitCgAtomicOp op, Operand dst,
    509                            Operand addr, Operand val, MemAccess mem,
    510                            KitCgMemOrder order) {
    511   CgIrRecorder* r = rec_of(t);
    512   CgIrInst* in = emit(r, CG_IR_ATOMIC_RMW);
    513   CgIrAtomicAux* aux = AUX_NEW(r, CgIrAtomicAux);
    514   Operand ops[3] = {dst, addr, val};
    515   aux->mem = mem;
    516   aux->order = order;
    517   aux->op = op;
    518   set_ops(r, in, ops, 3);
    519   in->extra.aux = aux;
    520 }
    521 
    522 static void rec_atomic_cas(CgTarget* t, Operand prior, Operand ok, Operand addr,
    523                            Operand expected, Operand desired, MemAccess mem,
    524                            KitCgMemOrder success, KitCgMemOrder failure) {
    525   CgIrRecorder* r = rec_of(t);
    526   CgIrInst* in = emit(r, CG_IR_ATOMIC_CAS);
    527   CgIrAtomicAux* aux = AUX_NEW(r, CgIrAtomicAux);
    528   Operand ops[5] = {prior, ok, addr, expected, desired};
    529   aux->mem = mem;
    530   aux->order = success;
    531   aux->failure = failure;
    532   set_ops(r, in, ops, 5);
    533   in->extra.aux = aux;
    534 }
    535 
    536 static void rec_fence(CgTarget* t, KitCgMemOrder order) {
    537   CgIrInst* in = emit(rec_of(t), CG_IR_FENCE);
    538   in->extra.imm = (i64)order;
    539 }
    540 
    541 static void rec_intrinsic(CgTarget* t, IntrinKind kind, Operand* dsts, u32 ndst,
    542                           const Operand* args, u32 narg) {
    543   CgIrRecorder* r = rec_of(t);
    544   CgIrInst* in = emit(r, CG_IR_INTRINSIC);
    545   CgIrIntrinsicAux* aux = AUX_NEW(r, CgIrIntrinsicAux);
    546   aux->kind = kind;
    547   aux->dsts = cg_ir_dup_operands(require_func(r)->arena, dsts, ndst);
    548   aux->args = cg_ir_dup_operands(require_func(r)->arena, args, narg);
    549   aux->ndst = ndst;
    550   aux->narg = narg;
    551   note_global_refs(r, dsts, ndst);
    552   note_global_refs(r, args, narg);
    553   in->extra.aux = aux;
    554 }
    555 
    556 static int rec_asm_is_reg_constraint(CgTarget* t, const char* constraint) {
    557   CgIrRecorder* r = rec_of(t);
    558   if (!r->asm_is_reg_constraint) return 0;
    559   return r->asm_is_reg_constraint(r->user, constraint);
    560 }
    561 
    562 static void rec_asm_block(CgTarget* t, const char* tmpl,
    563                           const AsmConstraint* outs, u32 nout, Operand* out_ops,
    564                           const AsmConstraint* ins, u32 nin,
    565                           const Operand* in_ops, const Sym* clobbers, u32 nclob,
    566                           u32 clobber_abi_sets) {
    567   CgIrRecorder* r = rec_of(t);
    568   CgIrFunc* f = require_func(r);
    569   CgIrInst* in = emit(r, CG_IR_ASM_BLOCK);
    570   CgIrAsmAux* aux = AUX_NEW(r, CgIrAsmAux);
    571   aux->tmpl = cg_ir_dup_cstr(f->arena, tmpl);
    572   aux->outs = cg_ir_dup_asm_constraints(f->arena, outs, nout);
    573   aux->out_ops = cg_ir_dup_operands(f->arena, out_ops, nout);
    574   aux->ins = cg_ir_dup_asm_constraints(f->arena, ins, nin);
    575   aux->in_ops = cg_ir_dup_operands(f->arena, in_ops, nin);
    576   note_global_refs(r, out_ops, nout);
    577   note_global_refs(r, in_ops, nin);
    578   if (nclob) {
    579     aux->clobbers = arena_array(f->arena, Sym, nclob);
    580     memcpy(aux->clobbers, clobbers, sizeof(*aux->clobbers) * nclob);
    581   }
    582   aux->nout = nout;
    583   aux->nin = nin;
    584   aux->nclob = nclob;
    585   aux->clobber_abi_sets = clobber_abi_sets;
    586   in->extra.aux = aux;
    587 }
    588 
    589 static void rec_file_scope_asm(CgTarget* t, const char* src, size_t len) {
    590   CgIrRecorder* r = rec_of(t);
    591   cg_ir_module_add_file_scope_asm(r->module, src, len);
    592 }
    593 
    594 static void rec_set_loc(CgTarget* t, SrcLoc loc) { rec_of(t)->loc = loc; }
    595 
    596 static void rec_finalize(CgTarget* t) {
    597   CgIrRecorder* r = rec_of(t);
    598   if (r->cur) rec_panic(r, "finalize with open function");
    599   if (r->finalize_recorded) r->finalize_recorded(r->user, r->module);
    600 }
    601 
    602 static void rec_destroy(CgTarget* t) {
    603   CgIrRecorder* r = rec_of(t);
    604   if (r->destroy_user) r->destroy_user(r->user);
    605   cg_ir_module_refsets_fini(r->module);
    606 }
    607 
    608 CgTarget* cg_ir_recorder_new(Compiler* c, ObjBuilder* obj,
    609                              const CgIrRecorderConfig* cfg) {
    610   CgIrRecorder* r;
    611   if (!c) return NULL;
    612   r = arena_znew(c->tu, CgIrRecorder);
    613   if (!r) return NULL;
    614   r->base.c = c;
    615   r->base.obj = obj;
    616   r->magic = CG_IR_RECORDER_MAGIC;
    617   r->module = cg_ir_module_new(c);
    618   if (!r->module) return NULL;
    619   if (cfg) {
    620     r->func_recorded = cfg->func_recorded;
    621     r->finalize_recorded = cfg->finalize;
    622     r->destroy_user = cfg->destroy;
    623     r->local_static_data_begin = cfg->local_static_data_begin;
    624     r->data_label_addr_unsupported_msg = cfg->data_label_addr_unsupported_msg;
    625     r->tail_call_unrealizable_reason = cfg->tail_call_unrealizable_reason;
    626     r->asm_is_reg_constraint = cfg->asm_is_reg_constraint;
    627     r->user = cfg->user;
    628   }
    629 
    630   r->base.func_begin = rec_func_begin;
    631   r->base.func_end = rec_func_end;
    632   r->base.alias = rec_alias;
    633   r->base.local = rec_local;
    634   r->base.local_addr = rec_local_addr;
    635   r->base.param = rec_param;
    636   r->base.label_new = rec_label_new;
    637   r->base.label_place = rec_label_place;
    638   r->base.jump = rec_jump;
    639   r->base.cmp_branch = rec_cmp_branch;
    640   r->base.switch_ = rec_switch;
    641   r->base.supports_label_table = rec_supports_label_table;
    642   r->base.indirect_branch = rec_indirect_branch;
    643   r->base.load_label_addr = rec_load_label_addr;
    644   r->base.local_static_data_begin = rec_local_static_data_begin;
    645   r->base.local_static_data_write = rec_local_static_data_write;
    646   r->base.local_static_data_label_addr = rec_local_static_data_label_addr;
    647   r->base.local_static_data_end = rec_local_static_data_end;
    648   r->base.data_label_addr_unsupported_msg = rec_data_label_addr_unsupported_msg;
    649   r->base.scope_begin = rec_scope_begin;
    650   r->base.scope_end = rec_scope_end;
    651   r->base.break_to = rec_break_to;
    652   r->base.continue_to = rec_continue_to;
    653   r->base.load_imm = rec_load_imm;
    654   r->base.load_const = rec_load_const;
    655   r->base.copy = rec_copy;
    656   r->base.load = rec_load;
    657   r->base.store = rec_store;
    658   r->base.addr_of = rec_addr_of;
    659   r->base.tls_addr_of = rec_tls_addr_of;
    660   r->base.copy_bytes = rec_copy_bytes;
    661   r->base.set_bytes = rec_set_bytes;
    662   r->base.binop = rec_binop;
    663   r->base.unop = rec_unop;
    664   r->base.cmp = rec_cmp;
    665   r->base.convert = rec_convert;
    666   r->base.call = rec_call;
    667   r->base.tail_call_unrealizable_reason = rec_tail_call_unrealizable_reason;
    668   r->base.ret = rec_ret;
    669   r->base.unreachable = rec_unreachable;
    670   r->base.alloca_ = rec_alloca;
    671   r->base.va_start_ = rec_va_start;
    672   r->base.va_arg_ = rec_va_arg;
    673   r->base.va_end_ = rec_va_end;
    674   r->base.va_copy_ = rec_va_copy;
    675   r->base.atomic_load = rec_atomic_load;
    676   r->base.atomic_store = rec_atomic_store;
    677   r->base.atomic_rmw = rec_atomic_rmw;
    678   r->base.atomic_cas = rec_atomic_cas;
    679   r->base.fence = rec_fence;
    680   r->base.intrinsic = rec_intrinsic;
    681   r->base.asm_is_reg_constraint = rec_asm_is_reg_constraint;
    682   r->base.asm_block = rec_asm_block;
    683   r->base.file_scope_asm = rec_file_scope_asm;
    684   r->base.set_loc = rec_set_loc;
    685   r->base.finalize = rec_finalize;
    686   r->base.destroy = rec_destroy;
    687   return &r->base;
    688 }
    689 
    690 CgIrRecorder* cg_ir_recorder_from_target(CgTarget* t) {
    691   CgIrRecorder* r = t ? rec_of(t) : NULL;
    692   return r && r->magic == CG_IR_RECORDER_MAGIC ? r : NULL;
    693 }
    694 
    695 void* cg_ir_recorder_user(const CgIrRecorder* r) { return r ? r->user : NULL; }
    696 
    697 const CgIrModule* cg_ir_recorder_module(const CgTarget* t) {
    698   const CgIrRecorder* r = (const CgIrRecorder*)t;
    699   return r && r->magic == CG_IR_RECORDER_MAGIC ? r->module : NULL;
    700 }
    701 
    702 CgIrFunc* cg_ir_recorder_current_func(const CgTarget* t) {
    703   const CgIrRecorder* r = (const CgIrRecorder*)t;
    704   return r && r->magic == CG_IR_RECORDER_MAGIC ? r->cur : NULL;
    705 }