pass_hard_live.c (9604B)
1 #include <string.h> 2 3 #include "core/arena.h" 4 #include "opt/opt_internal.h" 5 6 u32 opt_call_clobber_mask_for(Func* f, const Inst* in, u8 cls) { 7 if (cls >= OPT_REG_CLASSES) return 0; 8 if (in && (IROp)in->op == IR_CALL) { 9 IRCallAux* aux = (IRCallAux*)in->extra.aux; 10 if (aux && aux->plan_valid) return aux->plan.clobber_mask[cls]; 11 } 12 return f->opt_caller_saved[cls]; 13 } 14 static void hard_add(OptHardRegSet* s, u8 cls, Reg r) { 15 if (cls >= OPT_REG_CLASSES || r >= 32) return; 16 s->cls[cls] |= 1u << r; 17 } 18 19 int opt_hard_empty(const OptHardRegSet* s) { 20 for (u32 c = 0; c < OPT_REG_CLASSES; ++c) 21 if (s->cls[c]) return 0; 22 return 1; 23 } 24 25 int opt_hard_intersects(const OptHardRegSet* a, const OptHardRegSet* b) { 26 for (u32 c = 0; c < OPT_REG_CLASSES; ++c) 27 if (a->cls[c] & b->cls[c]) return 1; 28 return 0; 29 } 30 31 static int hard_eq(const OptHardRegSet* a, const OptHardRegSet* b) { 32 for (u32 c = 0; c < OPT_REG_CLASSES; ++c) 33 if (a->cls[c] != b->cls[c]) return 0; 34 return 1; 35 } 36 37 static void hard_or(OptHardRegSet* dst, const OptHardRegSet* src) { 38 for (u32 c = 0; c < OPT_REG_CLASSES; ++c) dst->cls[c] |= src->cls[c]; 39 } 40 41 static void hard_live_in_from_out(OptHardRegSet* dst, const OptHardRegSet* use, 42 const OptHardRegSet* out, 43 const OptHardRegSet* def) { 44 for (u32 c = 0; c < OPT_REG_CLASSES; ++c) 45 dst->cls[c] = use->cls[c] | (out->cls[c] & ~def->cls[c]); 46 } 47 48 void opt_hard_live_step(OptHardRegSet* live, const OptHardRegSet* use, 49 const OptHardRegSet* def) { 50 for (u32 c = 0; c < OPT_REG_CLASSES; ++c) 51 live->cls[c] = (live->cls[c] & ~def->cls[c]) | use->cls[c]; 52 } 53 54 static void hard_use_operand(OptHardRegSet* s, const Operand* op) { 55 if (!op) return; 56 if (op->kind == OPK_REG) { 57 hard_add(s, op->cls, op->v.reg); 58 } else if (op->kind == OPK_INDIRECT) { 59 hard_add(s, RC_INT, op->v.ind.base); 60 if (op->v.ind.index != (Reg)REG_NONE) hard_add(s, RC_INT, op->v.ind.index); 61 } 62 } 63 64 static void hard_def_operand(OptHardRegSet* s, const Operand* op) { 65 if (op && op->kind == OPK_REG) hard_add(s, op->cls, op->v.reg); 66 } 67 68 static void hard_def_clobber_mask(OptHardRegSet* s, const u32* masks) { 69 if (!masks) return; 70 for (u32 c = 0; c < OPT_REG_CLASSES; ++c) s->cls[c] |= masks[c]; 71 } 72 73 static void hard_use_abivalue(OptHardRegSet* use, const CGABIValue* v) { 74 if (!v) return; 75 hard_use_operand(use, &v->storage); 76 for (u32 i = 0; i < v->nparts; ++i) hard_use_operand(use, &v->parts[i].op); 77 } 78 79 static void hard_def_abivalue(OptHardRegSet* def, const CGABIValue* v) { 80 if (!v) return; 81 hard_def_operand(def, &v->storage); 82 for (u32 i = 0; i < v->nparts; ++i) hard_def_operand(def, &v->parts[i].op); 83 } 84 85 void opt_hard_inst_use_def(Func* f, const Inst* in, OptHardRegSet* use, 86 OptHardRegSet* def) { 87 memset(use, 0, sizeof *use); 88 memset(def, 0, sizeof *def); 89 switch ((IROp)in->op) { 90 case IR_LOAD_IMM: 91 case IR_LOAD_CONST: 92 case IR_TLS_ADDR_OF: 93 if (in->nopnds >= 1) hard_def_operand(def, &in->opnds[0]); 94 break; 95 case IR_COPY: 96 case IR_CONVERT: 97 case IR_UNOP: 98 case IR_VA_ARG: 99 if (in->nopnds >= 1) hard_def_operand(def, &in->opnds[0]); 100 if (in->nopnds >= 2) hard_use_operand(use, &in->opnds[1]); 101 break; 102 case IR_LOAD: 103 case IR_ADDR_OF: 104 case IR_BITFIELD_LOAD: 105 case IR_ATOMIC_LOAD: 106 if (in->nopnds >= 1) hard_def_operand(def, &in->opnds[0]); 107 if (in->nopnds >= 2) hard_use_operand(use, &in->opnds[1]); 108 break; 109 case IR_BINOP: 110 case IR_CMP: 111 if (in->nopnds >= 1) hard_def_operand(def, &in->opnds[0]); 112 if (in->nopnds >= 2) hard_use_operand(use, &in->opnds[1]); 113 if (in->nopnds >= 3) hard_use_operand(use, &in->opnds[2]); 114 break; 115 case IR_STORE: 116 case IR_AGG_COPY: 117 case IR_AGG_SET: 118 case IR_BITFIELD_STORE: 119 case IR_VA_COPY: 120 if (in->nopnds >= 1) hard_use_operand(use, &in->opnds[0]); 121 if (in->nopnds >= 2) hard_use_operand(use, &in->opnds[1]); 122 break; 123 case IR_CALL: { 124 IRCallAux* aux = (IRCallAux*)in->extra.aux; 125 if (!aux) break; 126 if (aux->use_plan_replay) { 127 hard_use_operand(use, &aux->plan.callee); 128 for (u32 i = 0; i < aux->plan.nargs; ++i) { 129 hard_use_operand(use, &aux->plan.args[i].src); 130 if (aux->plan.args[i].dst_kind == CG_CALL_PLAN_REG) 131 hard_add(def, aux->plan.args[i].cls, aux->plan.args[i].dst_reg); 132 } 133 for (u32 i = 0; i < aux->plan.nrets; ++i) { 134 hard_add(def, aux->plan.rets[i].cls, aux->plan.rets[i].src_reg); 135 hard_def_operand(def, &aux->plan.rets[i].dst); 136 } 137 } else { 138 hard_use_operand(use, &aux->desc.callee); 139 for (u32 i = 0; i < aux->desc.nargs; ++i) 140 hard_use_abivalue(use, &aux->desc.args[i]); 141 hard_def_abivalue(def, &aux->desc.ret); 142 } 143 for (u32 c = 0; c < OPT_REG_CLASSES; ++c) { 144 u32 idx = c; 145 u32 mask = opt_call_clobber_mask_for(f, in, (u8)idx); 146 u32 old = def->cls[idx]; 147 def->cls[idx] = old | mask; 148 } 149 break; 150 } 151 case IR_CMP_BRANCH: 152 case IR_CONDBR: 153 case IR_SWITCH: 154 case IR_INDIRECT_BRANCH: 155 for (u32 i = 0; i < in->nopnds; ++i) hard_use_operand(use, &in->opnds[i]); 156 break; 157 case IR_LOAD_LABEL_ADDR: 158 if (in->nopnds >= 1) hard_def_operand(def, &in->opnds[0]); 159 break; 160 case IR_RET: { 161 IRRetAux* aux = (IRRetAux*)in->extra.aux; 162 if (aux && aux->present) hard_use_abivalue(use, &aux->val); 163 break; 164 } 165 case IR_SCOPE_BEGIN: 166 break; 167 case IR_ALLOCA: 168 if (in->nopnds >= 1) hard_def_operand(def, &in->opnds[0]); 169 if (in->nopnds >= 2) hard_use_operand(use, &in->opnds[1]); 170 break; 171 case IR_VA_START: 172 case IR_VA_END: 173 if (in->nopnds >= 1) hard_use_operand(use, &in->opnds[0]); 174 break; 175 case IR_ATOMIC_STORE: 176 if (in->nopnds >= 1) hard_use_operand(use, &in->opnds[0]); 177 if (in->nopnds >= 2) hard_use_operand(use, &in->opnds[1]); 178 break; 179 case IR_ATOMIC_RMW: 180 if (in->nopnds >= 1) hard_def_operand(def, &in->opnds[0]); 181 if (in->nopnds >= 2) hard_use_operand(use, &in->opnds[1]); 182 if (in->nopnds >= 3) hard_use_operand(use, &in->opnds[2]); 183 break; 184 case IR_ATOMIC_CAS: 185 if (in->nopnds >= 1) hard_def_operand(def, &in->opnds[0]); 186 if (in->nopnds >= 2) hard_def_operand(def, &in->opnds[1]); 187 if (in->nopnds >= 3) hard_use_operand(use, &in->opnds[2]); 188 if (in->nopnds >= 4) hard_use_operand(use, &in->opnds[3]); 189 if (in->nopnds >= 5) hard_use_operand(use, &in->opnds[4]); 190 break; 191 case IR_ASM_BLOCK: { 192 IRAsmAux* aux = (IRAsmAux*)in->extra.aux; 193 if (!aux) break; 194 for (u32 i = 0; i < aux->nin; ++i) hard_use_operand(use, &aux->in_ops[i]); 195 for (u32 i = 0; i < aux->nout; ++i) 196 hard_def_operand(def, &aux->out_ops[i]); 197 hard_def_clobber_mask(def, aux->clobber_mask); 198 break; 199 } 200 case IR_INTRINSIC: { 201 IRIntrinAux* aux = (IRIntrinAux*)in->extra.aux; 202 if (!aux) break; 203 for (u32 i = 0; i < aux->narg; ++i) hard_use_operand(use, &aux->args[i]); 204 for (u32 i = 0; i < aux->ndst; ++i) hard_def_operand(def, &aux->dsts[i]); 205 break; 206 } 207 default: 208 break; 209 } 210 } 211 212 static void hard_live_blocks(Func* f, OptHardBlockLive* live) { 213 for (u32 b = 0; b < f->nblocks; ++b) { 214 Block* bl = &f->blocks[b]; 215 OptHardRegSet seen_def; 216 memset(&seen_def, 0, sizeof seen_def); 217 memset(&live[b], 0, sizeof live[b]); 218 for (u32 i = 0; i < bl->ninsts; ++i) { 219 OptHardRegSet use, def; 220 opt_hard_inst_use_def(f, &bl->insts[i], &use, &def); 221 for (u32 c = 0; c < OPT_REG_CLASSES; ++c) 222 live[b].live_use.cls[c] |= use.cls[c] & ~seen_def.cls[c]; 223 hard_or(&seen_def, &def); 224 hard_or(&live[b].live_def, &def); 225 } 226 } 227 228 int changed; 229 do { 230 changed = 0; 231 for (u32 bi = f->nblocks; bi > 0; --bi) { 232 u32 b = bi - 1u; 233 Block* bl = &f->blocks[b]; 234 OptHardRegSet new_out, new_in; 235 memset(&new_out, 0, sizeof new_out); 236 for (u32 s = 0; s < bl->nsucc; ++s) { 237 u32 t = bl->succ[s]; 238 if (t < f->nblocks) hard_or(&new_out, &live[t].live_in); 239 } 240 hard_live_in_from_out(&new_in, &live[b].live_use, &new_out, 241 &live[b].live_def); 242 if (!hard_eq(&live[b].live_out, &new_out)) { 243 live[b].live_out = new_out; 244 changed = 1; 245 } 246 if (!hard_eq(&live[b].live_in, &new_in)) { 247 live[b].live_in = new_in; 248 changed = 1; 249 } 250 } 251 } while (changed); 252 } 253 254 static int hard_live_out_has_phys_reg(const OptHardBlockLive* live, 255 const Operand* r) { 256 if (!live || !r || r->kind != OPK_REG || r->cls >= OPT_REG_CLASSES || 257 r->v.reg >= 32) 258 return 0; 259 return (live->live_out.cls[r->cls] & (1u << r->v.reg)) != 0; 260 } 261 262 OptHardBlockLive* opt_maybe_build_hard_live(Func* f) { 263 if (!f->opt_rewritten) return NULL; 264 OptHardBlockLive* live = 265 arena_zarray(f->arena, OptHardBlockLive, f->nblocks ? f->nblocks : 1u); 266 hard_live_blocks(f, live); 267 return live; 268 } 269 270 OptHardRegSet opt_hard_live_out_for_block(const OptHardBlockLive* live) { 271 OptHardRegSet out; 272 memset(&out, 0, sizeof out); 273 if (live) out = live->live_out; 274 return out; 275 } 276 277 int opt_block_live_out_has_phys_reg(Func* f, const OptHardBlockLive* hard_live, 278 u32 block, const Operand* r) { 279 (void)f; 280 if (!hard_live || block >= f->nblocks) return 0; 281 return hard_live_out_has_phys_reg(&hard_live[block], r); 282 }