abi.h (5702B)
1 #ifndef KIT_ABI_H 2 #define KIT_ABI_H 3 4 #include <kit/cg.h> 5 6 #include "core/core.h" 7 8 /* TargetABI is the single authority for target-dependent storage layout and 9 * calling convention decisions. Frontends lower source-language types to 10 * KitCgTypeId before entering this generic ABI layer. */ 11 typedef struct TargetABI TargetABI; 12 13 typedef enum ABIScalarKind { 14 ABI_SC_VOID, 15 ABI_SC_BOOL, 16 ABI_SC_INT, 17 ABI_SC_FLOAT, 18 ABI_SC_PTR, 19 } ABIScalarKind; 20 21 typedef struct ABITypeInfo { 22 u32 size; 23 u32 align; 24 u8 scalar_kind; /* ABIScalarKind; ABI_SC_VOID for aggregates/void */ 25 u8 signed_; 26 u8 atomic; 27 u8 pad; 28 } ABITypeInfo; 29 30 typedef enum ABIVaListKind { 31 ABI_VA_LIST_OPAQUE, 32 ABI_VA_LIST_POINTER, 33 ABI_VA_LIST_AAPCS64, 34 ABI_VA_LIST_SYSV_X64, 35 } ABIVaListKind; 36 37 typedef struct ABIVaListInfo { 38 ABITypeInfo type; 39 u8 kind; /* ABIVaListKind */ 40 u8 pad[3]; 41 u32 stack_offset; 42 u32 gr_top_offset; 43 u32 vr_top_offset; 44 u32 gr_offs_offset; 45 u32 vr_offs_offset; 46 u32 gp_reg_count; 47 u32 fp_reg_count; 48 u32 gp_slot_size; 49 u32 fp_slot_size; 50 } ABIVaListInfo; 51 52 typedef struct ABIFieldLayout { 53 u32 offset; /* byte offset from record base */ 54 u16 bit_offset; /* bit offset within storage unit for bitfields */ 55 u16 bit_width; /* 0 for non-bitfield */ 56 u32 storage_size; /* bytes in the bitfield storage unit; 0 otherwise */ 57 } ABIFieldLayout; 58 59 typedef struct ABIRecordLayout { 60 u32 size; 61 u32 align; 62 u32 nfields; 63 const ABIFieldLayout* fields; 64 } ABIRecordLayout; 65 66 typedef enum ABIArgKind { 67 ABI_ARG_IGNORE, 68 ABI_ARG_DIRECT, /* one or more inspectable parts */ 69 ABI_ARG_INDIRECT, /* caller passes address */ 70 ABI_ARG_EXPAND, /* aggregate split into parts below */ 71 } ABIArgKind; 72 73 typedef enum ABIArgClass { 74 ABI_CLASS_NONE, 75 ABI_CLASS_INT, 76 ABI_CLASS_FP, 77 ABI_CLASS_VEC, 78 ABI_CLASS_MEM, 79 } ABIArgClass; 80 81 typedef enum ABIArgLoc { 82 ABI_LOC_NONE, 83 ABI_LOC_REG, 84 ABI_LOC_STACK, 85 ABI_LOC_EITHER, 86 } ABIArgLoc; 87 88 typedef enum ABIArgFlag { 89 ABI_AF_NONE = 0, 90 ABI_AF_SRET = 1u << 0, /* hidden structure-return pointer */ 91 ABI_AF_BYVAL = 1u << 1, /* caller passes an address to a copy */ 92 ABI_AF_SIGN_EXT = 1u << 2, 93 ABI_AF_ZERO_EXT = 1u << 3, 94 ABI_AF_VARARG = 1u << 4, /* placement affected by variadic rules */ 95 ABI_AF_SPLIT = 1u << 5, /* source value is split across parts */ 96 } ABIArgFlag; 97 98 typedef struct ABIArgPart { 99 u8 cls; /* ABIArgClass */ 100 u8 loc; /* ABIArgLoc preference */ 101 u16 flags; /* ABIArgFlag */ 102 u32 src_offset; /* byte offset within source object */ 103 u32 size; /* bytes carried by this part */ 104 u32 align; /* part alignment */ 105 u32 stack_align; /* required stack alignment if stack-passed */ 106 } ABIArgPart; 107 108 typedef struct ABIArgInfo { 109 u8 kind; /* ABIArgKind */ 110 u8 flags; /* ABIArgFlag applying to the whole argument */ 111 u16 nparts; 112 u32 indirect_align; /* required alignment for ABI_ARG_INDIRECT/byval copy */ 113 const ABIArgPart* parts; 114 } ABIArgInfo; 115 116 typedef struct ABIFuncInfo { 117 ABIArgInfo ret; 118 const ABIArgInfo* params; 119 u16 nparams; 120 u8 variadic; 121 u8 has_sret; 122 /* True when the sret (indirect-result) pointer is passed in the first 123 * integer argument register and therefore consumes that arg slot — SysV-x64 124 * (rdi), Win64 (rcx), RISC-V (a0). ABIs that return it in a dedicated 125 * register (AArch64 x8) leave this 0. Lets generic code reason about arg-slot 126 * consumption from the ABI descriptor instead of by arch identity. */ 127 u8 sret_consumes_int_arg; 128 /* True when the trailing `...` portion of a variadic call must be 129 * routed to the stack exclusively, bypassing the GPR/FPR arg pools. 130 * Apple ARM64 sets this; AAPCS64 / SysV-x64 leave it 0 (variadics 131 * use the same register routing as fixed args). */ 132 u8 vararg_on_stack; 133 /* True when floating-point arguments to a variadic function are passed 134 * through the integer argument registers/slots rather than the FP pool. 135 * Windows-ARM64 sets this so its plain-pointer `va_list` can walk a single 136 * register save area; AAPCS64 / SysV-x64 / Apple ARM64 leave it 0. Lets the 137 * aarch64 backend stop inspecting target.os==WINDOWS for varargs routing. */ 138 u8 vararg_fp_via_int; 139 /* Minimum stack slot size/alignment for scalar stack-passed arguments. 140 * Zero means the backend default. Apple ARM64 uses 4-byte compact slots for 141 * stack arguments such as int32; AAPCS64 uses 8-byte slots. */ 142 u8 stack_arg_min_align; 143 /* Minimum stack slot size/alignment for variadic arguments forced to the 144 * stack. Zero means use stack_arg_min_align/backend default. Apple ARM64 145 * keeps fixed stack args compact but uses 8-byte variadic slots. */ 146 u8 vararg_stack_arg_min_align; 147 u32 vararg_gp_offset; 148 u32 vararg_fp_offset; 149 u32 vararg_overflow_offset; 150 } ABIFuncInfo; 151 152 void abi_init(TargetABI*, Compiler*); 153 void abi_fini(TargetABI*); 154 155 /* Heap-allocating wrappers around abi_init/abi_fini, used by compiler_init. 156 * The returned pointer is valid until abi_free returns. */ 157 TargetABI* abi_new(Compiler*); 158 void abi_free(TargetABI*); 159 Compiler* abi_compiler(TargetABI*); 160 161 ABITypeInfo abi_cg_type_info(TargetABI*, KitCgTypeId); 162 u32 abi_cg_sizeof(TargetABI*, KitCgTypeId); 163 u32 abi_cg_alignof(TargetABI*, KitCgTypeId); 164 u32 abi_cg_scalar_split_lane_size(TargetABI*, KitCgTypeId); 165 const ABIRecordLayout* abi_cg_record_layout(TargetABI*, KitCgTypeId); 166 const ABIFuncInfo* abi_cg_func_info(TargetABI*, KitCgTypeId fn_type); 167 ABITypeInfo abi_va_list_info(TargetABI*); 168 ABIVaListInfo abi_va_list_layout(TargetABI*); 169 /* Page granularity for Windows-style large-frame stack probing; 0 when the 170 * target auto-grows its stack and needs no probe. See ABIVtable. */ 171 u32 abi_stack_probe_interval(TargetABI*); 172 173 #endif