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