kit

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

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