kit

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

reg_effects.c (7636B)


      1 #include <string.h>
      2 
      3 #include "opt/opt_internal.h"
      4 
      5 #if defined(__GNUC__) || defined(__clang__)
      6 #define EFFECT_ALWAYS_INLINE static inline __attribute__((always_inline))
      7 #else
      8 #define EFFECT_ALWAYS_INLINE static inline
      9 #endif
     10 
     11 static void effect_add(OptHardRegSet* set, u8 cls, Reg reg) {
     12   if (!set || cls >= OPT_REG_CLASSES || reg >= OPT_MAX_HARD_REGS) return;
     13   set->cls[cls] |= 1u << reg;
     14 }
     15 
     16 static void effect_add_use(OptRegEffectMasks* effects,
     17                            u8 (*use_count)[OPT_MAX_HARD_REGS], u8 cls,
     18                            Reg reg) {
     19   if (!effects || cls >= OPT_REG_CLASSES || reg >= OPT_MAX_HARD_REGS) return;
     20   effect_add(&effects->uses, cls, reg);
     21   if (use_count && use_count[cls][reg] < 2u)
     22     ++use_count[cls][reg];
     23 }
     24 
     25 EFFECT_ALWAYS_INLINE void effect_use_operand(
     26     OptRegEffectMasks* effects, u8 (*use_count)[OPT_MAX_HARD_REGS],
     27     const Operand* op) {
     28   if (!effects || !op) return;
     29   if (op->kind == OPK_REG) {
     30     effect_add_use(effects, use_count, op->cls, op->v.reg);
     31   } else if (op->kind == OPK_INDIRECT) {
     32     if (op->v.ind.base_kind == OPT_INDIRECT_REG)
     33       effect_add_use(effects, use_count, RC_INT, op->v.ind.base);
     34     if (op->v.ind.index_kind == OPT_INDIRECT_REG &&
     35         op->v.ind.index != (Reg)REG_NONE)
     36       effect_add_use(effects, use_count, RC_INT, op->v.ind.index);
     37   }
     38 }
     39 
     40 static void effect_def_operand(OptRegEffectMasks* effects,
     41                                const Operand* op) {
     42   if (effects && op && op->kind == OPK_REG)
     43     effect_add(&effects->defs, op->cls, op->v.reg);
     44 }
     45 
     46 EFFECT_ALWAYS_INLINE void effect_use_abivalue(
     47     OptRegEffectMasks* effects, u8 (*use_count)[OPT_MAX_HARD_REGS],
     48     const CGABIValue* v) {
     49   if (!v) return;
     50   effect_use_operand(effects, use_count, &v->storage);
     51   for (u32 i = 0; i < v->nparts; ++i)
     52     effect_use_operand(effects, use_count, &v->parts[i].op);
     53 }
     54 
     55 static void effect_def_abivalue(OptRegEffectMasks* effects,
     56                                 const CGABIValue* v) {
     57   if (!v) return;
     58   effect_def_operand(effects, &v->storage);
     59   for (u32 i = 0; i < v->nparts; ++i)
     60     effect_def_operand(effects, &v->parts[i].op);
     61 }
     62 
     63 static void effect_add_masks(OptHardRegSet* set, const u32* masks) {
     64   if (!set || !masks) return;
     65   for (u32 c = 0; c < OPT_REG_CLASSES; ++c) set->cls[c] |= masks[c];
     66 }
     67 
     68 u32 opt_call_clobber_mask_for(Func* f, const Inst* in, u8 cls) {
     69   if (!f || cls >= OPT_REG_CLASSES) return 0;
     70   if (in && (IROp)in->op == IR_CALL) {
     71     const IRCallAux* aux = (const IRCallAux*)in->extra.aux;
     72     if (aux && aux->plan_valid) return aux->plan.clobber_mask[cls];
     73   }
     74   return f->opt_caller_saved[cls];
     75 }
     76 
     77 const u32* opt_inst_machine_clobber_masks(Func* f, const Inst* in) {
     78   if (!f || !in || !f->inst_clobbers || in->id == INST_ID_NONE ||
     79       in->id >= f->inst_clobbers_cap)
     80     return NULL;
     81   return f->inst_clobbers[in->id];
     82 }
     83 
     84 /* This is the sole opcode/ABI authority for physical-register effects. Every
     85  * detailed, masks-only, and kills-only view below is a projection of this
     86  * walker; consumers must not reproduce these operand or clobber rules. */
     87 EFFECT_ALWAYS_INLINE void effect_explicit_operands(
     88     Func* f, const Inst* in, OptRegEffectMasks* effects,
     89     u8 (*use_count)[OPT_MAX_HARD_REGS], int collect_uses) {
     90   for (u32 i = 0; i < in->nopnds; ++i) {
     91     if (opt_inst_operand_is_def(in, i))
     92       effect_def_operand(effects, &in->opnds[i]);
     93     else if (collect_uses)
     94       effect_use_operand(effects, use_count, &in->opnds[i]);
     95   }
     96 
     97   /* Direct operand roles come from opt_inst_operand_is_def above. Only
     98    * register-bearing auxiliary descriptions need instruction-specific work. */
     99   switch ((IROp)in->op) {
    100     case IR_CALL: {
    101       const IRCallAux* aux = (const IRCallAux*)in->extra.aux;
    102       if (aux && aux->use_plan_replay) {
    103         if (collect_uses)
    104           effect_use_operand(effects, use_count, &aux->plan.callee);
    105         for (u32 i = 0; i < aux->plan.nargs; ++i) {
    106           if (collect_uses)
    107             effect_use_operand(effects, use_count, &aux->plan.args[i].src);
    108           if (aux->plan.args[i].dst_kind == CG_CALL_PLAN_REG)
    109             effect_add(&effects->defs, aux->plan.args[i].cls,
    110                        aux->plan.args[i].dst_reg);
    111         }
    112         for (u32 i = 0; i < aux->plan.nrets; ++i) {
    113           effect_add(&effects->defs, aux->plan.rets[i].cls,
    114                      aux->plan.rets[i].src_reg);
    115           effect_def_operand(effects, &aux->plan.rets[i].dst);
    116         }
    117       } else if (aux) {
    118         if (collect_uses) {
    119           effect_use_operand(effects, use_count, &aux->desc.callee);
    120           for (u32 i = 0; i < aux->desc.nargs; ++i)
    121             effect_use_abivalue(effects, use_count, &aux->desc.args[i]);
    122         }
    123         effect_def_abivalue(effects, &aux->desc.ret);
    124       }
    125       for (u32 c = 0; c < OPT_REG_CLASSES; ++c)
    126         effects->clobbers.cls[c] |=
    127             opt_call_clobber_mask_for(f, in, (u8)c);
    128       break;
    129     }
    130     case IR_RET: {
    131       const IRRetAux* aux = (const IRRetAux*)in->extra.aux;
    132       if (collect_uses && aux && aux->present)
    133         effect_use_abivalue(effects, use_count, &aux->val);
    134       break;
    135     }
    136     case IR_ASM_BLOCK: {
    137       const IRAsmAux* aux = (const IRAsmAux*)in->extra.aux;
    138       if (!aux) break;
    139       if (collect_uses)
    140         for (u32 i = 0; i < aux->nin; ++i)
    141           effect_use_operand(effects, use_count, &aux->in_ops[i]);
    142       for (u32 i = 0; i < aux->nout; ++i)
    143         effect_def_operand(effects, &aux->out_ops[i]);
    144       effect_add_masks(&effects->clobbers, aux->clobber_mask);
    145       break;
    146     }
    147     case IR_INTRINSIC: {
    148       const IRIntrinAux* aux = (const IRIntrinAux*)in->extra.aux;
    149       if (!aux) break;
    150       if (collect_uses)
    151         for (u32 i = 0; i < aux->narg; ++i)
    152           effect_use_operand(effects, use_count, &aux->args[i]);
    153       for (u32 i = 0; i < aux->ndst; ++i)
    154         effect_def_operand(effects, &aux->dsts[i]);
    155       break;
    156     }
    157     default:
    158       break;
    159   }
    160 }
    161 
    162 static void effect_add_machine_clobbers(Func* f, const Inst* in,
    163                                         OptRegEffectMasks* effects) {
    164   effect_add_masks(&effects->clobbers,
    165                    opt_inst_machine_clobber_masks(f, in));
    166 }
    167 
    168 EFFECT_ALWAYS_INLINE void effect_build(
    169     Func* f, const Inst* in, OptRegEffectMasks* effects,
    170     u8 (*use_count)[OPT_MAX_HARD_REGS], int collect_uses) {
    171   if (!f || !in) return;
    172   effect_explicit_operands(f, in, effects, use_count, collect_uses);
    173   effect_add_machine_clobbers(f, in, effects);
    174 }
    175 
    176 void opt_inst_reg_effects(Func* f, const Inst* in, OptRegEffects* effects) {
    177   if (!effects) return;
    178   memset(effects, 0, sizeof *effects);
    179   effect_build(f, in, &effects->masks, effects->use_count, 1);
    180 }
    181 
    182 void opt_inst_reg_effect_masks(Func* f, const Inst* in,
    183                                OptRegEffectMasks* masks) {
    184   if (!masks) return;
    185   memset(masks, 0, sizeof *masks);
    186   effect_build(f, in, masks, NULL, 1);
    187 }
    188 
    189 void opt_inst_reg_kills(Func* f, const Inst* in, OptHardRegSet* kills) {
    190   OptRegEffectMasks effects;
    191   if (!kills) return;
    192   memset(&effects, 0, sizeof effects);
    193   effect_build(f, in, &effects, NULL, 0);
    194   opt_reg_effect_mask_kills(&effects, kills);
    195 }
    196 
    197 void opt_reg_effect_kills(const OptRegEffects* effects, OptHardRegSet* kills) {
    198   opt_reg_effect_mask_kills(effects ? &effects->masks : NULL, kills);
    199 }
    200 
    201 void opt_reg_effect_mask_kills(const OptRegEffectMasks* masks,
    202                                OptHardRegSet* kills) {
    203   if (!kills) return;
    204   memset(kills, 0, sizeof *kills);
    205   if (!masks) return;
    206   for (u32 c = 0; c < OPT_REG_CLASSES; ++c)
    207     kills->cls[c] = masks->defs.cls[c] | masks->clobbers.cls[c];
    208 }
    209 
    210 #undef EFFECT_ALWAYS_INLINE