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 }