kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

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 };