pass_copy.c (7715B)
1 #include <string.h> 2 3 #include "opt/opt_internal.h" 4 5 typedef struct ConvertStep { 6 Val src; 7 KitCgTypeId src_type; 8 KitCgTypeId dst_type; 9 u32 src_width; 10 u32 dst_width; 11 u8 kind; 12 } ConvertStep; 13 14 static int same_val_shape(Func* f, Val a, Val b) { 15 if (a == VAL_NONE || b == VAL_NONE || a >= f->nvals || b >= f->nvals) 16 return 0; 17 return f->val_cls[a] == f->val_cls[b] && f->val_type[a] == f->val_type[b]; 18 } 19 20 static int copy_values(const Inst* in, Val* dst, Val* src) { 21 if (!in || (IROp)in->op != IR_COPY || in->nopnds < 2) return 0; 22 if (in->opnds[0].kind != OPK_REG || in->opnds[1].kind != OPK_REG) return 0; 23 *dst = (Val)in->opnds[0].v.reg; 24 *src = (Val)in->opnds[1].v.reg; 25 if (in->def != VAL_NONE && in->def != *dst) return 0; 26 return 1; 27 } 28 29 static u32 def_count(Func* f, Val v) { 30 u32 n = 0; 31 if (v == VAL_NONE) return 0; 32 for (u32 b = 0; b < f->nblocks; ++b) { 33 Block* bl = &f->blocks[b]; 34 for (u32 i = 0; i < bl->ninsts; ++i) { 35 Inst* in = &bl->insts[i]; 36 if (in->def == v) ++n; 37 for (u32 d = 0; d < in->ndefs; ++d) 38 if (in->defs[d] == v) ++n; 39 } 40 } 41 return n; 42 } 43 44 static void replace_one_use(Func* f, const OptUse* use, Val src) { 45 Inst* in = &f->blocks[use->block].insts[use->inst]; 46 switch ((OptUseKind)use->kind) { 47 case OPT_USE_OPERAND: 48 use->operand->v.reg = (Reg)src; 49 use->operand->type = f->val_type[src]; 50 use->operand->cls = f->val_cls[src]; 51 break; 52 case OPT_USE_INDIRECT_BASE: 53 use->operand->v.ind.base = (Reg)src; 54 break; 55 case OPT_USE_INDIRECT_INDEX: 56 use->operand->v.ind.index = (Reg)src; 57 break; 58 case OPT_USE_PHI_INPUT: { 59 IRPhiAux* aux = (IRPhiAux*)in->extra.aux; 60 if (aux && use->phi_pred_index < aux->npreds) 61 aux->pred_vals[use->phi_pred_index] = src; 62 break; 63 } 64 default: 65 break; 66 } 67 } 68 69 static void remove_copy_inst(Inst* in) { 70 in->op = IR_NOP; 71 in->def = VAL_NONE; 72 in->ndefs = 0; 73 in->defs = NULL; 74 in->nopnds = 0; 75 in->opnds = NULL; 76 } 77 78 static void compact_copies(Func* f) { 79 for (u32 b = 0; b < f->nblocks; ++b) { 80 Block* bl = &f->blocks[b]; 81 u32 w = 0; 82 for (u32 i = 0; i < bl->ninsts; ++i) { 83 if ((IROp)bl->insts[i].op == IR_NOP) continue; 84 bl->insts[w] = bl->insts[i]; 85 if (bl->insts[w].def != VAL_NONE && bl->insts[w].def < f->nvals) { 86 f->val_def_block[bl->insts[w].def] = b; 87 f->val_def_inst[bl->insts[w].def] = w; 88 } 89 for (u32 d = 0; d < bl->insts[w].ndefs; ++d) { 90 Val v = bl->insts[w].defs[d]; 91 if (v != VAL_NONE && v < f->nvals) { 92 f->val_def_block[v] = b; 93 f->val_def_inst[v] = w; 94 } 95 } 96 ++w; 97 } 98 bl->ninsts = w; 99 } 100 } 101 102 static Inst* val_def_inst(Func* f, Val v) { 103 if (!f || v == VAL_NONE || v >= f->nvals) return NULL; 104 u32 b = f->val_def_block[v]; 105 u32 i = f->val_def_inst[v]; 106 if (b >= f->nblocks || i >= f->blocks[b].ninsts) return NULL; 107 return &f->blocks[b].insts[i]; 108 } 109 110 static int int_width(Func* f, KitCgTypeId ty, u32* out) { 111 u32 width = kit_cg_type_int_width((KitCompiler*)f->c, ty); 112 if (!width || width > 64u) return 0; 113 *out = width; 114 return 1; 115 } 116 117 static int convert_step(Func* f, const Inst* in, ConvertStep* out) { 118 if (!f || !in || !out || (IROp)in->op != IR_CONVERT || in->nopnds < 2) 119 return 0; 120 if (in->def == VAL_NONE || in->def >= f->nvals) return 0; 121 if (in->opnds[0].kind != OPK_REG || in->opnds[1].kind != OPK_REG) return 0; 122 123 memset(out, 0, sizeof *out); 124 out->src = (Val)in->opnds[1].v.reg; 125 if (out->src == VAL_NONE || out->src >= f->nvals) return 0; 126 out->src_type = in->opnds[1].type; 127 out->dst_type = in->opnds[0].type; 128 out->kind = (u8)in->extra.imm; 129 if (!int_width(f, out->src_type, &out->src_width) || 130 !int_width(f, out->dst_type, &out->dst_width)) 131 return 0; 132 return 1; 133 } 134 135 static int conversion_is_noop(const ConvertStep* s) { 136 if (!s || s->src_width != s->dst_width || s->src_type != s->dst_type) 137 return 0; 138 switch ((ConvKind)s->kind) { 139 case CV_ZEXT: 140 case CV_SEXT: 141 case CV_TRUNC: 142 case CV_BITCAST: 143 return 1; 144 default: 145 return 0; 146 } 147 } 148 149 static int extension_kind(u8 kind) { 150 return kind == CV_ZEXT || kind == CV_SEXT; 151 } 152 153 static void set_convert_source(Func* f, Inst* in, Val src) { 154 in->opnds[1].v.reg = (Reg)src; 155 in->opnds[1].type = f->val_type[src]; 156 in->opnds[1].cls = f->val_cls[src]; 157 } 158 159 static void make_copy_from(Func* f, Inst* in, Val src) { 160 Val dst = in->def; 161 Operand* opnds = in->opnds; 162 if (!opnds) opnds = arena_array(f->arena, Operand, 2); 163 memset(&opnds[0], 0, sizeof opnds[0]); 164 memset(&opnds[1], 0, sizeof opnds[1]); 165 opnds[0].kind = OPK_REG; 166 opnds[0].type = f->val_type[dst]; 167 opnds[0].cls = f->val_cls[dst]; 168 opnds[0].v.reg = (Reg)dst; 169 opnds[1].kind = OPK_REG; 170 opnds[1].type = f->val_type[src]; 171 opnds[1].cls = f->val_cls[src]; 172 opnds[1].v.reg = (Reg)src; 173 in->op = IR_COPY; 174 in->type = f->val_type[dst]; 175 in->opnds = opnds; 176 in->nopnds = 2; 177 } 178 179 static int simplify_convert_chain(Func* f, Inst* outer, const ConvertStep* o, 180 const ConvertStep* inner) { 181 if (!f || !outer || !o || !inner) return 0; 182 183 if (conversion_is_noop(o)) { 184 make_copy_from(f, outer, o->src); 185 return 1; 186 } 187 188 if (extension_kind(o->kind) && o->kind == inner->kind && 189 inner->src_width <= inner->dst_width && 190 inner->dst_width <= o->dst_width) { 191 set_convert_source(f, outer, inner->src); 192 return 1; 193 } 194 195 if (o->kind == CV_TRUNC && extension_kind(inner->kind) && 196 o->dst_width <= inner->dst_width) { 197 set_convert_source(f, outer, inner->src); 198 if (o->dst_width == inner->src_width && o->dst_type == inner->src_type) { 199 make_copy_from(f, outer, inner->src); 200 } else if (o->dst_width > inner->src_width) { 201 outer->extra.imm = inner->kind; 202 } 203 return 1; 204 } 205 206 return 0; 207 } 208 209 static int cleanup_one_copy(Func* f) { 210 opt_rebuild_def_use(f); 211 for (u32 b = 0; b < f->nblocks; ++b) { 212 Block* bl = &f->blocks[b]; 213 for (u32 i = 0; i < bl->ninsts; ++i) { 214 Inst* in = &bl->insts[i]; 215 Val dst = VAL_NONE; 216 Val src = VAL_NONE; 217 if (!copy_values(in, &dst, &src)) continue; 218 if (dst != src && !same_val_shape(f, dst, src)) continue; 219 if (dst != src && def_count(f, dst) != 1) continue; 220 for (u32 u = f->opt_first_use_by_val[dst]; u != OPT_USE_NONE; 221 u = f->opt_uses[u].next_for_val) 222 replace_one_use(f, &f->opt_uses[u], src); 223 remove_copy_inst(in); 224 opt_analysis_invalidate(f, OPT_ANALYSIS_DEF_USE); 225 compact_copies(f); 226 return 1; 227 } 228 } 229 return 0; 230 } 231 232 static int cleanup_one_extension(Func* f) { 233 for (u32 b = 0; b < f->nblocks; ++b) { 234 Block* bl = &f->blocks[b]; 235 for (u32 i = 0; i < bl->ninsts; ++i) { 236 Inst* outer = &bl->insts[i]; 237 ConvertStep o; 238 if (!convert_step(f, outer, &o)) continue; 239 240 Inst* inner_inst = val_def_inst(f, o.src); 241 ConvertStep inner; 242 if (!convert_step(f, inner_inst, &inner)) { 243 if (!conversion_is_noop(&o)) continue; 244 make_copy_from(f, outer, o.src); 245 } else if (!simplify_convert_chain(f, outer, &o, &inner)) { 246 continue; 247 } 248 249 opt_analysis_invalidate(f, OPT_ANALYSIS_DEF_USE); 250 return 1; 251 } 252 } 253 return 0; 254 } 255 256 void opt_copy_cleanup(Func* f) { 257 if (!f || f->opt_rewritten) return; 258 while (cleanup_one_copy(f)) { 259 } 260 opt_rebuild_def_use(f); 261 } 262 263 void opt_copy_prop(Func* f) { 264 if (!f || f->opt_rewritten) return; 265 if (!f->opt_reg_ssa && f->npregs > 1) { 266 opt_copy_cleanup(f); 267 return; 268 } 269 270 opt_copy_cleanup(f); 271 while (cleanup_one_extension(f)) { 272 opt_rebuild_def_use(f); 273 opt_copy_cleanup(f); 274 } 275 opt_copy_cleanup(f); 276 }