arch.c (8571B)
1 #include "arch/arch.h" 2 3 #include <string.h> 4 5 #include "arch/x64/asm.h" 6 #include "arch/x64/disasm.h" 7 #include "arch/x64/regs.h" 8 #include "arch/x64/x64.h" 9 #include "cg/native_direct_target.h" 10 #include "core/bytes.h" 11 #include "link/link_arch.h" 12 #include "obj/obj.h" 13 14 extern const LinkArchDesc link_arch_x64; 15 extern const ArchDbgOps x64_dbg_ops; 16 extern const ArchDwarfOps x64_dwarf_ops; 17 extern const ArchAsmOps x64_asm_ops; 18 19 static int x64_apply_label_fixup(Compiler* c, const ArchLabelFixup* fx) { 20 (void)c; 21 if (!fx || fx->kind != R_PC32 || fx->width != 4) return 1; 22 { 23 u8 bytes[4]; 24 wr_u32_le(bytes, (u32)(i32)fx->disp); 25 obj_patch(fx->obj, fx->sec_id, fx->offset, bytes, 4); 26 } 27 return 0; 28 } 29 30 static const KitPredefinedMacro x64_predefined_macros[] = { 31 {KIT_SLICE_LIT("__x86_64"), KIT_SLICE_LIT("1")}, 32 {KIT_SLICE_LIT("__x86_64__"), KIT_SLICE_LIT("1")}, 33 {KIT_SLICE_LIT("__amd64"), KIT_SLICE_LIT("1")}, 34 {KIT_SLICE_LIT("__amd64__"), KIT_SLICE_LIT("1")}, 35 {KIT_SLICE_LIT("__LP64__"), KIT_SLICE_LIT("1")}, 36 {KIT_SLICE_LIT("__ORDER_LITTLE_ENDIAN__"), KIT_SLICE_LIT("1234")}, 37 {KIT_SLICE_LIT("__ORDER_BIG_ENDIAN__"), KIT_SLICE_LIT("4321")}, 38 {KIT_SLICE_LIT("__BYTE_ORDER__"), KIT_SLICE_LIT("__ORDER_LITTLE_ENDIAN__")}, 39 {KIT_SLICE_LIT("__LITTLE_ENDIAN__"), KIT_SLICE_LIT("1")}, 40 }; 41 42 enum { 43 X64_FEAT_SSE = 0, 44 X64_FEAT_SSE2, 45 X64_FEAT_SSE3, 46 X64_FEAT_SSSE3, 47 X64_FEAT_SSE41, 48 X64_FEAT_SSE42, 49 X64_FEAT_AVX, 50 X64_FEAT_AVX2, 51 }; 52 53 static const ArchTargetFeature x64_target_features[] = { 54 {"sse"}, {"sse2"}, {"sse3"}, {"ssse3"}, 55 {"sse4.1"}, {"sse4.2"}, {"avx"}, {"avx2"}, 56 }; 57 58 static void x64_feature_set(u64* words, u32 nwords, u32 idx) { 59 if (!words || idx / 64u >= nwords) return; 60 words[idx / 64u] |= 1ull << (idx % 64u); 61 } 62 63 static KitStatus x64_target_feature_apply_isa(const Target* target, 64 KitSlice isa, u64* words, 65 u32 nwords) { 66 (void)target; 67 if (kit_slice_eq_cstr(isa, "x86-64") || kit_slice_eq_cstr(isa, "x86-64-v1")) { 68 x64_feature_set(words, nwords, X64_FEAT_SSE); 69 x64_feature_set(words, nwords, X64_FEAT_SSE2); 70 return KIT_OK; 71 } 72 if (kit_slice_eq_cstr(isa, "x86-64-v2")) { 73 x64_feature_set(words, nwords, X64_FEAT_SSE); 74 x64_feature_set(words, nwords, X64_FEAT_SSE2); 75 x64_feature_set(words, nwords, X64_FEAT_SSE3); 76 x64_feature_set(words, nwords, X64_FEAT_SSSE3); 77 x64_feature_set(words, nwords, X64_FEAT_SSE41); 78 x64_feature_set(words, nwords, X64_FEAT_SSE42); 79 return KIT_OK; 80 } 81 if (kit_slice_eq_cstr(isa, "x86-64-v3") || 82 kit_slice_eq_cstr(isa, "x86-64-v4") || 83 kit_slice_eq_cstr(isa, "haswell") || kit_slice_eq_cstr(isa, "skylake")) { 84 x64_feature_set(words, nwords, X64_FEAT_SSE); 85 x64_feature_set(words, nwords, X64_FEAT_SSE2); 86 x64_feature_set(words, nwords, X64_FEAT_SSE3); 87 x64_feature_set(words, nwords, X64_FEAT_SSSE3); 88 x64_feature_set(words, nwords, X64_FEAT_SSE41); 89 x64_feature_set(words, nwords, X64_FEAT_SSE42); 90 x64_feature_set(words, nwords, X64_FEAT_AVX); 91 x64_feature_set(words, nwords, X64_FEAT_AVX2); 92 return KIT_OK; 93 } 94 return KIT_UNSUPPORTED; 95 } 96 97 static void x64_target_feature_defaults(const Target* target, u64* words, 98 u32 nwords) { 99 (void)target; 100 x64_feature_set(words, nwords, X64_FEAT_SSE); 101 x64_feature_set(words, nwords, X64_FEAT_SSE2); 102 } 103 104 static int x64_register_at_public(uint32_t idx, KitArchReg* out) { 105 const char* nm = NULL; 106 int rc; 107 if (!out) return 1; 108 rc = x64_register_iter_get(idx, &out->dwarf_idx, &nm); 109 if (rc == 0) out->name = kit_slice_cstr(nm); 110 return rc; 111 } 112 113 static CgTarget* x64_backend_make(Compiler* c, ObjBuilder* o, 114 const KitCodeOptions* opts) { 115 MCEmitter* mc = NULL; 116 Debug* debug = NULL; 117 CgTarget* t; 118 NativeTarget* native; 119 NativeDirectTargetConfig cfg; 120 if (cg_mc_debug_new(c, o, opts, &mc, &debug) != KIT_OK) return NULL; 121 native = x64_native_target_new(c, o, mc); 122 if (!native) return NULL; 123 memset(&cfg, 0, sizeof cfg); 124 cfg.native = native; 125 cfg.ops = x64_native_direct_ops(); 126 t = native_direct_target_new(c, o, &cfg); 127 if (t) t->debug = debug; 128 return t; 129 } 130 131 static CgTarget* x64_semantic_target_new(Compiler* c, ObjBuilder* o, 132 MCEmitter* mc) { 133 NativeTarget* native; 134 NativeDirectTargetConfig cfg; 135 if (!mc) mc = mc_new(c, o); 136 native = x64_native_target_new(c, o, mc); 137 if (!native) return NULL; 138 memset(&cfg, 0, sizeof cfg); 139 cfg.native = native; 140 cfg.ops = x64_native_direct_ops(); 141 return native_direct_target_new(c, o, &cfg); 142 } 143 144 /* Which explicit calling conventions x86-64 can emit. SysV and Win64 split on 145 * the OS (a property, not arch identity); TARGET_C is always available. */ 146 static int x64_supports_call_conv(const Compiler* c, KitCgCallConv cc) { 147 switch (cc) { 148 case KIT_CG_CC_TARGET_C: 149 return 1; 150 case KIT_CG_CC_SYSV: 151 return c->target.os != KIT_OS_WINDOWS; 152 case KIT_CG_CC_WIN64: 153 return c->target.os == KIT_OS_WINDOWS; 154 case KIT_CG_CC_AAPCS: 155 case KIT_CG_CC_WASM: 156 case KIT_CG_CC_INTERRUPT: 157 return 0; 158 } 159 return 0; 160 } 161 162 /* Capability twin of x64_intrinsic (src/arch/x64/native.c); keep the two in 163 * sync. No default case, so a new KitCgIntrinsic trips -Wswitch here. */ 164 static int x64_supports_intrinsic(const Compiler* c, KitCgIntrinsic intrin) { 165 switch (intrin) { 166 case KIT_CG_INTRIN_TRAP: 167 case KIT_CG_INTRIN_CLZ: 168 case KIT_CG_INTRIN_CTZ: 169 case KIT_CG_INTRIN_POPCOUNT: 170 case KIT_CG_INTRIN_BSWAP: 171 case KIT_CG_INTRIN_SADD_OVERFLOW: 172 case KIT_CG_INTRIN_UADD_OVERFLOW: 173 case KIT_CG_INTRIN_SSUB_OVERFLOW: 174 case KIT_CG_INTRIN_USUB_OVERFLOW: 175 case KIT_CG_INTRIN_SMUL_OVERFLOW: 176 case KIT_CG_INTRIN_UMUL_OVERFLOW: 177 case KIT_CG_INTRIN_PREFETCH: 178 case KIT_CG_INTRIN_EXPECT: 179 case KIT_CG_INTRIN_ASSUME_ALIGNED: 180 case KIT_CG_INTRIN_CPU_NOP: 181 case KIT_CG_INTRIN_CPU_YIELD: 182 case KIT_CG_INTRIN_DMB: 183 case KIT_CG_INTRIN_DSB: 184 case KIT_CG_INTRIN_IRQ_ENABLE: 185 case KIT_CG_INTRIN_IRQ_DISABLE: 186 case KIT_CG_INTRIN_FRAME_ADDRESS: 187 case KIT_CG_INTRIN_RETURN_ADDRESS: 188 return 1; 189 case KIT_CG_INTRIN_SYSCALL: 190 return c->target.os == KIT_OS_LINUX || 191 c->target.os == KIT_OS_FREESTANDING; 192 case KIT_CG_INTRIN_SETJMP: 193 case KIT_CG_INTRIN_LONGJMP: 194 case KIT_CG_INTRIN_FMA: 195 case KIT_CG_INTRIN_IRQ_SAVE: 196 case KIT_CG_INTRIN_IRQ_RESTORE: 197 case KIT_CG_INTRIN_ISB: 198 case KIT_CG_INTRIN_WFI: 199 case KIT_CG_INTRIN_WFE: 200 case KIT_CG_INTRIN_SEV: 201 case KIT_CG_INTRIN_DCACHE_CLEAN: 202 case KIT_CG_INTRIN_DCACHE_INVALIDATE: 203 case KIT_CG_INTRIN_DCACHE_CLEAN_INVALIDATE: 204 case KIT_CG_INTRIN_ICACHE_INVALIDATE: 205 case KIT_CG_INTRIN_CORO_SWITCH: 206 return 0; 207 } 208 return 0; 209 } 210 211 const ArchImpl arch_impl_x64 = { 212 .backend = {.name = "x64", .make = x64_backend_make}, 213 .kind = KIT_ARCH_X86_64, 214 .name = "x64", 215 .cgtarget_new = x64_semantic_target_new, 216 .asm_new = x64_arch_asm_new, 217 .disasm_new = x64_disasm_new, 218 .apply_label_fixup = x64_apply_label_fixup, 219 .link = &link_arch_x64, 220 .dwarf = &x64_dwarf_ops, 221 .dbg = &x64_dbg_ops, 222 .asm_ops = &x64_asm_ops, 223 .predefined_macros = x64_predefined_macros, 224 .npredefined_macros = 225 (u32)(sizeof x64_predefined_macros / sizeof x64_predefined_macros[0]), 226 .target_features = x64_target_features, 227 .ntarget_features = 228 (u32)(sizeof x64_target_features / sizeof x64_target_features[0]), 229 .target_feature_defaults = x64_target_feature_defaults, 230 .target_feature_apply_isa = x64_target_feature_apply_isa, 231 .register_name = x64_register_name, 232 .register_index = x64_register_index, 233 .register_count = x64_register_iter_size, 234 .register_at = x64_register_at_public, 235 /* x86_64 psABI: return address in DWARF reg 16 (rip). 236 * Variable-length insns ⇒ code-align = 1; data-align = -8 matches 237 * qword stack stride. At entry CFA = rsp + 8 (pushed return addr). */ 238 .cfi_return_addr_reg = 16u, 239 .cfi_code_align_factor = 1, 240 .cfi_data_align_factor = -8, 241 .cfi_cfa_init_reg = 7u, 242 .cfi_cfa_init_offset = 8, 243 .backend_features = KIT_CG_BACKEND_UNALIGNED_MEMORY | 244 KIT_CG_BACKEND_RED_ZONE | KIT_CG_BACKEND_SIMD | 245 KIT_CG_BACKEND_ICACHE_COHERENT, 246 .atomic_lock_free_max = 8u, 247 .supports_call_conv = x64_supports_call_conv, 248 .supports_intrinsic = x64_supports_intrinsic, 249 };