arch.c (8000B)
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 X64_FEAT_POPCNT, 52 }; 53 54 static const ArchTargetFeature x64_target_features[] = { 55 {"sse"}, {"sse2"}, {"sse3"}, {"ssse3"}, 56 {"sse4.1"}, {"sse4.2"}, {"avx"}, {"avx2"}, {"popcnt"}, 57 }; 58 59 static void x64_feature_set(u64* words, u32 nwords, u32 idx) { 60 if (!words || idx / 64u >= nwords) return; 61 words[idx / 64u] |= 1ull << (idx % 64u); 62 } 63 64 static KitStatus x64_target_feature_apply_isa(const Target* target, 65 KitSlice isa, u64* words, 66 u32 nwords) { 67 (void)target; 68 if (kit_slice_eq_cstr(isa, "x86-64") || kit_slice_eq_cstr(isa, "x86-64-v1")) { 69 x64_feature_set(words, nwords, X64_FEAT_SSE); 70 x64_feature_set(words, nwords, X64_FEAT_SSE2); 71 return KIT_OK; 72 } 73 if (kit_slice_eq_cstr(isa, "x86-64-v2")) { 74 x64_feature_set(words, nwords, X64_FEAT_SSE); 75 x64_feature_set(words, nwords, X64_FEAT_SSE2); 76 x64_feature_set(words, nwords, X64_FEAT_SSE3); 77 x64_feature_set(words, nwords, X64_FEAT_SSSE3); 78 x64_feature_set(words, nwords, X64_FEAT_SSE41); 79 x64_feature_set(words, nwords, X64_FEAT_SSE42); 80 x64_feature_set(words, nwords, X64_FEAT_POPCNT); 81 return KIT_OK; 82 } 83 if (kit_slice_eq_cstr(isa, "x86-64-v3") || 84 kit_slice_eq_cstr(isa, "x86-64-v4") || 85 kit_slice_eq_cstr(isa, "haswell") || kit_slice_eq_cstr(isa, "skylake")) { 86 x64_feature_set(words, nwords, X64_FEAT_SSE); 87 x64_feature_set(words, nwords, X64_FEAT_SSE2); 88 x64_feature_set(words, nwords, X64_FEAT_SSE3); 89 x64_feature_set(words, nwords, X64_FEAT_SSSE3); 90 x64_feature_set(words, nwords, X64_FEAT_SSE41); 91 x64_feature_set(words, nwords, X64_FEAT_SSE42); 92 x64_feature_set(words, nwords, X64_FEAT_AVX); 93 x64_feature_set(words, nwords, X64_FEAT_AVX2); 94 x64_feature_set(words, nwords, X64_FEAT_POPCNT); 95 return KIT_OK; 96 } 97 return KIT_UNSUPPORTED; 98 } 99 100 static void x64_target_feature_defaults(const Target* target, u64* words, 101 u32 nwords) { 102 (void)target; 103 x64_feature_set(words, nwords, X64_FEAT_SSE); 104 x64_feature_set(words, nwords, X64_FEAT_SSE2); 105 } 106 107 static int x64_register_at_public(uint32_t idx, KitArchReg* out) { 108 return arch_register_at_public(idx, out, x64_register_iter_get); 109 } 110 111 static CgTarget* x64_backend_make(Compiler* c, ObjBuilder* o, 112 const KitCodeOptions* opts) { 113 return native_direct_backend_make(c, o, opts, x64_native_target_new, 114 x64_native_direct_ops()); 115 } 116 117 static CgTarget* x64_semantic_target_new(Compiler* c, ObjBuilder* o, 118 MCEmitter* mc) { 119 return native_direct_semantic_target_new(c, o, mc, x64_native_target_new, 120 x64_native_direct_ops()); 121 } 122 123 /* Which explicit calling conventions x86-64 can emit. SysV and Win64 split on 124 * the OS (a property, not arch identity); TARGET_C is always available. */ 125 static int x64_supports_call_conv(const Compiler* c, KitCgCallConv cc) { 126 (void)c; 127 return cc == KIT_CG_CC_TARGET_C; 128 } 129 130 /* Capability twin of x64_intrinsic (src/arch/x64/native.c); keep the two in 131 * sync. No default case, so a new KitCgIntrinsic trips -Wswitch here. */ 132 static int x64_supports_intrinsic(const Compiler* c, KitCgIntrinsic intrin) { 133 switch (intrin) { 134 case KIT_CG_INTRIN_TRAP: 135 case KIT_CG_INTRIN_CLZ: 136 case KIT_CG_INTRIN_CTZ: 137 case KIT_CG_INTRIN_POPCOUNT: 138 case KIT_CG_INTRIN_BSWAP: 139 case KIT_CG_INTRIN_SADD_OVERFLOW: 140 case KIT_CG_INTRIN_UADD_OVERFLOW: 141 case KIT_CG_INTRIN_SSUB_OVERFLOW: 142 case KIT_CG_INTRIN_USUB_OVERFLOW: 143 case KIT_CG_INTRIN_SMUL_OVERFLOW: 144 case KIT_CG_INTRIN_UMUL_OVERFLOW: 145 case KIT_CG_INTRIN_PREFETCH: 146 case KIT_CG_INTRIN_EXPECT: 147 case KIT_CG_INTRIN_ASSUME_ALIGNED: 148 case KIT_CG_INTRIN_CPU_NOP: 149 case KIT_CG_INTRIN_CPU_YIELD: 150 case KIT_CG_INTRIN_DMB: 151 case KIT_CG_INTRIN_DSB: 152 case KIT_CG_INTRIN_IRQ_ENABLE: 153 case KIT_CG_INTRIN_IRQ_DISABLE: 154 case KIT_CG_INTRIN_FRAME_ADDRESS: 155 case KIT_CG_INTRIN_RETURN_ADDRESS: 156 case KIT_CG_INTRIN_READCYCLECOUNTER: /* RDTSC */ 157 case KIT_CG_INTRIN_SMUL_HIGH: 158 case KIT_CG_INTRIN_UMUL_HIGH: 159 return 1; 160 case KIT_CG_INTRIN_SYSCALL: 161 return c->target.os == KIT_OS_LINUX || 162 c->target.os == KIT_OS_FREESTANDING; 163 case KIT_CG_INTRIN_SETJMP: 164 case KIT_CG_INTRIN_LONGJMP: 165 case KIT_CG_INTRIN_FMA: 166 case KIT_CG_INTRIN_IRQ_SAVE: 167 case KIT_CG_INTRIN_IRQ_RESTORE: 168 case KIT_CG_INTRIN_ISB: 169 case KIT_CG_INTRIN_WFI: 170 case KIT_CG_INTRIN_WFE: 171 case KIT_CG_INTRIN_SEV: 172 case KIT_CG_INTRIN_DCACHE_CLEAN: 173 case KIT_CG_INTRIN_DCACHE_INVALIDATE: 174 case KIT_CG_INTRIN_DCACHE_CLEAN_INVALIDATE: 175 case KIT_CG_INTRIN_ICACHE_INVALIDATE: 176 case KIT_CG_INTRIN_CORO_SWITCH: 177 return 0; 178 } 179 return 0; 180 } 181 182 const ArchImpl arch_impl_x64 = { 183 .backend = {.name = "x64", .make = x64_backend_make}, 184 .kind = KIT_ARCH_X86_64, 185 .name = "x64", 186 .cgtarget_new = x64_semantic_target_new, 187 .asm_new = x64_arch_asm_new, 188 .disasm_new = x64_disasm_new, 189 .apply_label_fixup = x64_apply_label_fixup, 190 .link = &link_arch_x64, 191 .dwarf = &x64_dwarf_ops, 192 .dbg = &x64_dbg_ops, 193 .asm_ops = &x64_asm_ops, 194 .predefined_macros = x64_predefined_macros, 195 .npredefined_macros = 196 (u32)(sizeof x64_predefined_macros / sizeof x64_predefined_macros[0]), 197 .target_features = x64_target_features, 198 .ntarget_features = 199 (u32)(sizeof x64_target_features / sizeof x64_target_features[0]), 200 .target_feature_defaults = x64_target_feature_defaults, 201 .target_feature_apply_isa = x64_target_feature_apply_isa, 202 .register_name = x64_register_name, 203 .register_index = x64_register_index, 204 .register_count = x64_register_iter_size, 205 .register_at = x64_register_at_public, 206 /* x86_64 psABI: return address in DWARF reg 16 (rip). 207 * Variable-length insns ⇒ code-align = 1; data-align = -8 matches 208 * qword stack stride. At entry CFA = rsp + 8 (pushed return addr). */ 209 .cfi_return_addr_reg = 16u, 210 .cfi_code_align_factor = 1, 211 .cfi_data_align_factor = -8, 212 .cfi_cfa_init_reg = 7u, 213 .cfi_cfa_init_offset = 8, 214 .backend_features = KIT_CG_BACKEND_UNALIGNED_MEMORY | 215 KIT_CG_BACKEND_RED_ZONE | KIT_CG_BACKEND_SIMD | 216 KIT_CG_BACKEND_ICACHE_COHERENT, 217 .atomic_lock_free_max = 8u, 218 .supports_call_conv = x64_supports_call_conv, 219 .supports_intrinsic = x64_supports_intrinsic, 220 };