builtins.c (61761B)
1 #include <string.h> 2 3 #include "internal.h" 4 5 static KitCgMemAccess toy_mem_access_align(ToyParser* p, KitCgTypeId type, 6 uint32_t align) { 7 KitCgMemAccess access = toy_mem_access(p, type); 8 access.align = align; 9 return access; 10 } 11 12 static int toy_parse_mem_flags_tail(ToyParser* p, KitCgMemAccess* access) { 13 static const ToyConstRow rows[] = {{"volatile", KIT_CG_MEM_VOLATILE}}; 14 return toy_parse_flag_set(p, rows, sizeof rows / sizeof rows[0], 15 "memory access flag", 1, &access->flags); 16 } 17 18 static void toy_store_top_to_local(ToyParser* p, KitCgLocal local, 19 KitCgTypeId ty) { 20 kit_cg_push_local(p->cg, local); 21 kit_cg_swap(p->cg); 22 kit_cg_store(p->cg, toy_mem_access(p, ty)); 23 } 24 25 static void toy_store_const_to_local(ToyParser* p, KitCgLocal local, 26 KitCgTypeId ty, uint64_t value) { 27 kit_cg_push_local(p->cg, local); 28 kit_cg_push_int(p->cg, value, ty); 29 kit_cg_store(p->cg, toy_mem_access(p, ty)); 30 } 31 32 static void toy_push_loaded_local(ToyParser* p, KitCgLocal local, 33 KitCgTypeId ty) { 34 kit_cg_push_local(p->cg, local); 35 kit_cg_load(p->cg, toy_mem_access(p, ty)); 36 } 37 38 static void toy_emit_dynamic_memory_loop(ToyParser* p, KitCgLocal dst_local, 39 KitCgLocal src_local, 40 KitCgLocal size_local, int is_memset, 41 uint8_t set_value) { 42 KitCgTypeId u8_ty = toy_builtin_type(p, KIT_CG_BUILTIN_I8); 43 KitCgTypeId u8_ptr_ty = kit_cg_type_ptr(p->c, u8_ty, 0); 44 KitCgLocal index_local = kit_cg_local(p->cg, p->size_type, toy_slot_attrs(0)); 45 KitCgLabel loop_label = kit_cg_label_new(p->cg); 46 KitCgLabel end_label = kit_cg_label_new(p->cg); 47 48 toy_store_const_to_local(p, index_local, p->size_type, 0); 49 kit_cg_label_place(p->cg, loop_label); 50 51 toy_push_loaded_local(p, index_local, p->size_type); 52 toy_push_loaded_local(p, size_local, p->size_type); 53 kit_cg_int_cmp(p->cg, KIT_CG_INT_LT_U); 54 kit_cg_branch_false(p->cg, end_label); 55 56 toy_push_loaded_local(p, dst_local, u8_ptr_ty); 57 toy_push_loaded_local(p, index_local, p->size_type); 58 /* Build the destination element place from [dst_ptr, index]; the element 59 * scale = sizeof(u8) = 1 is derived from the base type. The store then 60 * consumes [dst_place, value]. */ 61 kit_cg_elem(p->cg, 0); 62 if (is_memset) { 63 kit_cg_push_int(p->cg, set_value, u8_ty); 64 } else { 65 toy_push_loaded_local(p, src_local, u8_ptr_ty); 66 toy_push_loaded_local(p, index_local, p->size_type); 67 kit_cg_elem(p->cg, 0); 68 kit_cg_load(p->cg, toy_mem_access(p, u8_ty)); 69 } 70 kit_cg_store(p->cg, toy_mem_access(p, u8_ty)); 71 72 kit_cg_push_local(p->cg, index_local); 73 toy_push_loaded_local(p, index_local, p->size_type); 74 kit_cg_push_int(p->cg, 1, p->size_type); 75 kit_cg_int_binop(p->cg, KIT_CG_INT_ADD, 0); 76 kit_cg_store(p->cg, toy_mem_access(p, p->size_type)); 77 78 kit_cg_jump(p->cg, loop_label); 79 kit_cg_label_place(p->cg, end_label); 80 } 81 82 static int toy_parse_memory_align_operand(ToyParser* p, int64_t* align, 83 int* dynamic) { 84 *align = 0; 85 *dynamic = 0; 86 if (!toy_parser_match(p, TOK_COMMA)) return 1; 87 if (p->cur.kind == TOK_NUMBER && !p->cur.is_float) 88 return toy_parse_number_arg(p, align); 89 { 90 KitCgTypeId ty = toy_parse_expr(p); 91 if (ty == KIT_CG_TYPE_NONE) return 0; 92 if (!toy_type_can_implicitly_cast(p, ty, p->size_type)) { 93 toy_error(p, p->cur.loc, "memory alignment must be usize"); 94 return 0; 95 } 96 if (!toy_emit_implicit_cast(p, ty, p->size_type)) return 0; 97 kit_cg_drop(p->cg); 98 *dynamic = 1; 99 } 100 return 1; 101 } 102 103 static int toy_parse_access_group(ToyParser* p, KitCgMemAccess* access) { 104 KitSym access_name = kit_sym_intern(p->c, KIT_SLICE_LIT("access")); 105 if (p->cur.kind != TOK_IDENT || toy_tok_sym(p, p->cur) != access_name) 106 return 0; 107 toy_parser_advance(p); 108 if (!toy_parser_expect(p, TOK_LPAREN)) { 109 toy_error(p, p->cur.loc, "expected '(' after access"); 110 return 0; 111 } 112 while (p->cur.kind != TOK_RPAREN && p->cur.kind != TOK_EOF) { 113 KitSym name; 114 int64_t int_arg; 115 if (!toy_parse_attr_dot_name(p, &name)) return 0; 116 if (toy_sym_is(p, name, "align")) { 117 if (!toy_parse_attr_int_arg(p, &int_arg) || int_arg < 0) return 0; 118 access->align = (uint32_t)int_arg; 119 } else if (toy_sym_is(p, name, "addrspace")) { 120 if (!toy_parse_attr_int_arg(p, &int_arg) || int_arg < 0) return 0; 121 access->address_space = (uint32_t)int_arg; 122 } else if (toy_sym_is(p, name, "volatile")) { 123 access->flags |= KIT_CG_MEM_VOLATILE; 124 } else { 125 toy_error(p, p->cur.loc, "unknown access entry"); 126 return 0; 127 } 128 if (!toy_parser_match(p, TOK_COMMA)) break; 129 } 130 if (!toy_parser_expect(p, TOK_RPAREN)) { 131 toy_error(p, p->cur.loc, "expected ')' after access group"); 132 return 0; 133 } 134 return 1; 135 } 136 137 static int toy_parse_optional_access_arg(ToyParser* p, KitCgMemAccess* access) { 138 if (!toy_parser_match(p, TOK_COMMA)) return 1; 139 if (!toy_parse_access_group(p, access)) { 140 toy_error(p, p->cur.loc, "expected access group"); 141 return 0; 142 } 143 return 1; 144 } 145 146 static int toy_parse_mem_order(ToyParser* p, KitCgMemOrder* out) { 147 static const ToyConstRow rows[] = { 148 {"relaxed", KIT_CG_MO_RELAXED}, {"consume", KIT_CG_MO_CONSUME}, 149 {"acquire", KIT_CG_MO_ACQUIRE}, {"release", KIT_CG_MO_RELEASE}, 150 {"acq_rel", KIT_CG_MO_ACQ_REL}, {"seq_cst", KIT_CG_MO_SEQ_CST}, 151 }; 152 uint64_t v; 153 if (!toy_parse_dot_const(p, rows, sizeof rows / sizeof rows[0], 1, 154 "memory order", "memory order", &v)) 155 return 0; 156 *out = (KitCgMemOrder)v; 157 return 1; 158 } 159 160 static int toy_parse_atomic_op(ToyParser* p, KitCgAtomicOp* out) { 161 static const ToyConstRow rows[] = { 162 {"xchg", KIT_CG_ATOMIC_XCHG}, {"add", KIT_CG_ATOMIC_ADD}, 163 {"sub", KIT_CG_ATOMIC_SUB}, {"and", KIT_CG_ATOMIC_AND}, 164 {"or", KIT_CG_ATOMIC_OR}, {"xor", KIT_CG_ATOMIC_XOR}, 165 {"nand", KIT_CG_ATOMIC_NAND}, 166 }; 167 uint64_t v; 168 if (!toy_parse_dot_const(p, rows, sizeof rows / sizeof rows[0], 0, NULL, 169 "atomic op", &v)) 170 return 0; 171 *out = (KitCgAtomicOp)v; 172 return 1; 173 } 174 175 static int toy_parse_cmpxchg_strength(ToyParser* p, int* weak_out) { 176 static const ToyConstRow rows[] = { 177 {"strong", 0}, 178 {"weak", 1}, 179 }; 180 uint64_t v; 181 if (!toy_parse_dot_const(p, rows, sizeof rows / sizeof rows[0], 1, 182 "compare-exchange strength", 183 "compare-exchange strength", &v)) 184 return 0; 185 *weak_out = (int)v; 186 return 1; 187 } 188 189 static int toy_parse_call_attr(ToyParser* p, KitCgCallAttrs* attrs) { 190 KitSym name; 191 if (!toy_parse_attr_dot_name(p, &name)) return 0; 192 if (toy_sym_is(p, name, "cold")) { 193 attrs->flags |= KIT_CG_CALL_COLD; 194 } else if (toy_sym_is(p, name, "tail") || 195 toy_sym_is(p, name, "tail_allowed")) { 196 attrs->tail = KIT_CG_TAIL_ALLOWED; 197 } else if (toy_sym_is(p, name, "musttail")) { 198 attrs->tail = KIT_CG_TAIL_MUST; 199 } else if (toy_sym_is(p, name, "notail") || 200 toy_sym_is(p, name, "tail_never")) { 201 attrs->tail = KIT_CG_TAIL_DEFAULT; 202 } else if (toy_sym_is(p, name, "inline")) { 203 attrs->inline_policy = KIT_CG_INLINE_HINT; 204 } else if (toy_sym_is(p, name, "always_inline")) { 205 attrs->inline_policy = KIT_CG_INLINE_ALWAYS; 206 } else if (toy_sym_is(p, name, "noinline")) { 207 attrs->inline_policy = KIT_CG_INLINE_NEVER; 208 } else { 209 toy_error(p, p->cur.loc, "unknown call attribute"); 210 return 0; 211 } 212 return 1; 213 } 214 215 static int toy_parse_call_attr_tail(ToyParser* p, KitCgCallAttrs* attrs) { 216 while (toy_parser_match(p, TOK_COMMA)) { 217 if (p->cur.kind != TOK_DOT) { 218 toy_error(p, p->cur.loc, "expected call attribute"); 219 return 0; 220 } 221 if (!toy_parse_call_attr(p, attrs)) return 0; 222 } 223 return 1; 224 } 225 226 static int toy_reject_tail_call_operand(ToyParser* p) { 227 if (!p->tail_call_expr) return 0; 228 toy_error(p, p->cur.loc, "tail @call must be returned directly"); 229 return 1; 230 } 231 232 static int toy_parse_call_braced_args(ToyParser* p, ToyToken call_tok, 233 KitCgTypeId fn_ty, 234 const ToyTypeId* toy_params, 235 size_t toy_nparams, size_t* out_nargs) { 236 uint32_t nparams = kit_cg_type_func_nparams(p->c, fn_ty); 237 int variadic = kit_cg_type_func_is_variadic(p->c, fn_ty); 238 size_t nargs = 0; 239 if (!toy_parser_expect(p, TOK_LBRACE)) { 240 toy_error(p, p->cur.loc, "expected braced call arguments"); 241 return 0; 242 } 243 if (p->cur.kind != TOK_RBRACE) { 244 for (;;) { 245 KitCgTypeId arg_ty = toy_parse_expr(p); 246 if (arg_ty == KIT_CG_TYPE_NONE) return 0; 247 if (toy_reject_tail_call_operand(p)) return 0; 248 if (nargs < nparams) { 249 KitCgFuncParam param = 250 kit_cg_type_func_param(p->c, fn_ty, (uint32_t)nargs); 251 ToyTypeId expected = (toy_params && nargs < toy_nparams) 252 ? toy_params[nargs] 253 : TOY_TYPE_NONE; 254 ToyTypeId actual = p->last_type; 255 if (expected != TOY_TYPE_NONE && 256 !toy_type_accepts_type(p, expected, actual)) { 257 toy_error(p, call_tok.loc, "function argument type mismatch"); 258 return 0; 259 } 260 if (expected == TOY_TYPE_NONE && 261 !toy_type_can_implicitly_cast(p, arg_ty, param.type)) { 262 toy_error(p, call_tok.loc, "function argument type mismatch"); 263 return 0; 264 } 265 if (arg_ty != param.type) { 266 if (expected != TOY_TYPE_NONE) { 267 if (!toy_emit_checked_cast(p, arg_ty, param.type)) return 0; 268 } else if (!toy_emit_implicit_cast(p, arg_ty, param.type)) { 269 return 0; 270 } 271 } 272 } else if (!variadic) { 273 toy_error(p, call_tok.loc, "too many arguments"); 274 return 0; 275 } 276 ++nargs; 277 if (!toy_parser_match(p, TOK_COMMA)) break; 278 if (p->cur.kind == TOK_RBRACE) break; 279 } 280 } 281 if (!toy_parser_expect(p, TOK_RBRACE)) { 282 toy_error(p, p->cur.loc, "expected '}' after call arguments"); 283 return 0; 284 } 285 if (nargs < nparams) { 286 toy_error(p, call_tok.loc, "too few arguments"); 287 return 0; 288 } 289 *out_nargs = nargs; 290 return 1; 291 } 292 293 static KitCgTypeId toy_parse_call_builtin(ToyParser* p) { 294 KitCgCallAttrs attrs; 295 ToyFn* fn = NULL; 296 KitCgTypeId fn_ty = KIT_CG_TYPE_NONE; 297 KitCgTypeId ret_ty; 298 const ToyType* source_fn_type = NULL; 299 ToyTypeId ret_toy_type = TOY_TYPE_NONE; 300 ToyToken call_tok; 301 int direct = 0; 302 size_t nargs = 0; 303 int tail; 304 memset(&attrs, 0, sizeof attrs); 305 if (!toy_parser_expect(p, TOK_LPAREN)) return KIT_CG_TYPE_NONE; 306 call_tok = p->cur; 307 if (p->cur.kind == TOK_IDENT) { 308 KitSym callee_name = toy_tok_sym(p, p->cur); 309 fn = toy_find_fn(p, callee_name); 310 if (fn) { 311 direct = 1; 312 fn_ty = fn->type; 313 ret_toy_type = fn->toy_ret; 314 toy_parser_advance(p); 315 } 316 } 317 if (!direct) { 318 KitCgTypeId callee_ty = toy_parse_expr(p); 319 ToyTypeId callee_toy_type = p->last_type; 320 if (callee_ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE; 321 if (toy_reject_tail_call_operand(p)) return KIT_CG_TYPE_NONE; 322 fn_ty = toy_ptr_pointee_func_type(p, callee_ty); 323 if (fn_ty == KIT_CG_TYPE_NONE) { 324 toy_error(p, call_tok.loc, "@call callee is not a function pointer"); 325 return KIT_CG_TYPE_NONE; 326 } 327 source_fn_type = toy_type_get(p, toy_type_pointee(p, callee_toy_type)); 328 if (source_fn_type && source_fn_type->kind != TOY_TYPE_FUNC) 329 source_fn_type = NULL; 330 if (source_fn_type) ret_toy_type = source_fn_type->ret; 331 } 332 if (!toy_expect_comma(p)) return KIT_CG_TYPE_NONE; 333 if (!toy_parse_call_braced_args( 334 p, call_tok, fn_ty, 335 direct ? fn->toy_params 336 : (source_fn_type ? source_fn_type->params : NULL), 337 direct ? fn->nparams : (source_fn_type ? source_fn_type->nparams : 0), 338 &nargs)) { 339 return KIT_CG_TYPE_NONE; 340 } 341 if (!toy_parse_call_attr_tail(p, &attrs)) return KIT_CG_TYPE_NONE; 342 if (!toy_parser_expect(p, TOK_RPAREN)) return KIT_CG_TYPE_NONE; 343 344 ret_ty = toy_cg_func_ret(p, fn_ty); 345 tail = attrs.tail == KIT_CG_TAIL_ALLOWED || attrs.tail == KIT_CG_TAIL_MUST; 346 if (tail && !p->allow_tail_call_expr) { 347 toy_error(p, call_tok.loc, "tail @call requires return"); 348 return KIT_CG_TYPE_NONE; 349 } 350 351 if (!ret_toy_type) ret_toy_type = toy_type_from_cg(p, ret_ty); 352 if (tail) { 353 p->tail_call_expr = 1; 354 p->tail_call_ret_toy = ret_toy_type; 355 if (p->cur_fn_ret_toy != TOY_TYPE_NONE && ret_toy_type != TOY_TYPE_NONE && 356 !toy_type_accepts_type(p, p->cur_fn_ret_toy, ret_toy_type)) { 357 p->last_type = ret_toy_type; 358 return ret_ty; 359 } 360 } 361 362 if (direct) 363 kit_cg_call_symbol(p->cg, toy_fn_cur_sym(p, fn), (uint32_t)nargs, attrs); 364 else 365 kit_cg_call(p->cg, (uint32_t)nargs, fn_ty, attrs); 366 p->last_type = ret_toy_type; 367 return ret_ty; 368 } 369 370 static int toy_parse_barrier_scope(ToyParser* p, KitCgBarrierScope* out) { 371 static const ToyConstRow rows[] = { 372 {"full", KIT_CG_BARRIER_FULL}, 373 {"inner", KIT_CG_BARRIER_INNER}, 374 {"inner_store", KIT_CG_BARRIER_INNER_STORE}, 375 {"outer", KIT_CG_BARRIER_OUTER}, 376 {"outer_store", KIT_CG_BARRIER_OUTER_STORE}, 377 {"non_share", KIT_CG_BARRIER_NON_SHARE}, 378 }; 379 uint64_t v; 380 if (!toy_parse_dot_const(p, rows, sizeof rows / sizeof rows[0], 0, NULL, 381 "barrier scope", &v)) 382 return 0; 383 *out = (KitCgBarrierScope)v; 384 return 1; 385 } 386 387 static KitCgTypeId toy_unsupported_intrinsic(ToyParser* p) { 388 toy_error(p, p->cur.loc, "unsupported target intrinsic"); 389 return KIT_CG_TYPE_NONE; 390 } 391 392 KitCgTypeId toy_parse_builtin_call(ToyParser* p, KitSym name, int* recognized) { 393 *recognized = 1; 394 395 if (toy_sym_is(p, name, "call")) return toy_parse_call_builtin(p); 396 397 if (toy_sym_is(p, name, "popcount") || toy_sym_is(p, name, "ctz") || 398 toy_sym_is(p, name, "clz") || toy_sym_is(p, name, "bswap")) { 399 KitCgIntrinsic intrin = KIT_CG_INTRIN_POPCOUNT; 400 KitCgTypeId ty; 401 if (toy_sym_is(p, name, "ctz")) 402 intrin = KIT_CG_INTRIN_CTZ; 403 else if (toy_sym_is(p, name, "clz")) 404 intrin = KIT_CG_INTRIN_CLZ; 405 else if (toy_sym_is(p, name, "bswap")) 406 intrin = KIT_CG_INTRIN_BSWAP; 407 toy_parser_advance(p); /* ( */ 408 ty = toy_parse_expr(p); 409 if (ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE; 410 if (!toy_parser_expect(p, TOK_RPAREN)) { 411 toy_error(p, p->cur.loc, "expected ')'"); 412 return KIT_CG_TYPE_NONE; 413 } 414 if (!toy_type_is_intlike(p, ty)) { 415 toy_error(p, p->cur.loc, "integer intrinsic expects integer operand"); 416 return KIT_CG_TYPE_NONE; 417 } 418 kit_cg_intrinsic(p->cg, intrin, 1, ty); 419 return ty; 420 } 421 422 if (toy_sym_is(p, name, "frame_address") || 423 toy_sym_is(p, name, "return_address")) { 424 /* __builtin_frame_address / __builtin_return_address. The constant level 425 * rides as a single immediate operand; the result is a void*. */ 426 KitCgIntrinsic intrin = toy_sym_is(p, name, "return_address") 427 ? KIT_CG_INTRIN_RETURN_ADDRESS 428 : KIT_CG_INTRIN_FRAME_ADDRESS; 429 KitCgTypeId void_ptr = 430 kit_cg_type_ptr(p->c, toy_builtin_type(p, KIT_CG_BUILTIN_VOID), 0); 431 KitCgTypeId level_ty; 432 if (!toy_parser_expect(p, TOK_LPAREN)) return KIT_CG_TYPE_NONE; 433 level_ty = toy_parse_expr(p); 434 if (level_ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE; 435 if (!toy_type_is_intlike(p, level_ty)) { 436 toy_error(p, p->cur.loc, "frame/return address level must be integer"); 437 return KIT_CG_TYPE_NONE; 438 } 439 if (!toy_parser_expect(p, TOK_RPAREN)) { 440 toy_error(p, p->cur.loc, "expected ')'"); 441 return KIT_CG_TYPE_NONE; 442 } 443 if (!kit_cg_target_supports_intrinsic(p->c, intrin)) 444 return toy_unsupported_intrinsic(p); 445 kit_cg_intrinsic(p->cg, intrin, 1, void_ptr); 446 return void_ptr; 447 } 448 449 if (toy_sym_is(p, name, "expect")) { 450 KitCgTypeId a, b; 451 toy_parser_advance(p); 452 a = toy_parse_expr(p); 453 if (a == KIT_CG_TYPE_NONE || !toy_expect_comma(p)) return KIT_CG_TYPE_NONE; 454 b = toy_parse_expr(p); 455 if (b == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE; 456 if (!toy_parser_expect(p, TOK_RPAREN)) return KIT_CG_TYPE_NONE; 457 if (a != b) { 458 toy_error(p, p->cur.loc, "expect operands must have matching type"); 459 return KIT_CG_TYPE_NONE; 460 } 461 kit_cg_intrinsic(p->cg, KIT_CG_INTRIN_EXPECT, 2, a); 462 return a; 463 } 464 465 if (toy_sym_is(p, name, "trap")) { 466 if (!toy_parser_expect(p, TOK_LPAREN) || !toy_parser_expect(p, TOK_RPAREN)) 467 return KIT_CG_TYPE_NONE; 468 kit_cg_intrinsic(p->cg, KIT_CG_INTRIN_TRAP, 0, 469 toy_builtin_type(p, KIT_CG_BUILTIN_VOID)); 470 return toy_builtin_type(p, KIT_CG_BUILTIN_VOID); 471 } 472 473 if (toy_sym_is(p, name, "cpu_nop") || toy_sym_is(p, name, "cpu_yield") || 474 toy_sym_is(p, name, "irq_disable") || toy_sym_is(p, name, "irq_enable") || 475 toy_sym_is(p, name, "isb")) { 476 KitCgIntrinsic intrin = KIT_CG_INTRIN_CPU_NOP; 477 if (toy_sym_is(p, name, "cpu_yield")) 478 intrin = KIT_CG_INTRIN_CPU_YIELD; 479 else if (toy_sym_is(p, name, "irq_disable")) 480 intrin = KIT_CG_INTRIN_IRQ_DISABLE; 481 else if (toy_sym_is(p, name, "irq_enable")) 482 intrin = KIT_CG_INTRIN_IRQ_ENABLE; 483 else if (toy_sym_is(p, name, "isb")) 484 intrin = KIT_CG_INTRIN_ISB; 485 if (!toy_parser_expect(p, TOK_LPAREN) || !toy_parser_expect(p, TOK_RPAREN)) 486 return KIT_CG_TYPE_NONE; 487 if (!kit_cg_target_supports_intrinsic(p->c, intrin)) 488 return toy_unsupported_intrinsic(p); 489 kit_cg_intrinsic(p->cg, intrin, 0, 490 toy_builtin_type(p, KIT_CG_BUILTIN_VOID)); 491 return toy_builtin_type(p, KIT_CG_BUILTIN_VOID); 492 } 493 494 /* C99-style floating comparison builtins (Route A). Five map directly to an 495 * ordered FP predicate (NaN -> false); @islessgreater is ordered-and-not- 496 * equal (ONE), reachable only here (toy `!=` is the unordered UNE). The 497 * unordered duals are reached separately via `!(a < b)` etc. (Route B). 498 * @isunordered has no standalone predicate, so it is synthesized as 499 * isnan(a) || isnan(b), where UNE(x, x) is isnan(x). */ 500 if (toy_sym_is(p, name, "isless") || toy_sym_is(p, name, "islessequal") || 501 toy_sym_is(p, name, "isgreater") || 502 toy_sym_is(p, name, "isgreaterequal") || 503 toy_sym_is(p, name, "islessgreater") || 504 toy_sym_is(p, name, "isunordered")) { 505 KitCgTypeId a, b; 506 KitCgFpCmpOp pred = KIT_CG_FP_OLT; 507 int is_unordered = toy_sym_is(p, name, "isunordered"); 508 if (toy_sym_is(p, name, "islessequal")) 509 pred = KIT_CG_FP_OLE; 510 else if (toy_sym_is(p, name, "isgreater")) 511 pred = KIT_CG_FP_OGT; 512 else if (toy_sym_is(p, name, "isgreaterequal")) 513 pred = KIT_CG_FP_OGE; 514 else if (toy_sym_is(p, name, "islessgreater")) 515 pred = KIT_CG_FP_ONE; 516 if (!toy_parser_expect(p, TOK_LPAREN)) return KIT_CG_TYPE_NONE; 517 a = toy_parse_expr(p); 518 if (a == KIT_CG_TYPE_NONE || !toy_expect_comma(p)) return KIT_CG_TYPE_NONE; 519 b = toy_parse_expr(p); 520 if (b == KIT_CG_TYPE_NONE || !toy_parser_expect(p, TOK_RPAREN)) 521 return KIT_CG_TYPE_NONE; 522 if (a != b || !toy_type_is_float(p, a)) { 523 toy_error(p, p->cur.loc, 524 "floating comparison builtin expects two floating operands of " 525 "the same type"); 526 return KIT_CG_TYPE_NONE; 527 } 528 if (is_unordered) { 529 /* stack: [a, b] -> isnan(b) then isnan(a), OR'd. */ 530 kit_cg_dup(p->cg); /* [a, b, b] */ 531 kit_cg_fp_cmp(p->cg, KIT_CG_FP_UNE); /* [a, isnan_b] */ 532 kit_cg_swap(p->cg); /* [isnan_b, a] */ 533 kit_cg_dup(p->cg); /* [isnan_b, a, a] */ 534 kit_cg_fp_cmp(p->cg, KIT_CG_FP_UNE); /* [isnan_b, isnan_a] */ 535 kit_cg_int_binop(p->cg, KIT_CG_INT_OR, 0); 536 } else { 537 kit_cg_fp_cmp(p->cg, pred); 538 } 539 /* Widen the i32 0/1 to the toy int type, matching the comparison operators 540 * (toy_parse_expr_cmp zext's its result), so the builtin composes in 541 * arithmetic the same way `a < b` does. */ 542 kit_cg_zext(p->cg, p->int_type); 543 return p->int_type; 544 } 545 546 { 547 int low_level_recognized = 0; 548 KitCgTypeId low_level_ty = 549 toy_parse_low_level_builtin_call(p, name, &low_level_recognized); 550 if (low_level_recognized) return low_level_ty; 551 } 552 553 if (toy_sym_is(p, name, "compile_error")) { 554 KitSym msg; 555 size_t msg_len; 556 KitSlice text; 557 if (!toy_parser_expect(p, TOK_LPAREN) || 558 !toy_parse_string_sym(p, &msg, &msg_len) || 559 !toy_parser_expect(p, TOK_RPAREN)) 560 return KIT_CG_TYPE_NONE; 561 text = kit_sym_str(p->c, msg); 562 toy_error(p, p->cur.loc, "compile_error: %.*s", KIT_SLICE_ARG(text)); 563 kit_cg_push_int(p->cg, 0, p->int_type); 564 return p->int_type; 565 } 566 567 if (toy_sym_is(p, name, "unreachable")) { 568 if (!toy_parser_expect(p, TOK_LPAREN) || !toy_parser_expect(p, TOK_RPAREN)) 569 return KIT_CG_TYPE_NONE; 570 kit_cg_unreachable(p->cg); 571 return toy_builtin_type(p, KIT_CG_BUILTIN_VOID); 572 } 573 574 if (toy_sym_is(p, name, "bitget")) { 575 KitCgTypeId ty; 576 int64_t lo, width; 577 toy_parser_advance(p); 578 ty = toy_parse_expr(p); 579 if (ty == KIT_CG_TYPE_NONE || !toy_expect_comma(p) || 580 !toy_parse_number_arg(p, &lo) || !toy_expect_comma(p) || 581 !toy_parse_number_arg(p, &width) || !toy_parser_expect(p, TOK_RPAREN)) 582 return KIT_CG_TYPE_NONE; 583 if (!toy_validate_bit_range(p, ty, lo, width, 1)) { 584 toy_error(p, p->cur.loc, "invalid bitget arguments"); 585 return KIT_CG_TYPE_NONE; 586 } 587 kit_cg_bitget(p->cg, ty, (uint32_t)lo, (uint32_t)width); 588 return ty; 589 } 590 591 if (toy_sym_is(p, name, "bitset")) { 592 KitCgTypeId dst_ty, src_ty; 593 int64_t lo, width; 594 KitCgLocal dst_slot, src_slot; 595 uint64_t src_mask, field_mask, clear_mask; 596 toy_parser_advance(p); 597 dst_ty = toy_parse_expr(p); 598 if (dst_ty == KIT_CG_TYPE_NONE || !toy_expect_comma(p)) 599 return KIT_CG_TYPE_NONE; 600 src_ty = toy_parse_expr(p); 601 if (src_ty == KIT_CG_TYPE_NONE || !toy_expect_comma(p) || 602 !toy_parse_number_arg(p, &lo) || !toy_expect_comma(p) || 603 !toy_parse_number_arg(p, &width) || !toy_parser_expect(p, TOK_RPAREN)) 604 return KIT_CG_TYPE_NONE; 605 if (dst_ty != src_ty || !toy_validate_bit_range(p, dst_ty, lo, width, 0)) { 606 toy_error(p, p->cur.loc, "invalid bitset arguments"); 607 return KIT_CG_TYPE_NONE; 608 } 609 src_mask = (1ULL << (uint32_t)width) - 1u; 610 field_mask = src_mask << (uint32_t)lo; 611 clear_mask = ~field_mask; 612 src_slot = kit_cg_local(p->cg, src_ty, toy_slot_attrs(0)); 613 dst_slot = kit_cg_local(p->cg, dst_ty, toy_slot_attrs(0)); 614 kit_cg_push_local(p->cg, src_slot); 615 kit_cg_swap(p->cg); 616 kit_cg_store(p->cg, toy_mem_access(p, src_ty)); 617 kit_cg_push_local(p->cg, dst_slot); 618 kit_cg_swap(p->cg); 619 kit_cg_store(p->cg, toy_mem_access(p, dst_ty)); 620 621 kit_cg_push_local(p->cg, dst_slot); 622 kit_cg_load(p->cg, toy_mem_access(p, dst_ty)); 623 kit_cg_push_int(p->cg, clear_mask, dst_ty); 624 kit_cg_int_binop(p->cg, KIT_CG_INT_AND, 0); 625 kit_cg_push_local(p->cg, src_slot); 626 kit_cg_load(p->cg, toy_mem_access(p, src_ty)); 627 kit_cg_push_int(p->cg, src_mask, src_ty); 628 kit_cg_int_binop(p->cg, KIT_CG_INT_AND, 0); 629 if (lo > 0) { 630 kit_cg_push_int(p->cg, (uint64_t)lo, src_ty); 631 kit_cg_int_binop(p->cg, KIT_CG_INT_SHL, 0); 632 } 633 kit_cg_int_binop(p->cg, KIT_CG_INT_OR, 0); 634 return dst_ty; 635 } 636 637 if (toy_sym_is(p, name, "fma")) { 638 KitCgTypeId a, b, c; 639 toy_parser_advance(p); 640 a = toy_parse_expr(p); 641 if (a == KIT_CG_TYPE_NONE || !toy_expect_comma(p)) return KIT_CG_TYPE_NONE; 642 b = toy_parse_expr(p); 643 if (b == KIT_CG_TYPE_NONE || !toy_expect_comma(p)) return KIT_CG_TYPE_NONE; 644 c = toy_parse_expr(p); 645 if (c == KIT_CG_TYPE_NONE || !toy_parser_expect(p, TOK_RPAREN)) 646 return KIT_CG_TYPE_NONE; 647 if (a != b || a != c || !toy_type_is_float(p, a)) { 648 toy_error(p, p->cur.loc, "fma expects matching float operands"); 649 return KIT_CG_TYPE_NONE; 650 } 651 kit_cg_rot3(p->cg); /* [b, c, a] */ 652 kit_cg_rot3(p->cg); /* [c, a, b] */ 653 kit_cg_fp_binop(p->cg, KIT_CG_FP_MUL, 0); 654 kit_cg_swap(p->cg); 655 kit_cg_fp_binop(p->cg, KIT_CG_FP_ADD, 0); 656 return a; 657 } 658 659 if (toy_sym_is(p, name, "prefetch")) { 660 KitCgTypeId ptr_ty; 661 toy_parser_advance(p); 662 ptr_ty = toy_parse_expr(p); 663 if (ptr_ty == KIT_CG_TYPE_NONE || !toy_parser_expect(p, TOK_RPAREN)) 664 return KIT_CG_TYPE_NONE; 665 if (!toy_type_is_ptr(p, ptr_ty)) { 666 toy_error(p, p->cur.loc, "prefetch expects pointer"); 667 return KIT_CG_TYPE_NONE; 668 } 669 kit_cg_intrinsic(p->cg, KIT_CG_INTRIN_PREFETCH, 1, 670 toy_builtin_type(p, KIT_CG_BUILTIN_VOID)); 671 return toy_builtin_type(p, KIT_CG_BUILTIN_VOID); 672 } 673 674 { 675 int memory_recognized = 0; 676 KitCgTypeId memory_ty = 677 toy_parse_memory_builtin_call(p, name, &memory_recognized); 678 if (memory_recognized) return memory_ty; 679 } 680 681 if (toy_sym_is(p, name, "labeladdr")) { 682 KitSym label_name; 683 ToyLabel* label; 684 KitCgTypeId ptr_ty = 685 kit_cg_type_ptr(p->c, toy_builtin_type(p, KIT_CG_BUILTIN_VOID), 0); 686 if (!toy_parser_expect(p, TOK_LPAREN) || p->cur.kind != TOK_IDENT) { 687 toy_error(p, p->cur.loc, "expected label name"); 688 return KIT_CG_TYPE_NONE; 689 } 690 label_name = toy_tok_sym(p, p->cur); 691 toy_parser_advance(p); 692 if (!toy_parser_expect(p, TOK_RPAREN)) return KIT_CG_TYPE_NONE; 693 label = toy_find_label(p, label_name); 694 if (!label) { 695 toy_error(p, p->cur.loc, "unknown label"); 696 return KIT_CG_TYPE_NONE; 697 } 698 kit_cg_push_label_addr(p->cg, label->label, ptr_ty); 699 return ptr_ty; 700 } 701 702 if (toy_sym_is(p, name, "target_arch")) { 703 if (!toy_parser_expect(p, TOK_LPAREN) || !toy_parser_expect(p, TOK_RPAREN)) 704 return KIT_CG_TYPE_NONE; 705 kit_cg_push_int(p->cg, (uint64_t)toy_target_code(p), p->int_type); 706 return p->int_type; 707 } 708 709 if (toy_sym_is(p, name, "supports_callconv")) { 710 KitCgCallConv cc; 711 if (!toy_parser_expect(p, TOK_LPAREN) || 712 !toy_parse_callconv_const(p, &cc) || !toy_parser_expect(p, TOK_RPAREN)) 713 return KIT_CG_TYPE_NONE; 714 kit_cg_push_int(p->cg, kit_cg_target_supports_call_conv(p->c, cc) ? 1u : 0u, 715 toy_builtin_type(p, KIT_CG_BUILTIN_BOOL)); 716 return toy_builtin_type(p, KIT_CG_BUILTIN_BOOL); 717 } 718 719 if (toy_sym_is(p, name, "supports_symbol_feature")) { 720 KitCgSymbolFeature feature; 721 if (!toy_parser_expect(p, TOK_LPAREN) || 722 !toy_parse_symbol_feature_const(p, &feature) || 723 !toy_parser_expect(p, TOK_RPAREN)) 724 return KIT_CG_TYPE_NONE; 725 kit_cg_push_int( 726 p->cg, kit_cg_target_supports_symbol_feature(p->c, feature) ? 1u : 0u, 727 toy_builtin_type(p, KIT_CG_BUILTIN_BOOL)); 728 return toy_builtin_type(p, KIT_CG_BUILTIN_BOOL); 729 } 730 731 if (toy_sym_is(p, name, "supports_intrinsic")) { 732 KitCgIntrinsic intrin; 733 if (!toy_parser_expect(p, TOK_LPAREN) || 734 !toy_parse_intrinsic_const(p, &intrin) || 735 !toy_parser_expect(p, TOK_RPAREN)) 736 return KIT_CG_TYPE_NONE; 737 kit_cg_push_int(p->cg, 738 kit_cg_target_supports_intrinsic(p->c, intrin) ? 1u : 0u, 739 toy_builtin_type(p, KIT_CG_BUILTIN_BOOL)); 740 return toy_builtin_type(p, KIT_CG_BUILTIN_BOOL); 741 } 742 743 if (toy_sym_is(p, name, "has_backend_feature")) { 744 uint64_t feature; 745 if (!toy_parser_expect(p, TOK_LPAREN) || 746 !toy_parse_backend_feature_const(p, &feature) || 747 !toy_parser_expect(p, TOK_RPAREN)) 748 return KIT_CG_TYPE_NONE; 749 kit_cg_push_int(p->cg, 750 (kit_cg_target_backend_features(p->c) & feature) ? 1u : 0u, 751 toy_builtin_type(p, KIT_CG_BUILTIN_BOOL)); 752 return toy_builtin_type(p, KIT_CG_BUILTIN_BOOL); 753 } 754 755 if (toy_sym_is(p, name, "va_start")) { 756 if (!toy_parser_expect(p, TOK_LPAREN) || !toy_parse_va_list_addr_arg(p) || 757 !toy_parser_expect(p, TOK_RPAREN)) 758 return KIT_CG_TYPE_NONE; 759 kit_cg_vararg_start(p->cg); 760 kit_cg_push_int(p->cg, 0, p->int_type); 761 return p->int_type; 762 } 763 764 if (toy_sym_is(p, name, "va_end")) { 765 if (!toy_parser_expect(p, TOK_LPAREN) || !toy_parse_va_list_addr_arg(p) || 766 !toy_parser_expect(p, TOK_RPAREN)) 767 return KIT_CG_TYPE_NONE; 768 kit_cg_vararg_end(p->cg); 769 kit_cg_push_int(p->cg, 0, p->int_type); 770 return p->int_type; 771 } 772 773 if (toy_sym_is(p, name, "va_copy")) { 774 if (!toy_parser_expect(p, TOK_LPAREN) || !toy_parse_va_list_addr_arg(p) || 775 !toy_expect_comma(p) || !toy_parse_va_list_addr_arg(p) || 776 !toy_parser_expect(p, TOK_RPAREN)) 777 return KIT_CG_TYPE_NONE; 778 kit_cg_vararg_copy(p->cg); 779 kit_cg_push_int(p->cg, 0, p->int_type); 780 return p->int_type; 781 } 782 783 *recognized = 0; 784 return KIT_CG_TYPE_NONE; 785 } 786 787 KitCgTypeId toy_parse_generic_builtin(ToyParser* p, KitSym name, 788 int* recognized) { 789 KitCgTypeId ty; 790 *recognized = 1; 791 792 if (toy_sym_is(p, name, "alloca")) { 793 KitCgTypeId count_ty; 794 KitCgTypeId ptr_ty; 795 ToyTypeId elem_toy_type; 796 int64_t align; 797 if (!toy_parser_expect(p, TOK_LT)) return KIT_CG_TYPE_NONE; 798 ty = toy_parse_type(p); 799 elem_toy_type = p->last_type; 800 if (ty == KIT_CG_TYPE_NONE || !toy_parser_expect(p, TOK_GT) || 801 !toy_parser_expect(p, TOK_LPAREN)) 802 return KIT_CG_TYPE_NONE; 803 count_ty = toy_parse_expr(p); 804 if (count_ty == KIT_CG_TYPE_NONE || !toy_expect_comma(p) || 805 !toy_parse_number_arg(p, &align) || !toy_parser_expect(p, TOK_RPAREN)) 806 return KIT_CG_TYPE_NONE; 807 if (!toy_type_can_implicitly_cast(p, count_ty, p->size_type) || 808 align <= 0) { 809 toy_error(p, p->cur.loc, "invalid alloca arguments"); 810 return KIT_CG_TYPE_NONE; 811 } 812 if (!toy_emit_implicit_cast(p, count_ty, p->size_type)) 813 return KIT_CG_TYPE_NONE; 814 kit_cg_push_int(p->cg, kit_cg_type_size(p->c, ty), p->size_type); 815 kit_cg_int_binop(p->cg, KIT_CG_INT_MUL, 0); 816 ptr_ty = kit_cg_type_ptr(p->c, ty, 0); 817 kit_cg_alloca(p->cg, (uint32_t)align, ptr_ty); 818 p->last_type = toy_type_register_ptr(p, ptr_ty, elem_toy_type, 0); 819 return ptr_ty; 820 } 821 822 if (toy_sym_is(p, name, "asm")) { 823 KitSym tmpl; 824 size_t tmpl_len; 825 ToyTypeId result_toy_type; 826 if (!toy_parser_expect(p, TOK_LT)) return KIT_CG_TYPE_NONE; 827 ty = toy_parse_type(p); 828 result_toy_type = p->last_type; 829 if (ty == KIT_CG_TYPE_NONE || !toy_parser_expect(p, TOK_GT) || 830 !toy_parser_expect(p, TOK_LPAREN) || 831 !toy_parse_arch_string(p, &tmpl, &tmpl_len)) { 832 return KIT_CG_TYPE_NONE; 833 } 834 if (!toy_parse_typed_asm_tail(p, ty, tmpl, tmpl_len)) 835 return KIT_CG_TYPE_NONE; 836 p->last_type = result_toy_type; 837 return ty; 838 } 839 840 { 841 int low_level_recognized = 0; 842 KitCgTypeId low_level_ty = 843 toy_parse_low_level_generic_builtin(p, name, &low_level_recognized); 844 if (low_level_recognized) return low_level_ty; 845 } 846 847 if (toy_sym_is(p, name, "sext") || toy_sym_is(p, name, "zext") || 848 toy_sym_is(p, name, "trunc") || toy_sym_is(p, name, "ptr_to_int") || 849 toy_sym_is(p, name, "int_to_ptr") || toy_sym_is(p, name, "bitcast") || 850 toy_sym_is(p, name, "fpext") || toy_sym_is(p, name, "fptrunc")) { 851 KitCgTypeId src_ty; 852 ToyTypeId result_toy_type; 853 if (!toy_parser_expect(p, TOK_LT)) return KIT_CG_TYPE_NONE; 854 ty = toy_parse_type(p); 855 result_toy_type = p->last_type; 856 if (ty == KIT_CG_TYPE_NONE || !toy_parser_expect(p, TOK_GT) || 857 !toy_parser_expect(p, TOK_LPAREN)) 858 return KIT_CG_TYPE_NONE; 859 src_ty = toy_parse_expr(p); 860 if (src_ty == KIT_CG_TYPE_NONE || !toy_parser_expect(p, TOK_RPAREN)) 861 return KIT_CG_TYPE_NONE; 862 (void)src_ty; 863 if (toy_sym_is(p, name, "sext")) 864 kit_cg_sext(p->cg, ty); 865 else if (toy_sym_is(p, name, "zext")) 866 kit_cg_zext(p->cg, ty); 867 else if (toy_sym_is(p, name, "trunc")) 868 kit_cg_trunc(p->cg, ty); 869 else if (toy_sym_is(p, name, "ptr_to_int")) 870 kit_cg_ptr_to_int(p->cg, ty); 871 else if (toy_sym_is(p, name, "int_to_ptr")) 872 kit_cg_int_to_ptr(p->cg, ty); 873 else if (toy_sym_is(p, name, "bitcast")) 874 kit_cg_bitcast(p->cg, ty); 875 else if (toy_sym_is(p, name, "fpext")) 876 kit_cg_fpext(p->cg, ty); 877 else if (toy_sym_is(p, name, "fptrunc")) 878 kit_cg_fptrunc(p->cg, ty); 879 p->last_type = result_toy_type; 880 return ty; 881 } 882 883 if (toy_sym_is(p, name, "sint_to_float") || 884 toy_sym_is(p, name, "uint_to_float") || 885 toy_sym_is(p, name, "float_to_sint") || 886 toy_sym_is(p, name, "float_to_uint")) { 887 KitCgTypeId src_ty; 888 KitCgRounding rounding; 889 if (!toy_parser_expect(p, TOK_LT)) return KIT_CG_TYPE_NONE; 890 ty = toy_parse_type(p); 891 if (ty == KIT_CG_TYPE_NONE || !toy_parser_expect(p, TOK_GT) || 892 !toy_parser_expect(p, TOK_LPAREN)) 893 return KIT_CG_TYPE_NONE; 894 src_ty = toy_parse_expr(p); 895 if (src_ty == KIT_CG_TYPE_NONE || !toy_expect_comma(p) || 896 !toy_parse_rounding_const(p, &rounding) || 897 !toy_parser_expect(p, TOK_RPAREN)) { 898 return KIT_CG_TYPE_NONE; 899 } 900 (void)src_ty; 901 if (toy_sym_is(p, name, "sint_to_float")) 902 kit_cg_sint_to_float(p->cg, ty, rounding); 903 else if (toy_sym_is(p, name, "uint_to_float")) 904 kit_cg_uint_to_float(p->cg, ty, rounding); 905 else if (toy_sym_is(p, name, "float_to_sint")) 906 kit_cg_float_to_sint(p->cg, ty, rounding); 907 else 908 kit_cg_float_to_uint(p->cg, ty, rounding); 909 return ty; 910 } 911 912 if (toy_sym_is(p, name, "assume_aligned")) { 913 KitCgTypeId ptr_ty; 914 int64_t align; 915 if (!toy_parser_expect(p, TOK_LT)) return KIT_CG_TYPE_NONE; 916 ty = toy_parse_type(p); 917 if (ty == KIT_CG_TYPE_NONE || !toy_parser_expect(p, TOK_GT) || 918 !toy_parser_expect(p, TOK_LPAREN)) 919 return KIT_CG_TYPE_NONE; 920 ptr_ty = toy_parse_expr(p); 921 if (ptr_ty == KIT_CG_TYPE_NONE || !toy_expect_comma(p) || 922 !toy_parse_number_arg(p, &align) || !toy_parser_expect(p, TOK_RPAREN)) 923 return KIT_CG_TYPE_NONE; 924 if (ptr_ty != ty || !toy_type_is_ptr(p, ty) || align <= 0) { 925 toy_error(p, p->cur.loc, "invalid assume_aligned arguments"); 926 return KIT_CG_TYPE_NONE; 927 } 928 kit_cg_push_int(p->cg, (uint64_t)align, p->size_type); 929 kit_cg_intrinsic(p->cg, KIT_CG_INTRIN_ASSUME_ALIGNED, 2, ty); 930 return ty; 931 } 932 933 if (toy_sym_is(p, name, "sizeof") || toy_sym_is(p, name, "alignof")) { 934 int is_align = toy_sym_is(p, name, "alignof"); 935 if (!toy_parser_expect(p, TOK_LT)) return KIT_CG_TYPE_NONE; 936 ty = toy_parse_type(p); 937 if (ty == KIT_CG_TYPE_NONE || !toy_parser_expect(p, TOK_GT) || 938 !toy_parser_expect(p, TOK_LPAREN) || 939 !toy_parser_expect(p, TOK_RPAREN)) { 940 toy_error(p, p->cur.loc, "expected type query form"); 941 return KIT_CG_TYPE_NONE; 942 } 943 kit_cg_push_int( 944 p->cg, 945 is_align ? kit_cg_type_align(p->c, ty) : kit_cg_type_size(p->c, ty), 946 p->size_type); 947 return p->size_type; 948 } 949 950 if (toy_sym_is(p, name, "offsetof")) { 951 uint32_t i, nfields; 952 uint64_t off = 0; 953 int found = 0; 954 KitSym field_name = 0; 955 int64_t tuple_index = -1; 956 if (!toy_parser_expect(p, TOK_LT)) return KIT_CG_TYPE_NONE; 957 ty = toy_parse_type(p); 958 if (ty == KIT_CG_TYPE_NONE || !toy_parser_expect(p, TOK_GT) || 959 !toy_parser_expect(p, TOK_LPAREN) || 960 (p->cur.kind != TOK_IDENT && 961 !(p->cur.kind == TOK_NUMBER && !p->cur.is_float))) { 962 toy_error(p, p->cur.loc, "expected offsetof<T>(field)"); 963 return KIT_CG_TYPE_NONE; 964 } 965 if (p->cur.kind == TOK_NUMBER) 966 tuple_index = p->cur.int_value; 967 else 968 field_name = toy_tok_sym(p, p->cur); 969 toy_parser_advance(p); 970 if (!toy_parser_expect(p, TOK_RPAREN)) return KIT_CG_TYPE_NONE; 971 if (kit_cg_type_kind(p->c, ty) != KIT_CG_TYPE_RECORD) { 972 toy_error(p, p->cur.loc, "offsetof expects a record type"); 973 return KIT_CG_TYPE_NONE; 974 } 975 nfields = kit_cg_type_record_nfields(p->c, ty); 976 if (tuple_index >= 0) { 977 if (tuple_index >= (int64_t)nfields || 978 kit_cg_type_record_field(p->c, ty, (uint32_t)tuple_index, NULL, 979 &off) != 0) { 980 toy_error(p, p->cur.loc, "invalid tuple field"); 981 return KIT_CG_TYPE_NONE; 982 } 983 found = 1; 984 } else { 985 for (i = 0; i < nfields; ++i) { 986 KitCgField field; 987 uint64_t field_off = 0; 988 if (kit_cg_type_record_field(p->c, ty, i, &field, &field_off) == 0 && 989 field.name == field_name) { 990 off = field_off; 991 found = 1; 992 break; 993 } 994 } 995 if (!found) { 996 toy_error(p, p->cur.loc, "unknown record field"); 997 return KIT_CG_TYPE_NONE; 998 } 999 } 1000 kit_cg_push_int(p->cg, off, p->size_type); 1001 return p->size_type; 1002 } 1003 1004 if (toy_sym_is(p, name, "va_arg")) { 1005 if (!toy_parser_expect(p, TOK_LT)) return KIT_CG_TYPE_NONE; 1006 ty = toy_parse_type(p); 1007 if (ty == KIT_CG_TYPE_NONE || !toy_parser_expect(p, TOK_GT) || 1008 !toy_parser_expect(p, TOK_LPAREN) || !toy_parse_va_list_addr_arg(p) || 1009 !toy_parser_expect(p, TOK_RPAREN)) 1010 return KIT_CG_TYPE_NONE; 1011 kit_cg_vararg_next(p->cg, ty); 1012 return ty; 1013 } 1014 1015 { 1016 int atomic_recognized = 0; 1017 KitCgTypeId atomic_ty = 1018 toy_parse_atomic_generic_builtin(p, name, &atomic_recognized); 1019 if (atomic_recognized) return atomic_ty; 1020 } 1021 1022 if (toy_sym_is(p, name, "add_overflow") || 1023 toy_sym_is(p, name, "sub_overflow") || 1024 toy_sym_is(p, name, "mul_overflow")) { 1025 KitCgTypeId lhs_ty, rhs_ty, rec_ty; 1026 KitCgField fields[2]; 1027 KitCgLocal rec_slot; 1028 KitCgIntrinsic intrin = KIT_CG_INTRIN_SADD_OVERFLOW; 1029 if (toy_sym_is(p, name, "sub_overflow")) 1030 intrin = KIT_CG_INTRIN_SSUB_OVERFLOW; 1031 else if (toy_sym_is(p, name, "mul_overflow")) 1032 intrin = KIT_CG_INTRIN_SMUL_OVERFLOW; 1033 if (!toy_parser_expect(p, TOK_LT)) return KIT_CG_TYPE_NONE; 1034 ty = toy_parse_type(p); 1035 if (ty == KIT_CG_TYPE_NONE || !toy_parser_expect(p, TOK_GT) || 1036 !toy_parser_expect(p, TOK_LPAREN)) 1037 return KIT_CG_TYPE_NONE; 1038 lhs_ty = toy_parse_expr(p); 1039 if (lhs_ty == KIT_CG_TYPE_NONE || !toy_expect_comma(p)) 1040 return KIT_CG_TYPE_NONE; 1041 rhs_ty = toy_parse_expr(p); 1042 if (rhs_ty == KIT_CG_TYPE_NONE || !toy_parser_expect(p, TOK_RPAREN)) 1043 return KIT_CG_TYPE_NONE; 1044 if (!toy_type_is_intlike(p, ty) || 1045 !toy_type_can_implicitly_cast(p, lhs_ty, ty) || 1046 !toy_type_can_implicitly_cast(p, rhs_ty, ty)) { 1047 toy_error(p, p->cur.loc, "overflow operand type mismatch"); 1048 return KIT_CG_TYPE_NONE; 1049 } 1050 if (lhs_ty != ty) { 1051 kit_cg_swap(p->cg); 1052 if (!toy_emit_implicit_cast(p, lhs_ty, ty)) return KIT_CG_TYPE_NONE; 1053 kit_cg_swap(p->cg); 1054 } 1055 if (rhs_ty != ty && !toy_emit_implicit_cast(p, rhs_ty, ty)) 1056 return KIT_CG_TYPE_NONE; 1057 kit_cg_intrinsic(p->cg, intrin, 2, ty); 1058 memset(fields, 0, sizeof fields); 1059 fields[0].name = kit_sym_intern(p->c, KIT_SLICE_LIT("value")); 1060 fields[0].type = ty; 1061 fields[1].name = kit_sym_intern(p->c, KIT_SLICE_LIT("overflow")); 1062 fields[1].type = toy_builtin_type(p, KIT_CG_BUILTIN_BOOL); 1063 rec_ty = kit_cg_type_record(p->c, 0, fields, 2); 1064 rec_slot = kit_cg_local(p->cg, rec_ty, toy_slot_attrs(0)); 1065 { 1066 uint64_t f0_off = 0, f1_off = 0; 1067 kit_cg_type_record_field(p->c, rec_ty, 0, NULL, &f0_off); 1068 kit_cg_type_record_field(p->c, rec_ty, 1, NULL, &f1_off); 1069 kit_cg_push_local(p->cg, rec_slot); 1070 kit_cg_addr(p->cg); 1071 kit_cg_deref(p->cg, (int64_t)f1_off); 1072 kit_cg_swap(p->cg); 1073 kit_cg_store(p->cg, toy_mem_access(p, fields[1].type)); 1074 kit_cg_push_local(p->cg, rec_slot); 1075 kit_cg_addr(p->cg); 1076 kit_cg_deref(p->cg, (int64_t)f0_off); 1077 kit_cg_swap(p->cg); 1078 kit_cg_store(p->cg, toy_mem_access(p, fields[0].type)); 1079 } 1080 /* Record result lives as a pointer VALUE (its address) on the stack, the 1081 * shape record field-access / record-copy consume downstream. */ 1082 kit_cg_push_local_addr(p->cg, rec_slot); 1083 return rec_ty; 1084 } 1085 1086 *recognized = 0; 1087 return KIT_CG_TYPE_NONE; 1088 } 1089 1090 /* memcpy and memmove are identical except for the constant-size emission: 1091 * memcpy lowers to kit_cg_memcpy, memmove to kit_cg_memmove. The dynamic path 1092 * is byte-for-byte shared (both emit a forward element loop). */ 1093 static KitCgTypeId toy_parse_mem_copy_move(ToyParser* p, int is_move) { 1094 KitCgTypeId dst, src; 1095 int64_t size = 0, align = 0; 1096 int dynamic_size = 0, dynamic_align = 0; 1097 KitCgLocal dst_local = KIT_CG_LOCAL_NONE; 1098 KitCgLocal src_local = KIT_CG_LOCAL_NONE; 1099 KitCgLocal size_local = KIT_CG_LOCAL_NONE; 1100 KitCgMemAccess access; 1101 KitCgTypeId u8_ty = toy_builtin_type(p, KIT_CG_BUILTIN_I8); 1102 KitCgTypeId u8_ptr_ty = kit_cg_type_ptr(p->c, u8_ty, 0); 1103 toy_parser_advance(p); 1104 dst = toy_parse_expr(p); 1105 if (dst == KIT_CG_TYPE_NONE || !toy_expect_comma(p)) return KIT_CG_TYPE_NONE; 1106 src = toy_parse_expr(p); 1107 if (src == KIT_CG_TYPE_NONE || !toy_expect_comma(p)) return KIT_CG_TYPE_NONE; 1108 if (p->cur.kind == TOK_NUMBER && !p->cur.is_float) { 1109 if (!toy_parse_number_arg(p, &size)) return KIT_CG_TYPE_NONE; 1110 } else { 1111 KitCgTypeId size_ty = toy_parse_expr(p); 1112 if (size_ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE; 1113 if (!toy_type_can_implicitly_cast(p, size_ty, p->size_type)) { 1114 toy_error(p, p->cur.loc, "memory size must be usize"); 1115 return KIT_CG_TYPE_NONE; 1116 } 1117 if (!toy_emit_implicit_cast(p, size_ty, p->size_type)) 1118 return KIT_CG_TYPE_NONE; 1119 dynamic_size = 1; 1120 size_local = kit_cg_local(p->cg, p->size_type, toy_slot_attrs(0)); 1121 toy_store_top_to_local(p, size_local, p->size_type); 1122 } 1123 if (!toy_parse_memory_align_operand(p, &align, &dynamic_align)) 1124 return KIT_CG_TYPE_NONE; 1125 access = toy_mem_access_align(p, p->int_type, (uint32_t)align); 1126 if (!toy_parse_mem_flags_tail(p, &access)) return KIT_CG_TYPE_NONE; 1127 if (!toy_parser_expect(p, TOK_RPAREN)) return KIT_CG_TYPE_NONE; 1128 if (dynamic_size || dynamic_align) { 1129 if (!dynamic_size) { 1130 size_local = kit_cg_local(p->cg, p->size_type, toy_slot_attrs(0)); 1131 toy_store_const_to_local(p, size_local, p->size_type, (uint64_t)size); 1132 } 1133 src_local = kit_cg_local(p->cg, u8_ptr_ty, toy_slot_attrs(0)); 1134 kit_cg_bitcast(p->cg, u8_ptr_ty); 1135 toy_store_top_to_local(p, src_local, u8_ptr_ty); 1136 dst_local = kit_cg_local(p->cg, u8_ptr_ty, toy_slot_attrs(0)); 1137 kit_cg_bitcast(p->cg, u8_ptr_ty); 1138 toy_store_top_to_local(p, dst_local, u8_ptr_ty); 1139 toy_emit_dynamic_memory_loop(p, dst_local, src_local, size_local, 0, 0); 1140 return toy_builtin_type(p, KIT_CG_BUILTIN_VOID); 1141 } 1142 if (is_move) 1143 kit_cg_memmove(p->cg, (uint64_t)size, access, access); 1144 else 1145 kit_cg_memcpy(p->cg, (uint64_t)size, access, access); 1146 return toy_builtin_type(p, KIT_CG_BUILTIN_VOID); 1147 } 1148 1149 KitCgTypeId toy_parse_memory_builtin_call(ToyParser* p, KitSym name, 1150 int* recognized) { 1151 *recognized = 1; 1152 1153 if (toy_sym_is(p, name, "memset")) { 1154 KitCgTypeId dst; 1155 int64_t val, size = 0, align = 0; 1156 int dynamic_size = 0, dynamic_align = 0; 1157 KitCgLocal dst_local = KIT_CG_LOCAL_NONE; 1158 KitCgLocal size_local = KIT_CG_LOCAL_NONE; 1159 KitCgMemAccess access; 1160 KitCgTypeId u8_ty = toy_builtin_type(p, KIT_CG_BUILTIN_I8); 1161 KitCgTypeId u8_ptr_ty = kit_cg_type_ptr(p->c, u8_ty, 0); 1162 toy_parser_advance(p); 1163 dst = toy_parse_expr(p); 1164 if (dst == KIT_CG_TYPE_NONE || !toy_expect_comma(p) || 1165 !toy_parse_number_arg(p, &val) || !toy_expect_comma(p)) 1166 return KIT_CG_TYPE_NONE; 1167 if (p->cur.kind == TOK_NUMBER && !p->cur.is_float) { 1168 if (!toy_parse_number_arg(p, &size)) return KIT_CG_TYPE_NONE; 1169 } else { 1170 KitCgTypeId size_ty = toy_parse_expr(p); 1171 if (size_ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE; 1172 if (!toy_type_can_implicitly_cast(p, size_ty, p->size_type)) { 1173 toy_error(p, p->cur.loc, "memory size must be usize"); 1174 return KIT_CG_TYPE_NONE; 1175 } 1176 if (!toy_emit_implicit_cast(p, size_ty, p->size_type)) 1177 return KIT_CG_TYPE_NONE; 1178 dynamic_size = 1; 1179 size_local = kit_cg_local(p->cg, p->size_type, toy_slot_attrs(0)); 1180 toy_store_top_to_local(p, size_local, p->size_type); 1181 } 1182 if (!toy_parse_memory_align_operand(p, &align, &dynamic_align)) 1183 return KIT_CG_TYPE_NONE; 1184 access = toy_mem_access_align(p, p->int_type, (uint32_t)align); 1185 if (!toy_parse_mem_flags_tail(p, &access)) return KIT_CG_TYPE_NONE; 1186 if (!toy_parser_expect(p, TOK_RPAREN)) return KIT_CG_TYPE_NONE; 1187 if (dynamic_size || dynamic_align) { 1188 if (val < 0 || val > 255) { 1189 toy_error(p, p->cur.loc, "memset value out of range"); 1190 return KIT_CG_TYPE_NONE; 1191 } 1192 if (!dynamic_size) { 1193 size_local = kit_cg_local(p->cg, p->size_type, toy_slot_attrs(0)); 1194 toy_store_const_to_local(p, size_local, p->size_type, (uint64_t)size); 1195 } 1196 dst_local = kit_cg_local(p->cg, u8_ptr_ty, toy_slot_attrs(0)); 1197 kit_cg_bitcast(p->cg, u8_ptr_ty); 1198 toy_store_top_to_local(p, dst_local, u8_ptr_ty); 1199 toy_emit_dynamic_memory_loop(p, dst_local, KIT_CG_LOCAL_NONE, size_local, 1200 1, (uint8_t)val); 1201 return toy_builtin_type(p, KIT_CG_BUILTIN_VOID); 1202 } 1203 kit_cg_memset(p->cg, (uint8_t)val, (uint64_t)size, access); 1204 return toy_builtin_type(p, KIT_CG_BUILTIN_VOID); 1205 } 1206 1207 if (toy_sym_is(p, name, "memcpy")) return toy_parse_mem_copy_move(p, 0); 1208 1209 if (toy_sym_is(p, name, "memmove")) return toy_parse_mem_copy_move(p, 1); 1210 1211 if (toy_sym_is(p, name, "atomic_fence")) { 1212 KitCgMemOrder order; 1213 if (!toy_parser_expect(p, TOK_LPAREN) || !toy_parse_mem_order(p, &order) || 1214 !toy_parser_expect(p, TOK_RPAREN)) 1215 return KIT_CG_TYPE_NONE; 1216 kit_cg_atomic_fence(p->cg, order); 1217 return toy_builtin_type(p, KIT_CG_BUILTIN_VOID); 1218 } 1219 1220 *recognized = 0; 1221 return KIT_CG_TYPE_NONE; 1222 } 1223 1224 KitCgTypeId toy_parse_atomic_generic_builtin(ToyParser* p, KitSym name, 1225 int* recognized) { 1226 KitCgTypeId ty; 1227 *recognized = 1; 1228 1229 if (toy_sym_is(p, name, "atomic_load")) { 1230 KitCgTypeId ptr_ty; 1231 KitCgMemOrder order; 1232 KitCgMemAccess access; 1233 if (!toy_parser_expect(p, TOK_LT)) return KIT_CG_TYPE_NONE; 1234 ty = toy_parse_type(p); 1235 if (ty == KIT_CG_TYPE_NONE || !toy_parser_expect(p, TOK_GT) || 1236 !toy_parser_expect(p, TOK_LPAREN)) 1237 return KIT_CG_TYPE_NONE; 1238 ptr_ty = toy_parse_expr(p); 1239 if (ptr_ty == KIT_CG_TYPE_NONE || !toy_expect_comma(p) || 1240 !toy_parse_mem_order(p, &order)) 1241 return KIT_CG_TYPE_NONE; 1242 access = toy_mem_access(p, ty); 1243 if (!toy_parse_optional_access_arg(p, &access) || 1244 !toy_parser_expect(p, TOK_RPAREN)) 1245 return KIT_CG_TYPE_NONE; 1246 if (!toy_type_is_ptr(p, ptr_ty) || 1247 kit_cg_type_ptr_pointee(p->c, ptr_ty) != ty) { 1248 toy_error(p, p->cur.loc, "atomic_load pointer type mismatch"); 1249 return KIT_CG_TYPE_NONE; 1250 } 1251 kit_cg_atomic_load(p->cg, access, order); 1252 return ty; 1253 } 1254 1255 if (toy_sym_is(p, name, "atomic_store")) { 1256 KitCgTypeId ptr_ty, val_ty; 1257 KitCgMemOrder order; 1258 KitCgMemAccess access; 1259 if (!toy_parser_expect(p, TOK_LT)) return KIT_CG_TYPE_NONE; 1260 ty = toy_parse_type(p); 1261 if (ty == KIT_CG_TYPE_NONE || !toy_parser_expect(p, TOK_GT) || 1262 !toy_parser_expect(p, TOK_LPAREN)) 1263 return KIT_CG_TYPE_NONE; 1264 ptr_ty = toy_parse_expr(p); 1265 if (ptr_ty == KIT_CG_TYPE_NONE || !toy_expect_comma(p)) 1266 return KIT_CG_TYPE_NONE; 1267 val_ty = toy_parse_expr(p); 1268 if (val_ty == KIT_CG_TYPE_NONE || !toy_expect_comma(p) || 1269 !toy_parse_mem_order(p, &order)) 1270 return KIT_CG_TYPE_NONE; 1271 access = toy_mem_access(p, ty); 1272 if (!toy_parse_optional_access_arg(p, &access) || 1273 !toy_parser_expect(p, TOK_RPAREN)) 1274 return KIT_CG_TYPE_NONE; 1275 if (!toy_type_is_ptr(p, ptr_ty) || 1276 kit_cg_type_ptr_pointee(p->c, ptr_ty) != ty || 1277 !toy_type_can_implicitly_cast(p, val_ty, ty)) { 1278 toy_error(p, p->cur.loc, "atomic_store type mismatch"); 1279 return KIT_CG_TYPE_NONE; 1280 } 1281 if (val_ty != ty && !toy_emit_implicit_cast(p, val_ty, ty)) 1282 return KIT_CG_TYPE_NONE; 1283 kit_cg_atomic_store(p->cg, access, order); 1284 return toy_builtin_type(p, KIT_CG_BUILTIN_VOID); 1285 } 1286 1287 if (toy_sym_is(p, name, "atomic_rmw")) { 1288 KitCgAtomicOp op; 1289 KitCgTypeId ptr_ty, val_ty; 1290 KitCgMemOrder order; 1291 KitCgMemAccess access; 1292 if (!toy_parser_expect(p, TOK_LT)) return KIT_CG_TYPE_NONE; 1293 ty = toy_parse_type(p); 1294 if (ty == KIT_CG_TYPE_NONE || !toy_parser_expect(p, TOK_GT) || 1295 !toy_parser_expect(p, TOK_LPAREN) || !toy_parse_atomic_op(p, &op) || 1296 !toy_expect_comma(p)) 1297 return KIT_CG_TYPE_NONE; 1298 ptr_ty = toy_parse_expr(p); 1299 if (ptr_ty == KIT_CG_TYPE_NONE || !toy_expect_comma(p)) 1300 return KIT_CG_TYPE_NONE; 1301 val_ty = toy_parse_expr(p); 1302 if (val_ty == KIT_CG_TYPE_NONE || !toy_expect_comma(p) || 1303 !toy_parse_mem_order(p, &order)) 1304 return KIT_CG_TYPE_NONE; 1305 access = toy_mem_access(p, ty); 1306 if (!toy_parse_optional_access_arg(p, &access) || 1307 !toy_parser_expect(p, TOK_RPAREN)) 1308 return KIT_CG_TYPE_NONE; 1309 if (!toy_type_is_ptr(p, ptr_ty) || 1310 kit_cg_type_ptr_pointee(p->c, ptr_ty) != ty || 1311 !toy_type_can_implicitly_cast(p, val_ty, ty)) { 1312 toy_error(p, p->cur.loc, "atomic_rmw type mismatch"); 1313 return KIT_CG_TYPE_NONE; 1314 } 1315 if (val_ty != ty && !toy_emit_implicit_cast(p, val_ty, ty)) 1316 return KIT_CG_TYPE_NONE; 1317 kit_cg_atomic_rmw(p->cg, access, op, order); 1318 return ty; 1319 } 1320 1321 if (toy_sym_is(p, name, "atomic_cmpxchg")) { 1322 KitCgTypeId ptr_ty, expected_ty, desired_ty, rec_ty; 1323 KitCgMemOrder success_order, failure_order; 1324 int weak; 1325 KitCgMemAccess access; 1326 KitCgField fields[2]; 1327 KitCgLocal rec_slot; 1328 if (!toy_parser_expect(p, TOK_LT)) return KIT_CG_TYPE_NONE; 1329 ty = toy_parse_type(p); 1330 if (ty == KIT_CG_TYPE_NONE || !toy_parser_expect(p, TOK_GT) || 1331 !toy_parser_expect(p, TOK_LPAREN)) 1332 return KIT_CG_TYPE_NONE; 1333 ptr_ty = toy_parse_expr(p); 1334 if (ptr_ty == KIT_CG_TYPE_NONE || !toy_expect_comma(p)) 1335 return KIT_CG_TYPE_NONE; 1336 expected_ty = toy_parse_expr(p); 1337 if (expected_ty == KIT_CG_TYPE_NONE) 1338 return KIT_CG_TYPE_NONE; 1339 if (!toy_type_can_implicitly_cast(p, expected_ty, ty)) { 1340 toy_error(p, p->cur.loc, "atomic_cmpxchg type mismatch"); 1341 return KIT_CG_TYPE_NONE; 1342 } 1343 if (expected_ty != ty && !toy_emit_implicit_cast(p, expected_ty, ty)) 1344 return KIT_CG_TYPE_NONE; 1345 expected_ty = ty; 1346 if (!toy_expect_comma(p)) return KIT_CG_TYPE_NONE; 1347 desired_ty = toy_parse_expr(p); 1348 if (desired_ty == KIT_CG_TYPE_NONE || !toy_expect_comma(p) || 1349 !toy_parse_mem_order(p, &success_order) || !toy_expect_comma(p) || 1350 !toy_parse_mem_order(p, &failure_order) || !toy_expect_comma(p) || 1351 !toy_parse_cmpxchg_strength(p, &weak)) 1352 return KIT_CG_TYPE_NONE; 1353 access = toy_mem_access(p, ty); 1354 if (!toy_parse_optional_access_arg(p, &access) || 1355 !toy_parser_expect(p, TOK_RPAREN)) 1356 return KIT_CG_TYPE_NONE; 1357 if (!toy_type_is_ptr(p, ptr_ty) || 1358 kit_cg_type_ptr_pointee(p->c, ptr_ty) != ty || expected_ty != ty || 1359 !toy_type_can_implicitly_cast(p, desired_ty, ty)) { 1360 toy_error(p, p->cur.loc, "atomic_cmpxchg type mismatch"); 1361 return KIT_CG_TYPE_NONE; 1362 } 1363 if (desired_ty != ty && !toy_emit_implicit_cast(p, desired_ty, ty)) 1364 return KIT_CG_TYPE_NONE; 1365 kit_cg_atomic_cmpxchg(p->cg, access, success_order, failure_order, weak); 1366 memset(fields, 0, sizeof fields); 1367 fields[0].name = kit_sym_intern(p->c, KIT_SLICE_LIT("prior")); 1368 fields[0].type = ty; 1369 fields[1].name = kit_sym_intern(p->c, KIT_SLICE_LIT("ok")); 1370 fields[1].type = toy_builtin_type(p, KIT_CG_BUILTIN_BOOL); 1371 rec_ty = kit_cg_type_record(p->c, 0, fields, 2); 1372 rec_slot = kit_cg_local(p->cg, rec_ty, toy_slot_attrs(0)); 1373 { 1374 uint64_t f0_off = 0, f1_off = 0; 1375 kit_cg_type_record_field(p->c, rec_ty, 0, NULL, &f0_off); 1376 kit_cg_type_record_field(p->c, rec_ty, 1, NULL, &f1_off); 1377 kit_cg_push_local(p->cg, rec_slot); 1378 kit_cg_addr(p->cg); 1379 kit_cg_deref(p->cg, (int64_t)f1_off); 1380 kit_cg_swap(p->cg); 1381 kit_cg_store(p->cg, toy_mem_access(p, fields[1].type)); 1382 kit_cg_push_local(p->cg, rec_slot); 1383 kit_cg_addr(p->cg); 1384 kit_cg_deref(p->cg, (int64_t)f0_off); 1385 kit_cg_swap(p->cg); 1386 kit_cg_store(p->cg, toy_mem_access(p, fields[0].type)); 1387 } 1388 /* Record result lives as a pointer VALUE (its address) on the stack. */ 1389 kit_cg_push_local_addr(p->cg, rec_slot); 1390 return rec_ty; 1391 } 1392 1393 if (toy_sym_is(p, name, "atomic_is_legal")) { 1394 KitCgMemOrder order; 1395 KitCgMemAccess access; 1396 if (!toy_parser_expect(p, TOK_LT)) return KIT_CG_TYPE_NONE; 1397 ty = toy_parse_type(p); 1398 if (ty == KIT_CG_TYPE_NONE || !toy_parser_expect(p, TOK_GT) || 1399 !toy_parser_expect(p, TOK_LPAREN) || !toy_parse_mem_order(p, &order)) 1400 return KIT_CG_TYPE_NONE; 1401 access = toy_mem_access(p, ty); 1402 if (!toy_parse_optional_access_arg(p, &access) || 1403 !toy_parser_expect(p, TOK_RPAREN)) 1404 return KIT_CG_TYPE_NONE; 1405 kit_cg_push_int(p->cg, 1406 kit_cg_atomic_is_legal(p->c, access, order) ? 1u : 0u, 1407 toy_builtin_type(p, KIT_CG_BUILTIN_BOOL)); 1408 return toy_builtin_type(p, KIT_CG_BUILTIN_BOOL); 1409 } 1410 1411 if (toy_sym_is(p, name, "atomic_is_lock_free")) { 1412 KitCgMemAccess access; 1413 if (!toy_parser_expect(p, TOK_LT)) return KIT_CG_TYPE_NONE; 1414 ty = toy_parse_type(p); 1415 if (ty == KIT_CG_TYPE_NONE || !toy_parser_expect(p, TOK_GT) || 1416 !toy_parser_expect(p, TOK_LPAREN)) 1417 return KIT_CG_TYPE_NONE; 1418 access = toy_mem_access(p, ty); 1419 if (p->cur.kind != TOK_RPAREN && !toy_parse_access_group(p, &access)) 1420 return KIT_CG_TYPE_NONE; 1421 if (!toy_parser_expect(p, TOK_RPAREN)) return KIT_CG_TYPE_NONE; 1422 kit_cg_push_int(p->cg, kit_cg_atomic_is_lock_free(p->c, access) ? 1u : 0u, 1423 toy_builtin_type(p, KIT_CG_BUILTIN_BOOL)); 1424 return toy_builtin_type(p, KIT_CG_BUILTIN_BOOL); 1425 } 1426 1427 *recognized = 0; 1428 return KIT_CG_TYPE_NONE; 1429 } 1430 1431 KitCgTypeId toy_parse_low_level_builtin_call(ToyParser* p, KitSym name, 1432 int* recognized) { 1433 *recognized = 1; 1434 1435 if (toy_sym_is(p, name, "syscall")) { 1436 uint32_t nargs = 0; 1437 KitCgTypeId long_ty = p->int_type; 1438 if (!toy_parser_expect(p, TOK_LPAREN)) return KIT_CG_TYPE_NONE; 1439 if (!toy_parser_match(p, TOK_RPAREN)) { 1440 for (;;) { 1441 KitCgTypeId arg_ty = toy_parse_expr(p); 1442 if (arg_ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE; 1443 if (!toy_type_is_intlike(p, arg_ty) && !toy_type_is_ptr(p, arg_ty)) { 1444 toy_error(p, p->cur.loc, 1445 "syscall arguments must be integer or pointer"); 1446 return KIT_CG_TYPE_NONE; 1447 } 1448 if (arg_ty != long_ty && !toy_emit_cast(p, arg_ty, long_ty)) 1449 return KIT_CG_TYPE_NONE; 1450 nargs++; 1451 if (nargs > 7u) { 1452 toy_error(p, p->cur.loc, "too many syscall arguments"); 1453 return KIT_CG_TYPE_NONE; 1454 } 1455 if (!toy_parser_match(p, TOK_COMMA)) break; 1456 } 1457 if (!toy_parser_expect(p, TOK_RPAREN)) return KIT_CG_TYPE_NONE; 1458 } 1459 if (nargs == 0) { 1460 toy_error(p, p->cur.loc, "syscall expects a syscall number"); 1461 return KIT_CG_TYPE_NONE; 1462 } 1463 if (!kit_cg_target_supports_intrinsic(p->c, KIT_CG_INTRIN_SYSCALL)) 1464 return toy_unsupported_intrinsic(p); 1465 kit_cg_intrinsic(p->cg, KIT_CG_INTRIN_SYSCALL, nargs, long_ty); 1466 return long_ty; 1467 } 1468 1469 if (toy_sym_is(p, name, "setjmp")) { 1470 KitCgTypeId buf_ty; 1471 if (!toy_parser_expect(p, TOK_LPAREN)) return KIT_CG_TYPE_NONE; 1472 buf_ty = toy_parse_expr(p); 1473 if (buf_ty == KIT_CG_TYPE_NONE || !toy_parser_expect(p, TOK_RPAREN)) 1474 return KIT_CG_TYPE_NONE; 1475 if (!toy_type_is_ptr(p, buf_ty)) { 1476 toy_error(p, p->cur.loc, "setjmp expects pointer buffer"); 1477 return KIT_CG_TYPE_NONE; 1478 } 1479 return toy_unsupported_intrinsic(p); 1480 } 1481 1482 if (toy_sym_is(p, name, "longjmp")) { 1483 KitCgTypeId buf_ty, value_ty; 1484 if (!toy_parser_expect(p, TOK_LPAREN)) return KIT_CG_TYPE_NONE; 1485 buf_ty = toy_parse_expr(p); 1486 if (buf_ty == KIT_CG_TYPE_NONE || !toy_expect_comma(p)) 1487 return KIT_CG_TYPE_NONE; 1488 value_ty = toy_parse_expr(p); 1489 if (value_ty == KIT_CG_TYPE_NONE || !toy_parser_expect(p, TOK_RPAREN)) 1490 return KIT_CG_TYPE_NONE; 1491 if (!toy_type_is_ptr(p, buf_ty) || !toy_type_is_intlike(p, value_ty)) { 1492 toy_error(p, p->cur.loc, 1493 "longjmp expects pointer buffer and integer value"); 1494 return KIT_CG_TYPE_NONE; 1495 } 1496 return toy_unsupported_intrinsic(p); 1497 } 1498 1499 if (toy_sym_is(p, name, "wfi") || toy_sym_is(p, name, "wfe") || 1500 toy_sym_is(p, name, "sev")) { 1501 KitCgIntrinsic intrin = KIT_CG_INTRIN_WFI; 1502 if (toy_sym_is(p, name, "wfe")) 1503 intrin = KIT_CG_INTRIN_WFE; 1504 else if (toy_sym_is(p, name, "sev")) 1505 intrin = KIT_CG_INTRIN_SEV; 1506 if (!toy_parser_expect(p, TOK_LPAREN) || !toy_parser_expect(p, TOK_RPAREN)) 1507 return KIT_CG_TYPE_NONE; 1508 if (!kit_cg_target_supports_intrinsic(p->c, intrin)) 1509 return toy_unsupported_intrinsic(p); 1510 kit_cg_intrinsic(p->cg, intrin, 0, 1511 toy_builtin_type(p, KIT_CG_BUILTIN_VOID)); 1512 return toy_builtin_type(p, KIT_CG_BUILTIN_VOID); 1513 } 1514 1515 if (toy_sym_is(p, name, "irq_save")) { 1516 if (!toy_parser_expect(p, TOK_LPAREN) || !toy_parser_expect(p, TOK_RPAREN)) 1517 return KIT_CG_TYPE_NONE; 1518 if (!kit_cg_target_supports_intrinsic(p->c, KIT_CG_INTRIN_IRQ_SAVE)) 1519 return toy_unsupported_intrinsic(p); 1520 kit_cg_intrinsic(p->cg, KIT_CG_INTRIN_IRQ_SAVE, 0, p->size_type); 1521 return p->size_type; 1522 } 1523 1524 if (toy_sym_is(p, name, "irq_restore")) { 1525 KitCgTypeId prev_ty; 1526 if (!toy_parser_expect(p, TOK_LPAREN)) return KIT_CG_TYPE_NONE; 1527 prev_ty = toy_parse_expr(p); 1528 if (prev_ty == KIT_CG_TYPE_NONE || !toy_parser_expect(p, TOK_RPAREN)) 1529 return KIT_CG_TYPE_NONE; 1530 if (!toy_type_can_implicitly_cast(p, prev_ty, p->size_type)) { 1531 toy_error(p, p->cur.loc, "irq_restore expects usize state"); 1532 return KIT_CG_TYPE_NONE; 1533 } 1534 if (!toy_emit_implicit_cast(p, prev_ty, p->size_type)) 1535 return KIT_CG_TYPE_NONE; 1536 if (!kit_cg_target_supports_intrinsic(p->c, KIT_CG_INTRIN_IRQ_RESTORE)) 1537 return toy_unsupported_intrinsic(p); 1538 kit_cg_intrinsic(p->cg, KIT_CG_INTRIN_IRQ_RESTORE, 1, 1539 toy_builtin_type(p, KIT_CG_BUILTIN_VOID)); 1540 return toy_builtin_type(p, KIT_CG_BUILTIN_VOID); 1541 } 1542 1543 if (toy_sym_is(p, name, "dmb") || toy_sym_is(p, name, "dsb")) { 1544 KitCgIntrinsic intrin = 1545 toy_sym_is(p, name, "dsb") ? KIT_CG_INTRIN_DSB : KIT_CG_INTRIN_DMB; 1546 KitCgBarrierScope scope; 1547 if (!toy_parser_expect(p, TOK_LPAREN) || 1548 !toy_parse_barrier_scope(p, &scope) || 1549 !toy_parser_expect(p, TOK_RPAREN)) 1550 return KIT_CG_TYPE_NONE; 1551 if (!kit_cg_target_supports_intrinsic(p->c, intrin)) 1552 return toy_unsupported_intrinsic(p); 1553 /* The barrier domain rides as an immediate operand the backend maps onto 1554 * the arch's barrier-option field. */ 1555 kit_cg_push_int(p->cg, (uint64_t)scope, p->int_type); 1556 kit_cg_intrinsic(p->cg, intrin, 1, 1557 toy_builtin_type(p, KIT_CG_BUILTIN_VOID)); 1558 return toy_builtin_type(p, KIT_CG_BUILTIN_VOID); 1559 } 1560 1561 if (toy_sym_is(p, name, "dcache_clean") || 1562 toy_sym_is(p, name, "dcache_invalidate") || 1563 toy_sym_is(p, name, "dcache_clean_invalidate") || 1564 toy_sym_is(p, name, "icache_invalidate")) { 1565 KitCgTypeId ptr_ty, size_ty; 1566 if (!toy_parser_expect(p, TOK_LPAREN)) return KIT_CG_TYPE_NONE; 1567 ptr_ty = toy_parse_expr(p); 1568 if (ptr_ty == KIT_CG_TYPE_NONE || !toy_expect_comma(p)) 1569 return KIT_CG_TYPE_NONE; 1570 size_ty = toy_parse_expr(p); 1571 if (size_ty == KIT_CG_TYPE_NONE || !toy_parser_expect(p, TOK_RPAREN)) 1572 return KIT_CG_TYPE_NONE; 1573 if (!toy_type_is_ptr(p, ptr_ty) || !toy_type_is_intlike(p, size_ty)) { 1574 toy_error(p, p->cur.loc, 1575 "cache intrinsic expects pointer and integer size"); 1576 return KIT_CG_TYPE_NONE; 1577 } 1578 return toy_unsupported_intrinsic(p); 1579 } 1580 1581 *recognized = 0; 1582 return KIT_CG_TYPE_NONE; 1583 } 1584 1585 KitCgTypeId toy_parse_low_level_generic_builtin(ToyParser* p, KitSym name, 1586 int* recognized) { 1587 KitCgTypeId ty; 1588 *recognized = 1; 1589 1590 if (toy_sym_is(p, name, "coro_switch")) { 1591 KitCgTypeId from_ty, to_ty, value_ty; 1592 if (!toy_parser_expect(p, TOK_LT)) return KIT_CG_TYPE_NONE; 1593 ty = toy_parse_type(p); 1594 if (ty == KIT_CG_TYPE_NONE || !toy_parser_expect(p, TOK_GT) || 1595 !toy_parser_expect(p, TOK_LPAREN)) 1596 return KIT_CG_TYPE_NONE; 1597 from_ty = toy_parse_expr(p); 1598 if (from_ty == KIT_CG_TYPE_NONE || !toy_expect_comma(p)) 1599 return KIT_CG_TYPE_NONE; 1600 to_ty = toy_parse_expr(p); 1601 if (to_ty == KIT_CG_TYPE_NONE || !toy_expect_comma(p)) 1602 return KIT_CG_TYPE_NONE; 1603 value_ty = toy_parse_expr(p); 1604 if (value_ty == KIT_CG_TYPE_NONE || !toy_parser_expect(p, TOK_RPAREN)) 1605 return KIT_CG_TYPE_NONE; 1606 if (!toy_type_is_ptr(p, from_ty) || !toy_type_is_ptr(p, to_ty) || 1607 value_ty != ty) { 1608 toy_error(p, p->cur.loc, 1609 "coro_switch expects pointer contexts and matching value type"); 1610 return KIT_CG_TYPE_NONE; 1611 } 1612 return toy_unsupported_intrinsic(p); 1613 } 1614 1615 *recognized = 0; 1616 return KIT_CG_TYPE_NONE; 1617 }