cgtarget.c (3791B)
1 /* Public CgTarget constructor — dispatches through the registered arch impl. 2 * 3 * The lifecycle helpers (cgtarget_finalize, cgtarget_free) are arch-agnostic 4 * shims over the vtable. */ 5 6 #include <kit/config.h> 7 #include <string.h> 8 9 #include "arch/arch.h" 10 #include "cg/type.h" 11 #include "debug/debug.h" 12 13 CgTarget* cgtarget_new(Compiler* c, ObjBuilder* o) { 14 const ArchImpl* arch = arch_for_compiler(c); 15 if (arch && arch->cgtarget_new) { 16 return arch->cgtarget_new(c, o, NULL); 17 } 18 { 19 SrcLoc loc = {0, 0, 0}; 20 compiler_panic(c, loc, "cgtarget_new: unsupported target arch %d", 21 (int)c->target.arch); 22 } 23 } 24 25 void cgtarget_set_finish_policy(CgTarget* t, const CgFinishPolicy* policy) { 26 if (!t) return; 27 memset(&t->finish_policy, 0, sizeof(t->finish_policy)); 28 if (policy) t->finish_policy = *policy; 29 } 30 31 void cgtarget_finalize(CgTarget* t) { 32 if (t && t->finalize) t->finalize(t); 33 } 34 35 void cgtarget_free(CgTarget* t) { 36 if (!t) return; 37 if (t->destroy) t->destroy(t); 38 } 39 40 KitStatus cg_mc_debug_new(Compiler* c, ObjBuilder* o, 41 const KitCodeOptions* opts, MCEmitter** out_mc, 42 Debug** out_debug) { 43 MCEmitter* mc; 44 Debug* debug = NULL; 45 *out_mc = NULL; 46 *out_debug = NULL; 47 mc = mc_new(c, o); 48 if (!mc) return KIT_NOMEM; 49 #if KIT_DWARF_ENABLED 50 if (opts && opts->debug_info) { 51 debug = debug_new(c, o); 52 if (!debug) { 53 mc_free(mc); 54 return KIT_NOMEM; 55 } 56 mc->debug = debug; 57 } 58 #else 59 (void)o; 60 if (opts && opts->debug_info) { 61 mc_free(mc); 62 return KIT_UNSUPPORTED; 63 } 64 #endif 65 *out_mc = mc; 66 *out_debug = debug; 67 return KIT_OK; 68 } 69 70 /* Default fold for backends without a native indexed addressing mode. 71 * 72 * If `addr` carries an index local (addr.v.ind.index != CG_LOCAL_NONE), 73 * materialize `base + (index << log2_scale)` into `scratch` and return a plain 74 * OPK_INDIRECT(scratch, ofs) with `index == CG_LOCAL_NONE`. Otherwise return 75 * `addr` unchanged. 76 * 77 * The caller supplies `scratch` from its own scratch pool and is responsible 78 * for freeing it after the memop completes. The returned operand keeps the 79 * caller's `type` so the backend's load/store sees the same access type. */ 80 Operand arch_lower_indexed(CgTarget* t, Operand addr, Reg scratch) { 81 Operand scratch_op; 82 Operand shifted; 83 KitCgTypeId ty; 84 u8 log2; 85 86 if (addr.kind != OPK_INDIRECT || addr.v.ind.index == REG_NONE) return addr; 87 88 ty = builtin_id(KIT_CG_BUILTIN_I64); 89 log2 = addr.v.ind.log2_scale; 90 memset(&scratch_op, 0, sizeof scratch_op); 91 scratch_op.kind = OPK_LOCAL; 92 scratch_op.type = ty; 93 scratch_op.v.local = scratch; 94 95 memset(&shifted, 0, sizeof shifted); 96 shifted.kind = OPK_LOCAL; 97 shifted.type = ty; 98 shifted.v.local = addr.v.ind.index; 99 100 if (log2 == 0) { 101 /* index * 1: just add the index directly to the base. */ 102 Operand base_op; 103 memset(&base_op, 0, sizeof base_op); 104 base_op.kind = OPK_LOCAL; 105 base_op.type = ty; 106 base_op.v.local = addr.v.ind.base; 107 t->binop(t, BO_IADD, scratch_op, base_op, shifted); 108 } else { 109 /* scratch = index << log2 */ 110 Operand shamt; 111 Operand base_op; 112 memset(&shamt, 0, sizeof shamt); 113 shamt.kind = OPK_IMM; 114 shamt.type = ty; 115 shamt.v.imm = (i64)log2; 116 t->binop(t, BO_SHL, scratch_op, shifted, shamt); 117 memset(&base_op, 0, sizeof base_op); 118 base_op.kind = OPK_LOCAL; 119 base_op.type = ty; 120 base_op.v.local = addr.v.ind.base; 121 /* scratch = base + scratch */ 122 t->binop(t, BO_IADD, scratch_op, base_op, scratch_op); 123 } 124 125 { 126 Operand out; 127 memset(&out, 0, sizeof out); 128 out.kind = OPK_INDIRECT; 129 out.type = ty; 130 out.v.ind.base = scratch; 131 out.v.ind.index = REG_NONE; 132 out.v.ind.log2_scale = 0; 133 out.v.ind.ofs = addr.v.ind.ofs; 134 return out; 135 } 136 }