kit

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

opt_util.c (7405B)


      1 #include <string.h>
      2 
      3 #include "opt/opt_internal.h"
      4 
      5 int opt_val_in_inst_defs(const Inst* in, Val v) {
      6   if (!in || v == VAL_NONE) return 0;
      7   if (in->def == v) return 1;
      8   for (u32 i = 0; i < in->ndefs; ++i)
      9     if (in->defs[i] == v) return 1;
     10   return 0;
     11 }
     12 
     13 int opt_indirect_index_type_valid(Func* f, KitCgTypeId type) {
     14   u64 size;
     15   if (!f || !f->c || type == KIT_CG_TYPE_NONE ||
     16       !cg_type_is_int(f->c, type) ||
     17       opt_value_reg_class(f->c, type) != RC_INT)
     18     return 0;
     19   size = cg_type_size(f->c, type);
     20   return size != 0u && size <= f->c->target.ptr_size;
     21 }
     22 
     23 int opt_inst_operand_is_def(const Inst* in, u32 i) {
     24   if (!in || i >= in->nopnds) return 0;
     25   switch ((IROp)in->op) {
     26     case IR_LOAD_IMM:
     27     case IR_LOAD_CONST:
     28     case IR_TLS_ADDR_OF:
     29     case IR_LOAD_LABEL_ADDR:
     30     case IR_COPY:
     31     case IR_CONVERT:
     32     case IR_UNOP:
     33     case IR_VA_ARG:
     34     case IR_LOAD:
     35     case IR_ADDR_OF:
     36     case IR_BITFIELD_LOAD:
     37     case IR_ATOMIC_LOAD:
     38     case IR_BINOP:
     39     case IR_CMP:
     40     case IR_ALLOCA:
     41     case IR_ATOMIC_RMW:
     42       return i == 0u;
     43     case IR_ATOMIC_CAS:
     44       return i == 0u || i == 1u;
     45     default:
     46       return 0;
     47   }
     48 }
     49 
     50 static KitCgTypeId indirect_frame_type(Func* f, FrameSlot slot,
     51                                        KitCgTypeId fallback) {
     52   if (f && slot != FRAME_SLOT_NONE && slot <= f->nframe_slots) {
     53     KitCgTypeId type = f->frame_slots[slot - 1u].type;
     54     if (type) return type;
     55   }
     56   return fallback;
     57 }
     58 
     59 static void indirect_part_operand(Func* f, const Operand* owner, u32 value,
     60                                   u8 kind, KitCgTypeId component_type,
     61                                   Operand* out) {
     62   *out = *owner;
     63   out->cls = RC_INT;
     64   out->flags |= OPT_OPERAND_WALK_INDIRECT_PART;
     65   if (component_type) out->type = component_type;
     66   switch ((OptIndirectLocKind)kind) {
     67     case OPT_INDIRECT_REG:
     68       out->kind = OPK_REG;
     69       out->v.reg = (Reg)value;
     70       if (!component_type && (PReg)value < opt_reg_count(f) &&
     71           opt_reg_type(f, (PReg)value))
     72         out->type = opt_reg_type(f, (PReg)value);
     73       return;
     74     case OPT_INDIRECT_FRAME:
     75       out->kind = OPK_STACK;
     76       out->v.frame_slot = (FrameSlot)value;
     77       if (!component_type)
     78         out->type = indirect_frame_type(f, (FrameSlot)value, owner->type);
     79       return;
     80     case OPT_INDIRECT_FRAME_ADDR:
     81       out->kind = OPK_FRAME_ADDR;
     82       out->v.frame_slot = (FrameSlot)value;
     83       return;
     84   }
     85 }
     86 
     87 static void indirect_part_commit(Func* f, Inst* in, Operand* owner,
     88                                  Operand* part, u32* value, u8* kind,
     89                                  KitCgTypeId* component_type) {
     90   if (component_type) *component_type = part->type;
     91   switch ((OptOperandKind)part->kind) {
     92     case OPK_REG:
     93       *value = part->v.reg;
     94       *kind = OPT_INDIRECT_REG;
     95       return;
     96     case OPK_STACK:
     97       *value = part->v.frame_slot;
     98       *kind = OPT_INDIRECT_FRAME;
     99       return;
    100     case OPK_FRAME_ADDR:
    101       *value = part->v.frame_slot;
    102       *kind = OPT_INDIRECT_FRAME_ADDR;
    103       return;
    104     default:
    105       compiler_panic(f->c, in ? in->loc : (SrcLoc){0, 0, 0},
    106                      "opt operand walk: invalid indirect location kind %u",
    107                      (unsigned)part->kind);
    108   }
    109   (void)owner;
    110 }
    111 
    112 void opt_walk_operand(Func* f, Inst* in, Operand* op, int is_def,
    113                       OptOperandWalkFn fn, void* ctx) {
    114   if (!op || !fn) return;
    115   if (op->kind != OPK_INDIRECT) {
    116     fn(f, in, op, is_def, ctx);
    117   } else if (op->kind == OPK_INDIRECT) {
    118     Operand base;
    119     /* Expose the complete address owner as well as its scalar components.
    120      * Location-aware consumers (notably MIR verification) need to validate
    121      * the tuple; register-rewrite callbacks simply ignore non-register kinds. */
    122     fn(f, in, op, 0, ctx);
    123     indirect_part_operand(f, op, op->v.ind.base, op->v.ind.base_kind,
    124                           op->v.ind.base_type, &base);
    125     fn(f, in, &base, 0, ctx);
    126     indirect_part_commit(f, in, op, &base, &op->v.ind.base,
    127                          &op->v.ind.base_kind, &op->v.ind.base_type);
    128     if (op->v.ind.index_kind != OPT_INDIRECT_REG ||
    129         op->v.ind.index != (Reg)REG_NONE) {
    130       Operand idx;
    131       indirect_part_operand(f, op, op->v.ind.index, op->v.ind.index_kind,
    132                             op->v.ind.index_type, &idx);
    133       fn(f, in, &idx, 0, ctx);
    134       indirect_part_commit(f, in, op, &idx, &op->v.ind.index,
    135                            &op->v.ind.index_kind, &op->v.ind.index_type);
    136     }
    137   }
    138 }
    139 
    140 void opt_walk_abivalue(Func* f, Inst* in, CGABIValue* v, int storage_def,
    141                        OptOperandWalkFn fn, void* ctx) {
    142   if (!v) return;
    143   opt_walk_operand(f, in, &v->storage, storage_def, fn, ctx);
    144   for (u32 i = 0; i < v->nparts; ++i)
    145     opt_walk_operand(f, in, (Operand*)&v->parts[i].op, storage_def, fn, ctx);
    146 }
    147 
    148 void opt_walk_inst_operands(Func* f, Inst* in, OptOperandWalkFn fn, void* ctx) {
    149   if (!in || !fn) return;
    150   for (u32 i = 0; i < in->nopnds; ++i) {
    151     int is_def = opt_inst_operand_is_def(in, i);
    152     if (!is_def) opt_walk_operand(f, in, &in->opnds[i], 0, fn, ctx);
    153   }
    154   for (u32 i = 0; i < in->nopnds; ++i) {
    155     int is_def = opt_inst_operand_is_def(in, i);
    156     if (is_def) opt_walk_operand(f, in, &in->opnds[i], 1, fn, ctx);
    157   }
    158 
    159   switch ((IROp)in->op) {
    160     case IR_PARAM_DECL: {
    161       Operand def;
    162       if (in->def == VAL_NONE) break;
    163       memset(&def, 0, sizeof def);
    164       def.kind = OPK_REG;
    165       def.cls = (f->preg_info && in->def < opt_reg_count(f))
    166                     ? f->preg_info[in->def].cls
    167                     : 0;
    168       def.type = in->type;
    169       def.v.reg = (Reg)in->def;
    170       opt_walk_operand(f, in, &def, 1, fn, ctx);
    171       break;
    172     }
    173     case IR_CALL: {
    174       IRCallAux* aux = (IRCallAux*)in->extra.aux;
    175       if (!aux) break;
    176       if (aux->use_plan_replay) {
    177         opt_walk_operand(f, in, &aux->plan.callee, 0, fn, ctx);
    178         for (u32 i = 0; i < aux->plan.nargs; ++i)
    179           opt_walk_operand(f, in, &aux->plan.args[i].src, 0, fn, ctx);
    180         for (u32 i = 0; i < aux->plan.nrets; ++i)
    181           opt_walk_operand(f, in, &aux->plan.rets[i].dst, 1, fn, ctx);
    182       } else {
    183         opt_walk_operand(f, in, &aux->desc.callee, 0, fn, ctx);
    184         for (u32 i = 0; i < aux->desc.nargs; ++i)
    185           opt_walk_abivalue(f, in, (CGABIValue*)&aux->desc.args[i], 0, fn, ctx);
    186         opt_walk_abivalue(f, in, &aux->desc.ret, 1, fn, ctx);
    187       }
    188       break;
    189     }
    190     case IR_RET: {
    191       IRRetAux* aux = (IRRetAux*)in->extra.aux;
    192       if (aux && aux->present) opt_walk_abivalue(f, in, &aux->val, 0, fn, ctx);
    193       break;
    194     }
    195     case IR_SCOPE_BEGIN:
    196       break;
    197     case IR_ASM_BLOCK: {
    198       IRAsmAux* aux = (IRAsmAux*)in->extra.aux;
    199       if (!aux) break;
    200       for (u32 i = 0; i < aux->nin; ++i)
    201         opt_walk_operand(f, in, &aux->in_ops[i], 0, fn, ctx);
    202       for (u32 i = 0; i < aux->nout; ++i)
    203         opt_walk_operand(f, in, &aux->out_ops[i], 1, fn, ctx);
    204       break;
    205     }
    206     case IR_INTRINSIC: {
    207       IRIntrinAux* aux = (IRIntrinAux*)in->extra.aux;
    208       if (!aux) break;
    209       for (u32 i = 0; i < aux->narg; ++i)
    210         opt_walk_operand(f, in, &aux->args[i], 0, fn, ctx);
    211       for (u32 i = 0; i < aux->ndst; ++i)
    212         opt_walk_operand(f, in, &aux->dsts[i], 1, fn, ctx);
    213       break;
    214     }
    215     default:
    216       break;
    217   }
    218 }
    219 
    220 int opt_mem_observable(const MemAccess* m) {
    221   return (m->flags & (MF_VOLATILE | MF_ATOMIC)) != 0;
    222 }