native_direct_target.h (6340B)
1 #ifndef KIT_CG_NATIVE_DIRECT_TARGET_H 2 #define KIT_CG_NATIVE_DIRECT_TARGET_H 3 4 #include "arch/native_target.h" 5 #include "cg/cgtarget.h" 6 7 /* NativeDirectTarget is the shared direct -O0 implementation of CgTarget for 8 * native backends. It owns semantic local homes, direct-mode scratch policy, 9 * local register caching, and conservative flushes. Arch code supplies a 10 * NativeTarget plus this small adapter for ABI/frame/legality decisions. */ 11 12 typedef struct NativeDirectTarget NativeDirectTarget; 13 14 typedef struct NativeDirectScope { 15 u8 kind; /* ScopeKind */ 16 u8 owns_break; 17 u8 pad[2]; 18 Label break_label; 19 Label continue_label; 20 } NativeDirectScope; 21 22 typedef enum NativeDirectBarrier { 23 NATIVE_DIRECT_BARRIER_CALL = 1u << 0, 24 NATIVE_DIRECT_BARRIER_MEMORY = 1u << 1, 25 NATIVE_DIRECT_BARRIER_VOLATILE = 1u << 2, 26 NATIVE_DIRECT_BARRIER_ATOMIC = 1u << 3, 27 NATIVE_DIRECT_BARRIER_INLINE_ASM = 1u << 4, 28 } NativeDirectBarrier; 29 30 typedef struct NativeDirectLocal { 31 KitCgTypeId type; 32 u32 size; 33 u32 align; 34 u32 flags; /* CGLocalFlag */ 35 36 NativeFrameSlot home; 37 Reg reg; 38 u8 cls; /* NativeAllocClass */ 39 u8 dirty; 40 u8 address_taken; 41 u8 memory_required; 42 u32 last_use; /* d->use_tick at the most recent cache touch (LRU victim key) 43 */ 44 /* Intrusive doubly-linked list of currently-cached locals, in insertion 45 * (caching) order so nd_cache_link is O(1) tail insertion. Values are 0-based 46 * indices into NativeDirectTarget.locals (or -1); only valid while this local 47 * is cached (l->reg != REG_NONE). */ 48 i32 cache_next; 49 i32 cache_prev; 50 } NativeDirectLocal; 51 52 typedef enum NativeDirectAddrLegality { 53 NATIVE_DIRECT_ADDR_ILLEGAL, 54 NATIVE_DIRECT_ADDR_LEGAL, 55 NATIVE_DIRECT_ADDR_LEGAL_IF_UNSCALED, 56 } NativeDirectAddrLegality; 57 58 typedef struct NativeOps NativeOps; 59 /* Semantic-only adapter the arch supplies on the NDT path. `ops` is mandatory: 60 * aa64_backend_make and aa64_semantic_target_new always pass it. Pure 61 * pass-throughs to NativeTarget (reg_info, func_begin/func_end, frame-slot 62 * allocation, class_for_type, addr_legal) are not mirrored here -- NDT calls 63 * d->native->X directly for those. */ 64 struct NativeOps { 65 void (*bind_param)(NativeDirectTarget*, const CGParamDesc*, CGLocal, 66 NativeDirectLocal*); 67 68 int (*operand_legal)(NativeDirectTarget*, const Operand*, NativeAllocClass); 69 NativeDirectAddrLegality (*semantic_addr_legal)(NativeDirectTarget*, 70 Operand addr, MemAccess); 71 72 void (*plan_call)(NativeDirectTarget*, const NativeCallDesc*, 73 NativeCallPlan*); 74 const char* (*tail_call_unrealizable_reason)(NativeDirectTarget*, 75 const CGCallDesc*); 76 void (*emit_call)(NativeDirectTarget*, const NativeCallPlan*); 77 /* `value` is the single returned local, or CG_LOCAL_NONE for void. */ 78 void (*emit_ret)(NativeDirectTarget*, CGLocal value); 79 80 void (*va_start_)(NativeDirectTarget*, Operand ap_addr); 81 void (*va_arg_)(NativeDirectTarget*, Operand dst, Operand ap_addr, 82 KitCgTypeId type); 83 void (*va_end_)(NativeDirectTarget*, Operand ap_addr); 84 void (*va_copy_)(NativeDirectTarget*, Operand dst_ap_addr, 85 Operand src_ap_addr); 86 87 void (*asm_block)(NativeDirectTarget*, const char* tmpl, 88 const AsmConstraint* outs, u32 nout, Operand* out_ops, 89 const AsmConstraint* ins, u32 nin, const Operand* in_ops, 90 const Sym* clobbers, u32 nclob, u32 clobber_abi_sets); 91 92 void (*barrier)(NativeDirectTarget*, u32 flags); 93 }; 94 95 /* Fixed transient buffers for per-op location/label arrays (call args/results, 96 * return values, intrinsic operands, indirect-branch targets). The common case 97 * fits these and allocates nothing; overflow falls back to the TU arena. */ 98 #define ND_ARG_BUF 16u 99 #define ND_RET_BUF 8u 100 #define ND_LBL_BUF 16u 101 102 typedef struct NativeDirectTargetConfig { 103 NativeTarget* native; 104 const NativeOps* ops; 105 void* user; 106 u32 flags; 107 } NativeDirectTargetConfig; 108 109 struct NativeDirectTarget { 110 CgTarget base; 111 u32 magic; 112 NativeTarget* native; 113 const NativeOps* ops; 114 void* user; 115 116 /* Register info and per-class info resolved once at construction (constant 117 * for the program), so scratch acquire / cache alloc / evict do an O(1) 118 * lookup instead of re-resolving reg_info and linearly scanning ri->classes. 119 */ 120 const NativeRegInfo* reg_info; 121 const NativeAllocClassInfo* class_info[3]; 122 123 const CGFuncDesc* func; 124 SrcLoc loc; 125 126 NativeDirectLocal* locals; 127 u32 nlocals; 128 u32 locals_cap; 129 130 MCLabel* labels; 131 u32 nlabels; 132 u32 labels_cap; 133 134 NativeDirectScope* scopes; 135 u32 nscopes; 136 u32 scopes_cap; 137 138 u32 scratch_used[3]; 139 /* Per-function callee-saved registers borrowed by direct scratch/cache 140 * allocation. Reported to the native backend before prologue patching. */ 141 u32 callee_saved_used[3]; 142 /* Local register cache (write-back, basic-block-scoped). reg_owner[cls][reg] 143 * names the semantic local currently cached in that physical register, or 144 * CG_LOCAL_NONE. scratch_used doubles as the per-class "pinned for the 145 * current instruction" mask. Per-local cache state (reg/cls/dirty) lives on 146 * NativeDirectLocal. See doc/CODEGEN.md "local register cache". */ 147 CGLocal reg_owner[3][32]; 148 u32 use_tick; /* monotonic counter stamped onto NativeDirectLocal.last_use */ 149 /* Head/tail of the intrusive cached-locals list (in caching order), -1 when 150 * empty; ncached is its length. Lets nd_flush_all run in O(cached) instead of 151 * scanning all nlocals on every control-flow / barrier op; cache_tail makes 152 * nd_cache_link an O(1) tail insertion. */ 153 i32 cache_head; 154 i32 cache_tail; 155 u32 ncached; 156 u32 max_outgoing; 157 158 /* Transient per-op buffers; see ND_*_BUF. Inputs use argbuf, outputs retbuf; 159 * never live across more than one op, so reuse between ops is safe. */ 160 NativeLoc argbuf[ND_ARG_BUF]; 161 NativeLoc retbuf[ND_RET_BUF]; 162 MCLabel lblbuf[ND_LBL_BUF]; 163 164 ObjSecId local_static_sec; 165 ObjSymId local_static_sym; 166 u32 local_static_base; 167 u32 local_static_size; 168 u8 local_static_active; 169 }; 170 171 CgTarget* native_direct_target_new(Compiler*, ObjBuilder*, 172 const NativeDirectTargetConfig*); 173 NativeTarget* native_direct_target_native(CgTarget*); 174 175 #endif