kit

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

abi.c (4876B)


      1 /* wasm32 BasicCABI classifier.
      2  *
      3  * Reference:
      4  * https://github.com/WebAssembly/tool-conventions/blob/main/BasicCABI.md
      5  *
      6  * Coverage for v1:
      7  *   void          -> IGNORE
      8  *   scalar ≤ 8B   -> DIRECT, one part (i32/i64/f32/f64 per scalar kind)
      9  *   pointer       -> DIRECT, one INT part (4 bytes, ILP32)
     10  *   empty struct  -> IGNORE
     11  *   singleton struct (one scalar field, size matches) -> DIRECT, one part
     12  *   other aggregate -> INDIRECT (sret/byval)
     13  *   array         -> INDIRECT
     14  *
     15  * Wasm has no native 128-bit integer or x87 long-double; those panic on
     16  * classification rather than silently routing through memory. */
     17 
     18 #include <string.h>
     19 
     20 #include "abi/abi_internal.h"
     21 #include "cg/type.h"
     22 #include "core/arena.h"
     23 #include "core/core.h"
     24 
     25 static void classify_void(ABIArgInfo* out) {
     26   memset(out, 0, sizeof *out);
     27   out->kind = ABI_ARG_IGNORE;
     28 }
     29 
     30 static void classify_scalar(TargetABI* a, KitCgTypeId t, ABIArgInfo* out) {
     31   ABITypeInfo ti = abi_internal_type_info(a, t);
     32   ABIArgPart* parts;
     33 
     34   if (ti.size > 8) {
     35     SrcLoc loc = {0, 0, 0};
     36     /* A >8-byte float is binary128 long double (the only such C scalar);
     37      * report it specifically. Wider integers are __int128. */
     38     if (ti.scalar_kind == ABI_SC_FLOAT) {
     39       compiler_panic(a->c, loc, "wasm: long double not supported");
     40     }
     41     compiler_panic(a->c, loc,
     42                    "wasm32 ABI: scalar %u-byte values are not supported",
     43                    (unsigned)ti.size);
     44   }
     45 
     46   out->kind = ABI_ARG_DIRECT;
     47   out->flags = ABI_AF_NONE;
     48   out->indirect_align = 0;
     49 
     50   parts = arena_new(a->c->tu, ABIArgPart);
     51   memset(parts, 0, sizeof *parts);
     52   parts->cls = (ti.scalar_kind == ABI_SC_FLOAT) ? ABI_CLASS_FP : ABI_CLASS_INT;
     53   parts->loc = ABI_LOC_REG;
     54   parts->size = ti.size;
     55   parts->align = ti.align;
     56   parts->src_offset = 0;
     57 
     58   out->parts = parts;
     59   out->nparts = 1;
     60 }
     61 
     62 /* BasicCABI singleton rule: a record with exactly one scalar field whose size
     63  * equals the record's size is passed as that scalar. Otherwise the aggregate
     64  * is passed indirectly. */
     65 static int try_classify_singleton(TargetABI* a, KitCgTypeId t,
     66                                   ABIArgInfo* out) {
     67   const CgType* ty = cg_type_get(a->c, t);
     68   ABITypeInfo ti;
     69   KitCgTypeId field_ty;
     70   const CgType* field;
     71   if (!ty || ty->kind != KIT_CG_TYPE_RECORD || ty->record.nfields != 1)
     72     return 0;
     73   if (ty->record.is_union) return 0;
     74   field_ty = ty->record.fields[0].type;
     75   field = cg_type_get(a->c, field_ty);
     76   if (!field) return 0;
     77   if (field->kind == KIT_CG_TYPE_RECORD || field->kind == KIT_CG_TYPE_ARRAY)
     78     return 0;
     79   ti = abi_internal_type_info(a, field_ty);
     80   if (ti.size != (u32)ty->size) return 0;
     81   classify_scalar(a, field_ty, out);
     82   return 1;
     83 }
     84 
     85 static void classify_aggregate(TargetABI* a, KitCgTypeId t, ABIArgInfo* out,
     86                                int is_return) {
     87   ABITypeInfo ti = abi_internal_type_info(a, t);
     88   if (ti.size == 0) {
     89     classify_void(out);
     90     return;
     91   }
     92   if (try_classify_singleton(a, t, out)) return;
     93   out->kind = ABI_ARG_INDIRECT;
     94   out->flags = is_return ? ABI_AF_SRET : ABI_AF_BYVAL;
     95   out->indirect_align = ti.align ? ti.align : 4;
     96   out->parts = NULL;
     97   out->nparts = 0;
     98 }
     99 
    100 static void classify_one(TargetABI* a, KitCgTypeId t, ABIArgInfo* out,
    101                          int is_return) {
    102   const CgType* ty = cg_type_get(a->c, t);
    103   if (!ty || ty->kind == KIT_CG_TYPE_VOID) {
    104     classify_void(out);
    105     return;
    106   }
    107   switch (ty->kind) {
    108     case KIT_CG_TYPE_RECORD:
    109       classify_aggregate(a, t, out, is_return);
    110       return;
    111     case KIT_CG_TYPE_ARRAY:
    112       /* Arrays decay to pointers in C function signatures; if one reaches
    113        * the classifier, route indirect. */
    114       classify_aggregate(a, t, out, is_return);
    115       return;
    116     case KIT_CG_TYPE_ALIAS:
    117       classify_one(a, ty->alias.base, out, is_return);
    118       return;
    119     default:
    120       classify_scalar(a, t, out);
    121       return;
    122   }
    123 }
    124 
    125 static ABIFuncInfo* wasm32_compute_func_info(TargetABI* a, KitCgTypeId fn) {
    126   ABIFuncInfo* info = arena_new(a->c->tu, ABIFuncInfo);
    127   const CgType* fnty = cg_type_get(a->c, fn);
    128   memset(info, 0, sizeof *info);
    129 
    130   classify_one(a, cg_func_ret_type(fnty), &info->ret, /*is_return=*/1);
    131   info->has_sret = (info->ret.kind == ABI_ARG_INDIRECT) ? 1 : 0;
    132   info->variadic = fnty->func.abi_variadic ? 1u : 0u;
    133 
    134   info->nparams = (u16)fnty->func.nparams;
    135   if (fnty->func.nparams) {
    136     ABIArgInfo* arr = arena_array(a->c->tu, ABIArgInfo, fnty->func.nparams);
    137     memset(arr, 0, sizeof(ABIArgInfo) * fnty->func.nparams);
    138     for (u32 i = 0; i < fnty->func.nparams; ++i) {
    139       classify_one(a, fnty->func.params[i].type, &arr[i], /*is_return=*/0);
    140     }
    141     info->params = arr;
    142   } else {
    143     info->params = NULL;
    144   }
    145   return info;
    146 }
    147 
    148 const ABIVtable wasm32_vtable = {
    149     .compute_func_info = wasm32_compute_func_info,
    150     .va_list_info = {4, 4, ABI_SC_PTR, 0, 0, 0},
    151 };