cg_control_test.c (19493B)
1 /* cg_control_test — drives the conditional structured control-flow ops 2 * (break_true / break_false / continue_true / continue_false) through the 3 * public KitCg API. break_true / continue_true / continue_false have zero 4 * callers in any frontend (toy uses only break / break_false / continue), so 5 * like the unordered FP compares they are reachable *only* through this entry 6 * point — this is the guard against an advertise-but-ignore gap in the 7 * structured-control surface. 8 * 9 * Each variant builds the same loop, `int f(int n) { return 0+1+..+(n-1); }`, 10 * spelled with a different conditional break/continue, and: 11 * 12 * Execution — captures each into the in-process interpreter (target- 13 * independent IR) and asserts the sum for a spread of n. 14 * 15 * Emission — builds each for aarch64 / x86-64 / riscv64 at -O0 and -O1 and 16 * finalizes; a backend that mishandles the lowered branches panics, which 17 * fails the test. 18 * 19 * Rejection — confirms `continue` on a forward-only block scope (which has no 20 * loop header) is rejected with a clean diagnostic rather than emitting a 21 * jump to a nonexistent label. 22 * 23 * Run by: make test-cg-api 24 */ 25 26 #include <kit/cg.h> 27 #include <kit/core.h> 28 #include <kit/frontend.h> 29 #include <kit/interp.h> 30 #include <kit/object.h> 31 #include <stdint.h> 32 #include <stdio.h> 33 #include <string.h> 34 35 #include "lib/kit_unit.h" 36 37 static KitUnit g_u; 38 #define EXPECT(cond, ...) CU_EXPECT(&g_u, cond, __VA_ARGS__) 39 40 typedef enum { 41 V_BREAK_TRUE, 42 V_BREAK_FALSE, 43 V_CONTINUE_TRUE, 44 V_CONTINUE_FALSE 45 } Variant; 46 47 typedef struct { 48 Variant variant; 49 const char* name; 50 } VariantDesc; 51 52 static const VariantDesc VARIANTS[] = { 53 {V_BREAK_TRUE, "break_true"}, 54 {V_BREAK_FALSE, "break_false"}, 55 {V_CONTINUE_TRUE, "continue_true"}, 56 {V_CONTINUE_FALSE, "continue_false"}, 57 }; 58 enum { NVAR = (int)(sizeof VARIANTS / sizeof VARIANTS[0]) }; 59 60 /* Reference: sum 0 + 1 + ... + (n-1), with n clamped at 0. */ 61 static int64_t loop_expected(int64_t n) { 62 int64_t acc = 0, i; 63 for (i = 0; i < n; ++i) acc += i; 64 return acc; 65 } 66 67 /* Build `int <name>(int n)` computing sum(0..n-1) via `variant`. 68 * 69 * break_* : cond-at-top loop — test, conditionally exit, else body, continue. 70 * continue_*: cond-at-bottom loop — body, test, conditionally re-loop. 71 * All four are equivalent; they exercise the four conditional ops plus plain 72 * `continue` (in the break_* shapes). */ 73 static void build_loop_fn(KitCompiler* c, KitCg* cg, const char* name, 74 Variant variant) { 75 KitCgTypeId i32 = kit_cg_type_builtin(c, KIT_CG_BUILTIN_I32); 76 KitCgFuncParam param; 77 KitCgFuncResult result; 78 KitCgFuncSig sig; 79 KitCgDecl decl; 80 KitCgSym sym; 81 KitCgLocalAttrs la; 82 KitCgLocal n_param, i_local, acc_local; 83 KitCgMemAccess ma; 84 KitCgScope scope; 85 86 memset(¶m, 0, sizeof param); 87 param.type = i32; 88 memset(&result, 0, sizeof result); 89 result.type = i32; 90 memset(&sig, 0, sizeof sig); 91 sig.result = result; 92 sig.params = ¶m; 93 sig.nparams = 1; 94 sig.call_conv = KIT_CG_CC_TARGET_C; 95 96 memset(&decl, 0, sizeof decl); 97 decl.kind = KIT_CG_DECL_FUNC; 98 decl.linkage_name = kit_sym_intern(c, kit_slice_cstr(name)); 99 decl.display_name = decl.linkage_name; 100 decl.type = kit_cg_type_func(c, sig); 101 decl.sym.bind = KIT_SB_GLOBAL; 102 decl.sym.visibility = KIT_CG_VIS_DEFAULT; 103 sym = kit_cg_decl(cg, decl); 104 EXPECT(sym != KIT_CG_SYM_NONE, "%s: decl failed", name); 105 106 kit_cg_func_begin(cg, sym); 107 memset(&la, 0, sizeof la); 108 n_param = kit_cg_param(cg, 0, i32, la); 109 i_local = kit_cg_local(cg, i32, la); 110 acc_local = kit_cg_local(cg, i32, la); 111 112 memset(&ma, 0, sizeof ma); 113 ma.type = i32; 114 ma.align = kit_cg_type_align(c, i32); 115 116 /* i = 0; acc = 0; */ 117 kit_cg_push_int(cg, 0, i32); 118 kit_cg_local_write(cg, i_local, ma); 119 kit_cg_push_int(cg, 0, i32); 120 kit_cg_local_write(cg, acc_local, ma); 121 122 scope = kit_cg_scope_begin(cg); 123 124 if (variant == V_BREAK_TRUE || variant == V_BREAK_FALSE) { 125 /* test at top: break out when i has reached n */ 126 kit_cg_local_read(cg, i_local, ma); 127 kit_cg_local_read(cg, n_param, ma); 128 if (variant == V_BREAK_TRUE) { 129 kit_cg_int_cmp(cg, KIT_CG_INT_GE_S); /* i >= n */ 130 kit_cg_break_true(cg, scope); /* exit when true */ 131 } else { 132 kit_cg_int_cmp(cg, KIT_CG_INT_LT_S); /* i < n */ 133 kit_cg_break_false(cg, scope); /* exit when false (i >= n) */ 134 } 135 /* acc += i; i += 1; */ 136 kit_cg_local_read(cg, acc_local, ma); 137 kit_cg_local_read(cg, i_local, ma); 138 kit_cg_int_binop(cg, KIT_CG_INT_ADD, 0); 139 kit_cg_local_write(cg, acc_local, ma); 140 kit_cg_local_read(cg, i_local, ma); 141 kit_cg_push_int(cg, 1, i32); 142 kit_cg_int_binop(cg, KIT_CG_INT_ADD, 0); 143 kit_cg_local_write(cg, i_local, ma); 144 kit_cg_continue(cg, scope); 145 } else { 146 /* body first, test at bottom: re-loop while i < n */ 147 kit_cg_local_read(cg, acc_local, ma); 148 kit_cg_local_read(cg, i_local, ma); 149 kit_cg_int_binop(cg, KIT_CG_INT_ADD, 0); 150 kit_cg_local_write(cg, acc_local, ma); 151 kit_cg_local_read(cg, i_local, ma); 152 kit_cg_push_int(cg, 1, i32); 153 kit_cg_int_binop(cg, KIT_CG_INT_ADD, 0); 154 kit_cg_local_write(cg, i_local, ma); 155 kit_cg_local_read(cg, i_local, ma); 156 kit_cg_local_read(cg, n_param, ma); 157 if (variant == V_CONTINUE_TRUE) { 158 kit_cg_int_cmp(cg, KIT_CG_INT_LT_S); /* i < n */ 159 kit_cg_continue_true(cg, scope); /* re-loop while true */ 160 } else { 161 kit_cg_int_cmp(cg, KIT_CG_INT_GE_S); /* i >= n */ 162 kit_cg_continue_false(cg, scope); /* re-loop while false (i < n) */ 163 } 164 } 165 166 kit_cg_scope_end(cg, scope); 167 kit_cg_local_read(cg, acc_local, ma); 168 kit_cg_ret(cg); 169 kit_cg_func_end(cg); 170 } 171 172 /* ---- Multi-value scopes (kit_cg_*_begin_sig) ------------------------- * 173 * Drives the multi-value structured-scope surface added for Wasm multi-value 174 * blocks: a block carrying N results, and a loop carrying N params snapshotted 175 * across the back edge via kit_cg_scope_store_params. Each builds `int f(int)` 176 * so the same interpreter/emit harness as the conditional variants applies. */ 177 178 /* Boilerplate: declare `int <name>(int)` and open it; returns the param 179 * local and fills *out_i32 with the i32 type id and *out_ma with an i32 access. 180 */ 181 static KitCgLocal begin_int_int_fn(KitCompiler* c, KitCg* cg, const char* name, 182 KitCgTypeId* out_i32, 183 KitCgMemAccess* out_ma) { 184 KitCgTypeId i32 = kit_cg_type_builtin(c, KIT_CG_BUILTIN_I32); 185 KitCgFuncParam param; 186 KitCgFuncResult result; 187 KitCgFuncSig sig; 188 KitCgDecl decl; 189 KitCgSym sym; 190 KitCgLocalAttrs la; 191 memset(¶m, 0, sizeof param); 192 param.type = i32; 193 memset(&result, 0, sizeof result); 194 result.type = i32; 195 memset(&sig, 0, sizeof sig); 196 sig.result = result; 197 sig.params = ¶m; 198 sig.nparams = 1; 199 sig.call_conv = KIT_CG_CC_TARGET_C; 200 memset(&decl, 0, sizeof decl); 201 decl.kind = KIT_CG_DECL_FUNC; 202 decl.linkage_name = kit_sym_intern(c, kit_slice_cstr(name)); 203 decl.display_name = decl.linkage_name; 204 decl.type = kit_cg_type_func(c, sig); 205 decl.sym.bind = KIT_SB_GLOBAL; 206 decl.sym.visibility = KIT_CG_VIS_DEFAULT; 207 sym = kit_cg_decl(cg, decl); 208 EXPECT(sym != KIT_CG_SYM_NONE, "%s: decl failed", name); 209 kit_cg_func_begin(cg, sym); 210 memset(&la, 0, sizeof la); 211 *out_i32 = i32; 212 memset(out_ma, 0, sizeof *out_ma); 213 out_ma->type = i32; 214 out_ma->align = kit_cg_type_align(c, i32); 215 return kit_cg_param(cg, 0, i32, la); 216 } 217 218 /* int two_result_block(int x) { return (x+1) + (x+2); } // == 2x + 3 219 * via a block carrying two i32 results that scope_end yields bottom->top. */ 220 static void build_two_result_block(KitCompiler* c, KitCg* cg, 221 const char* name) { 222 KitCgTypeId i32; 223 KitCgMemAccess ma; 224 KitCgLocal x = begin_int_int_fn(c, cg, name, &i32, &ma); 225 KitCgTypeId results[2] = {i32, i32}; 226 KitCgScopeSig sig; 227 KitCgScope blk; 228 memset(&sig, 0, sizeof sig); 229 sig.results = results; 230 sig.nresults = 2; 231 blk = kit_cg_block_begin_sig(cg, &sig); 232 kit_cg_local_read(cg, x, ma); /* x */ 233 kit_cg_push_int(cg, 1, i32); 234 kit_cg_int_binop(cg, KIT_CG_INT_ADD, 0); /* x+1 */ 235 kit_cg_local_read(cg, x, ma); 236 kit_cg_push_int(cg, 2, i32); 237 kit_cg_int_binop(cg, KIT_CG_INT_ADD, 0); /* x+2 */ 238 kit_cg_scope_end(cg, blk); /* yields [x+1, x+2] */ 239 kit_cg_int_binop(cg, KIT_CG_INT_ADD, 0); /* (x+1)+(x+2) */ 240 kit_cg_ret(cg); 241 kit_cg_func_end(cg); 242 } 243 244 /* int one_param_loop(int n) { int acc=0; for (int i=0;i<n;i++) acc+=i; return 245 * acc; } The loop carries i as a single param across the back edge; acc is a 246 * plain local. Exercises scope_begin_sig(1 param) + store_params + continue, 247 * with the loop exited by falling through the body bottom (no break). */ 248 static void build_one_param_loop(KitCompiler* c, KitCg* cg, const char* name) { 249 KitCgTypeId i32; 250 KitCgMemAccess ma; 251 KitCgLocal n = begin_int_int_fn(c, cg, name, &i32, &ma); 252 KitCgLocalAttrs la; 253 KitCgLocal i_l, acc; 254 KitCgTypeId params[1]; 255 KitCgScopeSig sig; 256 KitCgScope loop; 257 KitCgLabel done; 258 memset(&la, 0, sizeof la); 259 i_l = kit_cg_local(cg, i32, la); 260 acc = kit_cg_local(cg, i32, la); 261 kit_cg_push_int(cg, 0, i32); 262 kit_cg_local_write(cg, acc, ma); 263 kit_cg_push_int(cg, 0, i32); /* initial loop param i = 0 */ 264 params[0] = i32; 265 memset(&sig, 0, sizeof sig); 266 sig.params = params; 267 sig.nparams = 1; 268 loop = kit_cg_scope_begin_sig(cg, &sig); 269 done = kit_cg_label_new(cg); 270 kit_cg_local_write(cg, i_l, ma); /* pop the loop param i */ 271 kit_cg_local_read(cg, i_l, ma); 272 kit_cg_local_read(cg, n, ma); 273 kit_cg_int_cmp(cg, KIT_CG_INT_LT_S); /* i < n ? */ 274 kit_cg_branch_false(cg, done); /* exit when i >= n */ 275 kit_cg_local_read(cg, acc, ma); 276 kit_cg_local_read(cg, i_l, ma); 277 kit_cg_int_binop(cg, KIT_CG_INT_ADD, 0); 278 kit_cg_local_write(cg, acc, ma); /* acc += i */ 279 kit_cg_local_read(cg, i_l, ma); 280 kit_cg_push_int(cg, 1, i32); 281 kit_cg_int_binop(cg, KIT_CG_INT_ADD, 0); 282 kit_cg_local_write(cg, i_l, ma); /* i += 1 */ 283 kit_cg_local_read(cg, i_l, ma); /* fresh loop param */ 284 kit_cg_scope_store_params(cg, loop); 285 kit_cg_jump(cg, kit_cg_scope_continue_label(cg, loop)); 286 kit_cg_label_place(cg, done); 287 kit_cg_scope_end(cg, loop); 288 kit_cg_local_read(cg, acc, ma); 289 kit_cg_ret(cg); 290 kit_cg_func_end(cg); 291 } 292 293 /* int two_param_loop(int n) { ... same sum, both i and acc carried as the two 294 * loop params, and the result carried out as the loop's single result. } 295 * Exercises scope_begin_sig(2 params, 1 result) + reverse-order store_params + 296 * a value-carrying fall-through scope_end. */ 297 static void build_two_param_loop(KitCompiler* c, KitCg* cg, const char* name) { 298 KitCgTypeId i32; 299 KitCgMemAccess ma; 300 KitCgLocal n = begin_int_int_fn(c, cg, name, &i32, &ma); 301 KitCgLocalAttrs la; 302 KitCgLocal i_l, acc_l; 303 KitCgTypeId params[2]; 304 KitCgTypeId results[1]; 305 KitCgScopeSig sig; 306 KitCgScope loop; 307 KitCgLabel done; 308 memset(&la, 0, sizeof la); 309 i_l = kit_cg_local(cg, i32, la); 310 acc_l = kit_cg_local(cg, i32, la); 311 kit_cg_push_int(cg, 0, i32); /* i */ 312 kit_cg_push_int(cg, 0, i32); /* acc */ 313 params[0] = i32; 314 params[1] = i32; 315 results[0] = i32; 316 memset(&sig, 0, sizeof sig); 317 sig.params = params; 318 sig.nparams = 2; 319 sig.results = results; 320 sig.nresults = 1; 321 loop = kit_cg_scope_begin_sig(cg, &sig); 322 done = kit_cg_label_new(cg); 323 /* stack on body entry: [i, acc] (bottom->top). Pop acc then i. */ 324 kit_cg_local_write(cg, acc_l, ma); 325 kit_cg_local_write(cg, i_l, ma); 326 kit_cg_local_read(cg, i_l, ma); 327 kit_cg_local_read(cg, n, ma); 328 kit_cg_int_cmp(cg, KIT_CG_INT_LT_S); 329 kit_cg_branch_false(cg, done); /* exit (with acc) when i >= n */ 330 kit_cg_local_read(cg, acc_l, ma); 331 kit_cg_local_read(cg, i_l, ma); 332 kit_cg_int_binop(cg, KIT_CG_INT_ADD, 0); 333 kit_cg_local_write(cg, acc_l, ma); /* acc += i */ 334 kit_cg_local_read(cg, i_l, ma); 335 kit_cg_push_int(cg, 1, i32); 336 kit_cg_int_binop(cg, KIT_CG_INT_ADD, 0); 337 kit_cg_local_write(cg, i_l, ma); /* i += 1 */ 338 kit_cg_local_read(cg, i_l, ma); /* fresh param i */ 339 kit_cg_local_read(cg, acc_l, ma); /* fresh param acc */ 340 kit_cg_scope_store_params(cg, loop); /* reverse-pop into [i,acc] locals */ 341 kit_cg_jump(cg, kit_cg_scope_continue_label(cg, loop)); 342 kit_cg_label_place(cg, done); 343 kit_cg_local_read(cg, acc_l, ma); /* fall-through result */ 344 kit_cg_scope_end(cg, loop); /* yields acc */ 345 kit_cg_ret(cg); 346 kit_cg_func_end(cg); 347 } 348 349 typedef struct { 350 const char* name; 351 void (*build)(KitCompiler*, KitCg*, const char*); 352 } MvDesc; 353 static const MvDesc MVS[] = { 354 {"two_result_block", build_two_result_block}, 355 {"one_param_loop", build_one_param_loop}, 356 {"two_param_loop", build_two_param_loop}, 357 }; 358 enum { NMV = (int)(sizeof MVS / sizeof MVS[0]) }; 359 360 /* Reference value for the multi-value builders given input x. */ 361 static int64_t mv_expected(const char* name, int64_t x) { 362 if (strcmp(name, "two_result_block") == 0) return 2 * x + 3; 363 return loop_expected(x); /* the two loops both compute sum(0..x-1) */ 364 } 365 366 /* ---- Execution coverage (in-process interpreter) -------------------- */ 367 368 static const int64_t NS[] = {0, 1, 2, 5, 10}; 369 enum { NNS = (int)(sizeof NS / sizeof NS[0]) }; 370 371 static void run_exec(void) { 372 KitTargetSpec tgt = 373 kit_unit_target(KIT_ARCH_X86_64, KIT_OS_LINUX, KIT_OBJ_ELF); 374 KitCompiler* c = NULL; 375 KitInterpProgram* pp; 376 KitObjBuilder* ob = NULL; 377 KitCg* cg = NULL; 378 KitCodeOptions opts; 379 int i, j; 380 char nm[32]; 381 382 if (kit_unit_compiler_new(&g_u, tgt, &c) != KIT_OK || !c) { 383 EXPECT(0, "exec: compiler_new failed"); 384 return; 385 } 386 pp = kit_interp_program_new(c); 387 EXPECT(pp != NULL, "exec: interp_program_new failed"); 388 kit_interp_program_attach(pp, c); 389 390 EXPECT(kit_obj_builder_new(c, &ob) == KIT_OK && ob, "exec: obj_new"); 391 EXPECT(kit_cg_new(c, &cg) == KIT_OK && cg, "exec: cg_new"); 392 memset(&opts, 0, sizeof opts); 393 opts.opt_level = 1; /* interp capture requires the optimizer pass */ 394 kit_cg_begin(cg, ob, &opts); 395 396 for (i = 0; i < NVAR; ++i) { 397 snprintf(nm, sizeof nm, "loop_%s", VARIANTS[i].name); 398 build_loop_fn(c, cg, nm, VARIANTS[i].variant); 399 } 400 for (i = 0; i < NMV; ++i) MVS[i].build(c, cg, MVS[i].name); 401 EXPECT(kit_cg_finish(cg, NULL) == KIT_OK, "exec: finish"); 402 EXPECT(kit_cg_detach(cg) == KIT_OK, "exec: detach"); 403 404 for (i = 0; i < NVAR; ++i) { 405 KitInterpFunc* fn; 406 snprintf(nm, sizeof nm, "loop_%s", VARIANTS[i].name); 407 fn = kit_interp_lookup(pp, kit_slice_cstr(nm)); 408 EXPECT(fn != NULL, "exec: %s not captured", VARIANTS[i].name); 409 if (!fn) continue; 410 for (j = 0; j < NNS; ++j) { 411 uint64_t args[1] = {(uint64_t)NS[j]}; 412 int64_t ret = -1; 413 int64_t want = loop_expected(NS[j]); 414 KitInterpStatus s = kit_interp_call_args(pp, fn, args, 1, &ret); 415 EXPECT(s == KIT_INTERP_DONE && ret == want, 416 "%s(%lld): want %lld got %lld (status %d)", VARIANTS[i].name, 417 (long long)NS[j], (long long)want, (long long)ret, (int)s); 418 } 419 } 420 421 for (i = 0; i < NMV; ++i) { 422 KitInterpFunc* fn = kit_interp_lookup(pp, kit_slice_cstr(MVS[i].name)); 423 EXPECT(fn != NULL, "exec: %s not captured", MVS[i].name); 424 if (!fn) continue; 425 for (j = 0; j < NNS; ++j) { 426 uint64_t args[1] = {(uint64_t)NS[j]}; 427 int64_t ret = -1; 428 int64_t want = mv_expected(MVS[i].name, NS[j]); 429 KitInterpStatus s = kit_interp_call_args(pp, fn, args, 1, &ret); 430 EXPECT(s == KIT_INTERP_DONE && ret == want, 431 "%s(%lld): want %lld got %lld (status %d)", MVS[i].name, 432 (long long)NS[j], (long long)want, (long long)ret, (int)s); 433 } 434 } 435 436 kit_cg_free(cg); 437 kit_obj_builder_free(ob); 438 kit_interp_program_free(pp); 439 kit_compiler_free(c); 440 } 441 442 /* ---- Emission coverage (every native backend, no execution) --------- */ 443 444 static void run_emit(KitArchKind arch, KitOSKind os, KitObjFmt fmt, 445 const char* tag, int opt_level) { 446 KitTargetSpec tgt = kit_unit_target(arch, os, fmt); 447 KitCompiler* c = NULL; 448 KitObjBuilder* ob = NULL; 449 KitCg* cg = NULL; 450 KitCodeOptions opts; 451 int i; 452 char nm[48]; 453 454 if (kit_unit_compiler_new(&g_u, tgt, &c) != KIT_OK || !c) { 455 EXPECT(0, "%s/O%d: compiler_new failed", tag, opt_level); 456 return; 457 } 458 EXPECT(kit_obj_builder_new(c, &ob) == KIT_OK && ob, "%s: obj_new", tag); 459 EXPECT(kit_cg_new(c, &cg) == KIT_OK && cg, "%s: cg_new", tag); 460 memset(&opts, 0, sizeof opts); 461 opts.opt_level = opt_level; 462 kit_cg_begin(cg, ob, &opts); 463 464 for (i = 0; i < NVAR; ++i) { 465 snprintf(nm, sizeof nm, "emit_%s_o%d_%s", tag, opt_level, VARIANTS[i].name); 466 build_loop_fn(c, cg, nm, VARIANTS[i].variant); 467 } 468 for (i = 0; i < NMV; ++i) { 469 snprintf(nm, sizeof nm, "emit_%s_o%d_%s", tag, opt_level, MVS[i].name); 470 MVS[i].build(c, cg, nm); 471 } 472 EXPECT(kit_cg_finish(cg, NULL) == KIT_OK, "%s/O%d: finish failed", tag, 473 opt_level); 474 EXPECT(kit_cg_detach(cg) == KIT_OK, "%s/O%d: detach failed", tag, opt_level); 475 476 kit_cg_free(cg); 477 kit_obj_builder_free(ob); 478 kit_compiler_free(c); 479 } 480 481 /* ---- Rejection: continue on a forward-only block scope -------------- */ 482 483 typedef struct { 484 KitObjBuilder* ob; 485 KitCg* cg; 486 } RejectCtx; 487 488 static KitStatus reject_body(KitCompiler* c, void* user) { 489 RejectCtx* r = (RejectCtx*)user; 490 KitCgFuncSig sig; 491 KitCgFuncResult result; 492 KitCgDecl decl; 493 KitCgSym sym; 494 KitCgScope blk; 495 memset(&sig, 0, sizeof sig); 496 memset(&result, 0, sizeof result); 497 result.type = kit_cg_type_builtin(c, KIT_CG_BUILTIN_VOID); 498 sig.result = result; 499 sig.call_conv = KIT_CG_CC_TARGET_C; /* void() */ 500 memset(&decl, 0, sizeof decl); 501 decl.kind = KIT_CG_DECL_FUNC; 502 decl.linkage_name = kit_sym_intern(c, kit_slice_cstr("reject_fn")); 503 decl.display_name = decl.linkage_name; 504 decl.type = kit_cg_type_func(c, sig); 505 decl.sym.bind = KIT_SB_GLOBAL; 506 decl.sym.visibility = KIT_CG_VIS_DEFAULT; 507 sym = kit_cg_decl(r->cg, decl); 508 kit_cg_func_begin(r->cg, sym); 509 blk = kit_cg_block_begin(r->cg); 510 kit_cg_continue(r->cg, blk); /* <- must panic: blocks have no loop header */ 511 kit_cg_scope_end(r->cg, blk); 512 kit_cg_ret(r->cg); 513 kit_cg_func_end(r->cg); 514 return KIT_OK; 515 } 516 517 static void run_reject(void) { 518 KitTargetSpec tgt = 519 kit_unit_target(KIT_ARCH_X86_64, KIT_OS_LINUX, KIT_OBJ_ELF); 520 KitCompiler* c = NULL; 521 RejectCtx r; 522 KitCodeOptions opts; 523 KitStatus st; 524 memset(&r, 0, sizeof r); 525 if (kit_unit_compiler_new(&g_u, tgt, &c) != KIT_OK || !c) { 526 EXPECT(0, "reject: compiler_new failed"); 527 return; 528 } 529 EXPECT(kit_obj_builder_new(c, &r.ob) == KIT_OK && r.ob, "reject: obj_new"); 530 EXPECT(kit_cg_new(c, &r.cg) == KIT_OK && r.cg, "reject: cg_new"); 531 memset(&opts, 0, sizeof opts); 532 kit_cg_begin(r.cg, r.ob, &opts); 533 534 g_u.suppress_fatal = 1; 535 st = kit_frontend_run(c, reject_body, &r); 536 g_u.suppress_fatal = 0; 537 538 EXPECT(st == KIT_ERR, "continue on block scope should be rejected"); 539 EXPECT(strstr(g_u.last_diag, "forward-only block scope") != NULL, 540 "rejection diagnostic should name the block scope (got: %s)", 541 g_u.last_diag); 542 543 kit_compiler_free(c); 544 } 545 546 int main(void) { 547 int opt; 548 kit_unit_init(&g_u); 549 550 run_exec(); 551 552 for (opt = 0; opt <= 1; ++opt) { 553 run_emit(KIT_ARCH_ARM_64, KIT_OS_LINUX, KIT_OBJ_ELF, "aa64", opt); 554 run_emit(KIT_ARCH_X86_64, KIT_OS_LINUX, KIT_OBJ_ELF, "x64", opt); 555 run_emit(KIT_ARCH_RV64, KIT_OS_LINUX, KIT_OBJ_ELF, "rv64", opt); 556 } 557 558 run_reject(); 559 560 kit_unit_summary(&g_u, "cg_control_test"); 561 return kit_unit_status(&g_u); 562 }