kit

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

call.c (10350B)


      1 #include "cg/internal.h"
      2 
      3 static u32 api_func_nparams(KitCg* g, KitCgTypeId fty) {
      4   const CgType* ty = cg_type_get(g->c, api_unalias_type(g->c, fty));
      5   if (!ty || ty->kind != KIT_CG_TYPE_FUNC) return 0;
      6   return ty->func.nparams;
      7 }
      8 
      9 CGLocal* api_alloc_call_args(KitCg* g, u32 nargs) {
     10   if (!nargs) return NULL;
     11   CGLocal* args = arena_array(g->c->tu, CGLocal, nargs);
     12   memset(args, 0, sizeof(CGLocal) * nargs);
     13   return args;
     14 }
     15 
     16 static CGLocal api_materialize_call_local(KitCg* g, ApiSValue* arg,
     17                                           KitCgTypeId ty) {
     18   if (cg_type_is_aggregate(g->c, ty)) {
     19     if (api_is_lvalue_sv(arg) && arg->op.kind == OPK_LOCAL) {
     20       if (api_unalias_type(g->c, arg->op.type) == api_unalias_type(g->c, ty))
     21         return arg->op.v.local;
     22     }
     23     CGLocal r = api_alloc_temp_local(g, ty);
     24     Operand dst = api_op_local(r, ty);
     25     MemAccess ma;
     26     memset(&ma, 0, sizeof ma);
     27     ma.type = ty;
     28     ma.size = abi_cg_sizeof(g->c->abi, ty);
     29     ma.align = abi_cg_alignof(g->c->abi, ty);
     30     if (api_is_lvalue_sv(arg) && api_operand_can_address(&arg->op)) {
     31       g->target->load(g->target, dst, arg->op, ma);
     32     } else if (arg->op.kind == OPK_GLOBAL || arg->op.kind == OPK_INDIRECT) {
     33       g->target->load(g->target, dst, arg->op, ma);
     34     } else if (arg->op.kind == OPK_LOCAL) {
     35       g->target->load(g->target, dst, api_op_indirect(arg->op.v.local, 0, ty),
     36                       ma);
     37     } else {
     38       compiler_panic(g->c, g->cur_loc,
     39                      "KitCg: aggregate call argument is not addressable");
     40     }
     41     return r;
     42   }
     43   KitCgTypeId src_ty = api_sv_type(arg);
     44   Operand op;
     45   /* A 16-byte scalar immediate (an i128 small constant) only carries 64 bits in
     46    * op.v.imm; materialize it into both sign-extended lanes so it flows as an
     47    * ordinary 16-byte value rather than load_imm'ing only the low lane. */
     48   if (api_sv_op_is(arg, OPK_IMM) && api_is_wide16_scalar_type(g->c, ty)) {
     49     *arg = api_make_wide16_int_const(g, arg->op.v.imm, ty);
     50   }
     51   /* Same for a split-lane 8-byte immediate argument: materialize it as a
     52    * 2-lane memory value so the multi-part ABI path marshals both words. */
     53   if (api_sv_op_is(arg, OPK_IMM) && api_is_wide8_scalar_type(g->c, ty)) {
     54     *arg = api_make_wide8_int_const(g, arg->op.v.imm, ty);
     55   }
     56   op = api_force_local_unless_imm(g, arg, src_ty);
     57   if (op.kind == OPK_LOCAL &&
     58       api_unalias_type(g->c, op.type) == api_unalias_type(g->c, ty)) {
     59     return op.v.local;
     60   }
     61 
     62   CGLocal r = api_alloc_temp_local(g, ty);
     63   Operand dst = api_op_local(r, ty);
     64   if (op.kind == OPK_IMM) {
     65     g->target->load_imm(g->target, dst, op.v.imm);
     66   } else if (op.kind == OPK_LOCAL) {
     67     g->target->copy(g->target, dst, op);
     68   } else {
     69     compiler_panic(g->c, g->cur_loc,
     70                    "KitCg: scalar call argument is not materialized");
     71   }
     72   api_release(g, arg);
     73   return r;
     74 }
     75 
     76 void api_pack_call_arg(KitCg* g, CGLocal* out, KitCgTypeId fty, u32 idx) {
     77   ApiSValue arg = api_pop(g);
     78   u32 nfixed = api_func_nparams(g, fty);
     79   KitCgTypeId aty =
     80       idx >= nfixed ? api_sv_type(&arg) : cg_type_func_param_id(g->c, fty, idx);
     81   if (!aty) aty = api_sv_type(&arg);
     82   *out = api_materialize_call_local(g, &arg, aty);
     83 }
     84 
     85 CGLocal api_alloc_call_result(KitCg* g, KitCgTypeId ret_ty) {
     86   return api_alloc_temp_local(g, ret_ty);
     87 }
     88 
     89 void api_release_call_args(KitCg* g, CGLocal* args, u32 nargs) {
     90   for (u32 i = 0; i < nargs; ++i) {
     91     if (args[i] != CG_LOCAL_NONE) api_release_temp_local(g, args[i]);
     92   }
     93 }
     94 
     95 void api_push_call_result(KitCg* g, CGLocal result, KitCgTypeId ret_ty) {
     96   Operand op = api_op_local(result, ret_ty);
     97   /* An aggregate result is a PLACE (it is addressed/copied, never a scalar
     98    * VALUE); i128/f128 are scalar VALUEs and flow like any other result. */
     99   if (cg_type_is_aggregate(g->c, ret_ty)) {
    100     api_push(g, api_make_lv(op, ret_ty));
    101   } else {
    102     api_push(g, api_make_sv(op, ret_ty));
    103   }
    104 }
    105 
    106 static void api_call_clobber_boundary(KitCg* g, const CGCallDesc* d) {
    107   (void)g;
    108   (void)d;
    109 }
    110 
    111 static int api_tail_ret_compatible(KitCg* g, KitCgTypeId callee_fn_type) {
    112   KitCgTypeId cr = cg_type_func_result_id(g->c, callee_fn_type);
    113   return api_unalias_type(g->c, g->fn_desc.result_type) ==
    114          api_unalias_type(g->c, cr);
    115 }
    116 
    117 static int api_tail_decide(KitCg* g, const CGCallDesc* desc,
    118                            KitCgTailPolicy policy) {
    119   CgTarget* T = g->target;
    120   const char* reason;
    121   if (!api_tail_ret_compatible(g, desc->fn_type)) {
    122     compiler_panic(g->c, g->cur_loc,
    123                    "tail call: callee return type is incompatible with the "
    124                    "enclosing function's return type");
    125     return 0;
    126   }
    127   reason = T->tail_call_unrealizable_reason
    128                ? T->tail_call_unrealizable_reason(T, desc)
    129                : "target does not support tail calls";
    130   if (!reason) return 1;
    131   if (policy == KIT_CG_TAIL_MUST) {
    132     compiler_panic(g->c, g->cur_loc, "musttail call not realizable: %s",
    133                    reason);
    134     return 0;
    135   }
    136   return 0;
    137 }
    138 
    139 static void api_finish_call(KitCg* g, CGCallDesc* desc, CGLocal* args,
    140                             u32 nargs, Operand callee_op, ApiSValue* callee,
    141                             int want_tail, int emit_tail) {
    142   if (emit_tail) api_temp_locals_finish(g);
    143   if (!emit_tail) api_call_clobber_boundary(g, desc);
    144   g->target->call(g->target, desc);
    145 
    146   api_release_call_args(g, args, nargs);
    147   if (callee && callee->op.kind != OPK_GLOBAL) {
    148     api_release_temp_local(g, callee_op.v.local);
    149   }
    150   /* Push the single result (if any) onto the stack. */
    151   if (desc->result != CG_LOCAL_NONE) {
    152     KitCgTypeId rty = cg_type_func_result_id(g->c, desc->fn_type);
    153     api_push_call_result(g, desc->result, rty);
    154   }
    155   /* ALLOWED tail call that degraded to an ordinary call: synthesize the
    156    * caller's return of the just-pushed result. */
    157   if (want_tail && !emit_tail) kit_cg_ret(g);
    158 }
    159 
    160 void kit_cg_call(KitCg* g, uint32_t nargs, KitCgTypeId fn_type,
    161                  KitCgCallAttrs attrs) {
    162   CgTarget* T;
    163   KitCgTypeId fty;
    164   KitCgTypeId result_type;
    165   CGLocal* args;
    166   CGCallDesc desc;
    167   ApiSValue callee;
    168   Operand callee_op;
    169   int want_tail;
    170   int emit_tail;
    171   if (!g) return;
    172   api_local_const_memory_boundary(g);
    173   want_tail =
    174       attrs.tail == KIT_CG_TAIL_ALLOWED || attrs.tail == KIT_CG_TAIL_MUST;
    175   T = g->target;
    176   fty = resolve_type(g->c, fn_type);
    177   if (!fty) return;
    178 
    179   if (g->sp < (u32)nargs + 1u) {
    180     compiler_panic(g->c, g->cur_loc, "KitCg: call stack underflow");
    181     return;
    182   }
    183 
    184   args = api_alloc_call_args(g, nargs);
    185   for (u32 i = 0; i < nargs; ++i) {
    186     u32 idx = nargs - 1u - i;
    187     api_pack_call_arg(g, &args[idx], fty, idx);
    188   }
    189 
    190   callee = api_pop(g);
    191   api_ensure_local(g, &callee);
    192   callee_op = (callee.op.kind == OPK_GLOBAL)
    193                   ? callee.op
    194                   : api_force_local(g, &callee, api_sv_type(&callee));
    195   KitCgInlinePolicy inline_policy = attrs.inline_policy;
    196   if (inline_policy == KIT_CG_INLINE_DEFAULT && callee_op.kind == OPK_GLOBAL &&
    197       callee_op.v.global.addend == 0) {
    198     KitCgDecl callee_attrs = api_sym_attrs(g, (KitCgSym)callee_op.v.global.sym);
    199     if (callee_attrs.kind == KIT_CG_DECL_FUNC)
    200       inline_policy = callee_attrs.as.func.inline_policy;
    201   }
    202 
    203   memset(&desc, 0, sizeof desc);
    204   desc.fn_type = fty;
    205   desc.callee = callee_op;
    206   desc.args = args;
    207   desc.nargs = nargs;
    208   desc.tail_policy = (u8)attrs.tail;
    209   desc.inline_policy = inline_policy;
    210 
    211   emit_tail = want_tail ? api_tail_decide(g, &desc, attrs.tail) : 0;
    212   desc.flags = emit_tail ? CG_CALL_TAIL : CG_CALL_NONE;
    213   result_type = emit_tail ? KIT_CG_TYPE_NONE : cg_type_func_result_id(g->c, fty);
    214   if (result_type != KIT_CG_TYPE_NONE)
    215     desc.result = api_alloc_call_result(g, result_type);
    216 
    217   (void)T;
    218   api_finish_call(g, &desc, args, nargs, callee_op, &callee, want_tail,
    219                   emit_tail);
    220 }
    221 
    222 void api_call_symbol_common(KitCg* g, KitCgSym sym, uint32_t nargs,
    223                             KitCgCallAttrs attrs) {
    224   KitCgTypeId fty;
    225   KitCgTypeId result_type;
    226   CGLocal* args;
    227   CGCallDesc desc;
    228   Operand callee_op;
    229   KitCgInlinePolicy inline_policy;
    230   int want_tail;
    231   int emit_tail;
    232   if (!g) return;
    233   api_local_const_memory_boundary(g);
    234   want_tail =
    235       attrs.tail == KIT_CG_TAIL_ALLOWED || attrs.tail == KIT_CG_TAIL_MUST;
    236   fty = api_sym_type(g, sym);
    237   if (!fty) return;
    238   if (g->sp < nargs) {
    239     compiler_panic(g->c, g->cur_loc, "KitCg: call stack underflow");
    240     return;
    241   }
    242   args = api_alloc_call_args(g, nargs);
    243   for (u32 i = 0; i < nargs; ++i) {
    244     u32 idx = nargs - 1u - i;
    245     api_pack_call_arg(g, &args[idx], fty, idx);
    246   }
    247   callee_op = api_op_global((ObjSymId)sym, 0, cg_type_ptr_to(g->c, fty));
    248   inline_policy = attrs.inline_policy;
    249   if (inline_policy == KIT_CG_INLINE_DEFAULT) {
    250     KitCgDecl callee_attrs = api_sym_attrs(g, sym);
    251     if (callee_attrs.kind == KIT_CG_DECL_FUNC)
    252       inline_policy = callee_attrs.as.func.inline_policy;
    253   }
    254   memset(&desc, 0, sizeof desc);
    255   desc.fn_type = fty;
    256   desc.callee = callee_op;
    257   desc.args = args;
    258   desc.nargs = nargs;
    259   desc.tail_policy = (u8)attrs.tail;
    260   desc.inline_policy = inline_policy;
    261 
    262   emit_tail = want_tail ? api_tail_decide(g, &desc, attrs.tail) : 0;
    263   desc.flags = emit_tail ? CG_CALL_TAIL : CG_CALL_NONE;
    264   result_type = emit_tail ? KIT_CG_TYPE_NONE : cg_type_func_result_id(g->c, fty);
    265   if (result_type != KIT_CG_TYPE_NONE)
    266     desc.result = api_alloc_call_result(g, result_type);
    267   api_finish_call(g, &desc, args, nargs, callee_op, NULL, want_tail, emit_tail);
    268 }
    269 
    270 void kit_cg_call_symbol(KitCg* g, KitCgSym sym, uint32_t nargs,
    271                         KitCgCallAttrs attrs) {
    272   api_call_symbol_common(g, sym, nargs, attrs);
    273 }
    274 
    275 void kit_cg_ret(KitCg* g) {
    276   KitCgTypeId rty;
    277   ApiSValue v;
    278   CGLocal value;
    279   if (!g) return;
    280   rty = g->fn_desc.result_type;
    281   if (rty == KIT_CG_TYPE_NONE) {
    282     g->target->ret(g->target, CG_LOCAL_NONE);
    283     return;
    284   }
    285   /* TOS holds the single result value. */
    286   v = api_pop(g);
    287   if (cg_type_is_aggregate(g->c, rty)) {
    288     value = api_materialize_call_local(g, &v, rty);
    289   } else {
    290     Operand ret_op = api_force_local(g, &v, rty);
    291     value = ret_op.v.local;
    292   }
    293   g->target->ret(g->target, value);
    294   api_release(g, &v);
    295 }
    296 
    297 /* ============================================================
    298  * Data definitions (stubs)
    299  * ============================================================ */