kit

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

mir_clone.c (12226B)


      1 #include <string.h>
      2 
      3 #include "opt/opt_internal.h"
      4 
      5 /*
      6  * MIR-owned containers form an independently mutable graph.  During lowering,
      7  * the temporary destination Func borrows HIR instruction arrays read-only;
      8  * rewrite_func deep-copies each instruction into its final MIR array before
      9  * mutating it.  Other mutable containers are cloned here.  Leaf descriptors
     10  * explicitly left shared below (types, ABI descriptions, symbol/string storage,
     11  * and constant byte payloads) are immutable compiler-owned data.
     12  */
     13 
     14 static void clone_abi_value(Arena* arena, CGABIValue* dst,
     15                             const CGABIValue* src) {
     16   *dst = *src;
     17   if (!src->parts || !src->nparts) return;
     18   dst->parts = arena_array(arena, CGABIPart, src->nparts);
     19   memcpy(dst->parts, src->parts, sizeof(dst->parts[0]) * src->nparts);
     20 }
     21 
     22 static IRCallAux* clone_call_aux(Arena* arena, const IRCallAux* src) {
     23   IRCallAux* dst = arena_new(arena, IRCallAux);
     24   *dst = *src;
     25 
     26   if (src->desc.args && src->desc.nargs) {
     27     dst->desc.args = arena_array(arena, CGABIValue, src->desc.nargs);
     28     for (u32 i = 0; i < src->desc.nargs; ++i)
     29       clone_abi_value(arena, &dst->desc.args[i], &src->desc.args[i]);
     30   }
     31   clone_abi_value(arena, &dst->desc.ret, &src->desc.ret);
     32 
     33   if (src->plan.args && src->plan.nargs) {
     34     dst->plan.args = arena_array(arena, CGCallPlanMove, src->plan.nargs);
     35     memcpy(dst->plan.args, src->plan.args,
     36            sizeof(dst->plan.args[0]) * src->plan.nargs);
     37   }
     38   if (src->plan.rets && src->plan.nrets) {
     39     dst->plan.rets = arena_array(arena, CGCallPlanRet, src->plan.nrets);
     40     memcpy(dst->plan.rets, src->plan.rets,
     41            sizeof(dst->plan.rets[0]) * src->plan.nrets);
     42   }
     43   if (src->results && src->nresults) {
     44     dst->results = arena_array(arena, Val, src->nresults);
     45     memcpy(dst->results, src->results,
     46            sizeof(dst->results[0]) * src->nresults);
     47   }
     48   return dst;
     49 }
     50 
     51 static IRRetAux* clone_ret_aux(Arena* arena, const IRRetAux* src) {
     52   IRRetAux* dst = arena_new(arena, IRRetAux);
     53   *dst = *src;
     54   clone_abi_value(arena, &dst->val, &src->val);
     55   return dst;
     56 }
     57 
     58 static IRAsmAux* clone_asm_aux(Arena* arena, const IRAsmAux* src) {
     59   IRAsmAux* dst = arena_new(arena, IRAsmAux);
     60   *dst = *src;
     61 
     62 #define CLONE_ASM_ARRAY(field, T, count)                                     \
     63   do {                                                                        \
     64     if (src->field && (count)) {                                              \
     65       dst->field = arena_array(arena, T, (count));                            \
     66       memcpy(dst->field, src->field, sizeof(dst->field[0]) * (count));        \
     67     }                                                                         \
     68   } while (0)
     69 
     70   CLONE_ASM_ARRAY(outs, AsmConstraint, src->nout);
     71   CLONE_ASM_ARRAY(ins, AsmConstraint, src->nin);
     72   CLONE_ASM_ARRAY(clobbers, Sym, src->nclob);
     73   CLONE_ASM_ARRAY(out_ops, Operand, src->nout);
     74   CLONE_ASM_ARRAY(in_ops, Operand, src->nin);
     75   CLONE_ASM_ARRAY(out_reg_reqs, IRAsmRegRequirement, src->nout);
     76   CLONE_ASM_ARRAY(in_reg_reqs, IRAsmRegRequirement, src->nin);
     77 
     78 #undef CLONE_ASM_ARRAY
     79   return dst;
     80 }
     81 
     82 static IRIntrinAux* clone_intrin_aux(Arena* arena, const IRIntrinAux* src) {
     83   IRIntrinAux* dst = arena_new(arena, IRIntrinAux);
     84   *dst = *src;
     85   if (src->dsts && src->ndst) {
     86     dst->dsts = arena_array(arena, Operand, src->ndst);
     87     memcpy(dst->dsts, src->dsts, sizeof(dst->dsts[0]) * src->ndst);
     88   }
     89   if (src->args && src->narg) {
     90     dst->args = arena_array(arena, Operand, src->narg);
     91     memcpy(dst->args, src->args, sizeof(dst->args[0]) * src->narg);
     92   }
     93   if (src->result_vals && src->ndst) {
     94     dst->result_vals = arena_array(arena, Val, src->ndst);
     95     memcpy(dst->result_vals, src->result_vals,
     96            sizeof(dst->result_vals[0]) * src->ndst);
     97   }
     98   return dst;
     99 }
    100 
    101 static int inst_uses_aux(IROp op) {
    102   switch (op) {
    103     case IR_PARAM_DECL:
    104     case IR_TLS_ADDR_OF:
    105     case IR_AGG_COPY:
    106     case IR_AGG_SET:
    107     case IR_BITFIELD_LOAD:
    108     case IR_BITFIELD_STORE:
    109     case IR_CALL:
    110     case IR_PHI:
    111     case IR_SWITCH:
    112     case IR_INDIRECT_BRANCH:
    113     case IR_LOCAL_STATIC_DATA_BEGIN:
    114     case IR_LOCAL_STATIC_DATA_WRITE:
    115     case IR_LOCAL_STATIC_DATA_LABEL_ADDR:
    116     case IR_RET:
    117     case IR_SCOPE_BEGIN:
    118     case IR_ATOMIC_LOAD:
    119     case IR_ATOMIC_STORE:
    120     case IR_ATOMIC_RMW:
    121     case IR_ATOMIC_CAS:
    122     case IR_ASM_BLOCK:
    123     case IR_INTRINSIC:
    124       return 1;
    125     default:
    126       return 0;
    127   }
    128 }
    129 
    130 static void* clone_inst_aux(Arena* arena, const Inst* src) {
    131   if (!src->extra.aux) return NULL;
    132 
    133 #define CLONE_PLAIN_AUX(T)                                                    \
    134   do {                                                                        \
    135     const T* src_aux = (const T*)src->extra.aux;                              \
    136     T* dst_aux = arena_new(arena, T);                                         \
    137     *dst_aux = *src_aux;                                                      \
    138     return dst_aux;                                                           \
    139   } while (0)
    140 
    141   switch ((IROp)src->op) {
    142     case IR_PARAM_DECL: {
    143       const IRParamDeclAux* src_aux =
    144           (const IRParamDeclAux*)src->extra.aux;
    145       IRParamDeclAux* dst_aux = arena_new(arena, IRParamDeclAux);
    146       *dst_aux = *src_aux;
    147       if (src_aux->desc.incoming && src_aux->desc.nincoming) {
    148         CGABIPart* incoming =
    149             arena_array(arena, CGABIPart, src_aux->desc.nincoming);
    150         memcpy(incoming, src_aux->desc.incoming,
    151                sizeof(incoming[0]) * src_aux->desc.nincoming);
    152         dst_aux->desc.incoming = incoming;
    153       }
    154       return dst_aux;
    155     }
    156     case IR_TLS_ADDR_OF:
    157       CLONE_PLAIN_AUX(IRTlsAux);
    158     case IR_AGG_COPY:
    159     case IR_AGG_SET:
    160       CLONE_PLAIN_AUX(IRAggAux);
    161     case IR_BITFIELD_LOAD:
    162     case IR_BITFIELD_STORE:
    163       CLONE_PLAIN_AUX(IRBitFieldAux);
    164     case IR_CALL:
    165       return clone_call_aux(arena, (const IRCallAux*)src->extra.aux);
    166     case IR_PHI: {
    167       const IRPhiAux* src_aux = (const IRPhiAux*)src->extra.aux;
    168       IRPhiAux* dst_aux = arena_new(arena, IRPhiAux);
    169       *dst_aux = *src_aux;
    170       if (src_aux->pred_blocks && src_aux->npreds) {
    171         dst_aux->pred_blocks = arena_array(arena, u32, src_aux->npreds);
    172         memcpy(dst_aux->pred_blocks, src_aux->pred_blocks,
    173                sizeof(dst_aux->pred_blocks[0]) * src_aux->npreds);
    174       }
    175       if (src_aux->pred_vals && src_aux->npreds) {
    176         dst_aux->pred_vals = arena_array(arena, Val, src_aux->npreds);
    177         memcpy(dst_aux->pred_vals, src_aux->pred_vals,
    178                sizeof(dst_aux->pred_vals[0]) * src_aux->npreds);
    179       }
    180       return dst_aux;
    181     }
    182     case IR_SWITCH: {
    183       const IRSwitchAux* src_aux = (const IRSwitchAux*)src->extra.aux;
    184       IRSwitchAux* dst_aux = arena_new(arena, IRSwitchAux);
    185       *dst_aux = *src_aux;
    186       if (src_aux->cases && src_aux->ncases) {
    187         dst_aux->cases =
    188             arena_array(arena, IRSwitchAuxCase, src_aux->ncases);
    189         memcpy(dst_aux->cases, src_aux->cases,
    190                sizeof(dst_aux->cases[0]) * src_aux->ncases);
    191       }
    192       return dst_aux;
    193     }
    194     case IR_INDIRECT_BRANCH: {
    195       const IRIndirectAux* src_aux = (const IRIndirectAux*)src->extra.aux;
    196       IRIndirectAux* dst_aux = arena_new(arena, IRIndirectAux);
    197       *dst_aux = *src_aux;
    198       if (src_aux->targets && src_aux->ntargets) {
    199         dst_aux->targets = arena_array(arena, u32, src_aux->ntargets);
    200         memcpy(dst_aux->targets, src_aux->targets,
    201                sizeof(dst_aux->targets[0]) * src_aux->ntargets);
    202       }
    203       return dst_aux;
    204     }
    205     case IR_LOCAL_STATIC_DATA_BEGIN:
    206       CLONE_PLAIN_AUX(CgIrLocalStaticBeginAux);
    207     case IR_LOCAL_STATIC_DATA_WRITE:
    208       /* The data payload is an immutable byte string owned by the semantic IR;
    209        * only the mutable descriptor object is graph-local. */
    210       CLONE_PLAIN_AUX(CgIrLocalStaticWriteAux);
    211     case IR_LOCAL_STATIC_DATA_LABEL_ADDR:
    212       CLONE_PLAIN_AUX(CgIrLocalStaticLabelAux);
    213     case IR_RET:
    214       return clone_ret_aux(arena, (const IRRetAux*)src->extra.aux);
    215     case IR_SCOPE_BEGIN:
    216       CLONE_PLAIN_AUX(IRScopeAux);
    217     case IR_ATOMIC_LOAD:
    218     case IR_ATOMIC_STORE:
    219     case IR_ATOMIC_RMW:
    220       CLONE_PLAIN_AUX(IRAtomicAux);
    221     case IR_ATOMIC_CAS:
    222       CLONE_PLAIN_AUX(IRCasAux);
    223     case IR_ASM_BLOCK:
    224       return clone_asm_aux(arena, (const IRAsmAux*)src->extra.aux);
    225     case IR_INTRINSIC:
    226       return clone_intrin_aux(arena, (const IRIntrinAux*)src->extra.aux);
    227     default:
    228       return NULL;
    229   }
    230 
    231 #undef CLONE_PLAIN_AUX
    232 }
    233 
    234 void opt_mir_clone_inst(Arena* arena, Inst* dst, const Inst* src) {
    235   *dst = *src;
    236   if (src->defs && src->ndefs) {
    237     dst->defs = arena_array(arena, Val, src->ndefs);
    238     memcpy(dst->defs, src->defs, sizeof(dst->defs[0]) * src->ndefs);
    239   }
    240   if (src->opnds && src->nopnds) {
    241     dst->opnds = arena_array(arena, Operand, src->nopnds);
    242     memcpy(dst->opnds, src->opnds, sizeof(dst->opnds[0]) * src->nopnds);
    243   }
    244   if (inst_uses_aux((IROp)src->op))
    245     dst->extra.aux = clone_inst_aux(arena, src);
    246 }
    247 
    248 void opt_mir_prepare_rewrite(Func* dst, const Func* src) {
    249   Arena* arena;
    250   u32 blocks_cap;
    251   u32 frame_slots_cap;
    252   u32 emit_order_cap;
    253 
    254   if (!dst || !src) return;
    255   *dst = *src;
    256   arena = src->arena;
    257   dst->mir = NULL;
    258   dst->opt_rewritten = 0;
    259 
    260   /* The source graph's spare capacity reflects its recording history, not a
    261    * useful property of MIR. Keep only live structural entries. */
    262   blocks_cap = src->nblocks;
    263   dst->blocks = arena_zarray(arena, Block, blocks_cap ? blocks_cap : 1u);
    264   dst->blocks_cap = blocks_cap;
    265   for (u32 b = 0; b < src->nblocks; ++b) {
    266     const Block* src_block = &src->blocks[b];
    267     Block* dst_block = &dst->blocks[b];
    268     *dst_block = *src_block;
    269     /* rewrite_func only reads this array and replaces it with independently
    270      * owned output before the structural view can escape opt_lower_to_mir. */
    271     dst_block->insts = src_block->insts;
    272     dst_block->cap = src_block->ninsts;
    273 
    274     dst_block->preds = NULL;
    275     if (src_block->preds && src_block->npreds) {
    276       dst_block->preds = arena_array(arena, u32, src_block->npreds);
    277       memcpy(dst_block->preds, src_block->preds,
    278              sizeof(dst_block->preds[0]) * src_block->npreds);
    279     }
    280     dst_block->succ = NULL;
    281     dst_block->succ_cap = src_block->nsucc;
    282     if (src_block->succ && src_block->nsucc) {
    283       dst_block->succ = arena_array(arena, u32, src_block->nsucc);
    284       memcpy(dst_block->succ, src_block->succ,
    285              sizeof(dst_block->succ[0]) * src_block->nsucc);
    286     }
    287   }
    288 
    289   frame_slots_cap = src->nframe_slots;
    290   dst->frame_slots = NULL;
    291   dst->frame_slots_cap = frame_slots_cap;
    292   if (src->frame_slots && frame_slots_cap) {
    293     dst->frame_slots = arena_zarray(arena, IRFrameSlot, frame_slots_cap);
    294     memcpy(dst->frame_slots, src->frame_slots,
    295            sizeof(dst->frame_slots[0]) * src->nframe_slots);
    296   }
    297 
    298   emit_order_cap = src->emit_order_n;
    299   dst->emit_order = NULL;
    300   dst->emit_order_cap = emit_order_cap;
    301   if (src->emit_order && emit_order_cap) {
    302     dst->emit_order = arena_array(arena, u32, emit_order_cap);
    303     memcpy(dst->emit_order, src->emit_order,
    304            sizeof(dst->emit_order[0]) * src->emit_order_n);
    305   }
    306 
    307   /* spill_slot_for may add a call-save home during rewriting.  Keep that
    308    * allocation bookkeeping private to the lowering view. */
    309   if (src->preg_info && opt_reg_count(src)) {
    310     u32 nregs = opt_reg_count(src);
    311     dst->preg_info = arena_array(arena, OptPRegInfo, nregs);
    312     memcpy(dst->preg_info, src->preg_info,
    313            sizeof(dst->preg_info[0]) * nregs);
    314   }
    315 
    316   /* Structured scopes are fully lowered before this boundary. Their lookup
    317    * table is a semantic-recording cache of HIR Inst pointers, so MIR neither
    318    * needs it nor should spend an O(scopes * instructions) scan rebuilding it. */
    319   dst->scope_aux_inst = NULL;
    320   dst->nscopes = 0;
    321   dst->scopes_cap = 0;
    322 
    323   /* Def-use entries contain direct Operand pointers into HIR.  They are an
    324    * analysis cache, not part of the MIR graph, and must never cross this
    325    * boundary. */
    326   dst->opt_uses = NULL;
    327   dst->opt_nuses = 0;
    328   dst->opt_uses_cap = 0;
    329   dst->opt_first_use_by_val = NULL;
    330   dst->opt_first_use_by_val_cap = 0;
    331   dst->opt_valid_analyses = 0;
    332 }