blob 4e57bbf9 (41454B) - Raw
1 const std = @import("std"); 2 const TestContext = @import("../../src/test.zig").TestContext; 3 4 // Self-hosted has differing levels of support for various architectures. For now we pass explicit 5 // target parameters to each test case. At some point we will take this to the next level and have 6 // a set of targets that all test cases run on unless specifically overridden. For now, each test 7 // case applies to only the specified target. 8 9 const linux_x64 = std.zig.CrossTarget{ 10 .cpu_arch = .x86_64, 11 .os_tag = .linux, 12 }; 13 14 const macosx_x64 = std.zig.CrossTarget{ 15 .cpu_arch = .x86_64, 16 .os_tag = .macos, 17 }; 18 19 const linux_riscv64 = std.zig.CrossTarget{ 20 .cpu_arch = .riscv64, 21 .os_tag = .linux, 22 }; 23 24 const wasi = std.zig.CrossTarget{ 25 .cpu_arch = .wasm32, 26 .os_tag = .wasi, 27 }; 28 29 pub fn addCases(ctx: *TestContext) !void { 30 try @import("zir.zig").addCases(ctx); 31 try @import("cbe.zig").addCases(ctx); 32 try @import("spu-ii.zig").addCases(ctx); 33 try @import("arm.zig").addCases(ctx); 34 try @import("aarch64.zig").addCases(ctx); 35 36 { 37 var case = ctx.exe("hello world with updates", linux_x64); 38 39 case.addError("", &[_][]const u8{"no entry point found"}); 40 41 // Incorrect return type 42 case.addError( 43 \\export fn _start() noreturn { 44 \\} 45 , &[_][]const u8{":2:1: error: expected noreturn, found void"}); 46 47 // Regular old hello world 48 case.addCompareOutput( 49 \\export fn _start() noreturn { 50 \\ print(); 51 \\ 52 \\ exit(); 53 \\} 54 \\ 55 \\fn print() void { 56 \\ asm volatile ("syscall" 57 \\ : 58 \\ : [number] "{rax}" (1), 59 \\ [arg1] "{rdi}" (1), 60 \\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")), 61 \\ [arg3] "{rdx}" (14) 62 \\ : "rcx", "r11", "memory" 63 \\ ); 64 \\ return; 65 \\} 66 \\ 67 \\fn exit() noreturn { 68 \\ asm volatile ("syscall" 69 \\ : 70 \\ : [number] "{rax}" (231), 71 \\ [arg1] "{rdi}" (0) 72 \\ : "rcx", "r11", "memory" 73 \\ ); 74 \\ unreachable; 75 \\} 76 , 77 "Hello, World!\n", 78 ); 79 // Now change the message only 80 case.addCompareOutput( 81 \\export fn _start() noreturn { 82 \\ print(); 83 \\ 84 \\ exit(); 85 \\} 86 \\ 87 \\fn print() void { 88 \\ asm volatile ("syscall" 89 \\ : 90 \\ : [number] "{rax}" (1), 91 \\ [arg1] "{rdi}" (1), 92 \\ [arg2] "{rsi}" (@ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n")), 93 \\ [arg3] "{rdx}" (104) 94 \\ : "rcx", "r11", "memory" 95 \\ ); 96 \\ return; 97 \\} 98 \\ 99 \\fn exit() noreturn { 100 \\ asm volatile ("syscall" 101 \\ : 102 \\ : [number] "{rax}" (231), 103 \\ [arg1] "{rdi}" (0) 104 \\ : "rcx", "r11", "memory" 105 \\ ); 106 \\ unreachable; 107 \\} 108 , 109 "What is up? This is a longer message that will force the data to be relocated in virtual address space.\n", 110 ); 111 // Now we print it twice. 112 case.addCompareOutput( 113 \\export fn _start() noreturn { 114 \\ print(); 115 \\ print(); 116 \\ 117 \\ exit(); 118 \\} 119 \\ 120 \\fn print() void { 121 \\ asm volatile ("syscall" 122 \\ : 123 \\ : [number] "{rax}" (1), 124 \\ [arg1] "{rdi}" (1), 125 \\ [arg2] "{rsi}" (@ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n")), 126 \\ [arg3] "{rdx}" (104) 127 \\ : "rcx", "r11", "memory" 128 \\ ); 129 \\ return; 130 \\} 131 \\ 132 \\fn exit() noreturn { 133 \\ asm volatile ("syscall" 134 \\ : 135 \\ : [number] "{rax}" (231), 136 \\ [arg1] "{rdi}" (0) 137 \\ : "rcx", "r11", "memory" 138 \\ ); 139 \\ unreachable; 140 \\} 141 , 142 \\What is up? This is a longer message that will force the data to be relocated in virtual address space. 143 \\What is up? This is a longer message that will force the data to be relocated in virtual address space. 144 \\ 145 ); 146 } 147 148 { 149 var case = ctx.exe("hello world with updates", macosx_x64); 150 case.addError("", &[_][]const u8{"no entry point found"}); 151 152 // Incorrect return type 153 case.addError( 154 \\export fn _start() noreturn { 155 \\} 156 , &[_][]const u8{":2:1: error: expected noreturn, found void"}); 157 158 // Regular old hello world 159 case.addCompareOutput( 160 \\export fn _start() noreturn { 161 \\ print(); 162 \\ 163 \\ exit(); 164 \\} 165 \\ 166 \\fn print() void { 167 \\ asm volatile ("syscall" 168 \\ : 169 \\ : [number] "{rax}" (0x2000004), 170 \\ [arg1] "{rdi}" (1), 171 \\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")), 172 \\ [arg3] "{rdx}" (14) 173 \\ : "memory" 174 \\ ); 175 \\ return; 176 \\} 177 \\ 178 \\fn exit() noreturn { 179 \\ asm volatile ("syscall" 180 \\ : 181 \\ : [number] "{rax}" (0x2000001), 182 \\ [arg1] "{rdi}" (0) 183 \\ : "memory" 184 \\ ); 185 \\ unreachable; 186 \\} 187 , 188 "Hello, World!\n", 189 ); 190 // Now change the message only 191 case.addCompareOutput( 192 \\export fn _start() noreturn { 193 \\ print(); 194 \\ 195 \\ exit(); 196 \\} 197 \\ 198 \\fn print() void { 199 \\ asm volatile ("syscall" 200 \\ : 201 \\ : [number] "{rax}" (0x2000004), 202 \\ [arg1] "{rdi}" (1), 203 \\ [arg2] "{rsi}" (@ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n")), 204 \\ [arg3] "{rdx}" (104) 205 \\ : "memory" 206 \\ ); 207 \\ return; 208 \\} 209 \\ 210 \\fn exit() noreturn { 211 \\ asm volatile ("syscall" 212 \\ : 213 \\ : [number] "{rax}" (0x2000001), 214 \\ [arg1] "{rdi}" (0) 215 \\ : "memory" 216 \\ ); 217 \\ unreachable; 218 \\} 219 , 220 "What is up? This is a longer message that will force the data to be relocated in virtual address space.\n", 221 ); 222 // Now we print it twice. 223 case.addCompareOutput( 224 \\export fn _start() noreturn { 225 \\ print(); 226 \\ print(); 227 \\ 228 \\ exit(); 229 \\} 230 \\ 231 \\fn print() void { 232 \\ asm volatile ("syscall" 233 \\ : 234 \\ : [number] "{rax}" (0x2000004), 235 \\ [arg1] "{rdi}" (1), 236 \\ [arg2] "{rsi}" (@ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n")), 237 \\ [arg3] "{rdx}" (104) 238 \\ : "memory" 239 \\ ); 240 \\ return; 241 \\} 242 \\ 243 \\fn exit() noreturn { 244 \\ asm volatile ("syscall" 245 \\ : 246 \\ : [number] "{rax}" (0x2000001), 247 \\ [arg1] "{rdi}" (0) 248 \\ : "memory" 249 \\ ); 250 \\ unreachable; 251 \\} 252 , 253 \\What is up? This is a longer message that will force the data to be relocated in virtual address space. 254 \\What is up? This is a longer message that will force the data to be relocated in virtual address space. 255 \\ 256 ); 257 } 258 259 { 260 var case = ctx.exe("hello world", linux_riscv64); 261 // Regular old hello world 262 case.addCompareOutput( 263 \\export fn _start() noreturn { 264 \\ print(); 265 \\ 266 \\ exit(); 267 \\} 268 \\ 269 \\fn print() void { 270 \\ asm volatile ("ecall" 271 \\ : 272 \\ : [number] "{a7}" (64), 273 \\ [arg1] "{a0}" (1), 274 \\ [arg2] "{a1}" (@ptrToInt("Hello, World!\n")), 275 \\ [arg3] "{a2}" ("Hello, World!\n".len) 276 \\ : "rcx", "r11", "memory" 277 \\ ); 278 \\ return; 279 \\} 280 \\ 281 \\fn exit() noreturn { 282 \\ asm volatile ("ecall" 283 \\ : 284 \\ : [number] "{a7}" (94), 285 \\ [arg1] "{a0}" (0) 286 \\ : "rcx", "r11", "memory" 287 \\ ); 288 \\ unreachable; 289 \\} 290 , 291 "Hello, World!\n", 292 ); 293 } 294 295 { 296 var case = ctx.exe("adding numbers at comptime", linux_x64); 297 case.addCompareOutput( 298 \\export fn _start() noreturn { 299 \\ asm volatile ("syscall" 300 \\ : 301 \\ : [number] "{rax}" (1), 302 \\ [arg1] "{rdi}" (1), 303 \\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")), 304 \\ [arg3] "{rdx}" (10 + 4) 305 \\ : "rcx", "r11", "memory" 306 \\ ); 307 \\ asm volatile ("syscall" 308 \\ : 309 \\ : [number] "{rax}" (@as(usize, 230) + @as(usize, 1)), 310 \\ [arg1] "{rdi}" (0) 311 \\ : "rcx", "r11", "memory" 312 \\ ); 313 \\ unreachable; 314 \\} 315 , 316 "Hello, World!\n", 317 ); 318 } 319 320 { 321 var case = ctx.exe("adding numbers at runtime", linux_x64); 322 case.addCompareOutput( 323 \\export fn _start() noreturn { 324 \\ add(3, 4); 325 \\ 326 \\ exit(); 327 \\} 328 \\ 329 \\fn add(a: u32, b: u32) void { 330 \\ if (a + b != 7) unreachable; 331 \\} 332 \\ 333 \\fn exit() noreturn { 334 \\ asm volatile ("syscall" 335 \\ : 336 \\ : [number] "{rax}" (231), 337 \\ [arg1] "{rdi}" (0) 338 \\ : "rcx", "r11", "memory" 339 \\ ); 340 \\ unreachable; 341 \\} 342 , 343 "", 344 ); 345 } 346 347 { 348 var case = ctx.exe("subtracting numbers at runtime", linux_x64); 349 case.addCompareOutput( 350 \\export fn _start() noreturn { 351 \\ sub(7, 4); 352 \\ 353 \\ exit(); 354 \\} 355 \\ 356 \\fn sub(a: u32, b: u32) void { 357 \\ if (a - b != 3) unreachable; 358 \\} 359 \\ 360 \\fn exit() noreturn { 361 \\ asm volatile ("syscall" 362 \\ : 363 \\ : [number] "{rax}" (231), 364 \\ [arg1] "{rdi}" (0) 365 \\ : "rcx", "r11", "memory" 366 \\ ); 367 \\ unreachable; 368 \\} 369 , 370 "", 371 ); 372 } 373 { 374 var case = ctx.exe("@TypeOf", linux_x64); 375 case.addCompareOutput( 376 \\export fn _start() noreturn { 377 \\ var x: usize = 0; 378 \\ const z = @TypeOf(x, @as(u128, 5)); 379 \\ assert(z == u128); 380 \\ 381 \\ exit(); 382 \\} 383 \\ 384 \\pub fn assert(ok: bool) void { 385 \\ if (!ok) unreachable; // assertion failure 386 \\} 387 \\ 388 \\fn exit() noreturn { 389 \\ asm volatile ("syscall" 390 \\ : 391 \\ : [number] "{rax}" (231), 392 \\ [arg1] "{rdi}" (0) 393 \\ : "rcx", "r11", "memory" 394 \\ ); 395 \\ unreachable; 396 \\} 397 , 398 "", 399 ); 400 case.addCompareOutput( 401 \\export fn _start() noreturn { 402 \\ const z = @TypeOf(true); 403 \\ assert(z == bool); 404 \\ 405 \\ exit(); 406 \\} 407 \\ 408 \\pub fn assert(ok: bool) void { 409 \\ if (!ok) unreachable; // assertion failure 410 \\} 411 \\ 412 \\fn exit() noreturn { 413 \\ asm volatile ("syscall" 414 \\ : 415 \\ : [number] "{rax}" (231), 416 \\ [arg1] "{rdi}" (0) 417 \\ : "rcx", "r11", "memory" 418 \\ ); 419 \\ unreachable; 420 \\} 421 , 422 "", 423 ); 424 case.addError( 425 \\export fn _start() noreturn { 426 \\ const z = @TypeOf(true, 1); 427 \\ unreachable; 428 \\} 429 , &[_][]const u8{":2:29: error: incompatible types: 'bool' and 'comptime_int'"}); 430 } 431 432 { 433 var case = ctx.exe("assert function", linux_x64); 434 case.addCompareOutput( 435 \\export fn _start() noreturn { 436 \\ add(3, 4); 437 \\ 438 \\ exit(); 439 \\} 440 \\ 441 \\fn add(a: u32, b: u32) void { 442 \\ assert(a + b == 7); 443 \\} 444 \\ 445 \\pub fn assert(ok: bool) void { 446 \\ if (!ok) unreachable; // assertion failure 447 \\} 448 \\ 449 \\fn exit() noreturn { 450 \\ asm volatile ("syscall" 451 \\ : 452 \\ : [number] "{rax}" (231), 453 \\ [arg1] "{rdi}" (0) 454 \\ : "rcx", "r11", "memory" 455 \\ ); 456 \\ unreachable; 457 \\} 458 , 459 "", 460 ); 461 462 // Tests copying a register. For the `c = a + b`, it has to 463 // preserve both a and b, because they are both used later. 464 case.addCompareOutput( 465 \\export fn _start() noreturn { 466 \\ add(3, 4); 467 \\ 468 \\ exit(); 469 \\} 470 \\ 471 \\fn add(a: u32, b: u32) void { 472 \\ const c = a + b; // 7 473 \\ const d = a + c; // 10 474 \\ const e = d + b; // 14 475 \\ assert(e == 14); 476 \\} 477 \\ 478 \\pub fn assert(ok: bool) void { 479 \\ if (!ok) unreachable; // assertion failure 480 \\} 481 \\ 482 \\fn exit() noreturn { 483 \\ asm volatile ("syscall" 484 \\ : 485 \\ : [number] "{rax}" (231), 486 \\ [arg1] "{rdi}" (0) 487 \\ : "rcx", "r11", "memory" 488 \\ ); 489 \\ unreachable; 490 \\} 491 , 492 "", 493 ); 494 495 // More stress on the liveness detection. 496 case.addCompareOutput( 497 \\export fn _start() noreturn { 498 \\ add(3, 4); 499 \\ 500 \\ exit(); 501 \\} 502 \\ 503 \\fn add(a: u32, b: u32) void { 504 \\ const c = a + b; // 7 505 \\ const d = a + c; // 10 506 \\ const e = d + b; // 14 507 \\ const f = d + e; // 24 508 \\ const g = e + f; // 38 509 \\ const h = f + g; // 62 510 \\ const i = g + h; // 100 511 \\ assert(i == 100); 512 \\} 513 \\ 514 \\pub fn assert(ok: bool) void { 515 \\ if (!ok) unreachable; // assertion failure 516 \\} 517 \\ 518 \\fn exit() noreturn { 519 \\ asm volatile ("syscall" 520 \\ : 521 \\ : [number] "{rax}" (231), 522 \\ [arg1] "{rdi}" (0) 523 \\ : "rcx", "r11", "memory" 524 \\ ); 525 \\ unreachable; 526 \\} 527 , 528 "", 529 ); 530 531 // Requires a second move. The register allocator should figure out to re-use rax. 532 case.addCompareOutput( 533 \\export fn _start() noreturn { 534 \\ add(3, 4); 535 \\ 536 \\ exit(); 537 \\} 538 \\ 539 \\fn add(a: u32, b: u32) void { 540 \\ const c = a + b; // 7 541 \\ const d = a + c; // 10 542 \\ const e = d + b; // 14 543 \\ const f = d + e; // 24 544 \\ const g = e + f; // 38 545 \\ const h = f + g; // 62 546 \\ const i = g + h; // 100 547 \\ const j = i + d; // 110 548 \\ assert(j == 110); 549 \\} 550 \\ 551 \\pub fn assert(ok: bool) void { 552 \\ if (!ok) unreachable; // assertion failure 553 \\} 554 \\ 555 \\fn exit() noreturn { 556 \\ asm volatile ("syscall" 557 \\ : 558 \\ : [number] "{rax}" (231), 559 \\ [arg1] "{rdi}" (0) 560 \\ : "rcx", "r11", "memory" 561 \\ ); 562 \\ unreachable; 563 \\} 564 , 565 "", 566 ); 567 568 // Now we test integer return values. 569 case.addCompareOutput( 570 \\export fn _start() noreturn { 571 \\ assert(add(3, 4) == 7); 572 \\ assert(add(20, 10) == 30); 573 \\ 574 \\ exit(); 575 \\} 576 \\ 577 \\fn add(a: u32, b: u32) u32 { 578 \\ return a + b; 579 \\} 580 \\ 581 \\pub fn assert(ok: bool) void { 582 \\ if (!ok) unreachable; // assertion failure 583 \\} 584 \\ 585 \\fn exit() noreturn { 586 \\ asm volatile ("syscall" 587 \\ : 588 \\ : [number] "{rax}" (231), 589 \\ [arg1] "{rdi}" (0) 590 \\ : "rcx", "r11", "memory" 591 \\ ); 592 \\ unreachable; 593 \\} 594 , 595 "", 596 ); 597 598 // Local mutable variables. 599 case.addCompareOutput( 600 \\export fn _start() noreturn { 601 \\ assert(add(3, 4) == 7); 602 \\ assert(add(20, 10) == 30); 603 \\ 604 \\ exit(); 605 \\} 606 \\ 607 \\fn add(a: u32, b: u32) u32 { 608 \\ var x: u32 = undefined; 609 \\ x = 0; 610 \\ x += a; 611 \\ x += b; 612 \\ return x; 613 \\} 614 \\ 615 \\pub fn assert(ok: bool) void { 616 \\ if (!ok) unreachable; // assertion failure 617 \\} 618 \\ 619 \\fn exit() noreturn { 620 \\ asm volatile ("syscall" 621 \\ : 622 \\ : [number] "{rax}" (231), 623 \\ [arg1] "{rdi}" (0) 624 \\ : "rcx", "r11", "memory" 625 \\ ); 626 \\ unreachable; 627 \\} 628 , 629 "", 630 ); 631 632 // Optionals 633 case.addCompareOutput( 634 \\export fn _start() noreturn { 635 \\ const a: u32 = 2; 636 \\ const b: ?u32 = a; 637 \\ const c = b.?; 638 \\ if (c != 2) unreachable; 639 \\ 640 \\ exit(); 641 \\} 642 \\ 643 \\fn exit() noreturn { 644 \\ asm volatile ("syscall" 645 \\ : 646 \\ : [number] "{rax}" (231), 647 \\ [arg1] "{rdi}" (0) 648 \\ : "rcx", "r11", "memory" 649 \\ ); 650 \\ unreachable; 651 \\} 652 , 653 "", 654 ); 655 656 // While loops 657 case.addCompareOutput( 658 \\export fn _start() noreturn { 659 \\ var i: u32 = 0; 660 \\ while (i < 4) : (i += 1) print(); 661 \\ assert(i == 4); 662 \\ 663 \\ exit(); 664 \\} 665 \\ 666 \\fn print() void { 667 \\ asm volatile ("syscall" 668 \\ : 669 \\ : [number] "{rax}" (1), 670 \\ [arg1] "{rdi}" (1), 671 \\ [arg2] "{rsi}" (@ptrToInt("hello\n")), 672 \\ [arg3] "{rdx}" (6) 673 \\ : "rcx", "r11", "memory" 674 \\ ); 675 \\ return; 676 \\} 677 \\ 678 \\pub fn assert(ok: bool) void { 679 \\ if (!ok) unreachable; // assertion failure 680 \\} 681 \\ 682 \\fn exit() noreturn { 683 \\ asm volatile ("syscall" 684 \\ : 685 \\ : [number] "{rax}" (231), 686 \\ [arg1] "{rdi}" (0) 687 \\ : "rcx", "r11", "memory" 688 \\ ); 689 \\ unreachable; 690 \\} 691 , 692 "hello\nhello\nhello\nhello\n", 693 ); 694 695 // Labeled blocks (no conditional branch) 696 case.addCompareOutput( 697 \\export fn _start() noreturn { 698 \\ assert(add(3, 4) == 20); 699 \\ 700 \\ exit(); 701 \\} 702 \\ 703 \\fn add(a: u32, b: u32) u32 { 704 \\ const x: u32 = blk: { 705 \\ const c = a + b; // 7 706 \\ const d = a + c; // 10 707 \\ const e = d + b; // 14 708 \\ break :blk e; 709 \\ }; 710 \\ const y = x + a; // 17 711 \\ const z = y + a; // 20 712 \\ return z; 713 \\} 714 \\ 715 \\pub fn assert(ok: bool) void { 716 \\ if (!ok) unreachable; // assertion failure 717 \\} 718 \\ 719 \\fn exit() noreturn { 720 \\ asm volatile ("syscall" 721 \\ : 722 \\ : [number] "{rax}" (231), 723 \\ [arg1] "{rdi}" (0) 724 \\ : "rcx", "r11", "memory" 725 \\ ); 726 \\ unreachable; 727 \\} 728 , 729 "", 730 ); 731 732 // This catches a possible bug in the logic for re-using dying operands. 733 case.addCompareOutput( 734 \\export fn _start() noreturn { 735 \\ assert(add(3, 4) == 116); 736 \\ 737 \\ exit(); 738 \\} 739 \\ 740 \\fn add(a: u32, b: u32) u32 { 741 \\ const x: u32 = blk: { 742 \\ const c = a + b; // 7 743 \\ const d = a + c; // 10 744 \\ const e = d + b; // 14 745 \\ const f = d + e; // 24 746 \\ const g = e + f; // 38 747 \\ const h = f + g; // 62 748 \\ const i = g + h; // 100 749 \\ const j = i + d; // 110 750 \\ break :blk j; 751 \\ }; 752 \\ const y = x + a; // 113 753 \\ const z = y + a; // 116 754 \\ return z; 755 \\} 756 \\ 757 \\pub fn assert(ok: bool) void { 758 \\ if (!ok) unreachable; // assertion failure 759 \\} 760 \\ 761 \\fn exit() noreturn { 762 \\ asm volatile ("syscall" 763 \\ : 764 \\ : [number] "{rax}" (231), 765 \\ [arg1] "{rdi}" (0) 766 \\ : "rcx", "r11", "memory" 767 \\ ); 768 \\ unreachable; 769 \\} 770 , 771 "", 772 ); 773 774 // Spilling registers to the stack. 775 case.addCompareOutput( 776 \\export fn _start() noreturn { 777 \\ assert(add(3, 4) == 791); 778 \\ 779 \\ exit(); 780 \\} 781 \\ 782 \\fn add(a: u32, b: u32) u32 { 783 \\ const x: u32 = blk: { 784 \\ const c = a + b; // 7 785 \\ const d = a + c; // 10 786 \\ const e = d + b; // 14 787 \\ const f = d + e; // 24 788 \\ const g = e + f; // 38 789 \\ const h = f + g; // 62 790 \\ const i = g + h; // 100 791 \\ const j = i + d; // 110 792 \\ const k = i + j; // 210 793 \\ const l = k + c; // 217 794 \\ const m = l + d; // 227 795 \\ const n = m + e; // 241 796 \\ const o = n + f; // 265 797 \\ const p = o + g; // 303 798 \\ const q = p + h; // 365 799 \\ const r = q + i; // 465 800 \\ const s = r + j; // 575 801 \\ const t = s + k; // 785 802 \\ break :blk t; 803 \\ }; 804 \\ const y = x + a; // 788 805 \\ const z = y + a; // 791 806 \\ return z; 807 \\} 808 \\ 809 \\pub fn assert(ok: bool) void { 810 \\ if (!ok) unreachable; // assertion failure 811 \\} 812 \\ 813 \\fn exit() noreturn { 814 \\ asm volatile ("syscall" 815 \\ : 816 \\ : [number] "{rax}" (231), 817 \\ [arg1] "{rdi}" (0) 818 \\ : "rcx", "r11", "memory" 819 \\ ); 820 \\ unreachable; 821 \\} 822 , 823 "", 824 ); 825 826 // Reusing the registers of dead operands playing nicely with conditional branching. 827 case.addCompareOutput( 828 \\export fn _start() noreturn { 829 \\ assert(add(3, 4) == 791); 830 \\ assert(add(4, 3) == 79); 831 \\ 832 \\ exit(); 833 \\} 834 \\ 835 \\fn add(a: u32, b: u32) u32 { 836 \\ const x: u32 = if (a < b) blk: { 837 \\ const c = a + b; // 7 838 \\ const d = a + c; // 10 839 \\ const e = d + b; // 14 840 \\ const f = d + e; // 24 841 \\ const g = e + f; // 38 842 \\ const h = f + g; // 62 843 \\ const i = g + h; // 100 844 \\ const j = i + d; // 110 845 \\ const k = i + j; // 210 846 \\ const l = k + c; // 217 847 \\ const m = l + d; // 227 848 \\ const n = m + e; // 241 849 \\ const o = n + f; // 265 850 \\ const p = o + g; // 303 851 \\ const q = p + h; // 365 852 \\ const r = q + i; // 465 853 \\ const s = r + j; // 575 854 \\ const t = s + k; // 785 855 \\ break :blk t; 856 \\ } else blk: { 857 \\ const t = b + b + a; // 10 858 \\ const c = a + t; // 14 859 \\ const d = c + t; // 24 860 \\ const e = d + t; // 34 861 \\ const f = e + t; // 44 862 \\ const g = f + t; // 54 863 \\ const h = c + g; // 68 864 \\ break :blk h + b; // 71 865 \\ }; 866 \\ const y = x + a; // 788, 75 867 \\ const z = y + a; // 791, 79 868 \\ return z; 869 \\} 870 \\ 871 \\pub fn assert(ok: bool) void { 872 \\ if (!ok) unreachable; // assertion failure 873 \\} 874 \\ 875 \\fn exit() noreturn { 876 \\ asm volatile ("syscall" 877 \\ : 878 \\ : [number] "{rax}" (231), 879 \\ [arg1] "{rdi}" (0) 880 \\ : "rcx", "r11", "memory" 881 \\ ); 882 \\ unreachable; 883 \\} 884 , 885 "", 886 ); 887 888 // Character literals and multiline strings. 889 case.addCompareOutput( 890 \\export fn _start() noreturn { 891 \\ const ignore = 892 \\ \\ cool thx 893 \\ \\ 894 \\ ; 895 \\ add('ぁ', '\x03'); 896 \\ 897 \\ exit(); 898 \\} 899 \\ 900 \\fn add(a: u32, b: u32) void { 901 \\ assert(a + b == 12356); 902 \\} 903 \\ 904 \\pub fn assert(ok: bool) void { 905 \\ if (!ok) unreachable; // assertion failure 906 \\} 907 \\ 908 \\fn exit() noreturn { 909 \\ asm volatile ("syscall" 910 \\ : 911 \\ : [number] "{rax}" (231), 912 \\ [arg1] "{rdi}" (0) 913 \\ : "rcx", "r11", "memory" 914 \\ ); 915 \\ unreachable; 916 \\} 917 , 918 "", 919 ); 920 921 // Global const. 922 case.addCompareOutput( 923 \\export fn _start() noreturn { 924 \\ add(aa, bb); 925 \\ 926 \\ exit(); 927 \\} 928 \\ 929 \\const aa = 'ぁ'; 930 \\const bb = '\x03'; 931 \\ 932 \\fn add(a: u32, b: u32) void { 933 \\ assert(a + b == 12356); 934 \\} 935 \\ 936 \\pub fn assert(ok: bool) void { 937 \\ if (!ok) unreachable; // assertion failure 938 \\} 939 \\ 940 \\fn exit() noreturn { 941 \\ asm volatile ("syscall" 942 \\ : 943 \\ : [number] "{rax}" (231), 944 \\ [arg1] "{rdi}" (0) 945 \\ : "rcx", "r11", "memory" 946 \\ ); 947 \\ unreachable; 948 \\} 949 , 950 "", 951 ); 952 953 // Array access. 954 case.addCompareOutput( 955 \\export fn _start() noreturn { 956 \\ assert("hello"[0] == 'h'); 957 \\ 958 \\ exit(); 959 \\} 960 \\ 961 \\pub fn assert(ok: bool) void { 962 \\ if (!ok) unreachable; // assertion failure 963 \\} 964 \\ 965 \\fn exit() noreturn { 966 \\ asm volatile ("syscall" 967 \\ : 968 \\ : [number] "{rax}" (231), 969 \\ [arg1] "{rdi}" (0) 970 \\ : "rcx", "r11", "memory" 971 \\ ); 972 \\ unreachable; 973 \\} 974 , 975 "", 976 ); 977 978 // 64bit set stack 979 case.addCompareOutput( 980 \\export fn _start() noreturn { 981 \\ var i: u64 = 0xFFEEDDCCBBAA9988; 982 \\ assert(i == 0xFFEEDDCCBBAA9988); 983 \\ 984 \\ exit(); 985 \\} 986 \\ 987 \\pub fn assert(ok: bool) void { 988 \\ if (!ok) unreachable; // assertion failure 989 \\} 990 \\ 991 \\fn exit() noreturn { 992 \\ asm volatile ("syscall" 993 \\ : 994 \\ : [number] "{rax}" (231), 995 \\ [arg1] "{rdi}" (0) 996 \\ : "rcx", "r11", "memory" 997 \\ ); 998 \\ unreachable; 999 \\} 1000 , 1001 "", 1002 ); 1003 1004 // Basic for loop 1005 case.addCompareOutput( 1006 \\export fn _start() noreturn { 1007 \\ for ("hello") |_| print(); 1008 \\ 1009 \\ exit(); 1010 \\} 1011 \\ 1012 \\fn print() void { 1013 \\ asm volatile ("syscall" 1014 \\ : 1015 \\ : [number] "{rax}" (1), 1016 \\ [arg1] "{rdi}" (1), 1017 \\ [arg2] "{rsi}" (@ptrToInt("hello\n")), 1018 \\ [arg3] "{rdx}" (6) 1019 \\ : "rcx", "r11", "memory" 1020 \\ ); 1021 \\ return; 1022 \\} 1023 \\ 1024 \\fn exit() noreturn { 1025 \\ asm volatile ("syscall" 1026 \\ : 1027 \\ : [number] "{rax}" (231), 1028 \\ [arg1] "{rdi}" (0) 1029 \\ : "rcx", "r11", "memory" 1030 \\ ); 1031 \\ unreachable; 1032 \\} 1033 , 1034 "hello\nhello\nhello\nhello\nhello\n", 1035 ); 1036 1037 // comptime switch 1038 1039 // Basic for loop 1040 case.addCompareOutput( 1041 \\pub export fn _start() noreturn { 1042 \\ assert(foo() == 1); 1043 \\ exit(); 1044 \\} 1045 \\ 1046 \\fn foo() u32 { 1047 \\ const a: comptime_int = 1; 1048 \\ var b: u32 = 0; 1049 \\ switch (a) { 1050 \\ 1 => b = 1, 1051 \\ 2 => b = 2, 1052 \\ else => unreachable, 1053 \\ } 1054 \\ return b; 1055 \\} 1056 \\ 1057 \\pub fn assert(ok: bool) void { 1058 \\ if (!ok) unreachable; // assertion failure 1059 \\} 1060 \\ 1061 \\fn exit() noreturn { 1062 \\ asm volatile ("syscall" 1063 \\ : 1064 \\ : [number] "{rax}" (231), 1065 \\ [arg1] "{rdi}" (0) 1066 \\ : "rcx", "r11", "memory" 1067 \\ ); 1068 \\ unreachable; 1069 \\} 1070 , 1071 "", 1072 ); 1073 } 1074 1075 { 1076 var case = ctx.exe("basic import", linux_x64); 1077 case.addCompareOutput( 1078 \\export fn _start() noreturn { 1079 \\ @import("print.zig").print(); 1080 \\ exit(); 1081 \\} 1082 \\ 1083 \\fn exit() noreturn { 1084 \\ asm volatile ("syscall" 1085 \\ : 1086 \\ : [number] "{rax}" (231), 1087 \\ [arg1] "{rdi}" (@as(usize, 0)) 1088 \\ : "rcx", "r11", "memory" 1089 \\ ); 1090 \\ unreachable; 1091 \\} 1092 , 1093 "Hello, World!\n", 1094 ); 1095 try case.files.append(.{ 1096 .src = 1097 \\pub fn print() void { 1098 \\ asm volatile ("syscall" 1099 \\ : 1100 \\ : [number] "{rax}" (@as(usize, 1)), 1101 \\ [arg1] "{rdi}" (@as(usize, 1)), 1102 \\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")), 1103 \\ [arg3] "{rdx}" (@as(usize, 14)) 1104 \\ : "rcx", "r11", "memory" 1105 \\ ); 1106 \\ return; 1107 \\} 1108 , 1109 .path = "print.zig", 1110 }); 1111 } 1112 1113 { 1114 var case = ctx.exe("wasm function calls", wasi); 1115 1116 case.addCompareOutput( 1117 \\export fn _start() u32 { 1118 \\ foo(); 1119 \\ bar(); 1120 \\ return 42; 1121 \\} 1122 \\fn foo() void { 1123 \\ bar(); 1124 \\ bar(); 1125 \\} 1126 \\fn bar() void {} 1127 , 1128 "42\n", 1129 ); 1130 1131 case.addCompareOutput( 1132 \\export fn _start() i64 { 1133 \\ bar(); 1134 \\ foo(); 1135 \\ foo(); 1136 \\ bar(); 1137 \\ foo(); 1138 \\ bar(); 1139 \\ return 42; 1140 \\} 1141 \\fn foo() void { 1142 \\ bar(); 1143 \\} 1144 \\fn bar() void {} 1145 , 1146 "42\n", 1147 ); 1148 1149 case.addCompareOutput( 1150 \\export fn _start() f32 { 1151 \\ bar(); 1152 \\ foo(); 1153 \\ return 42.0; 1154 \\} 1155 \\fn foo() void { 1156 \\ bar(); 1157 \\ bar(); 1158 \\ bar(); 1159 \\} 1160 \\fn bar() void {} 1161 , 1162 // This is what you get when you take the bits of the IEE-754 1163 // representation of 42.0 and reinterpret them as an unsigned 1164 // integer. Guess that's a bug in wasmtime. 1165 "1109917696\n", 1166 ); 1167 } 1168 1169 ctx.compileError("function redefinition", linux_x64, 1170 \\fn entry() void {} 1171 \\fn entry() void {} 1172 , &[_][]const u8{":2:4: error: redefinition of 'entry'"}); 1173 1174 ctx.compileError("compileLog", linux_x64, 1175 \\export fn _start() noreturn { 1176 \\ const b = true; 1177 \\ var f: u32 = 1; 1178 \\ @compileLog(b, 20, f, x, .foo); 1179 \\ var y: u32 = true; 1180 \\ unreachable; 1181 \\} 1182 \\fn x() void {} 1183 , &[_][]const u8{ 1184 ":4:3: error: found compile log statement", ":5:16: error: expected u32, found bool", 1185 }); 1186 1187 // "| true, 20, (runtime value), (function)" // TODO if this is here it invalidates the compile error checker. Need a way to check though. 1188 1189 ctx.compileError("compileError", linux_x64, 1190 \\export fn _start() noreturn { 1191 \\ @compileError("this is an error"); 1192 \\ unreachable; 1193 \\} 1194 , &[_][]const u8{":2:3: error: this is an error"}); 1195 { 1196 var case = ctx.obj("variable shadowing", linux_x64); 1197 case.addError( 1198 \\export fn _start() noreturn { 1199 \\ var i: u32 = 10; 1200 \\ var i: u32 = 10; 1201 \\ unreachable; 1202 \\} 1203 , &[_][]const u8{":3:9: error: redefinition of 'i'"}); 1204 case.addError( 1205 \\var testing: i64 = 10; 1206 \\export fn _start() noreturn { 1207 \\ var testing: i64 = 20; 1208 \\ unreachable; 1209 \\} 1210 , &[_][]const u8{":3:9: error: redefinition of 'testing'"}); 1211 } 1212 1213 { 1214 var case = ctx.obj("extern variable has no type", linux_x64); 1215 case.addError( 1216 \\comptime { 1217 \\ _ = foo; 1218 \\} 1219 \\extern var foo: i32; 1220 , &[_][]const u8{":2:9: error: unable to resolve comptime value"}); 1221 case.addError( 1222 \\export fn entry() void { 1223 \\ _ = foo; 1224 \\} 1225 \\extern var foo; 1226 , &[_][]const u8{":4:1: error: unable to infer variable type"}); 1227 } 1228 1229 { 1230 var case = ctx.exe("break/continue", linux_x64); 1231 1232 // Break out of loop 1233 case.addCompareOutput( 1234 \\export fn _start() noreturn { 1235 \\ while (true) { 1236 \\ break; 1237 \\ } 1238 \\ 1239 \\ exit(); 1240 \\} 1241 \\ 1242 \\fn exit() noreturn { 1243 \\ asm volatile ("syscall" 1244 \\ : 1245 \\ : [number] "{rax}" (231), 1246 \\ [arg1] "{rdi}" (0) 1247 \\ : "rcx", "r11", "memory" 1248 \\ ); 1249 \\ unreachable; 1250 \\} 1251 , 1252 "", 1253 ); 1254 case.addCompareOutput( 1255 \\export fn _start() noreturn { 1256 \\ foo: while (true) { 1257 \\ break :foo; 1258 \\ } 1259 \\ 1260 \\ exit(); 1261 \\} 1262 \\ 1263 \\fn exit() noreturn { 1264 \\ asm volatile ("syscall" 1265 \\ : 1266 \\ : [number] "{rax}" (231), 1267 \\ [arg1] "{rdi}" (0) 1268 \\ : "rcx", "r11", "memory" 1269 \\ ); 1270 \\ unreachable; 1271 \\} 1272 , 1273 "", 1274 ); 1275 1276 // Continue in loop 1277 case.addCompareOutput( 1278 \\export fn _start() noreturn { 1279 \\ var i: u64 = 0; 1280 \\ while (true) : (i+=1) { 1281 \\ if (i == 4) exit(); 1282 \\ continue; 1283 \\ } 1284 \\} 1285 \\ 1286 \\fn exit() noreturn { 1287 \\ asm volatile ("syscall" 1288 \\ : 1289 \\ : [number] "{rax}" (231), 1290 \\ [arg1] "{rdi}" (0) 1291 \\ : "rcx", "r11", "memory" 1292 \\ ); 1293 \\ unreachable; 1294 \\} 1295 , 1296 "", 1297 ); 1298 case.addCompareOutput( 1299 \\export fn _start() noreturn { 1300 \\ var i: u64 = 0; 1301 \\ foo: while (true) : (i+=1) { 1302 \\ if (i == 4) exit(); 1303 \\ continue :foo; 1304 \\ } 1305 \\} 1306 \\ 1307 \\fn exit() noreturn { 1308 \\ asm volatile ("syscall" 1309 \\ : 1310 \\ : [number] "{rax}" (231), 1311 \\ [arg1] "{rdi}" (0) 1312 \\ : "rcx", "r11", "memory" 1313 \\ ); 1314 \\ unreachable; 1315 \\} 1316 , 1317 "", 1318 ); 1319 } 1320 1321 { 1322 var case = ctx.exe("unused labels", linux_x64); 1323 case.addError( 1324 \\comptime { 1325 \\ foo: {} 1326 \\} 1327 , &[_][]const u8{":2:5: error: unused block label"}); 1328 case.addError( 1329 \\comptime { 1330 \\ foo: while (true) {} 1331 \\} 1332 , &[_][]const u8{":2:5: error: unused while label"}); 1333 case.addError( 1334 \\comptime { 1335 \\ foo: for ("foo") |_| {} 1336 \\} 1337 , &[_][]const u8{":2:5: error: unused for label"}); 1338 } 1339 }