registry.c (5873B)
1 /* CGBackend / ArchImpl registry. 2 * 3 * This file is the *only* place in the codebase that checks 4 * KIT_ARCH_*_ENABLED. Everything downstream operates on the registry's 5 * outputs — `const CGBackend*` for session-level code emission, and 6 * `const ArchImpl*` for arch-specific metadata (DWARF, debugger hooks, 7 * register file, etc.). 8 * 9 * Conceptually: 10 * - A CGBackend is "something that can build a CgTarget from a Compiler + 11 * ObjBuilder + KitCodeOptions". Machine-code arches and c_target both 12 * qualify. 13 * - An ArchImpl is a CGBackend plus the machine-code metadata (its first 14 * field is a CGBackend, so `(const CGBackend*)&arch_impl_x` is valid). 15 * - c_target has no ArchImpl — it is a CGBackend and nothing more. 16 */ 17 18 #include "arch/arch.h" 19 #include "kit/config.h" 20 #include "kit/target.h" 21 22 #if KIT_ARCH_AA64_ENABLED 23 extern const ArchImpl arch_impl_aa64; 24 #endif 25 #if KIT_ARCH_RV32_ENABLED 26 extern const ArchImpl arch_impl_rv32; 27 #endif 28 #if KIT_ARCH_RV64_ENABLED 29 extern const ArchImpl arch_impl_rv64; 30 #endif 31 #if KIT_ARCH_X64_ENABLED 32 extern const ArchImpl arch_impl_x64; 33 #endif 34 #if KIT_ARCH_ARM32_ENABLED 35 extern const ArchImpl arch_impl_arm32; 36 #endif 37 #if KIT_ARCH_C_TARGET_ENABLED 38 extern const CGBackend cg_backend_c_target; 39 #endif 40 extern const CGBackend cg_backend_check; 41 #if KIT_ARCH_WASM_ENABLED 42 extern const ArchImpl arch_impl_wasm; 43 #endif 44 45 /* Arch-metadata roster. The arch_lookup_* helpers iterate this list when a 46 * caller needs machine-arch metadata — answers only come from backends that 47 * have an ArchImpl, so c_target is intentionally absent. 48 * cg_backend_for_session() picks the CGBackend (which is &impl->backend or 49 * &cg_backend_c_target) without consulting this list. */ 50 static const ArchImpl* const arch_impls[] = { 51 #if KIT_ARCH_AA64_ENABLED 52 &arch_impl_aa64, 53 #endif 54 #if KIT_ARCH_X64_ENABLED 55 &arch_impl_x64, 56 #endif 57 #if KIT_ARCH_ARM32_ENABLED 58 &arch_impl_arm32, 59 #endif 60 #if KIT_ARCH_RV32_ENABLED 61 &arch_impl_rv32, 62 #endif 63 #if KIT_ARCH_RV64_ENABLED 64 &arch_impl_rv64, 65 #endif 66 #if KIT_ARCH_WASM_ENABLED 67 &arch_impl_wasm, 68 #endif 69 #if !KIT_ARCH_AA64_ENABLED && !KIT_ARCH_X64_ENABLED && \ 70 !KIT_ARCH_ARM32_ENABLED && !KIT_ARCH_RV32_ENABLED && \ 71 !KIT_ARCH_RV64_ENABLED && !KIT_ARCH_WASM_ENABLED 72 NULL, 73 #endif 74 }; 75 76 static u32 arch_impls_count(void) { 77 return (u32)(sizeof arch_impls / sizeof arch_impls[0]); 78 } 79 80 const char* arch_kind_name(KitArchKind arch) { 81 /* The arch diagnostic-name table lives with the triple parser/renderer in 82 * src/api/target.c so all arch-name spellings have one source. */ 83 return kit_target_arch_diag_name(arch); 84 } 85 86 const ArchImpl* arch_lookup(KitArchKind arch) { 87 for (u32 i = 0; i < arch_impls_count(); ++i) { 88 if (arch_impls[i] && arch_impls[i]->kind == arch) return arch_impls[i]; 89 } 90 return NULL; 91 } 92 93 const ArchImpl* arch_for_compiler(const Compiler* c) { 94 if (!c) return NULL; 95 return arch_lookup(c->target.arch); 96 } 97 98 int arch_target_feature_index(const ArchImpl* a, KitSlice name, u32* idx_out) { 99 u32 i; 100 if (!a || !name.s) return 0; 101 for (i = 0; i < a->ntarget_features; ++i) { 102 if (kit_slice_eq_cstr(name, a->target_features[i].name)) { 103 if (idx_out) *idx_out = i; 104 return 1; 105 } 106 } 107 return 0; 108 } 109 110 void arch_target_feature_defaults(const ArchImpl* a, const Target* target, 111 u64* words, u32 nwords) { 112 if (!a || !words || nwords == 0) return; 113 if (a->target_feature_defaults) { 114 a->target_feature_defaults(target, words, nwords); 115 } 116 } 117 118 KitStatus arch_target_feature_apply_isa(const ArchImpl* a, const Target* target, 119 KitSlice isa, u64* words, u32 nwords) { 120 if (!a || !isa.s || isa.len == 0) return KIT_OK; 121 if (!words && nwords != 0) return KIT_INVALID; 122 if (!a->target_feature_apply_isa) return KIT_UNSUPPORTED; 123 return a->target_feature_apply_isa(target, isa, words, nwords); 124 } 125 126 KitStatus arch_target_feature_apply_cpu(const ArchImpl* a, const Target* target, 127 KitSlice cpu, u64* words, u32 nwords) { 128 if (!a || !cpu.s || cpu.len == 0) return KIT_OK; 129 if (!words && nwords != 0) return KIT_INVALID; 130 /* An arch with no CPU axis ignores -mcpu= (no-op success), matching the way 131 * non-RISC-V arches ignore -march= today (the spec selectors are advisory for 132 * those targets). */ 133 if (!a->target_feature_apply_cpu) return KIT_OK; 134 return a->target_feature_apply_cpu(target, cpu, words, nwords); 135 } 136 137 int arch_reloc_operand(const Compiler* c, u16 reloc_kind, 138 ArchRelocOperand* out) { 139 const ArchImpl* a = arch_for_compiler(c); 140 if (!a || !a->asm_ops || !a->asm_ops->reloc_operand) return 0; 141 return a->asm_ops->reloc_operand(reloc_kind, c->target.obj, out); 142 } 143 144 int arch_is_local_branch(const Compiler* c, KitSlice mnemonic) { 145 const ArchImpl* a = arch_for_compiler(c); 146 if (!a || !a->asm_ops || !a->asm_ops->is_local_branch) return 0; 147 return a->asm_ops->is_local_branch(mnemonic); 148 } 149 150 int arch_reloc_call_pair(const Compiler* c, u16 reloc_kind, 151 KitSlice pair_mnemonic, KitSlice pair_ops, 152 const char** mnemonic_out) { 153 const ArchImpl* a = arch_for_compiler(c); 154 if (!a || !a->asm_ops || !a->asm_ops->reloc_call_pair) return 0; 155 return a->asm_ops->reloc_call_pair(reloc_kind, pair_mnemonic, pair_ops, 156 mnemonic_out); 157 } 158 159 const CGBackend* cg_backend_for_session(const Compiler* c, 160 const KitCodeOptions* opts) { 161 if (opts && opts->check_only) { 162 return &cg_backend_check; 163 } 164 if (opts && opts->emit_c_source) { 165 #if KIT_ARCH_C_TARGET_ENABLED 166 return &cg_backend_c_target; 167 #else 168 return NULL; 169 #endif 170 } 171 { 172 const ArchImpl* impl = arch_for_compiler(c); 173 return impl ? &impl->backend : NULL; 174 } 175 }