builtins.c (61905B)
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 { 976 const KitCgRecordLayout* L = kit_cg_type_record_layout(p->c, ty); 977 if (!L) { 978 toy_error(p, p->cur.loc, "offsetof expects a record type"); 979 return KIT_CG_TYPE_NONE; 980 } 981 nfields = L->nfields; 982 if (tuple_index >= 0) { 983 if (tuple_index >= (int64_t)nfields) { 984 toy_error(p, p->cur.loc, "invalid tuple field"); 985 return KIT_CG_TYPE_NONE; 986 } 987 off = L->fields[tuple_index].offset; 988 found = 1; 989 } else { 990 for (i = 0; i < nfields; ++i) { 991 if (L->fields[i].name == field_name) { 992 off = L->fields[i].offset; 993 found = 1; 994 break; 995 } 996 } 997 if (!found) { 998 toy_error(p, p->cur.loc, "unknown record field"); 999 return KIT_CG_TYPE_NONE; 1000 } 1001 } 1002 } 1003 kit_cg_push_int(p->cg, off, p->size_type); 1004 return p->size_type; 1005 } 1006 1007 if (toy_sym_is(p, name, "va_arg")) { 1008 if (!toy_parser_expect(p, TOK_LT)) return KIT_CG_TYPE_NONE; 1009 ty = toy_parse_type(p); 1010 if (ty == KIT_CG_TYPE_NONE || !toy_parser_expect(p, TOK_GT) || 1011 !toy_parser_expect(p, TOK_LPAREN) || !toy_parse_va_list_addr_arg(p) || 1012 !toy_parser_expect(p, TOK_RPAREN)) 1013 return KIT_CG_TYPE_NONE; 1014 kit_cg_vararg_next(p->cg, ty); 1015 return ty; 1016 } 1017 1018 { 1019 int atomic_recognized = 0; 1020 KitCgTypeId atomic_ty = 1021 toy_parse_atomic_generic_builtin(p, name, &atomic_recognized); 1022 if (atomic_recognized) return atomic_ty; 1023 } 1024 1025 if (toy_sym_is(p, name, "add_overflow") || 1026 toy_sym_is(p, name, "sub_overflow") || 1027 toy_sym_is(p, name, "mul_overflow")) { 1028 KitCgTypeId lhs_ty, rhs_ty, rec_ty; 1029 KitCgFieldDesc fields[2]; 1030 KitCgLocal rec_slot; 1031 KitCgIntrinsic intrin = KIT_CG_INTRIN_SADD_OVERFLOW; 1032 if (toy_sym_is(p, name, "sub_overflow")) 1033 intrin = KIT_CG_INTRIN_SSUB_OVERFLOW; 1034 else if (toy_sym_is(p, name, "mul_overflow")) 1035 intrin = KIT_CG_INTRIN_SMUL_OVERFLOW; 1036 if (!toy_parser_expect(p, TOK_LT)) return KIT_CG_TYPE_NONE; 1037 ty = toy_parse_type(p); 1038 if (ty == KIT_CG_TYPE_NONE || !toy_parser_expect(p, TOK_GT) || 1039 !toy_parser_expect(p, TOK_LPAREN)) 1040 return KIT_CG_TYPE_NONE; 1041 lhs_ty = toy_parse_expr(p); 1042 if (lhs_ty == KIT_CG_TYPE_NONE || !toy_expect_comma(p)) 1043 return KIT_CG_TYPE_NONE; 1044 rhs_ty = toy_parse_expr(p); 1045 if (rhs_ty == KIT_CG_TYPE_NONE || !toy_parser_expect(p, TOK_RPAREN)) 1046 return KIT_CG_TYPE_NONE; 1047 if (!toy_type_is_intlike(p, ty) || 1048 !toy_type_can_implicitly_cast(p, lhs_ty, ty) || 1049 !toy_type_can_implicitly_cast(p, rhs_ty, ty)) { 1050 toy_error(p, p->cur.loc, "overflow operand type mismatch"); 1051 return KIT_CG_TYPE_NONE; 1052 } 1053 if (lhs_ty != ty) { 1054 kit_cg_swap(p->cg); 1055 if (!toy_emit_implicit_cast(p, lhs_ty, ty)) return KIT_CG_TYPE_NONE; 1056 kit_cg_swap(p->cg); 1057 } 1058 if (rhs_ty != ty && !toy_emit_implicit_cast(p, rhs_ty, ty)) 1059 return KIT_CG_TYPE_NONE; 1060 kit_cg_intrinsic(p->cg, intrin, 2, ty); 1061 memset(fields, 0, sizeof fields); 1062 fields[0].name = kit_sym_intern(p->c, KIT_SLICE_LIT("value")); 1063 fields[0].type = ty; 1064 fields[1].name = kit_sym_intern(p->c, KIT_SLICE_LIT("overflow")); 1065 fields[1].type = toy_builtin_type(p, KIT_CG_BUILTIN_BOOL); 1066 rec_ty = toy_cg_record_type(p, 0, fields, 2, 0, 0); 1067 rec_slot = kit_cg_local(p->cg, rec_ty, toy_slot_attrs(0)); 1068 { 1069 const KitCgRecordLayout* L = kit_cg_type_record_layout(p->c, rec_ty); 1070 uint64_t f0_off = (L && L->nfields > 0) ? L->fields[0].offset : 0; 1071 uint64_t f1_off = (L && L->nfields > 1) ? L->fields[1].offset : 0; 1072 kit_cg_push_local(p->cg, rec_slot); 1073 kit_cg_addr(p->cg); 1074 kit_cg_deref(p->cg, (int64_t)f1_off); 1075 kit_cg_swap(p->cg); 1076 kit_cg_store(p->cg, toy_mem_access(p, fields[1].type)); 1077 kit_cg_push_local(p->cg, rec_slot); 1078 kit_cg_addr(p->cg); 1079 kit_cg_deref(p->cg, (int64_t)f0_off); 1080 kit_cg_swap(p->cg); 1081 kit_cg_store(p->cg, toy_mem_access(p, fields[0].type)); 1082 } 1083 /* Record result lives as a pointer VALUE (its address) on the stack, the 1084 * shape record field-access / record-copy consume downstream. */ 1085 kit_cg_push_local_addr(p->cg, rec_slot); 1086 return rec_ty; 1087 } 1088 1089 *recognized = 0; 1090 return KIT_CG_TYPE_NONE; 1091 } 1092 1093 /* memcpy and memmove are identical except for the constant-size emission: 1094 * memcpy lowers to kit_cg_memcpy, memmove to kit_cg_memmove. The dynamic path 1095 * is byte-for-byte shared (both emit a forward element loop). */ 1096 static KitCgTypeId toy_parse_mem_copy_move(ToyParser* p, int is_move) { 1097 KitCgTypeId dst, src; 1098 int64_t size = 0, align = 0; 1099 int dynamic_size = 0, dynamic_align = 0; 1100 KitCgLocal dst_local = KIT_CG_LOCAL_NONE; 1101 KitCgLocal src_local = KIT_CG_LOCAL_NONE; 1102 KitCgLocal size_local = KIT_CG_LOCAL_NONE; 1103 KitCgMemAccess access; 1104 KitCgTypeId u8_ty = toy_builtin_type(p, KIT_CG_BUILTIN_I8); 1105 KitCgTypeId u8_ptr_ty = kit_cg_type_ptr(p->c, u8_ty, 0); 1106 toy_parser_advance(p); 1107 dst = toy_parse_expr(p); 1108 if (dst == KIT_CG_TYPE_NONE || !toy_expect_comma(p)) return KIT_CG_TYPE_NONE; 1109 src = toy_parse_expr(p); 1110 if (src == KIT_CG_TYPE_NONE || !toy_expect_comma(p)) return KIT_CG_TYPE_NONE; 1111 if (p->cur.kind == TOK_NUMBER && !p->cur.is_float) { 1112 if (!toy_parse_number_arg(p, &size)) return KIT_CG_TYPE_NONE; 1113 } else { 1114 KitCgTypeId size_ty = toy_parse_expr(p); 1115 if (size_ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE; 1116 if (!toy_type_can_implicitly_cast(p, size_ty, p->size_type)) { 1117 toy_error(p, p->cur.loc, "memory size must be usize"); 1118 return KIT_CG_TYPE_NONE; 1119 } 1120 if (!toy_emit_implicit_cast(p, size_ty, p->size_type)) 1121 return KIT_CG_TYPE_NONE; 1122 dynamic_size = 1; 1123 size_local = kit_cg_local(p->cg, p->size_type, toy_slot_attrs(0)); 1124 toy_store_top_to_local(p, size_local, p->size_type); 1125 } 1126 if (!toy_parse_memory_align_operand(p, &align, &dynamic_align)) 1127 return KIT_CG_TYPE_NONE; 1128 access = toy_mem_access_align(p, p->int_type, (uint32_t)align); 1129 if (!toy_parse_mem_flags_tail(p, &access)) return KIT_CG_TYPE_NONE; 1130 if (!toy_parser_expect(p, TOK_RPAREN)) return KIT_CG_TYPE_NONE; 1131 if (dynamic_size || dynamic_align) { 1132 if (!dynamic_size) { 1133 size_local = kit_cg_local(p->cg, p->size_type, toy_slot_attrs(0)); 1134 toy_store_const_to_local(p, size_local, p->size_type, (uint64_t)size); 1135 } 1136 src_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, src_local, u8_ptr_ty); 1139 dst_local = kit_cg_local(p->cg, u8_ptr_ty, toy_slot_attrs(0)); 1140 kit_cg_bitcast(p->cg, u8_ptr_ty); 1141 toy_store_top_to_local(p, dst_local, u8_ptr_ty); 1142 toy_emit_dynamic_memory_loop(p, dst_local, src_local, size_local, 0, 0); 1143 return toy_builtin_type(p, KIT_CG_BUILTIN_VOID); 1144 } 1145 if (is_move) 1146 kit_cg_memmove(p->cg, (uint64_t)size, access, access); 1147 else 1148 kit_cg_memcpy(p->cg, (uint64_t)size, access, access); 1149 return toy_builtin_type(p, KIT_CG_BUILTIN_VOID); 1150 } 1151 1152 KitCgTypeId toy_parse_memory_builtin_call(ToyParser* p, KitSym name, 1153 int* recognized) { 1154 *recognized = 1; 1155 1156 if (toy_sym_is(p, name, "memset")) { 1157 KitCgTypeId dst; 1158 int64_t val, size = 0, align = 0; 1159 int dynamic_size = 0, dynamic_align = 0; 1160 KitCgLocal dst_local = KIT_CG_LOCAL_NONE; 1161 KitCgLocal size_local = KIT_CG_LOCAL_NONE; 1162 KitCgMemAccess access; 1163 KitCgTypeId u8_ty = toy_builtin_type(p, KIT_CG_BUILTIN_I8); 1164 KitCgTypeId u8_ptr_ty = kit_cg_type_ptr(p->c, u8_ty, 0); 1165 toy_parser_advance(p); 1166 dst = toy_parse_expr(p); 1167 if (dst == KIT_CG_TYPE_NONE || !toy_expect_comma(p) || 1168 !toy_parse_number_arg(p, &val) || !toy_expect_comma(p)) 1169 return KIT_CG_TYPE_NONE; 1170 if (p->cur.kind == TOK_NUMBER && !p->cur.is_float) { 1171 if (!toy_parse_number_arg(p, &size)) return KIT_CG_TYPE_NONE; 1172 } else { 1173 KitCgTypeId size_ty = toy_parse_expr(p); 1174 if (size_ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE; 1175 if (!toy_type_can_implicitly_cast(p, size_ty, p->size_type)) { 1176 toy_error(p, p->cur.loc, "memory size must be usize"); 1177 return KIT_CG_TYPE_NONE; 1178 } 1179 if (!toy_emit_implicit_cast(p, size_ty, p->size_type)) 1180 return KIT_CG_TYPE_NONE; 1181 dynamic_size = 1; 1182 size_local = kit_cg_local(p->cg, p->size_type, toy_slot_attrs(0)); 1183 toy_store_top_to_local(p, size_local, p->size_type); 1184 } 1185 if (!toy_parse_memory_align_operand(p, &align, &dynamic_align)) 1186 return KIT_CG_TYPE_NONE; 1187 access = toy_mem_access_align(p, p->int_type, (uint32_t)align); 1188 if (!toy_parse_mem_flags_tail(p, &access)) return KIT_CG_TYPE_NONE; 1189 if (!toy_parser_expect(p, TOK_RPAREN)) return KIT_CG_TYPE_NONE; 1190 if (dynamic_size || dynamic_align) { 1191 if (val < 0 || val > 255) { 1192 toy_error(p, p->cur.loc, "memset value out of range"); 1193 return KIT_CG_TYPE_NONE; 1194 } 1195 if (!dynamic_size) { 1196 size_local = kit_cg_local(p->cg, p->size_type, toy_slot_attrs(0)); 1197 toy_store_const_to_local(p, size_local, p->size_type, (uint64_t)size); 1198 } 1199 dst_local = kit_cg_local(p->cg, u8_ptr_ty, toy_slot_attrs(0)); 1200 kit_cg_bitcast(p->cg, u8_ptr_ty); 1201 toy_store_top_to_local(p, dst_local, u8_ptr_ty); 1202 toy_emit_dynamic_memory_loop(p, dst_local, KIT_CG_LOCAL_NONE, size_local, 1203 1, (uint8_t)val); 1204 return toy_builtin_type(p, KIT_CG_BUILTIN_VOID); 1205 } 1206 kit_cg_memset(p->cg, (uint8_t)val, (uint64_t)size, access); 1207 return toy_builtin_type(p, KIT_CG_BUILTIN_VOID); 1208 } 1209 1210 if (toy_sym_is(p, name, "memcpy")) return toy_parse_mem_copy_move(p, 0); 1211 1212 if (toy_sym_is(p, name, "memmove")) return toy_parse_mem_copy_move(p, 1); 1213 1214 if (toy_sym_is(p, name, "atomic_fence")) { 1215 KitCgMemOrder order; 1216 if (!toy_parser_expect(p, TOK_LPAREN) || !toy_parse_mem_order(p, &order) || 1217 !toy_parser_expect(p, TOK_RPAREN)) 1218 return KIT_CG_TYPE_NONE; 1219 kit_cg_atomic_fence(p->cg, order); 1220 return toy_builtin_type(p, KIT_CG_BUILTIN_VOID); 1221 } 1222 1223 *recognized = 0; 1224 return KIT_CG_TYPE_NONE; 1225 } 1226 1227 KitCgTypeId toy_parse_atomic_generic_builtin(ToyParser* p, KitSym name, 1228 int* recognized) { 1229 KitCgTypeId ty; 1230 *recognized = 1; 1231 1232 if (toy_sym_is(p, name, "atomic_load")) { 1233 KitCgTypeId ptr_ty; 1234 KitCgMemOrder order; 1235 KitCgMemAccess access; 1236 if (!toy_parser_expect(p, TOK_LT)) return KIT_CG_TYPE_NONE; 1237 ty = toy_parse_type(p); 1238 if (ty == KIT_CG_TYPE_NONE || !toy_parser_expect(p, TOK_GT) || 1239 !toy_parser_expect(p, TOK_LPAREN)) 1240 return KIT_CG_TYPE_NONE; 1241 ptr_ty = toy_parse_expr(p); 1242 if (ptr_ty == KIT_CG_TYPE_NONE || !toy_expect_comma(p) || 1243 !toy_parse_mem_order(p, &order)) 1244 return KIT_CG_TYPE_NONE; 1245 access = toy_mem_access(p, ty); 1246 if (!toy_parse_optional_access_arg(p, &access) || 1247 !toy_parser_expect(p, TOK_RPAREN)) 1248 return KIT_CG_TYPE_NONE; 1249 if (!toy_type_is_ptr(p, ptr_ty) || 1250 kit_cg_type_ptr_pointee(p->c, ptr_ty) != ty) { 1251 toy_error(p, p->cur.loc, "atomic_load pointer type mismatch"); 1252 return KIT_CG_TYPE_NONE; 1253 } 1254 kit_cg_atomic_load(p->cg, access, order); 1255 return ty; 1256 } 1257 1258 if (toy_sym_is(p, name, "atomic_store")) { 1259 KitCgTypeId ptr_ty, val_ty; 1260 KitCgMemOrder order; 1261 KitCgMemAccess access; 1262 if (!toy_parser_expect(p, TOK_LT)) return KIT_CG_TYPE_NONE; 1263 ty = toy_parse_type(p); 1264 if (ty == KIT_CG_TYPE_NONE || !toy_parser_expect(p, TOK_GT) || 1265 !toy_parser_expect(p, TOK_LPAREN)) 1266 return KIT_CG_TYPE_NONE; 1267 ptr_ty = toy_parse_expr(p); 1268 if (ptr_ty == KIT_CG_TYPE_NONE || !toy_expect_comma(p)) 1269 return KIT_CG_TYPE_NONE; 1270 val_ty = toy_parse_expr(p); 1271 if (val_ty == KIT_CG_TYPE_NONE || !toy_expect_comma(p) || 1272 !toy_parse_mem_order(p, &order)) 1273 return KIT_CG_TYPE_NONE; 1274 access = toy_mem_access(p, ty); 1275 if (!toy_parse_optional_access_arg(p, &access) || 1276 !toy_parser_expect(p, TOK_RPAREN)) 1277 return KIT_CG_TYPE_NONE; 1278 if (!toy_type_is_ptr(p, ptr_ty) || 1279 kit_cg_type_ptr_pointee(p->c, ptr_ty) != ty || 1280 !toy_type_can_implicitly_cast(p, val_ty, ty)) { 1281 toy_error(p, p->cur.loc, "atomic_store type mismatch"); 1282 return KIT_CG_TYPE_NONE; 1283 } 1284 if (val_ty != ty && !toy_emit_implicit_cast(p, val_ty, ty)) 1285 return KIT_CG_TYPE_NONE; 1286 kit_cg_atomic_store(p->cg, access, order); 1287 return toy_builtin_type(p, KIT_CG_BUILTIN_VOID); 1288 } 1289 1290 if (toy_sym_is(p, name, "atomic_rmw")) { 1291 KitCgAtomicOp op; 1292 KitCgTypeId ptr_ty, val_ty; 1293 KitCgMemOrder order; 1294 KitCgMemAccess access; 1295 if (!toy_parser_expect(p, TOK_LT)) return KIT_CG_TYPE_NONE; 1296 ty = toy_parse_type(p); 1297 if (ty == KIT_CG_TYPE_NONE || !toy_parser_expect(p, TOK_GT) || 1298 !toy_parser_expect(p, TOK_LPAREN) || !toy_parse_atomic_op(p, &op) || 1299 !toy_expect_comma(p)) 1300 return KIT_CG_TYPE_NONE; 1301 ptr_ty = toy_parse_expr(p); 1302 if (ptr_ty == KIT_CG_TYPE_NONE || !toy_expect_comma(p)) 1303 return KIT_CG_TYPE_NONE; 1304 val_ty = toy_parse_expr(p); 1305 if (val_ty == KIT_CG_TYPE_NONE || !toy_expect_comma(p) || 1306 !toy_parse_mem_order(p, &order)) 1307 return KIT_CG_TYPE_NONE; 1308 access = toy_mem_access(p, ty); 1309 if (!toy_parse_optional_access_arg(p, &access) || 1310 !toy_parser_expect(p, TOK_RPAREN)) 1311 return KIT_CG_TYPE_NONE; 1312 if (!toy_type_is_ptr(p, ptr_ty) || 1313 kit_cg_type_ptr_pointee(p->c, ptr_ty) != ty || 1314 !toy_type_can_implicitly_cast(p, val_ty, ty)) { 1315 toy_error(p, p->cur.loc, "atomic_rmw type mismatch"); 1316 return KIT_CG_TYPE_NONE; 1317 } 1318 if (val_ty != ty && !toy_emit_implicit_cast(p, val_ty, ty)) 1319 return KIT_CG_TYPE_NONE; 1320 kit_cg_atomic_rmw(p->cg, access, op, order); 1321 return ty; 1322 } 1323 1324 if (toy_sym_is(p, name, "atomic_cmpxchg")) { 1325 KitCgTypeId ptr_ty, expected_ty, desired_ty, rec_ty; 1326 KitCgMemOrder success_order, failure_order; 1327 int weak; 1328 KitCgMemAccess access; 1329 KitCgFieldDesc fields[2]; 1330 KitCgLocal rec_slot; 1331 if (!toy_parser_expect(p, TOK_LT)) return KIT_CG_TYPE_NONE; 1332 ty = toy_parse_type(p); 1333 if (ty == KIT_CG_TYPE_NONE || !toy_parser_expect(p, TOK_GT) || 1334 !toy_parser_expect(p, TOK_LPAREN)) 1335 return KIT_CG_TYPE_NONE; 1336 ptr_ty = toy_parse_expr(p); 1337 if (ptr_ty == KIT_CG_TYPE_NONE || !toy_expect_comma(p)) 1338 return KIT_CG_TYPE_NONE; 1339 expected_ty = toy_parse_expr(p); 1340 if (expected_ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE; 1341 if (!toy_type_can_implicitly_cast(p, expected_ty, ty)) { 1342 toy_error(p, p->cur.loc, "atomic_cmpxchg type mismatch"); 1343 return KIT_CG_TYPE_NONE; 1344 } 1345 if (expected_ty != ty && !toy_emit_implicit_cast(p, expected_ty, ty)) 1346 return KIT_CG_TYPE_NONE; 1347 expected_ty = ty; 1348 if (!toy_expect_comma(p)) return KIT_CG_TYPE_NONE; 1349 desired_ty = toy_parse_expr(p); 1350 if (desired_ty == KIT_CG_TYPE_NONE || !toy_expect_comma(p) || 1351 !toy_parse_mem_order(p, &success_order) || !toy_expect_comma(p) || 1352 !toy_parse_mem_order(p, &failure_order) || !toy_expect_comma(p) || 1353 !toy_parse_cmpxchg_strength(p, &weak)) 1354 return KIT_CG_TYPE_NONE; 1355 access = toy_mem_access(p, ty); 1356 if (!toy_parse_optional_access_arg(p, &access) || 1357 !toy_parser_expect(p, TOK_RPAREN)) 1358 return KIT_CG_TYPE_NONE; 1359 if (!toy_type_is_ptr(p, ptr_ty) || 1360 kit_cg_type_ptr_pointee(p->c, ptr_ty) != ty || expected_ty != ty || 1361 !toy_type_can_implicitly_cast(p, desired_ty, ty)) { 1362 toy_error(p, p->cur.loc, "atomic_cmpxchg type mismatch"); 1363 return KIT_CG_TYPE_NONE; 1364 } 1365 if (desired_ty != ty && !toy_emit_implicit_cast(p, desired_ty, ty)) 1366 return KIT_CG_TYPE_NONE; 1367 kit_cg_atomic_cmpxchg(p->cg, access, success_order, failure_order, weak); 1368 memset(fields, 0, sizeof fields); 1369 fields[0].name = kit_sym_intern(p->c, KIT_SLICE_LIT("prior")); 1370 fields[0].type = ty; 1371 fields[1].name = kit_sym_intern(p->c, KIT_SLICE_LIT("ok")); 1372 fields[1].type = toy_builtin_type(p, KIT_CG_BUILTIN_BOOL); 1373 rec_ty = toy_cg_record_type(p, 0, fields, 2, 0, 0); 1374 rec_slot = kit_cg_local(p->cg, rec_ty, toy_slot_attrs(0)); 1375 { 1376 const KitCgRecordLayout* L = kit_cg_type_record_layout(p->c, rec_ty); 1377 uint64_t f0_off = (L && L->nfields > 0) ? L->fields[0].offset : 0; 1378 uint64_t f1_off = (L && L->nfields > 1) ? L->fields[1].offset : 0; 1379 kit_cg_push_local(p->cg, rec_slot); 1380 kit_cg_addr(p->cg); 1381 kit_cg_deref(p->cg, (int64_t)f1_off); 1382 kit_cg_swap(p->cg); 1383 kit_cg_store(p->cg, toy_mem_access(p, fields[1].type)); 1384 kit_cg_push_local(p->cg, rec_slot); 1385 kit_cg_addr(p->cg); 1386 kit_cg_deref(p->cg, (int64_t)f0_off); 1387 kit_cg_swap(p->cg); 1388 kit_cg_store(p->cg, toy_mem_access(p, fields[0].type)); 1389 } 1390 /* Record result lives as a pointer VALUE (its address) on the stack. */ 1391 kit_cg_push_local_addr(p->cg, rec_slot); 1392 return rec_ty; 1393 } 1394 1395 if (toy_sym_is(p, name, "atomic_is_legal")) { 1396 KitCgMemOrder order; 1397 KitCgMemAccess access; 1398 if (!toy_parser_expect(p, TOK_LT)) return KIT_CG_TYPE_NONE; 1399 ty = toy_parse_type(p); 1400 if (ty == KIT_CG_TYPE_NONE || !toy_parser_expect(p, TOK_GT) || 1401 !toy_parser_expect(p, TOK_LPAREN) || !toy_parse_mem_order(p, &order)) 1402 return KIT_CG_TYPE_NONE; 1403 access = toy_mem_access(p, ty); 1404 if (!toy_parse_optional_access_arg(p, &access) || 1405 !toy_parser_expect(p, TOK_RPAREN)) 1406 return KIT_CG_TYPE_NONE; 1407 kit_cg_push_int(p->cg, 1408 kit_cg_atomic_is_legal(p->c, access, order) ? 1u : 0u, 1409 toy_builtin_type(p, KIT_CG_BUILTIN_BOOL)); 1410 return toy_builtin_type(p, KIT_CG_BUILTIN_BOOL); 1411 } 1412 1413 if (toy_sym_is(p, name, "atomic_is_lock_free")) { 1414 KitCgMemAccess access; 1415 if (!toy_parser_expect(p, TOK_LT)) return KIT_CG_TYPE_NONE; 1416 ty = toy_parse_type(p); 1417 if (ty == KIT_CG_TYPE_NONE || !toy_parser_expect(p, TOK_GT) || 1418 !toy_parser_expect(p, TOK_LPAREN)) 1419 return KIT_CG_TYPE_NONE; 1420 access = toy_mem_access(p, ty); 1421 if (p->cur.kind != TOK_RPAREN && !toy_parse_access_group(p, &access)) 1422 return KIT_CG_TYPE_NONE; 1423 if (!toy_parser_expect(p, TOK_RPAREN)) return KIT_CG_TYPE_NONE; 1424 kit_cg_push_int(p->cg, kit_cg_atomic_is_lock_free(p->c, access) ? 1u : 0u, 1425 toy_builtin_type(p, KIT_CG_BUILTIN_BOOL)); 1426 return toy_builtin_type(p, KIT_CG_BUILTIN_BOOL); 1427 } 1428 1429 *recognized = 0; 1430 return KIT_CG_TYPE_NONE; 1431 } 1432 1433 KitCgTypeId toy_parse_low_level_builtin_call(ToyParser* p, KitSym name, 1434 int* recognized) { 1435 *recognized = 1; 1436 1437 if (toy_sym_is(p, name, "syscall")) { 1438 uint32_t nargs = 0; 1439 KitCgTypeId long_ty = p->int_type; 1440 if (!toy_parser_expect(p, TOK_LPAREN)) return KIT_CG_TYPE_NONE; 1441 if (!toy_parser_match(p, TOK_RPAREN)) { 1442 for (;;) { 1443 KitCgTypeId arg_ty = toy_parse_expr(p); 1444 if (arg_ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE; 1445 if (!toy_type_is_intlike(p, arg_ty) && !toy_type_is_ptr(p, arg_ty)) { 1446 toy_error(p, p->cur.loc, 1447 "syscall arguments must be integer or pointer"); 1448 return KIT_CG_TYPE_NONE; 1449 } 1450 if (arg_ty != long_ty && !toy_emit_cast(p, arg_ty, long_ty)) 1451 return KIT_CG_TYPE_NONE; 1452 nargs++; 1453 if (nargs > 7u) { 1454 toy_error(p, p->cur.loc, "too many syscall arguments"); 1455 return KIT_CG_TYPE_NONE; 1456 } 1457 if (!toy_parser_match(p, TOK_COMMA)) break; 1458 } 1459 if (!toy_parser_expect(p, TOK_RPAREN)) return KIT_CG_TYPE_NONE; 1460 } 1461 if (nargs == 0) { 1462 toy_error(p, p->cur.loc, "syscall expects a syscall number"); 1463 return KIT_CG_TYPE_NONE; 1464 } 1465 if (!kit_cg_target_supports_intrinsic(p->c, KIT_CG_INTRIN_SYSCALL)) 1466 return toy_unsupported_intrinsic(p); 1467 kit_cg_intrinsic(p->cg, KIT_CG_INTRIN_SYSCALL, nargs, long_ty); 1468 return long_ty; 1469 } 1470 1471 if (toy_sym_is(p, name, "setjmp")) { 1472 KitCgTypeId buf_ty; 1473 if (!toy_parser_expect(p, TOK_LPAREN)) return KIT_CG_TYPE_NONE; 1474 buf_ty = toy_parse_expr(p); 1475 if (buf_ty == KIT_CG_TYPE_NONE || !toy_parser_expect(p, TOK_RPAREN)) 1476 return KIT_CG_TYPE_NONE; 1477 if (!toy_type_is_ptr(p, buf_ty)) { 1478 toy_error(p, p->cur.loc, "setjmp expects pointer buffer"); 1479 return KIT_CG_TYPE_NONE; 1480 } 1481 return toy_unsupported_intrinsic(p); 1482 } 1483 1484 if (toy_sym_is(p, name, "longjmp")) { 1485 KitCgTypeId buf_ty, value_ty; 1486 if (!toy_parser_expect(p, TOK_LPAREN)) return KIT_CG_TYPE_NONE; 1487 buf_ty = toy_parse_expr(p); 1488 if (buf_ty == KIT_CG_TYPE_NONE || !toy_expect_comma(p)) 1489 return KIT_CG_TYPE_NONE; 1490 value_ty = toy_parse_expr(p); 1491 if (value_ty == KIT_CG_TYPE_NONE || !toy_parser_expect(p, TOK_RPAREN)) 1492 return KIT_CG_TYPE_NONE; 1493 if (!toy_type_is_ptr(p, buf_ty) || !toy_type_is_intlike(p, value_ty)) { 1494 toy_error(p, p->cur.loc, 1495 "longjmp expects pointer buffer and integer value"); 1496 return KIT_CG_TYPE_NONE; 1497 } 1498 return toy_unsupported_intrinsic(p); 1499 } 1500 1501 if (toy_sym_is(p, name, "wfi") || toy_sym_is(p, name, "wfe") || 1502 toy_sym_is(p, name, "sev")) { 1503 KitCgIntrinsic intrin = KIT_CG_INTRIN_WFI; 1504 if (toy_sym_is(p, name, "wfe")) 1505 intrin = KIT_CG_INTRIN_WFE; 1506 else if (toy_sym_is(p, name, "sev")) 1507 intrin = KIT_CG_INTRIN_SEV; 1508 if (!toy_parser_expect(p, TOK_LPAREN) || !toy_parser_expect(p, TOK_RPAREN)) 1509 return KIT_CG_TYPE_NONE; 1510 if (!kit_cg_target_supports_intrinsic(p->c, intrin)) 1511 return toy_unsupported_intrinsic(p); 1512 kit_cg_intrinsic(p->cg, intrin, 0, 1513 toy_builtin_type(p, KIT_CG_BUILTIN_VOID)); 1514 return toy_builtin_type(p, KIT_CG_BUILTIN_VOID); 1515 } 1516 1517 if (toy_sym_is(p, name, "irq_save")) { 1518 if (!toy_parser_expect(p, TOK_LPAREN) || !toy_parser_expect(p, TOK_RPAREN)) 1519 return KIT_CG_TYPE_NONE; 1520 if (!kit_cg_target_supports_intrinsic(p->c, KIT_CG_INTRIN_IRQ_SAVE)) 1521 return toy_unsupported_intrinsic(p); 1522 kit_cg_intrinsic(p->cg, KIT_CG_INTRIN_IRQ_SAVE, 0, p->size_type); 1523 return p->size_type; 1524 } 1525 1526 if (toy_sym_is(p, name, "irq_restore")) { 1527 KitCgTypeId prev_ty; 1528 if (!toy_parser_expect(p, TOK_LPAREN)) return KIT_CG_TYPE_NONE; 1529 prev_ty = toy_parse_expr(p); 1530 if (prev_ty == KIT_CG_TYPE_NONE || !toy_parser_expect(p, TOK_RPAREN)) 1531 return KIT_CG_TYPE_NONE; 1532 if (!toy_type_can_implicitly_cast(p, prev_ty, p->size_type)) { 1533 toy_error(p, p->cur.loc, "irq_restore expects usize state"); 1534 return KIT_CG_TYPE_NONE; 1535 } 1536 if (!toy_emit_implicit_cast(p, prev_ty, p->size_type)) 1537 return KIT_CG_TYPE_NONE; 1538 if (!kit_cg_target_supports_intrinsic(p->c, KIT_CG_INTRIN_IRQ_RESTORE)) 1539 return toy_unsupported_intrinsic(p); 1540 kit_cg_intrinsic(p->cg, KIT_CG_INTRIN_IRQ_RESTORE, 1, 1541 toy_builtin_type(p, KIT_CG_BUILTIN_VOID)); 1542 return toy_builtin_type(p, KIT_CG_BUILTIN_VOID); 1543 } 1544 1545 if (toy_sym_is(p, name, "dmb") || toy_sym_is(p, name, "dsb")) { 1546 KitCgIntrinsic intrin = 1547 toy_sym_is(p, name, "dsb") ? KIT_CG_INTRIN_DSB : KIT_CG_INTRIN_DMB; 1548 KitCgBarrierScope scope; 1549 if (!toy_parser_expect(p, TOK_LPAREN) || 1550 !toy_parse_barrier_scope(p, &scope) || 1551 !toy_parser_expect(p, TOK_RPAREN)) 1552 return KIT_CG_TYPE_NONE; 1553 if (!kit_cg_target_supports_intrinsic(p->c, intrin)) 1554 return toy_unsupported_intrinsic(p); 1555 /* The barrier domain rides as an immediate operand the backend maps onto 1556 * the arch's barrier-option field. */ 1557 kit_cg_push_int(p->cg, (uint64_t)scope, p->int_type); 1558 kit_cg_intrinsic(p->cg, intrin, 1, 1559 toy_builtin_type(p, KIT_CG_BUILTIN_VOID)); 1560 return toy_builtin_type(p, KIT_CG_BUILTIN_VOID); 1561 } 1562 1563 if (toy_sym_is(p, name, "dcache_clean") || 1564 toy_sym_is(p, name, "dcache_invalidate") || 1565 toy_sym_is(p, name, "dcache_clean_invalidate") || 1566 toy_sym_is(p, name, "icache_invalidate")) { 1567 KitCgTypeId ptr_ty, size_ty; 1568 if (!toy_parser_expect(p, TOK_LPAREN)) return KIT_CG_TYPE_NONE; 1569 ptr_ty = toy_parse_expr(p); 1570 if (ptr_ty == KIT_CG_TYPE_NONE || !toy_expect_comma(p)) 1571 return KIT_CG_TYPE_NONE; 1572 size_ty = toy_parse_expr(p); 1573 if (size_ty == KIT_CG_TYPE_NONE || !toy_parser_expect(p, TOK_RPAREN)) 1574 return KIT_CG_TYPE_NONE; 1575 if (!toy_type_is_ptr(p, ptr_ty) || !toy_type_is_intlike(p, size_ty)) { 1576 toy_error(p, p->cur.loc, 1577 "cache intrinsic expects pointer and integer size"); 1578 return KIT_CG_TYPE_NONE; 1579 } 1580 return toy_unsupported_intrinsic(p); 1581 } 1582 1583 *recognized = 0; 1584 return KIT_CG_TYPE_NONE; 1585 } 1586 1587 KitCgTypeId toy_parse_low_level_generic_builtin(ToyParser* p, KitSym name, 1588 int* recognized) { 1589 KitCgTypeId ty; 1590 *recognized = 1; 1591 1592 if (toy_sym_is(p, name, "coro_switch")) { 1593 KitCgTypeId from_ty, to_ty, value_ty; 1594 if (!toy_parser_expect(p, TOK_LT)) return KIT_CG_TYPE_NONE; 1595 ty = toy_parse_type(p); 1596 if (ty == KIT_CG_TYPE_NONE || !toy_parser_expect(p, TOK_GT) || 1597 !toy_parser_expect(p, TOK_LPAREN)) 1598 return KIT_CG_TYPE_NONE; 1599 from_ty = toy_parse_expr(p); 1600 if (from_ty == KIT_CG_TYPE_NONE || !toy_expect_comma(p)) 1601 return KIT_CG_TYPE_NONE; 1602 to_ty = toy_parse_expr(p); 1603 if (to_ty == KIT_CG_TYPE_NONE || !toy_expect_comma(p)) 1604 return KIT_CG_TYPE_NONE; 1605 value_ty = toy_parse_expr(p); 1606 if (value_ty == KIT_CG_TYPE_NONE || !toy_parser_expect(p, TOK_RPAREN)) 1607 return KIT_CG_TYPE_NONE; 1608 if (!toy_type_is_ptr(p, from_ty) || !toy_type_is_ptr(p, to_ty) || 1609 value_ty != ty) { 1610 toy_error(p, p->cur.loc, 1611 "coro_switch expects pointer contexts and matching value type"); 1612 return KIT_CG_TYPE_NONE; 1613 } 1614 return toy_unsupported_intrinsic(p); 1615 } 1616 1617 *recognized = 0; 1618 return KIT_CG_TYPE_NONE; 1619 }