From 810b0f67fa907bfb524a384c7565a0ffe8b303bc Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Sun, 26 Jan 2020 23:46:37 -0800 Subject: 5922 --- html/apps/mu.subx.html | 11230 ++++++++++++++++++++++++----------------------- 1 file changed, 5674 insertions(+), 5556 deletions(-) (limited to 'html/apps') diff --git a/html/apps/mu.subx.html b/html/apps/mu.subx.html index 47f33c8f..78d6532b 100644 --- a/html/apps/mu.subx.html +++ b/html/apps/mu.subx.html @@ -360,5603 +360,5721 @@ if ('onhashchange' in window) { 298 Stmt1-outputs: # (handle list var) 299 0xc/imm32 300 - 301 Vardef-name: # (handle array byte) + 301 Vardef-var: # (handle var) 302 4/imm32 - 303 Vardef-type: # (handle tree type-id) - 304 8/imm32 - 305 - 306 Regvardef-name: # (handle array byte) - 307 4/imm32 - 308 Regvardef-type: # (handle tree type-id) - 309 8/imm32 - 310 Regvardef-register: # (handle array byte) - 311 0xc/imm32 - 312 Regvardef-operation: # (handle array byte) - 313 0x10/imm32 - 314 Regvardef-inputs: # (handle list var) - 315 0x14/imm32 - 316 - 317 Named-block-name: - 318 4/imm32 - 319 Named-block-statements: # (handle list statement) - 320 8/imm32 - 321 - 322 Stmt-size: # (addr int) - 323 0x18/imm32 - 324 - 325 Var-name: - 326 0/imm32 - 327 Var-type: - 328 4/imm32 - 329 Var-block: - 330 8/imm32 - 331 Var-stack-offset: - 332 0xc/imm32 - 333 Var-register: - 334 0x10/imm32 - 335 Var-size: # (addr int) - 336 0x14/imm32 + 303 + 304 Regvardef-operation: # (handle array byte) + 305 4/imm32 + 306 Regvardef-inouts: # (handle list var) + 307 8/imm32 + 308 Regvardef-var: # (handle var) + 309 0xc/imm32 + 310 + 311 Named-block-name: + 312 4/imm32 + 313 Named-block-statements: # (handle list statement) + 314 8/imm32 + 315 + 316 Stmt-size: # (addr int) + 317 0x10/imm32 + 318 + 319 Var-name: + 320 0/imm32 + 321 Var-type: + 322 4/imm32 + 323 Var-block: + 324 8/imm32 + 325 Var-stack-offset: + 326 0xc/imm32 + 327 Var-register: + 328 0x10/imm32 + 329 Var-size: # (addr int) + 330 0x14/imm32 + 331 + 332 Any-register: # "*" + 333 # size + 334 1/imm32 + 335 # data + 336 2a/asterisk 337 - 338 Any-register: # "*" - 339 # size - 340 1/imm32 - 341 # data - 342 2a/asterisk - 343 - 344 List-value: - 345 0/imm32 - 346 List-next: - 347 4/imm32 - 348 List-size: # (addr int) - 349 8/imm32 + 338 List-value: + 339 0/imm32 + 340 List-next: + 341 4/imm32 + 342 List-size: # (addr int) + 343 8/imm32 + 344 + 345 # Types are expressed as trees (s-expressions) of type-ids (ints). + 346 # However, there's no need for singletons, so we can assume (int) == int + 347 # - if x->right == nil, x is an atom + 348 # - x->left contains either a pointer to a pair, or an atomic type-id directly. + 349 # type ids will be less than 0x10000 (MAX_TYPE_ID). 350 - 351 # Types are expressed as trees (s-expressions) of type-ids (ints). - 352 # However, there's no need for singletons, so we can assume (int) == int - 353 # - if x->right == nil, x is an atom - 354 # - x->left contains either a pointer to a pair, or an atomic type-id directly. - 355 # type ids will be less than 0x10000 (MAX_TYPE_ID). - 356 - 357 Tree-left: # either type-id or (addr tree type-id) - 358 0/imm32 - 359 Tree-right: # (addr tree type-id) - 360 4/imm32 - 361 Tree-size: # (addr int) - 362 8/imm32 - 363 - 364 Max-type-id: - 365 0x10000/imm32 - 366 - 367 == code - 368 - 369 Entry: - 370 # . prologue - 371 89/<- %ebp 4/r32/esp - 372 (new-segment *Heap-size Heap) - 373 # if (argv[1] == "test') run-tests() - 374 { - 375 # if (argc <= 1) break - 376 81 7/subop/compare *ebp 1/imm32 - 377 7e/jump-if-<= break/disp8 - 378 # if (argv[1] != "test") break - 379 (kernel-string-equal? *(ebp+8) "test") # => eax - 380 3d/compare-eax-and 0/imm32 - 381 74/jump-if-= break/disp8 - 382 # - 383 (run-tests) - 384 # syscall(exit, *Num-test-failures) - 385 8b/-> *Num-test-failures 3/r32/ebx - 386 eb/jump $mu-main:end/disp8 - 387 } - 388 # otherwise convert Stdin - 389 (convert-mu Stdin Stdout) - 390 (flush Stdout) - 391 # syscall(exit, 0) - 392 bb/copy-to-ebx 0/imm32 - 393 $mu-main:end: - 394 b8/copy-to-eax 1/imm32/exit - 395 cd/syscall 0x80/imm8 - 396 - 397 convert-mu: # in : (addr buffered-file), out : (addr buffered-file) - 398 # . prologue - 399 55/push-ebp - 400 89/<- %ebp 4/r32/esp - 401 # - 402 (parse-mu *(ebp+8)) - 403 (check-mu-types) - 404 (emit-subx *(ebp+0xc)) - 405 $convert-mu:end: - 406 # . epilogue - 407 89/<- %esp 5/r32/ebp - 408 5d/pop-to-ebp - 409 c3/return - 410 - 411 test-convert-empty-input: - 412 # empty input => empty output - 413 # . prologue - 414 55/push-ebp - 415 89/<- %ebp 4/r32/esp - 416 # setup - 417 (clear-stream _test-input-stream) - 418 (clear-stream $_test-input-buffered-file->buffer) - 419 (clear-stream _test-output-stream) - 420 (clear-stream $_test-output-buffered-file->buffer) - 421 # - 422 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 423 (flush _test-output-buffered-file) - 424 (check-stream-equal _test-output-stream "" "F - test-convert-empty-input") - 425 # . epilogue - 426 89/<- %esp 5/r32/ebp - 427 5d/pop-to-ebp - 428 c3/return - 429 - 430 test-convert-function-skeleton: - 431 # empty function decl => function prologue and epilogue - 432 # fn foo { - 433 # } - 434 # => - 435 # foo: - 436 # # . prologue - 437 # 55/push-ebp - 438 # 89/<- %ebp 4/r32/esp - 439 # # . epilogue - 440 # 89/<- %esp 5/r32/ebp - 441 # 5d/pop-to-ebp - 442 # c3/return - 443 # . prologue - 444 55/push-ebp - 445 89/<- %ebp 4/r32/esp - 446 # setup - 447 (clear-stream _test-input-stream) - 448 (clear-stream $_test-input-buffered-file->buffer) - 449 (clear-stream _test-output-stream) - 450 (clear-stream $_test-output-buffered-file->buffer) - 451 # - 452 (write _test-input-stream "fn foo {\n") - 453 (write _test-input-stream "}\n") - 454 # convert - 455 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 456 (flush _test-output-buffered-file) - 457 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- - 463 # check output - 464 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-skeleton/0") - 465 (check-next-stream-line-equal _test-output-stream "# . prologue" "F - test-convert-function-skeleton/1") - 466 (check-next-stream-line-equal _test-output-stream "55/push-ebp" "F - test-convert-function-skeleton/2") - 467 (check-next-stream-line-equal _test-output-stream "89/<- %ebp 4/r32/esp" "F - test-convert-function-skeleton/3") - 468 (check-next-stream-line-equal _test-output-stream "# . epilogue" "F - test-convert-function-skeleton/4") - 469 (check-next-stream-line-equal _test-output-stream "89/<- %esp 5/r32/ebp" "F - test-convert-function-skeleton/5") - 470 (check-next-stream-line-equal _test-output-stream "5d/pop-to-ebp" "F - test-convert-function-skeleton/6") - 471 (check-next-stream-line-equal _test-output-stream "c3/return" "F - test-convert-function-skeleton/7") - 472 # . epilogue - 473 89/<- %esp 5/r32/ebp - 474 5d/pop-to-ebp - 475 c3/return - 476 - 477 test-convert-multiple-function-skeletons: - 478 # multiple functions correctly organized into a linked list - 479 # fn foo { - 480 # } - 481 # fn bar { - 482 # } - 483 # => - 484 # foo: - 485 # # . prologue - 486 # 55/push-ebp - 487 # 89/<- %ebp 4/r32/esp - 488 # # . epilogue - 489 # 89/<- %esp 5/r32/ebp - 490 # 5d/pop-to-ebp - 491 # c3/return - 492 # bar: - 493 # # . prologue - 494 # 55/push-ebp - 495 # 89/<- %ebp 4/r32/esp - 496 # # . epilogue - 497 # 89/<- %esp 5/r32/ebp - 498 # 5d/pop-to-ebp - 499 # c3/return - 500 # . prologue - 501 55/push-ebp - 502 89/<- %ebp 4/r32/esp - 503 # setup - 504 (clear-stream _test-input-stream) - 505 (clear-stream $_test-input-buffered-file->buffer) - 506 (clear-stream _test-output-stream) - 507 (clear-stream $_test-output-buffered-file->buffer) - 508 # - 509 (write _test-input-stream "fn foo {\n") - 510 (write _test-input-stream "}\n") - 511 (write _test-input-stream "fn bar {\n") - 512 (write _test-input-stream "}\n") - 513 # convert - 514 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 515 (flush _test-output-buffered-file) - 516 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- - 522 # check first function - 523 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-multiple-function-skeletons/0") - 524 (check-next-stream-line-equal _test-output-stream "# . prologue" "F - test-convert-multiple-function-skeletons/1") - 525 (check-next-stream-line-equal _test-output-stream "55/push-ebp" "F - test-convert-multiple-function-skeletons/2") - 526 (check-next-stream-line-equal _test-output-stream "89/<- %ebp 4/r32/esp" "F - test-convert-multiple-function-skeletons/3") - 527 (check-next-stream-line-equal _test-output-stream "# . epilogue" "F - test-convert-multiple-function-skeletons/4") - 528 (check-next-stream-line-equal _test-output-stream "89/<- %esp 5/r32/ebp" "F - test-convert-multiple-function-skeletons/5") - 529 (check-next-stream-line-equal _test-output-stream "5d/pop-to-ebp" "F - test-convert-multiple-function-skeletons/6") - 530 (check-next-stream-line-equal _test-output-stream "c3/return" "F - test-convert-multiple-function-skeletons/7") - 531 # check second function - 532 (check-next-stream-line-equal _test-output-stream "bar:" "F - test-convert-multiple-function-skeletons/10") - 533 (check-next-stream-line-equal _test-output-stream "# . prologue" "F - test-convert-multiple-function-skeletons/11") - 534 (check-next-stream-line-equal _test-output-stream "55/push-ebp" "F - test-convert-multiple-function-skeletons/12") - 535 (check-next-stream-line-equal _test-output-stream "89/<- %ebp 4/r32/esp" "F - test-convert-multiple-function-skeletons/13") - 536 (check-next-stream-line-equal _test-output-stream "# . epilogue" "F - test-convert-multiple-function-skeletons/14") - 537 (check-next-stream-line-equal _test-output-stream "89/<- %esp 5/r32/ebp" "F - test-convert-multiple-function-skeletons/15") - 538 (check-next-stream-line-equal _test-output-stream "5d/pop-to-ebp" "F - test-convert-multiple-function-skeletons/16") - 539 (check-next-stream-line-equal _test-output-stream "c3/return" "F - test-convert-multiple-function-skeletons/17") - 540 # . epilogue - 541 89/<- %esp 5/r32/ebp - 542 5d/pop-to-ebp - 543 c3/return - 544 - 545 test-convert-function-with-arg: - 546 # function with one arg - 547 # fn foo n : int { - 548 # } - 549 # => - 550 # foo: - 551 # # . prologue - 552 # 55/push-ebp - 553 # 89/<- %ebp 4/r32/esp - 554 # # . epilogue - 555 # 89/<- %esp 5/r32/ebp - 556 # 5d/pop-to-ebp - 557 # c3/return - 558 # . prologue - 559 55/push-ebp - 560 89/<- %ebp 4/r32/esp - 561 # setup - 562 (clear-stream _test-input-stream) - 563 (clear-stream $_test-input-buffered-file->buffer) - 564 (clear-stream _test-output-stream) - 565 (clear-stream $_test-output-buffered-file->buffer) - 566 # - 567 (write _test-input-stream "fn foo n : int {\n") - 568 (write _test-input-stream "}\n") - 569 # convert - 570 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 571 (flush _test-output-buffered-file) - 572 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- - 578 # check output - 579 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-arg/0") - 580 (check-next-stream-line-equal _test-output-stream "# . prologue" "F - test-convert-function-with-arg/1") - 581 (check-next-stream-line-equal _test-output-stream "55/push-ebp" "F - test-convert-function-with-arg/2") - 582 (check-next-stream-line-equal _test-output-stream "89/<- %ebp 4/r32/esp" "F - test-convert-function-with-arg/3") - 583 (check-next-stream-line-equal _test-output-stream "# . epilogue" "F - test-convert-function-with-arg/4") - 584 (check-next-stream-line-equal _test-output-stream "89/<- %esp 5/r32/ebp" "F - test-convert-function-with-arg/5") - 585 (check-next-stream-line-equal _test-output-stream "5d/pop-to-ebp" "F - test-convert-function-with-arg/6") - 586 (check-next-stream-line-equal _test-output-stream "c3/return" "F - test-convert-function-with-arg/7") - 587 # . epilogue - 588 89/<- %esp 5/r32/ebp - 589 5d/pop-to-ebp - 590 c3/return - 591 - 592 test-convert-function-with-arg-and-body: - 593 # function with one arg and one instruction in the body - 594 # fn foo n : int { - 595 # increment n - 596 # } - 597 # => - 598 # foo: - 599 # # . prologue - 600 # 55/push-ebp - 601 # 89/<- %ebp 4/r32/esp - 602 # { - 603 # ff 0/subop/increment *(ebp+8) - 604 # } - 605 # # . epilogue - 606 # 89/<- %esp 5/r32/ebp - 607 # 5d/pop-to-ebp - 608 # c3/return - 609 # . prologue - 610 55/push-ebp - 611 89/<- %ebp 4/r32/esp - 612 # setup - 613 (clear-stream _test-input-stream) - 614 (clear-stream $_test-input-buffered-file->buffer) - 615 (clear-stream _test-output-stream) - 616 (clear-stream $_test-output-buffered-file->buffer) - 617 # - 618 (write _test-input-stream "fn foo n : int {\n") - 619 (write _test-input-stream " increment n\n") - 620 (write _test-input-stream "}\n") - 621 # convert - 622 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 623 (flush _test-output-buffered-file) - 624 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- - 630 # check output - 631 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-arg-and-body/0") - 632 (check-next-stream-line-equal _test-output-stream "# . prologue" "F - test-convert-function-with-arg-and-body/1") - 633 (check-next-stream-line-equal _test-output-stream "55/push-ebp" "F - test-convert-function-with-arg-and-body/2") - 634 (check-next-stream-line-equal _test-output-stream "89/<- %ebp 4/r32/esp" "F - test-convert-function-with-arg-and-body/3") - 635 (check-next-stream-line-equal _test-output-stream "{" "F - test-convert-function-with-arg-and-body/4") - 636 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment *(ebp+0x00000008)" "F - test-convert-function-with-arg-and-body/5") - 637 (check-next-stream-line-equal _test-output-stream "}" "F - test-convert-function-with-arg-and-body/6") - 638 (check-next-stream-line-equal _test-output-stream "# . epilogue" "F - test-convert-function-with-arg-and-body/7") - 639 (check-next-stream-line-equal _test-output-stream "89/<- %esp 5/r32/ebp" "F - test-convert-function-with-arg-and-body/8") - 640 (check-next-stream-line-equal _test-output-stream "5d/pop-to-ebp" "F - test-convert-function-with-arg-and-body/9") - 641 (check-next-stream-line-equal _test-output-stream "c3/return" "F - test-convert-function-with-arg-and-body/10") - 642 # . epilogue - 643 89/<- %esp 5/r32/ebp - 644 5d/pop-to-ebp - 645 c3/return - 646 - 647 test-convert-function-distinguishes-args: - 648 # function with two args refers to second one in body - 649 # fn foo a: int, b: int { - 650 # increment b - 651 # } - 652 # => - 653 # foo: - 654 # # . prologue - 655 # 55/push-ebp - 656 # 89/<- %ebp 4/r32/esp - 657 # { - 658 # ff 0/subop/increment *(ebp+0xc) - 659 # } - 660 # # . epilogue - 661 # 89/<- %esp 5/r32/ebp - 662 # 5d/pop-to-ebp - 663 # c3/return - 664 # . prologue - 665 55/push-ebp - 666 89/<- %ebp 4/r32/esp - 667 # setup - 668 (clear-stream _test-input-stream) - 669 (clear-stream $_test-input-buffered-file->buffer) - 670 (clear-stream _test-output-stream) - 671 (clear-stream $_test-output-buffered-file->buffer) - 672 # - 673 (write _test-input-stream "fn foo a: int, b: int {\n") - 674 (write _test-input-stream " increment b\n") - 675 (write _test-input-stream "}\n") - 676 # convert - 677 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 678 (flush _test-output-buffered-file) - 679 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- - 685 # check output - 686 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-distinguishes-args/0") - 687 (check-next-stream-line-equal _test-output-stream "# . prologue" "F - test-convert-function-distinguishes-args/1") - 688 (check-next-stream-line-equal _test-output-stream "55/push-ebp" "F - test-convert-function-distinguishes-args/2") - 689 (check-next-stream-line-equal _test-output-stream "89/<- %ebp 4/r32/esp" "F - test-convert-function-distinguishes-args/3") - 690 (check-next-stream-line-equal _test-output-stream "{" "F - test-convert-function-distinguishes-args/4") - 691 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment *(ebp+0x0000000c)" "F - test-convert-function-distinguishes-args/5") - 692 (check-next-stream-line-equal _test-output-stream "}" "F - test-convert-function-distinguishes-args/6") - 693 (check-next-stream-line-equal _test-output-stream "# . epilogue" "F - test-convert-function-distinguishes-args/7") - 694 (check-next-stream-line-equal _test-output-stream "89/<- %esp 5/r32/ebp" "F - test-convert-function-distinguishes-args/8") - 695 (check-next-stream-line-equal _test-output-stream "5d/pop-to-ebp" "F - test-convert-function-distinguishes-args/9") - 696 (check-next-stream-line-equal _test-output-stream "c3/return" "F - test-convert-function-distinguishes-args/10") - 697 # . epilogue - 698 89/<- %esp 5/r32/ebp - 699 5d/pop-to-ebp - 700 c3/return - 701 - 702 test-convert-function-returns-result: - 703 # function writes to output - 704 # fn foo a: int, b: int -> result/eax: int { - 705 # result <- copy a - 706 # result <- increment - 707 # } - 708 # => - 709 # foo: - 710 # # . prologue - 711 # 55/push-ebp - 712 # 89/<- %ebp 4/r32/esp - 713 # { - 714 # 89/-> *(ebp+8) 0/r32/eax - 715 # 40/increment-eax - 716 # } - 717 # # . epilogue - 718 # 89/<- %esp 5/r32/ebp - 719 # 5d/pop-to-ebp - 720 # c3/return - 721 # . prologue - 722 55/push-ebp - 723 89/<- %ebp 4/r32/esp - 724 # setup - 725 (clear-stream _test-input-stream) - 726 (clear-stream $_test-input-buffered-file->buffer) - 727 (clear-stream _test-output-stream) - 728 (clear-stream $_test-output-buffered-file->buffer) - 729 # - 730 (write _test-input-stream "fn foo a: int, b: int -> result/eax: int {\n") - 731 (write _test-input-stream " result <- copy a\n") - 732 (write _test-input-stream " result <- increment\n") - 733 (write _test-input-stream "}\n") - 734 # convert - 735 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 736 (flush _test-output-buffered-file) - 737 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- - 743 # check output - 744 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-returns-result/0") - 745 (check-next-stream-line-equal _test-output-stream "# . prologue" "F - test-convert-function-returns-result/1") - 746 (check-next-stream-line-equal _test-output-stream "55/push-ebp" "F - test-convert-function-returns-result/2") - 747 (check-next-stream-line-equal _test-output-stream "89/<- %ebp 4/r32/esp" "F - test-convert-function-returns-result/3") - 748 (check-next-stream-line-equal _test-output-stream "{" "F - test-convert-function-returns-result/4") - 749 (check-next-stream-line-equal _test-output-stream "8b/copy-from *(ebp+0x00000008) 0x00000000/r32" "F - test-convert-function-returns-result/5") - 750 (check-next-stream-line-equal _test-output-stream "40/increment-eax" "F - test-convert-function-returns-result/6") - 751 (check-next-stream-line-equal _test-output-stream "}" "F - test-convert-function-returns-result/7") - 752 (check-next-stream-line-equal _test-output-stream "# . epilogue" "F - test-convert-function-returns-result/8") - 753 (check-next-stream-line-equal _test-output-stream "89/<- %esp 5/r32/ebp" "F - test-convert-function-returns-result/9") - 754 (check-next-stream-line-equal _test-output-stream "5d/pop-to-ebp" "F - test-convert-function-returns-result/10") - 755 (check-next-stream-line-equal _test-output-stream "c3/return" "F - test-convert-function-returns-result/11") - 756 # . epilogue - 757 89/<- %esp 5/r32/ebp - 758 5d/pop-to-ebp - 759 c3/return - 760 - 761 test-convert-function-literal-arg: - 762 # function writes to output - 763 # fn foo a: int, b: int -> result/eax: int { - 764 # result <- copy a - 765 # result <- add 1 - 766 # } - 767 # => - 768 # foo: - 769 # # . prologue - 770 # 55/push-ebp - 771 # 89/<- %ebp 4/r32/esp - 772 # { - 773 # 89/-> *(ebp+8) 0/r32/eax - 774 # 05/add-to-eax 1/imm32 - 775 # } - 776 # # . epilogue - 777 # 89/<- %esp 5/r32/ebp - 778 # 5d/pop-to-ebp - 779 # c3/return - 780 # . prologue - 781 55/push-ebp - 782 89/<- %ebp 4/r32/esp - 783 # setup - 784 (clear-stream _test-input-stream) - 785 (clear-stream $_test-input-buffered-file->buffer) - 786 (clear-stream _test-output-stream) - 787 (clear-stream $_test-output-buffered-file->buffer) - 788 # - 789 (write _test-input-stream "fn foo a: int, b: int -> result/eax: int {\n") - 790 (write _test-input-stream " result <- copy a\n") - 791 (write _test-input-stream " result <- add 1\n") - 792 (write _test-input-stream "}\n") - 793 # convert - 794 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 795 (flush _test-output-buffered-file) - 796 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- - 802 # check output - 803 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-literal-arg/0") - 804 (check-next-stream-line-equal _test-output-stream "# . prologue" "F - test-convert-function-literal-arg/1") - 805 (check-next-stream-line-equal _test-output-stream "55/push-ebp" "F - test-convert-function-literal-arg/2") - 806 (check-next-stream-line-equal _test-output-stream "89/<- %ebp 4/r32/esp" "F - test-convert-function-literal-arg/3") - 807 (check-next-stream-line-equal _test-output-stream "{" "F - test-convert-function-literal-arg/4") - 808 (check-next-stream-line-equal _test-output-stream "8b/copy-from *(ebp+0x00000008) 0x00000000/r32" "F - test-convert-function-literal-arg/5") - 809 (check-next-stream-line-equal _test-output-stream "05/add-to-eax 1/imm32" "F - test-convert-function-literal-arg/6") - 810 (check-next-stream-line-equal _test-output-stream "}" "F - test-convert-function-literal-arg/7") - 811 (check-next-stream-line-equal _test-output-stream "# . epilogue" "F - test-convert-function-literal-arg/8") - 812 (check-next-stream-line-equal _test-output-stream "89/<- %esp 5/r32/ebp" "F - test-convert-function-literal-arg/9") - 813 (check-next-stream-line-equal _test-output-stream "5d/pop-to-ebp" "F - test-convert-function-literal-arg/10") - 814 (check-next-stream-line-equal _test-output-stream "c3/return" "F - test-convert-function-literal-arg/11") - 815 # . epilogue - 816 89/<- %esp 5/r32/ebp - 817 5d/pop-to-ebp - 818 c3/return - 819 - 820 test-convert-function-literal-arg-2: - 821 # function writes to output - 822 # fn foo a: int, b: int -> result/ebx: int { - 823 # result <- copy a - 824 # result <- add 1 - 825 # } - 826 # => - 827 # foo: - 828 # # . prologue - 829 # 55/push-ebp - 830 # 89/<- %ebp 4/r32/esp - 831 # { - 832 # 89/-> *(ebp+8) 3/r32/ebx - 833 # 81 0/subop/add %ebx 1/imm32 - 834 # } - 835 # # . epilogue - 836 # 89/<- %esp 5/r32/ebp - 837 # 5d/pop-to-ebp - 838 # c3/return - 839 # . prologue - 840 55/push-ebp - 841 89/<- %ebp 4/r32/esp - 842 # setup - 843 (clear-stream _test-input-stream) - 844 (clear-stream $_test-input-buffered-file->buffer) - 845 (clear-stream _test-output-stream) - 846 (clear-stream $_test-output-buffered-file->buffer) - 847 # - 848 (write _test-input-stream "fn foo a: int, b: int -> result/ebx: int {\n") - 849 (write _test-input-stream " result <- copy a\n") - 850 (write _test-input-stream " result <- add 1\n") - 851 (write _test-input-stream "}\n") - 852 # convert - 853 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 854 (flush _test-output-buffered-file) - 855 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- - 861 # check output - 862 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-literal-arg-2/0") - 863 (check-next-stream-line-equal _test-output-stream "# . prologue" "F - test-convert-function-literal-arg-2/1") - 864 (check-next-stream-line-equal _test-output-stream "55/push-ebp" "F - test-convert-function-literal-arg-2/2") - 865 (check-next-stream-line-equal _test-output-stream "89/<- %ebp 4/r32/esp" "F - test-convert-function-literal-arg-2/3") - 866 (check-next-stream-line-equal _test-output-stream "{" "F - test-convert-function-literal-arg-2/4") - 867 (check-next-stream-line-equal _test-output-stream "8b/copy-from *(ebp+0x00000008) 0x00000003/r32" "F - test-convert-function-literal-arg-2/5") - 868 (check-next-stream-line-equal _test-output-stream "81 0/subop/add %ebx 1/imm32" "F - test-convert-function-literal-arg-2/6") - 869 (check-next-stream-line-equal _test-output-stream "}" "F - test-convert-function-literal-arg-2/7") - 870 (check-next-stream-line-equal _test-output-stream "# . epilogue" "F - test-convert-function-literal-arg-2/8") - 871 (check-next-stream-line-equal _test-output-stream "89/<- %esp 5/r32/ebp" "F - test-convert-function-literal-arg-2/9") - 872 (check-next-stream-line-equal _test-output-stream "5d/pop-to-ebp" "F - test-convert-function-literal-arg-2/10") - 873 (check-next-stream-line-equal _test-output-stream "c3/return" "F - test-convert-function-literal-arg-2/11") - 874 # . epilogue - 875 89/<- %esp 5/r32/ebp - 876 5d/pop-to-ebp - 877 c3/return - 878 - 879 test-convert-function-call-with-literal-arg: - 880 # function writes to output - 881 # fn main -> result/ebx: int { - 882 # result <- do-add 3 4 - 883 # } - 884 # - 885 # fn do-add a: int, b: int -> result/ebx: int { - 886 # result <- copy a - 887 # result <- add b - 888 # } - 889 # => - 890 # main: - 891 # # . prologue - 892 # 55/push-ebp - 893 # 89/<- %ebp 4/r32/esp - 894 # { - 895 # (do-add 3 4) - 896 # } - 897 # # . epilogue - 898 # 89/<- %esp 5/r32/ebp - 899 # 5d/pop-to-ebp - 900 # c3/return - 901 # do-add: - 902 # # . prologue - 903 # 55/push-ebp - 904 # 89/<- %ebp 4/r32/esp - 905 # { - 906 # 8b/-> *(ebp+8) 3/r32/ebx - 907 # 03/add-to 3/r32/ebx *(ebp+0xc) - 908 # } - 909 # # . epilogue - 910 # 89/<- %esp 5/r32/ebp - 911 # 5d/pop-to-ebp - 912 # c3/return - 913 # . prologue - 914 55/push-ebp - 915 89/<- %ebp 4/r32/esp - 916 # setup - 917 (clear-stream _test-input-stream) - 918 (clear-stream $_test-input-buffered-file->buffer) - 919 (clear-stream _test-output-stream) - 920 (clear-stream $_test-output-buffered-file->buffer) - 921 # - 922 (write _test-input-stream "fn main -> result/ebx: int {\n") - 923 (write _test-input-stream " result <- do-add 3 4\n") - 924 (write _test-input-stream "}\n") - 925 (write _test-input-stream "fn do-add a: int, b: int -> result/ebx: int {\n") - 926 (write _test-input-stream " result <- copy a\n") - 927 (write _test-input-stream " result <- add b\n") - 928 (write _test-input-stream "}\n") - 929 # convert - 930 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 931 (flush _test-output-buffered-file) - 932 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- - 938 # check output - 939 (check-next-stream-line-equal _test-output-stream "main:" "F - test-convert-function-call-with-literal-arg/0") - 940 (check-next-stream-line-equal _test-output-stream "# . prologue" "F - test-convert-function-call-with-literal-arg/1") - 941 (check-next-stream-line-equal _test-output-stream "55/push-ebp" "F - test-convert-function-call-with-literal-arg/2") - 942 (check-next-stream-line-equal _test-output-stream "89/<- %ebp 4/r32/esp" "F - test-convert-function-call-with-literal-arg/3") - 943 (check-next-stream-line-equal _test-output-stream "{" "F - test-convert-function-call-with-literal-arg/4") - 944 (check-next-stream-line-equal _test-output-stream "(do-add 3 4)" "F - test-convert-function-call-with-literal-arg/5") - 945 (check-next-stream-line-equal _test-output-stream "}" "F - test-convert-function-call-with-literal-arg/6") - 946 (check-next-stream-line-equal _test-output-stream "# . epilogue" "F - test-convert-function-call-with-literal-arg/7") - 947 (check-next-stream-line-equal _test-output-stream "89/<- %esp 5/r32/ebp" "F - test-convert-function-call-with-literal-arg/8") - 948 (check-next-stream-line-equal _test-output-stream "5d/pop-to-ebp" "F - test-convert-function-call-with-literal-arg/9") - 949 (check-next-stream-line-equal _test-output-stream "c3/return" "F - test-convert-function-call-with-literal-arg/10") - 950 (check-next-stream-line-equal _test-output-stream "do-add:" "F - test-convert-function-call-with-literal-arg/11") - 951 (check-next-stream-line-equal _test-output-stream "# . prologue" "F - test-convert-function-call-with-literal-arg/12") - 952 (check-next-stream-line-equal _test-output-stream "55/push-ebp" "F - test-convert-function-call-with-literal-arg/13") - 953 (check-next-stream-line-equal _test-output-stream "89/<- %ebp 4/r32/esp" "F - test-convert-function-call-with-literal-arg/14") - 954 (check-next-stream-line-equal _test-output-stream "{" "F - test-convert-function-call-with-literal-arg/15") - 955 (check-next-stream-line-equal _test-output-stream "8b/copy-from *(ebp+0x00000008) 0x00000003/r32" "F - test-convert-function-call-with-literal-arg/16") - 956 (check-next-stream-line-equal _test-output-stream "03/add *(ebp+0x0000000c) 0x00000003/r32" "F - test-convert-function-call-with-literal-arg/17") - 957 (check-next-stream-line-equal _test-output-stream "}" "F - test-convert-function-call-with-literal-arg/18") - 958 (check-next-stream-line-equal _test-output-stream "# . epilogue" "F - test-convert-function-call-with-literal-arg/19") - 959 (check-next-stream-line-equal _test-output-stream "89/<- %esp 5/r32/ebp" "F - test-convert-function-call-with-literal-arg/20") - 960 (check-next-stream-line-equal _test-output-stream "5d/pop-to-ebp" "F - test-convert-function-call-with-literal-arg/21") - 961 (check-next-stream-line-equal _test-output-stream "c3/return" "F - test-convert-function-call-with-literal-arg/22") - 962 # . epilogue - 963 89/<- %esp 5/r32/ebp - 964 5d/pop-to-ebp - 965 c3/return - 966 - 967 ####################################################### - 968 # Parsing - 969 ####################################################### - 970 - 971 parse-mu: # in : (addr buffered-file) - 972 # pseudocode - 973 # var curr-function : (addr (handle function)) = Program - 974 # var line : (stream byte 512) - 975 # var word-slice : slice - 976 # while true # line loop - 977 # clear-stream(line) - 978 # read-line-buffered(in, line) - 979 # if (line->write == 0) break # end of file - 980 # word-slice = next-word-or-string(line) - 981 # if slice-empty?(word-slice) # end of line - 982 # continue - 983 # else if slice-starts-with?(word-slice, "#") # comment - 984 # continue # end of line - 985 # else if slice-equal(word-slice, "fn") - 986 # var new-function : (handle function) = allocate(function) - 987 # var vars : (stack (addr var) 256) - 988 # populate-mu-function-header(in, new-function, vars) - 989 # populate-mu-function-body(in, new-function, vars) - 990 # assert(vars->top == 0) - 991 # *curr-function = new-function - 992 # curr-function = &new-function->next - 993 # else - 994 # abort() - 995 # - 996 # . prologue - 997 55/push-ebp - 998 89/<- %ebp 4/r32/esp - 999 # . save registers -1000 50/push-eax -1001 51/push-ecx -1002 52/push-edx -1003 53/push-ebx -1004 57/push-edi -1005 # var line/ecx : (stream byte 512) -1006 81 5/subop/subtract %esp 0x200/imm32 -1007 68/push 0x200/imm32/length -1008 68/push 0/imm32/read -1009 68/push 0/imm32/write -1010 89/<- %ecx 4/r32/esp -1011 # var word-slice/edx : slice -1012 68/push 0/imm32/end -1013 68/push 0/imm32/start -1014 89/<- %edx 4/r32/esp -1015 # var curr-function/edi : (addr (handle function)) = Program -1016 bf/copy-to-edi Program/imm32 -1017 # var vars/ebx : (stack (addr var) 256) -1018 81 5/subop/subtract %esp 0x400/imm32 -1019 68/push 0x400/imm32/length -1020 68/push 0/imm32/top -1021 89/<- %ebx 4/r32/esp -1022 { -1023 $parse-mu:line-loop: -1024 (clear-stream %ecx) -1025 (read-line-buffered *(ebp+8) %ecx) -1026 # if (line->write == 0) break -1027 81 7/subop/compare *ecx 0/imm32 -1028 0f 84/jump-if-= break/disp32 -1029 +-- 6 lines: #? # dump line --------------------------------------------------------------------------------------------------------------------------- -1035 (next-word-or-string %ecx %edx) -1036 # if slice-empty?(word-slice) continue -1037 (slice-empty? %edx) -1038 3d/compare-eax-and 0/imm32 -1039 0f 85/jump-if-!= loop/disp32 -1040 # if (*word-slice->start == "#") continue -1041 # . eax = *word-slice->start -1042 8b/-> *edx 0/r32/eax -1043 8a/copy-byte *eax 0/r32/AL -1044 81 4/subop/and %eax 0xff/imm32 -1045 # . if (eax == '#') continue -1046 3d/compare-eax-and 0x23/imm32/hash -1047 0f 84/jump-if-= loop/disp32 -1048 # if (slice-equal?(word-slice, "fn")) parse a function -1049 { -1050 $parse-mu:fn: -1051 (slice-equal? %edx "fn") -1052 3d/compare-eax-and 0/imm32 -1053 0f 84/jump-if-= break/disp32 -1054 # var new-function/eax : (handle function) = populate-mu-function(in, new-function, vars) -1055 (allocate Heap *Function-size) # => eax -1056 (zero-out %eax *Function-size) -1057 (clear-stack %ebx) -1058 (populate-mu-function-header %ecx %eax %ebx) -1059 (populate-mu-function-body *(ebp+8) %eax %ebx) -1060 # *curr-function = new-function -1061 89/<- *edi 0/r32/eax -1062 # curr-function = &new-function->next -1063 8d/address-> *(eax+0x14) 7/r32/edi # Function-next -1064 e9/jump $parse-mu:line-loop/disp32 -1065 } -1066 # otherwise abort -1067 e9/jump $parse-mu:error1/disp32 -1068 } # end line loop -1069 $parse-mu:end: -1070 # . reclaim locals -1071 81 0/subop/add %esp 0x630/imm32 -1072 # . restore registers -1073 5f/pop-to-edi -1074 5b/pop-to-ebx -1075 5a/pop-to-edx -1076 59/pop-to-ecx -1077 58/pop-to-eax -1078 # . epilogue -1079 89/<- %esp 5/r32/ebp -1080 5d/pop-to-ebp -1081 c3/return -1082 -1083 $parse-mu:error1: -1084 # error("unexpected top-level command: " word-slice "\n") -1085 (write-buffered Stderr "unexpected top-level command: ") -1086 (write-slice-buffered Stderr %edx) -1087 (write-buffered Stderr "\n") -1088 (flush Stderr) -1089 # . syscall(exit, 1) -1090 bb/copy-to-ebx 1/imm32 -1091 b8/copy-to-eax 1/imm32/exit -1092 cd/syscall 0x80/imm8 -1093 # never gets here -1094 -1095 $parse-mu:error2: -1096 # error(vars->top " vars not reclaimed after fn '" new-function->name "'\n") -1097 (print-int32-buffered Stderr *ebx) -1098 (write-buffered Stderr " vars not reclaimed after fn '") -1099 (write-slice-buffered Stderr *eax) # Function-name -1100 (write-buffered Stderr "'\n") -1101 (flush Stderr) -1102 # . syscall(exit, 1) -1103 bb/copy-to-ebx 1/imm32 -1104 b8/copy-to-eax 1/imm32/exit -1105 cd/syscall 0x80/imm8 -1106 # never gets here -1107 -1108 # scenarios considered: -1109 # ✗ fn foo # no block -1110 # ✓ fn foo { -1111 # ✗ fn foo { { -1112 # ✗ fn foo { } -1113 # ✗ fn foo { } { -1114 # ✗ fn foo x { -1115 # ✗ fn foo x : { -1116 # ✓ fn foo x : int { -1117 # ✓ fn foo x: int { -1118 # ✓ fn foo x: int -> y/eax: int { -1119 populate-mu-function-header: # first-line : (addr stream byte), out : (handle function), vars : (addr stack (handle var)) -1120 # pseudocode: -1121 # var name : slice -1122 # next-word(first-line, name) -1123 # assert(name not in '{' '}' '->') -1124 # out->name = slice-to-string(name) -1125 # var next-offset : int = 8 -1126 # ## inouts -1127 # while true -1128 # ## name -1129 # name = next-word(first-line) -1130 # if (name == '{') goto done -1131 # if (name == '->') break -1132 # assert(name != '}') -1133 # var v : (handle var) = parse-var-with-type(name, first-line) -1134 # assert(v->register == null) -1135 # v->stack-offset = next-offset -1136 # next-offset += size-of(v) -1137 # out->inouts = append(out->inouts, v) -1138 # push(vars, v) -1139 # ## outputs -1140 # while true -1141 # ## name -1142 # name = next-word(first-line) -1143 # assert(name not in '{' '}' '->') -1144 # var v : (handle var) = parse-var-with-type(name, first-line) -1145 # assert(v->register != null) -1146 # out->outputs = append(out->outputs, v) -1147 # done: -1148 # -1149 # . prologue -1150 55/push-ebp -1151 89/<- %ebp 4/r32/esp -1152 # . save registers -1153 50/push-eax -1154 51/push-ecx -1155 52/push-edx -1156 53/push-ebx -1157 57/push-edi -1158 # edi = out -1159 8b/-> *(ebp+0xc) 7/r32/edi -1160 # var word-slice/ecx : slice -1161 68/push 0/imm32/end -1162 68/push 0/imm32/start -1163 89/<- %ecx 4/r32/esp -1164 # var next-offset/edx = 8 -1165 ba/copy-to-edx 8/imm32 -1166 # read function name -1167 (next-word *(ebp+8) %ecx) -1168 # error checking -1169 # if (word-slice == '{') abort -1170 (slice-equal? %ecx "{") # => eax -1171 3d/compare-eax-and 0/imm32 -1172 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 -1173 # if (word-slice == '->') abort -1174 (slice-equal? %ecx "->") # => eax -1175 3d/compare-eax-and 0/imm32 -1176 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 -1177 # if (word-slice == '}') abort -1178 (slice-equal? %ecx "}") # => eax -1179 3d/compare-eax-and 0/imm32 -1180 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 -1181 # save function name -1182 (slice-to-string Heap %ecx) # => eax -1183 89/<- *edi 0/r32/eax # Function-name -1184 # initialize default subx-name as well -1185 89/<- *(edi+4) 0/r32/eax # Function-subx-name -1186 # save function inouts -1187 { -1188 $populate-mu-function-header:check-for-inout: -1189 (next-word *(ebp+8) %ecx) -1190 # if (word-slice == '{') goto done -1191 (slice-equal? %ecx "{") # => eax -1192 3d/compare-eax-and 0/imm32 -1193 0f 85/jump-if-!= $populate-mu-function-header:done/disp32 -1194 # if (word-slice == '->') break -1195 (slice-equal? %ecx "->") # => eax -1196 3d/compare-eax-and 0/imm32 -1197 0f 85/jump-if-!= break/disp32 -1198 # if (word-slice == '}') abort -1199 (slice-equal? %ecx "}") # => eax -1200 3d/compare-eax-and 0/imm32 -1201 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 -1202 # var v/ebx : (handle var) = parse-var-with-type(word-slice, first-line) -1203 (parse-var-with-type %ecx *(ebp+8)) # => eax -1204 89/<- %ebx 0/r32/eax -1205 # assert(v->register == null) -1206 81 7/subop/compare *(ebx+0x10) 0/imm32 # Var-register -1207 0f 85/jump-if-!= $populate-mu-function-header:error2/disp32 -1208 # v->stack-offset = next-offset -1209 89/<- *(ebx+0xc) 2/r32/edx # Var-stack-offset -1210 # next-offset += size-of(v) -1211 (size-of %ebx) # => eax -1212 01/add %edx 0/r32/eax -1213 # -1214 (append-list Heap %ebx *(edi+8)) # Function-inouts => eax -1215 89/<- *(edi+8) 0/r32/eax # Function-inouts -1216 (push *(ebp+0x10) %ebx) -1217 # -1218 e9/jump loop/disp32 -1219 } -1220 # save function outputs -1221 { -1222 $parse-var-with-type:check-for-out: -1223 (next-word *(ebp+8) %ecx) -1224 # if (word-slice == '{') break -1225 (slice-equal? %ecx "{") # => eax -1226 3d/compare-eax-and 0/imm32 -1227 0f 85/jump-if-!= break/disp32 -1228 # if (word-slice == '->') abort -1229 (slice-equal? %ecx "->") # => eax -1230 3d/compare-eax-and 0/imm32 -1231 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 -1232 # if (word-slice == '}') abort -1233 (slice-equal? %ecx "}") # => eax -1234 3d/compare-eax-and 0/imm32 -1235 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 -1236 # -1237 (parse-var-with-type %ecx *(ebp+8)) # => eax -1238 89/<- %ebx 0/r32/eax -1239 # assert(var->register != null) -1240 81 7/subop/compare *(ebx+0x10) 0/imm32 # Var-register -1241 0f 84/jump-if-= $populate-mu-function-header:error3/disp32 -1242 (append-list Heap %ebx *(edi+0xc)) # Function-outputs => eax -1243 89/<- *(edi+0xc) 0/r32/eax # Function-outputs -1244 e9/jump loop/disp32 -1245 } -1246 $populate-mu-function-header:done: -1247 (check-no-tokens-left *(ebp+8)) -1248 $populate-mu-function-header:end: -1249 # . reclaim locals -1250 81 0/subop/add %esp 8/imm32 -1251 # . restore registers -1252 5f/pop-to-edi -1253 5b/pop-to-ebx -1254 5a/pop-to-edx -1255 59/pop-to-ecx -1256 58/pop-to-eax -1257 # . epilogue -1258 89/<- %esp 5/r32/ebp -1259 5d/pop-to-ebp -1260 c3/return -1261 -1262 $populate-mu-function-header:error1: -1263 # error("function header not in form 'fn <name> {'") -1264 (write-buffered Stderr "function header not in form 'fn <name> [inouts] [-> outputs] {' -- '") -1265 (flush Stderr) -1266 (rewind-stream *(ebp+8)) -1267 (write-stream 2 *(ebp+8)) -1268 (write-buffered Stderr "'\n") -1269 (flush Stderr) -1270 # . syscall(exit, 1) -1271 bb/copy-to-ebx 1/imm32 -1272 b8/copy-to-eax 1/imm32/exit -1273 cd/syscall 0x80/imm8 -1274 # never gets here -1275 -1276 $populate-mu-function-header:error2: -1277 # error("function input '" var "' cannot be in a register") -1278 (write-buffered Stderr "function input '") -1279 (write-buffered Stderr *ebx) # Var-name -1280 (write-buffered Stderr "' cannot be in a register") -1281 (flush Stderr) -1282 # . syscall(exit, 1) -1283 bb/copy-to-ebx 1/imm32 -1284 b8/copy-to-eax 1/imm32/exit -1285 cd/syscall 0x80/imm8 -1286 # never gets here -1287 -1288 $populate-mu-function-header:error3: -1289 # error("function input '" var "' must be in a register") -1290 (write-buffered Stderr "function input '") -1291 (write-buffered Stderr *eax) # Var-name -1292 (write-buffered Stderr " must be in a register'") -1293 (flush Stderr) -1294 (rewind-stream *(ebp+8)) -1295 (write-stream 2 *(ebp+8)) -1296 (write-buffered Stderr "'\n") -1297 (flush Stderr) -1298 # . syscall(exit, 1) -1299 bb/copy-to-ebx 1/imm32 -1300 b8/copy-to-eax 1/imm32/exit -1301 cd/syscall 0x80/imm8 -1302 # never gets here -1303 -1304 test-function-header-with-arg: -1305 # 'foo n : int {' -1306 # . prologue -1307 55/push-ebp -1308 89/<- %ebp 4/r32/esp -1309 # setup -1310 (clear-stream _test-input-stream) -1311 (write _test-input-stream "foo n : int {\n") -1312 # result/ecx : function -1313 2b/subtract-> *Function-size 4/r32/esp -1314 89/<- %ecx 4/r32/esp -1315 (zero-out %ecx *Function-size) -1316 # var vars/ebx : (stack (addr var) 16) -1317 81 5/subop/subtract %esp 0x10/imm32 -1318 68/push 0x10/imm32/length -1319 68/push 0/imm32/top -1320 89/<- %ebx 4/r32/esp -1321 # convert -1322 (populate-mu-function-header _test-input-stream %ecx %ebx) -1323 # check result -1324 (check-strings-equal *ecx "foo" "F - test-function-header-with-arg/name") # Function-name -1325 # edx : (handle list var) = result->inouts -1326 8b/-> *(ecx+8) 2/r32/edx # Function-inouts -1327 # ebx : (handle var) = result->inouts->value -1328 8b/-> *edx 3/r32/ebx # List-value -1329 (check-strings-equal *ebx "n" "F - test-function-header-with-arg/inout:0") # Var-name -1330 8b/-> *(ebx+4) 3/r32/ebx # Var-type -1331 (check-ints-equal *ebx 1 "F - test-function-header-with-arg/inout:0/type:0") # Tree-left -1332 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-arg/inout:0/type:1") # Tree-right -1333 # . epilogue -1334 89/<- %esp 5/r32/ebp -1335 5d/pop-to-ebp -1336 c3/return -1337 -1338 test-function-header-with-multiple-args: -1339 # 'fn foo a: int, b: int, c: int {' -1340 # . prologue -1341 55/push-ebp -1342 89/<- %ebp 4/r32/esp -1343 # setup -1344 (clear-stream _test-input-stream) -1345 (write _test-input-stream "foo a: int, b: int c: int {\n") -1346 # result/ecx : (handle function) -1347 2b/subtract-> *Function-size 4/r32/esp -1348 89/<- %ecx 4/r32/esp -1349 (zero-out %ecx *Function-size) -1350 # var vars/ebx : (stack (addr var) 16) -1351 81 5/subop/subtract %esp 0x10/imm32 -1352 68/push 0x10/imm32/length -1353 68/push 0/imm32/top -1354 89/<- %ebx 4/r32/esp -1355 # convert -1356 (populate-mu-function-header _test-input-stream %ecx %ebx) -1357 # check result -1358 (check-strings-equal *ecx "foo") # Function-name -1359 # edx : (handle list var) = result->inouts -1360 8b/-> *(ecx+8) 2/r32/edx # Function-inouts -1361 $test-function-header-with-multiple-args:inout0: -1362 # ebx : (handle var) = result->inouts->value -1363 8b/-> *edx 3/r32/ebx # List-value -1364 (check-strings-equal *ebx "a" "F - test-function-header-with-multiple-args/inout:0") # Var-name -1365 8b/-> *(ebx+4) 3/r32/ebx # Var-type -1366 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args/inout:0/type:0") # Tree-left -1367 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args/inout:0/type:1") # Tree-right -1368 # edx = result->inouts->next -1369 8b/-> *(edx+4) 2/r32/edx # List-next -1370 $test-function-header-with-multiple-args:inout1: -1371 # ebx = result->inouts->next->value -1372 8b/-> *edx 3/r32/ebx # List-value -1373 (check-strings-equal *ebx "b" "F - test-function-header-with-multiple-args/inout:1") # Var-name -1374 8b/-> *(ebx+4) 3/r32/ebx # Var-type -1375 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args/inout:1/type:0") # Tree-left -1376 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args/inout:1/type:1") # Tree-right -1377 # edx = result->inouts->next->next -1378 8b/-> *(edx+4) 2/r32/edx # List-next -1379 $test-function-header-with-multiple-args:inout2: -1380 # ebx = result->inouts->next->next->value -1381 8b/-> *edx 3/r32/ebx # List-value -1382 (check-strings-equal *ebx "c" "F - test-function-header-with-multiple-args/inout:2") # Var-name -1383 8b/-> *(ebx+4) 3/r32/ebx # Var-type -1384 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args/inout:2/type:0") # Tree-left -1385 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args/inout:2/type:1") # Tree-right -1386 # . epilogue -1387 89/<- %esp 5/r32/ebp -1388 5d/pop-to-ebp -1389 c3/return -1390 -1391 test-function-with-multiple-args-and-outputs: -1392 # fn foo a: int, b: int, c: int -> x: int, y: int { -1393 # . prologue -1394 55/push-ebp -1395 89/<- %ebp 4/r32/esp -1396 # setup -1397 (clear-stream _test-input-stream) -1398 (write _test-input-stream "foo a: int, b: int, c: int -> x/ecx: int y/edx : int {\n") -1399 # result/ecx : (handle function) -1400 2b/subtract-> *Function-size 4/r32/esp -1401 89/<- %ecx 4/r32/esp -1402 (zero-out %ecx *Function-size) -1403 # var vars/ebx : (stack (addr var) 16) -1404 81 5/subop/subtract %esp 0x10/imm32 -1405 68/push 0x10/imm32/length -1406 68/push 0/imm32/top -1407 89/<- %ebx 4/r32/esp -1408 # convert -1409 (populate-mu-function-header _test-input-stream %ecx %ebx) -1410 # check result -1411 (check-strings-equal *ecx "foo") # Function-name -1412 # edx : (handle list var) = result->inouts -1413 8b/-> *(ecx+8) 2/r32/edx # Function-inouts -1414 # ebx : (handle var) = result->inouts->value -1415 8b/-> *edx 3/r32/ebx # List-value -1416 (check-strings-equal *ebx "a" "F - test-function-header-with-multiple-args-and-outputs/inout:0") # Var-name -1417 8b/-> *(ebx+4) 3/r32/ebx # Var-type -1418 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:0") # Tree-left -1419 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:1") # Tree-right -1420 # edx = result->inouts->next -1421 8b/-> *(edx+4) 2/r32/edx # List-next -1422 # ebx = result->inouts->next->value -1423 8b/-> *edx 3/r32/ebx # List-value -1424 (check-strings-equal *ebx "b" "F - test-function-header-with-multiple-args-and-outputs/inout:1") # Var-name -1425 8b/-> *(ebx+4) 3/r32/ebx # Var-type -1426 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:0") # Tree-left -1427 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:1") # Tree-right -1428 # edx = result->inouts->next->next -1429 8b/-> *(edx+4) 2/r32/edx # List-next -1430 # ebx = result->inouts->next->next->value -1431 8b/-> *edx 3/r32/ebx # List-value -1432 (check-strings-equal *ebx "c" "F - test-function-header-with-multiple-args-and-outputs/inout:2") # Var-name -1433 8b/-> *(ebx+4) 3/r32/ebx # Var-type -1434 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:0") # Tree-left -1435 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:1") # Tree-right -1436 # edx : (handle list var) = result->outputs -1437 8b/-> *(ecx+0xc) 2/r32/edx # Function-outputs -1438 # ebx : (handle var) = result->outputs->value -1439 8b/-> *edx 3/r32/ebx # List-value -1440 (check-strings-equal *ebx "x" "F - test-function-header-with-multiple-args-and-outputs/output:0") # Var-name -1441 (check-strings-equal *(ebx+0x10) "ecx" "F - test-function-header-with-multiple-args-and-outputs/output:0/register") # Var-register -1442 8b/-> *(ebx+4) 3/r32/ebx # Var-type -1443 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:1") # Tree-left -1444 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:1") # Tree-right -1445 # edx = result->outputs->next -1446 8b/-> *(edx+4) 2/r32/edx # List-next -1447 # ebx = result->outputs->next->value -1448 8b/-> *edx 3/r32/ebx # List-value -1449 (check-strings-equal *ebx "y" "F - test-function-header-with-multiple-args-and-outputs/output:1") # Var-name -1450 (check-strings-equal *(ebx+0x10) "edx" "F - test-function-header-with-multiple-args-and-outputs/output:0/register") # Var-register -1451 8b/-> *(ebx+4) 3/r32/ebx # Var-type -1452 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:1") # Tree-left -1453 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:1") # Tree-right -1454 # . epilogue -1455 89/<- %esp 5/r32/ebp -1456 5d/pop-to-ebp -1457 c3/return -1458 -1459 # format for variables with types -1460 # x : int -1461 # x: int -1462 # x: int, -1463 # ignores at most one trailing colon or comma -1464 parse-var-with-type: # name: (addr slice), first-line: (addr stream byte) -> result/eax: (handle var) -1465 # pseudocode: -1466 # var v : (handle var) = allocate(Heap, Var-size) -1467 # var s : slice -1468 # next-token-from-slice(name->start, name->end, '/', s) -1469 # var end : (addr byte) = s->end -1470 # if (slice-ends-with(s, ":")) -1471 # decrement s->end -1472 # if (slice-ends-with(s, ",")) -1473 # decrement s->end -1474 # v->name = slice-to-string(s) -1475 # ## register -1476 # next-token-from-slice(end, name->end, '/', s) -1477 # if (slice-ends-with(s, ":")) -1478 # decrement s->end -1479 # if (slice-ends-with(s, ",")) -1480 # decrement s->end -1481 # if (!slice-empty?(s)) -1482 # v->register = slice-to-string(s) -1483 # ## type -1484 # var type : (handle tree type-id) = parse-type(first-line) -1485 # v->type = type -1486 # return v -1487 # -1488 # . prologue -1489 55/push-ebp -1490 89/<- %ebp 4/r32/esp -1491 # . save registers -1492 51/push-ecx -1493 52/push-edx -1494 53/push-ebx -1495 56/push-esi -1496 57/push-edi -1497 # var result/edi : (handle var) = allocate(Heap, Var-size) -1498 (allocate Heap *Var-size) # => eax -1499 (zero-out %eax *Var-size) -1500 89/<- %edi 0/r32/eax -1501 # esi = name -1502 8b/-> *(ebp+8) 6/r32/esi -1503 # var s/ecx : slice -1504 68/push 0/imm32/end -1505 68/push 0/imm32/start -1506 89/<- %ecx 4/r32/esp -1507 $parse-var-with-type:save-name: -1508 # save v->name -1509 (next-token-from-slice *esi *(esi+4) 0x2f %ecx) # Slice-start, Slice-end, '/' -1510 # . end/edx = s->end -1511 8b/-> *(ecx+4) 2/r32/edx -1512 # . if s ends with ':', decrement s->end -1513 { -1514 8b/-> *(ecx+4) 0/r32/eax -1515 48/decrement-eax -1516 8a/copy-byte *eax 3/r32/BL -1517 81 4/subop/and %ebx 0xff/imm32 -1518 81 7/subop/compare %ebx 0x3a/imm32/colon -1519 75/jump-if-!= break/disp8 -1520 89/<- *(ecx+4) 0/r32/eax -1521 } -1522 # . if s ends with ',', decrement s->end -1523 { -1524 8b/-> *(ecx+4) 0/r32/eax -1525 48/decrement-eax -1526 8a/copy-byte *eax 3/r32/BL -1527 81 4/subop/and %ebx 0xff/imm32 -1528 81 7/subop/compare %ebx 0x2c/imm32/comma -1529 75/jump-if-!= break/disp8 -1530 89/<- *(ecx+4) 0/r32/eax -1531 } -1532 $parse-var-with-type:write-name: -1533 (slice-to-string Heap %ecx) # => eax -1534 89/<- *edi 0/r32/eax # Var-name -1535 # save v->register -1536 $parse-var-with-type:save-register: -1537 (next-token-from-slice %edx *(esi+4) 0x2f %ecx) # end, name->end, '/' -1538 # . if s ends with ':', decrement s->end -1539 { -1540 8b/-> *(ecx+4) 0/r32/eax -1541 48/decrement-eax -1542 8a/copy-byte *eax 3/r32/BL -1543 81 4/subop/and %ebx 0xff/imm32 -1544 81 7/subop/compare %ebx 0x3a/imm32/colon -1545 75/jump-if-!= break/disp8 -1546 89/<- *(ecx+4) 0/r32/eax -1547 } -1548 # . if s ends with ',', decrement s->end -1549 { -1550 8b/-> *(ecx+4) 0/r32/eax -1551 48/decrement-eax -1552 8a/copy-byte *eax 3/r32/BL -1553 81 4/subop/and %ebx 0xff/imm32 -1554 81 7/subop/compare %ebx 0x2c/imm32/comma -1555 75/jump-if-!= break/disp8 -1556 89/<- *(ecx+4) 0/r32/eax -1557 } -1558 # if (!slice-empty?(s)) v->register = slice-to-string(s) -1559 { -1560 $parse-var-with-type:write-register: -1561 # HACK: s->end can be less than s->start with all the decrements above -1562 # That's probably a sign we have the wrong algorithm for this function. -1563 8b/-> *ecx 0/r32/eax -1564 39/compare 0/r32/eax *(ecx+4) -1565 76/jump-if-<= break/disp8 -1566 (slice-to-string Heap %ecx) -1567 89/<- *(edi+0x10) 0/r32/eax # Var-register -1568 } -1569 $parse-var-with-type:save-type: -1570 (parse-type Heap *(ebp+0xc)) # => eax -1571 89/<- *(edi+4) 0/r32/eax # Var-type -1572 $parse-var-with-type:end: -1573 # return result -1574 89/<- %eax 7/r32/edi -1575 # . reclaim locals -1576 81 0/subop/add %esp 8/imm32 -1577 # . restore registers -1578 5f/pop-to-edi -1579 5e/pop-to-esi -1580 5b/pop-to-ebx -1581 5a/pop-to-edx -1582 59/pop-to-ecx -1583 # . epilogue -1584 89/<- %esp 5/r32/ebp -1585 5d/pop-to-ebp -1586 c3/return -1587 -1588 $parse-var-with-type:abort: -1589 # error("function header not in form 'fn <name> {'") -1590 (write-buffered Stderr "var should have form 'name: type' in '") -1591 (flush Stderr) -1592 (rewind-stream *(ebp+0xc)) -1593 (write-stream 2 *(ebp+0xc)) -1594 (write-buffered Stderr "'\n") -1595 (flush Stderr) -1596 # . syscall(exit, 1) -1597 bb/copy-to-ebx 1/imm32 -1598 b8/copy-to-eax 1/imm32/exit -1599 cd/syscall 0x80/imm8 -1600 # never gets here -1601 -1602 parse-type: # ad: (address allocation-descriptor), in: (addr stream byte) -> result/eax: (handle tree type-id) -1603 # pseudocode: -1604 # var s: slice = next-mu-token(in) -1605 # assert s != "" -1606 # assert s != "->" -1607 # assert s != "{" -1608 # assert s != "}" -1609 # if s == ")" -1610 # return 0 -1611 # result = allocate(Tree) -1612 # zero-out(result, *Tree-size) -1613 # if s != "(" -1614 # result->left = pos-slice(Type-id, s) -1615 # return -1616 # result->left = parse-type(ad, in) -1617 # result->right = parse-type-tree(ad, in) -1618 # -1619 # . prologue -1620 55/push-ebp -1621 89/<- %ebp 4/r32/esp -1622 # . save registers -1623 51/push-ecx -1624 52/push-edx -1625 # var s/ecx: slice -1626 68/push 0/imm32 -1627 68/push 0/imm32 -1628 89/<- %ecx 4/r32/esp -1629 # s = next-mu-token(in) -1630 (next-mu-token *(ebp+0xc) %ecx) -1631 #? (write-buffered Stderr "tok: ") -1632 #? (write-slice-buffered Stderr %ecx) -1633 #? (write-buffered Stderr "$\n") -1634 #? (flush Stderr) -1635 # assert s != "" -1636 (slice-equal? %ecx "") -1637 3d/compare-eax-and 0/imm32 -1638 0f 85/jump-if-not-equal $parse-type:abort/disp32 -1639 # assert s != "{" -1640 (slice-equal? %ecx "{") -1641 3d/compare-eax-and 0/imm32 -1642 0f 85/jump-if-not-equal $parse-type:abort/disp32 -1643 # assert s != "}" -1644 (slice-equal? %ecx "}") -1645 3d/compare-eax-and 0/imm32 -1646 0f 85/jump-if-not-equal $parse-type:abort/disp32 -1647 # assert s != "->" -1648 (slice-equal? %ecx "->") -1649 3d/compare-eax-and 0/imm32 -1650 0f 85/jump-if-not-equal $parse-type:abort/disp32 -1651 # if (s == ")") return 0 -1652 (slice-equal? %ecx ")") -1653 3d/compare-eax-and 0/imm32 -1654 b8/copy-to-eax 0/imm32 -1655 0f 85/jump-if-not-equal $parse-type:end/disp32 -1656 # var result/edx: (handle tree type-id) -1657 (allocate *(ebp+8) *Tree-size) # => eax -1658 (zero-out %eax *Tree-size) -1659 89/<- %edx 0/r32/eax -1660 { -1661 # if (s != "(") break -1662 (slice-equal? %ecx "(") -1663 3d/compare-eax-and 0/imm32 -1664 75/jump-if-not-equal break/disp8 -1665 # result->left = pos-slice(Type-id, s) -1666 (pos-slice Type-id %ecx) -1667 #? (write-buffered Stderr "=> {") -1668 #? (print-int32-buffered Stderr %eax) -1669 #? (write-buffered Stderr ", 0}\n") -1670 #? (flush Stderr) -1671 89/<- *edx 0/r32/eax # Tree-left -1672 e9/jump $parse-type:return-edx/disp32 -1673 } -1674 # otherwise s == "(" -1675 # result->left = parse-type(ad, in) -1676 (parse-type *(ebp+8) *(ebp+0xc)) -1677 #? (write-buffered Stderr "=> {") -1678 #? (print-int32-buffered Stderr %eax) -1679 89/<- *edx 0/r32/eax # Tree-left -1680 # result->right = parse-type-tree(ad, in) -1681 (parse-type-tree *(ebp+8) *(ebp+0xc)) -1682 #? (write-buffered Stderr Space) -1683 #? (print-int32-buffered Stderr %eax) -1684 #? (write-buffered Stderr "}\n") -1685 #? (flush Stderr) -1686 89/<- *(edx+4) 0/r32/eax # Tree-right -1687 $parse-type:return-edx: -1688 89/<- %eax 2/r32/edx -1689 $parse-type:end: -1690 # . reclaim locals -1691 81 0/subop/add %esp 8/imm32 -1692 # . restore registers -1693 5a/pop-to-edx -1694 59/pop-to-ecx -1695 # . epilogue -1696 89/<- %esp 5/r32/ebp -1697 5d/pop-to-ebp -1698 c3/return -1699 -1700 $parse-type:abort: -1701 # error("unexpected token when parsing type: '" s "'\n") -1702 (write-buffered Stderr "unexpected token when parsing type: '") -1703 (write-slice-buffered Stderr %ecx) -1704 (write-buffered Stderr "'\n") -1705 (flush Stderr) -1706 # . syscall(exit, 1) -1707 bb/copy-to-ebx 1/imm32 -1708 b8/copy-to-eax 1/imm32/exit -1709 cd/syscall 0x80/imm8 -1710 # never gets here -1711 -1712 parse-type-tree: # ad: (address allocation-descriptor), in: (addr stream byte) -> result/eax: (handle tree type-id) -1713 # pseudocode: -1714 # var tmp: (handle tree type-id) = parse-type(ad, in) -1715 # if tmp == 0 -1716 # return 0 -1717 # result = allocate(Tree) -1718 # zero-out(result, *Tree-size) -1719 # result->left = tmp -1720 # result->right = parse-type-tree(ad, in) -1721 # -1722 # . prologue -1723 55/push-ebp -1724 89/<- %ebp 4/r32/esp -1725 # . save registers -1726 51/push-ecx -1727 52/push-edx -1728 # var tmp/eax: (handle tree type-id) = parse-type(ad, in) -1729 (parse-type *(ebp+8) *(ebp+0xc)) -1730 # if (tmp == 0) return tmp -1731 3d/compare-eax-and 0/imm32 -1732 74/jump-if-equal $parse-type-tree:end/disp8 -1733 # var tmp2/ecx = tmp -1734 89/<- %ecx 0/r32/eax -1735 # var result/edx: (handle tree type-id) -1736 (allocate *(ebp+8) *Tree-size) # => eax -1737 (zero-out %eax *Tree-size) -1738 89/<- %edx 0/r32/eax -1739 # result->left = tmp2 -1740 89/<- *edx 1/r32/ecx # Tree-left -1741 # result->right = parse-type-tree(ad, in) -1742 (parse-type-tree *(ebp+8) *(ebp+0xc)) -1743 89/<- *(edx+4) 0/r32/eax # Tree-right -1744 $parse-type-tree:return-edx: -1745 89/<- %eax 2/r32/edx -1746 $parse-type-tree:end: -1747 # . restore registers -1748 5a/pop-to-edx -1749 59/pop-to-ecx -1750 # . epilogue -1751 89/<- %esp 5/r32/ebp -1752 5d/pop-to-ebp -1753 c3/return -1754 -1755 next-mu-token: # in: (addr stream byte), out: (addr slice) -1756 # pseudocode: -1757 # start: -1758 # skip-chars-matching(in, ' ') -1759 # if in->read >= in->write # end of in -1760 # out = {0, 0} -1761 # return -1762 # out->start = &in->data[in->read] -1763 # var curr-byte/eax: byte = in->data[in->read] -1764 # if curr->byte == ':' # comment token -1765 # ++in->read -1766 # goto start -1767 # if curr->byte == ',' # comment token -1768 # ++in->read -1769 # goto start -1770 # if curr-byte == '#' # comment -1771 # in->read = in->write # skip to end of in + 351 Tree-left: # either type-id or (addr tree type-id) + 352 0/imm32 + 353 Tree-right: # (addr tree type-id) + 354 4/imm32 + 355 Tree-size: # (addr int) + 356 8/imm32 + 357 + 358 Max-type-id: + 359 0x10000/imm32 + 360 + 361 == code + 362 + 363 Entry: + 364 # . prologue + 365 89/<- %ebp 4/r32/esp + 366 (new-segment *Heap-size Heap) + 367 # if (argv[1] == "test') run-tests() + 368 { + 369 # if (argc <= 1) break + 370 81 7/subop/compare *ebp 1/imm32 + 371 7e/jump-if-<= break/disp8 + 372 # if (argv[1] != "test") break + 373 (kernel-string-equal? *(ebp+8) "test") # => eax + 374 3d/compare-eax-and 0/imm32 + 375 74/jump-if-= break/disp8 + 376 # + 377 (run-tests) + 378 # syscall(exit, *Num-test-failures) + 379 8b/-> *Num-test-failures 3/r32/ebx + 380 eb/jump $mu-main:end/disp8 + 381 } + 382 # otherwise convert Stdin + 383 (convert-mu Stdin Stdout) + 384 (flush Stdout) + 385 # syscall(exit, 0) + 386 bb/copy-to-ebx 0/imm32 + 387 $mu-main:end: + 388 b8/copy-to-eax 1/imm32/exit + 389 cd/syscall 0x80/imm8 + 390 + 391 convert-mu: # in : (addr buffered-file), out : (addr buffered-file) + 392 # . prologue + 393 55/push-ebp + 394 89/<- %ebp 4/r32/esp + 395 # + 396 (parse-mu *(ebp+8)) + 397 (check-mu-types) + 398 (emit-subx *(ebp+0xc)) + 399 $convert-mu:end: + 400 # . epilogue + 401 89/<- %esp 5/r32/ebp + 402 5d/pop-to-ebp + 403 c3/return + 404 + 405 test-convert-empty-input: + 406 # empty input => empty output + 407 # . prologue + 408 55/push-ebp + 409 89/<- %ebp 4/r32/esp + 410 # setup + 411 (clear-stream _test-input-stream) + 412 (clear-stream $_test-input-buffered-file->buffer) + 413 (clear-stream _test-output-stream) + 414 (clear-stream $_test-output-buffered-file->buffer) + 415 # + 416 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 417 (flush _test-output-buffered-file) + 418 (check-stream-equal _test-output-stream "" "F - test-convert-empty-input") + 419 # . epilogue + 420 89/<- %esp 5/r32/ebp + 421 5d/pop-to-ebp + 422 c3/return + 423 + 424 test-convert-function-skeleton: + 425 # empty function decl => function prologue and epilogue + 426 # fn foo { + 427 # } + 428 # => + 429 # foo: + 430 # # . prologue + 431 # 55/push-ebp + 432 # 89/<- %ebp 4/r32/esp + 433 # # . epilogue + 434 # 89/<- %esp 5/r32/ebp + 435 # 5d/pop-to-ebp + 436 # c3/return + 437 # . prologue + 438 55/push-ebp + 439 89/<- %ebp 4/r32/esp + 440 # setup + 441 (clear-stream _test-input-stream) + 442 (clear-stream $_test-input-buffered-file->buffer) + 443 (clear-stream _test-output-stream) + 444 (clear-stream $_test-output-buffered-file->buffer) + 445 # + 446 (write _test-input-stream "fn foo {\n") + 447 (write _test-input-stream "}\n") + 448 # convert + 449 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 450 (flush _test-output-buffered-file) + 451 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- + 457 # check output + 458 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-skeleton/0") + 459 (check-next-stream-line-equal _test-output-stream "# . prologue" "F - test-convert-function-skeleton/1") + 460 (check-next-stream-line-equal _test-output-stream "55/push-ebp" "F - test-convert-function-skeleton/2") + 461 (check-next-stream-line-equal _test-output-stream "89/<- %ebp 4/r32/esp" "F - test-convert-function-skeleton/3") + 462 (check-next-stream-line-equal _test-output-stream "# . epilogue" "F - test-convert-function-skeleton/4") + 463 (check-next-stream-line-equal _test-output-stream "89/<- %esp 5/r32/ebp" "F - test-convert-function-skeleton/5") + 464 (check-next-stream-line-equal _test-output-stream "5d/pop-to-ebp" "F - test-convert-function-skeleton/6") + 465 (check-next-stream-line-equal _test-output-stream "c3/return" "F - test-convert-function-skeleton/7") + 466 # . epilogue + 467 89/<- %esp 5/r32/ebp + 468 5d/pop-to-ebp + 469 c3/return + 470 + 471 test-convert-multiple-function-skeletons: + 472 # multiple functions correctly organized into a linked list + 473 # fn foo { + 474 # } + 475 # fn bar { + 476 # } + 477 # => + 478 # foo: + 479 # # . prologue + 480 # 55/push-ebp + 481 # 89/<- %ebp 4/r32/esp + 482 # # . epilogue + 483 # 89/<- %esp 5/r32/ebp + 484 # 5d/pop-to-ebp + 485 # c3/return + 486 # bar: + 487 # # . prologue + 488 # 55/push-ebp + 489 # 89/<- %ebp 4/r32/esp + 490 # # . epilogue + 491 # 89/<- %esp 5/r32/ebp + 492 # 5d/pop-to-ebp + 493 # c3/return + 494 # . prologue + 495 55/push-ebp + 496 89/<- %ebp 4/r32/esp + 497 # setup + 498 (clear-stream _test-input-stream) + 499 (clear-stream $_test-input-buffered-file->buffer) + 500 (clear-stream _test-output-stream) + 501 (clear-stream $_test-output-buffered-file->buffer) + 502 # + 503 (write _test-input-stream "fn foo {\n") + 504 (write _test-input-stream "}\n") + 505 (write _test-input-stream "fn bar {\n") + 506 (write _test-input-stream "}\n") + 507 # convert + 508 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 509 (flush _test-output-buffered-file) + 510 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- + 516 # check first function + 517 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-multiple-function-skeletons/0") + 518 (check-next-stream-line-equal _test-output-stream "# . prologue" "F - test-convert-multiple-function-skeletons/1") + 519 (check-next-stream-line-equal _test-output-stream "55/push-ebp" "F - test-convert-multiple-function-skeletons/2") + 520 (check-next-stream-line-equal _test-output-stream "89/<- %ebp 4/r32/esp" "F - test-convert-multiple-function-skeletons/3") + 521 (check-next-stream-line-equal _test-output-stream "# . epilogue" "F - test-convert-multiple-function-skeletons/4") + 522 (check-next-stream-line-equal _test-output-stream "89/<- %esp 5/r32/ebp" "F - test-convert-multiple-function-skeletons/5") + 523 (check-next-stream-line-equal _test-output-stream "5d/pop-to-ebp" "F - test-convert-multiple-function-skeletons/6") + 524 (check-next-stream-line-equal _test-output-stream "c3/return" "F - test-convert-multiple-function-skeletons/7") + 525 # check second function + 526 (check-next-stream-line-equal _test-output-stream "bar:" "F - test-convert-multiple-function-skeletons/10") + 527 (check-next-stream-line-equal _test-output-stream "# . prologue" "F - test-convert-multiple-function-skeletons/11") + 528 (check-next-stream-line-equal _test-output-stream "55/push-ebp" "F - test-convert-multiple-function-skeletons/12") + 529 (check-next-stream-line-equal _test-output-stream "89/<- %ebp 4/r32/esp" "F - test-convert-multiple-function-skeletons/13") + 530 (check-next-stream-line-equal _test-output-stream "# . epilogue" "F - test-convert-multiple-function-skeletons/14") + 531 (check-next-stream-line-equal _test-output-stream "89/<- %esp 5/r32/ebp" "F - test-convert-multiple-function-skeletons/15") + 532 (check-next-stream-line-equal _test-output-stream "5d/pop-to-ebp" "F - test-convert-multiple-function-skeletons/16") + 533 (check-next-stream-line-equal _test-output-stream "c3/return" "F - test-convert-multiple-function-skeletons/17") + 534 # . epilogue + 535 89/<- %esp 5/r32/ebp + 536 5d/pop-to-ebp + 537 c3/return + 538 + 539 test-convert-function-with-arg: + 540 # function with one arg + 541 # fn foo n : int { + 542 # } + 543 # => + 544 # foo: + 545 # # . prologue + 546 # 55/push-ebp + 547 # 89/<- %ebp 4/r32/esp + 548 # # . epilogue + 549 # 89/<- %esp 5/r32/ebp + 550 # 5d/pop-to-ebp + 551 # c3/return + 552 # . prologue + 553 55/push-ebp + 554 89/<- %ebp 4/r32/esp + 555 # setup + 556 (clear-stream _test-input-stream) + 557 (clear-stream $_test-input-buffered-file->buffer) + 558 (clear-stream _test-output-stream) + 559 (clear-stream $_test-output-buffered-file->buffer) + 560 # + 561 (write _test-input-stream "fn foo n : int {\n") + 562 (write _test-input-stream "}\n") + 563 # convert + 564 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 565 (flush _test-output-buffered-file) + 566 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- + 572 # check output + 573 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-arg/0") + 574 (check-next-stream-line-equal _test-output-stream "# . prologue" "F - test-convert-function-with-arg/1") + 575 (check-next-stream-line-equal _test-output-stream "55/push-ebp" "F - test-convert-function-with-arg/2") + 576 (check-next-stream-line-equal _test-output-stream "89/<- %ebp 4/r32/esp" "F - test-convert-function-with-arg/3") + 577 (check-next-stream-line-equal _test-output-stream "# . epilogue" "F - test-convert-function-with-arg/4") + 578 (check-next-stream-line-equal _test-output-stream "89/<- %esp 5/r32/ebp" "F - test-convert-function-with-arg/5") + 579 (check-next-stream-line-equal _test-output-stream "5d/pop-to-ebp" "F - test-convert-function-with-arg/6") + 580 (check-next-stream-line-equal _test-output-stream "c3/return" "F - test-convert-function-with-arg/7") + 581 # . epilogue + 582 89/<- %esp 5/r32/ebp + 583 5d/pop-to-ebp + 584 c3/return + 585 + 586 test-convert-function-with-arg-and-body: + 587 # function with one arg and one instruction in the body + 588 # fn foo n : int { + 589 # increment n + 590 # } + 591 # => + 592 # foo: + 593 # # . prologue + 594 # 55/push-ebp + 595 # 89/<- %ebp 4/r32/esp + 596 # { + 597 # ff 0/subop/increment *(ebp+8) + 598 # } + 599 # # . epilogue + 600 # 89/<- %esp 5/r32/ebp + 601 # 5d/pop-to-ebp + 602 # c3/return + 603 # . prologue + 604 55/push-ebp + 605 89/<- %ebp 4/r32/esp + 606 # setup + 607 (clear-stream _test-input-stream) + 608 (clear-stream $_test-input-buffered-file->buffer) + 609 (clear-stream _test-output-stream) + 610 (clear-stream $_test-output-buffered-file->buffer) + 611 # + 612 (write _test-input-stream "fn foo n : int {\n") + 613 (write _test-input-stream " increment n\n") + 614 (write _test-input-stream "}\n") + 615 # convert + 616 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 617 (flush _test-output-buffered-file) + 618 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- + 624 # check output + 625 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-arg-and-body/0") + 626 (check-next-stream-line-equal _test-output-stream "# . prologue" "F - test-convert-function-with-arg-and-body/1") + 627 (check-next-stream-line-equal _test-output-stream "55/push-ebp" "F - test-convert-function-with-arg-and-body/2") + 628 (check-next-stream-line-equal _test-output-stream "89/<- %ebp 4/r32/esp" "F - test-convert-function-with-arg-and-body/3") + 629 (check-next-stream-line-equal _test-output-stream "{" "F - test-convert-function-with-arg-and-body/4") + 630 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment *(ebp+0x00000008)" "F - test-convert-function-with-arg-and-body/5") + 631 (check-next-stream-line-equal _test-output-stream "}" "F - test-convert-function-with-arg-and-body/6") + 632 (check-next-stream-line-equal _test-output-stream "# . epilogue" "F - test-convert-function-with-arg-and-body/7") + 633 (check-next-stream-line-equal _test-output-stream "89/<- %esp 5/r32/ebp" "F - test-convert-function-with-arg-and-body/8") + 634 (check-next-stream-line-equal _test-output-stream "5d/pop-to-ebp" "F - test-convert-function-with-arg-and-body/9") + 635 (check-next-stream-line-equal _test-output-stream "c3/return" "F - test-convert-function-with-arg-and-body/10") + 636 # . epilogue + 637 89/<- %esp 5/r32/ebp + 638 5d/pop-to-ebp + 639 c3/return + 640 + 641 test-convert-function-distinguishes-args: + 642 # function with two args refers to second one in body + 643 # fn foo a: int, b: int { + 644 # increment b + 645 # } + 646 # => + 647 # foo: + 648 # # . prologue + 649 # 55/push-ebp + 650 # 89/<- %ebp 4/r32/esp + 651 # { + 652 # ff 0/subop/increment *(ebp+0xc) + 653 # } + 654 # # . epilogue + 655 # 89/<- %esp 5/r32/ebp + 656 # 5d/pop-to-ebp + 657 # c3/return + 658 # . prologue + 659 55/push-ebp + 660 89/<- %ebp 4/r32/esp + 661 # setup + 662 (clear-stream _test-input-stream) + 663 (clear-stream $_test-input-buffered-file->buffer) + 664 (clear-stream _test-output-stream) + 665 (clear-stream $_test-output-buffered-file->buffer) + 666 # + 667 (write _test-input-stream "fn foo a: int, b: int {\n") + 668 (write _test-input-stream " increment b\n") + 669 (write _test-input-stream "}\n") + 670 # convert + 671 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 672 (flush _test-output-buffered-file) + 673 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- + 679 # check output + 680 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-distinguishes-args/0") + 681 (check-next-stream-line-equal _test-output-stream "# . prologue" "F - test-convert-function-distinguishes-args/1") + 682 (check-next-stream-line-equal _test-output-stream "55/push-ebp" "F - test-convert-function-distinguishes-args/2") + 683 (check-next-stream-line-equal _test-output-stream "89/<- %ebp 4/r32/esp" "F - test-convert-function-distinguishes-args/3") + 684 (check-next-stream-line-equal _test-output-stream "{" "F - test-convert-function-distinguishes-args/4") + 685 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment *(ebp+0x0000000c)" "F - test-convert-function-distinguishes-args/5") + 686 (check-next-stream-line-equal _test-output-stream "}" "F - test-convert-function-distinguishes-args/6") + 687 (check-next-stream-line-equal _test-output-stream "# . epilogue" "F - test-convert-function-distinguishes-args/7") + 688 (check-next-stream-line-equal _test-output-stream "89/<- %esp 5/r32/ebp" "F - test-convert-function-distinguishes-args/8") + 689 (check-next-stream-line-equal _test-output-stream "5d/pop-to-ebp" "F - test-convert-function-distinguishes-args/9") + 690 (check-next-stream-line-equal _test-output-stream "c3/return" "F - test-convert-function-distinguishes-args/10") + 691 # . epilogue + 692 89/<- %esp 5/r32/ebp + 693 5d/pop-to-ebp + 694 c3/return + 695 + 696 test-convert-function-returns-result: + 697 # function writes to output + 698 # fn foo a: int, b: int -> result/eax: int { + 699 # result <- copy a + 700 # result <- increment + 701 # } + 702 # => + 703 # foo: + 704 # # . prologue + 705 # 55/push-ebp + 706 # 89/<- %ebp 4/r32/esp + 707 # { + 708 # 89/-> *(ebp+8) 0/r32/eax + 709 # 40/increment-eax + 710 # } + 711 # # . epilogue + 712 # 89/<- %esp 5/r32/ebp + 713 # 5d/pop-to-ebp + 714 # c3/return + 715 # . prologue + 716 55/push-ebp + 717 89/<- %ebp 4/r32/esp + 718 # setup + 719 (clear-stream _test-input-stream) + 720 (clear-stream $_test-input-buffered-file->buffer) + 721 (clear-stream _test-output-stream) + 722 (clear-stream $_test-output-buffered-file->buffer) + 723 # + 724 (write _test-input-stream "fn foo a: int, b: int -> result/eax: int {\n") + 725 (write _test-input-stream " result <- copy a\n") + 726 (write _test-input-stream " result <- increment\n") + 727 (write _test-input-stream "}\n") + 728 # convert + 729 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 730 (flush _test-output-buffered-file) + 731 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- + 737 # check output + 738 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-returns-result/0") + 739 (check-next-stream-line-equal _test-output-stream "# . prologue" "F - test-convert-function-returns-result/1") + 740 (check-next-stream-line-equal _test-output-stream "55/push-ebp" "F - test-convert-function-returns-result/2") + 741 (check-next-stream-line-equal _test-output-stream "89/<- %ebp 4/r32/esp" "F - test-convert-function-returns-result/3") + 742 (check-next-stream-line-equal _test-output-stream "{" "F - test-convert-function-returns-result/4") + 743 (check-next-stream-line-equal _test-output-stream "8b/copy-from *(ebp+0x00000008) 0x00000000/r32" "F - test-convert-function-returns-result/5") + 744 (check-next-stream-line-equal _test-output-stream "40/increment-eax" "F - test-convert-function-returns-result/6") + 745 (check-next-stream-line-equal _test-output-stream "}" "F - test-convert-function-returns-result/7") + 746 (check-next-stream-line-equal _test-output-stream "# . epilogue" "F - test-convert-function-returns-result/8") + 747 (check-next-stream-line-equal _test-output-stream "89/<- %esp 5/r32/ebp" "F - test-convert-function-returns-result/9") + 748 (check-next-stream-line-equal _test-output-stream "5d/pop-to-ebp" "F - test-convert-function-returns-result/10") + 749 (check-next-stream-line-equal _test-output-stream "c3/return" "F - test-convert-function-returns-result/11") + 750 # . epilogue + 751 89/<- %esp 5/r32/ebp + 752 5d/pop-to-ebp + 753 c3/return + 754 + 755 test-convert-function-literal-arg: + 756 # function writes to output + 757 # fn foo a: int, b: int -> result/eax: int { + 758 # result <- copy a + 759 # result <- add 1 + 760 # } + 761 # => + 762 # foo: + 763 # # . prologue + 764 # 55/push-ebp + 765 # 89/<- %ebp 4/r32/esp + 766 # { + 767 # 89/-> *(ebp+8) 0/r32/eax + 768 # 05/add-to-eax 1/imm32 + 769 # } + 770 # # . epilogue + 771 # 89/<- %esp 5/r32/ebp + 772 # 5d/pop-to-ebp + 773 # c3/return + 774 # . prologue + 775 55/push-ebp + 776 89/<- %ebp 4/r32/esp + 777 # setup + 778 (clear-stream _test-input-stream) + 779 (clear-stream $_test-input-buffered-file->buffer) + 780 (clear-stream _test-output-stream) + 781 (clear-stream $_test-output-buffered-file->buffer) + 782 # + 783 (write _test-input-stream "fn foo a: int, b: int -> result/eax: int {\n") + 784 (write _test-input-stream " result <- copy a\n") + 785 (write _test-input-stream " result <- add 1\n") + 786 (write _test-input-stream "}\n") + 787 # convert + 788 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 789 (flush _test-output-buffered-file) + 790 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- + 796 # check output + 797 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-literal-arg/0") + 798 (check-next-stream-line-equal _test-output-stream "# . prologue" "F - test-convert-function-literal-arg/1") + 799 (check-next-stream-line-equal _test-output-stream "55/push-ebp" "F - test-convert-function-literal-arg/2") + 800 (check-next-stream-line-equal _test-output-stream "89/<- %ebp 4/r32/esp" "F - test-convert-function-literal-arg/3") + 801 (check-next-stream-line-equal _test-output-stream "{" "F - test-convert-function-literal-arg/4") + 802 (check-next-stream-line-equal _test-output-stream "8b/copy-from *(ebp+0x00000008) 0x00000000/r32" "F - test-convert-function-literal-arg/5") + 803 (check-next-stream-line-equal _test-output-stream "05/add-to-eax 1/imm32" "F - test-convert-function-literal-arg/6") + 804 (check-next-stream-line-equal _test-output-stream "}" "F - test-convert-function-literal-arg/7") + 805 (check-next-stream-line-equal _test-output-stream "# . epilogue" "F - test-convert-function-literal-arg/8") + 806 (check-next-stream-line-equal _test-output-stream "89/<- %esp 5/r32/ebp" "F - test-convert-function-literal-arg/9") + 807 (check-next-stream-line-equal _test-output-stream "5d/pop-to-ebp" "F - test-convert-function-literal-arg/10") + 808 (check-next-stream-line-equal _test-output-stream "c3/return" "F - test-convert-function-literal-arg/11") + 809 # . epilogue + 810 89/<- %esp 5/r32/ebp + 811 5d/pop-to-ebp + 812 c3/return + 813 + 814 test-convert-function-literal-arg-2: + 815 # function writes to output + 816 # fn foo a: int, b: int -> result/ebx: int { + 817 # result <- copy a + 818 # result <- add 1 + 819 # } + 820 # => + 821 # foo: + 822 # # . prologue + 823 # 55/push-ebp + 824 # 89/<- %ebp 4/r32/esp + 825 # { + 826 # 89/-> *(ebp+8) 3/r32/ebx + 827 # 81 0/subop/add %ebx 1/imm32 + 828 # } + 829 # # . epilogue + 830 # 89/<- %esp 5/r32/ebp + 831 # 5d/pop-to-ebp + 832 # c3/return + 833 # . prologue + 834 55/push-ebp + 835 89/<- %ebp 4/r32/esp + 836 # setup + 837 (clear-stream _test-input-stream) + 838 (clear-stream $_test-input-buffered-file->buffer) + 839 (clear-stream _test-output-stream) + 840 (clear-stream $_test-output-buffered-file->buffer) + 841 # + 842 (write _test-input-stream "fn foo a: int, b: int -> result/ebx: int {\n") + 843 (write _test-input-stream " result <- copy a\n") + 844 (write _test-input-stream " result <- add 1\n") + 845 (write _test-input-stream "}\n") + 846 # convert + 847 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 848 (flush _test-output-buffered-file) + 849 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- + 855 # check output + 856 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-literal-arg-2/0") + 857 (check-next-stream-line-equal _test-output-stream "# . prologue" "F - test-convert-function-literal-arg-2/1") + 858 (check-next-stream-line-equal _test-output-stream "55/push-ebp" "F - test-convert-function-literal-arg-2/2") + 859 (check-next-stream-line-equal _test-output-stream "89/<- %ebp 4/r32/esp" "F - test-convert-function-literal-arg-2/3") + 860 (check-next-stream-line-equal _test-output-stream "{" "F - test-convert-function-literal-arg-2/4") + 861 (check-next-stream-line-equal _test-output-stream "8b/copy-from *(ebp+0x00000008) 0x00000003/r32" "F - test-convert-function-literal-arg-2/5") + 862 (check-next-stream-line-equal _test-output-stream "81 0/subop/add %ebx 1/imm32" "F - test-convert-function-literal-arg-2/6") + 863 (check-next-stream-line-equal _test-output-stream "}" "F - test-convert-function-literal-arg-2/7") + 864 (check-next-stream-line-equal _test-output-stream "# . epilogue" "F - test-convert-function-literal-arg-2/8") + 865 (check-next-stream-line-equal _test-output-stream "89/<- %esp 5/r32/ebp" "F - test-convert-function-literal-arg-2/9") + 866 (check-next-stream-line-equal _test-output-stream "5d/pop-to-ebp" "F - test-convert-function-literal-arg-2/10") + 867 (check-next-stream-line-equal _test-output-stream "c3/return" "F - test-convert-function-literal-arg-2/11") + 868 # . epilogue + 869 89/<- %esp 5/r32/ebp + 870 5d/pop-to-ebp + 871 c3/return + 872 + 873 test-convert-function-call-with-literal-arg: + 874 # function writes to output + 875 # fn main -> result/ebx: int { + 876 # result <- do-add 3 4 + 877 # } + 878 # + 879 # fn do-add a: int, b: int -> result/ebx: int { + 880 # result <- copy a + 881 # result <- add b + 882 # } + 883 # => + 884 # main: + 885 # # . prologue + 886 # 55/push-ebp + 887 # 89/<- %ebp 4/r32/esp + 888 # { + 889 # (do-add 3 4) + 890 # } + 891 # # . epilogue + 892 # 89/<- %esp 5/r32/ebp + 893 # 5d/pop-to-ebp + 894 # c3/return + 895 # do-add: + 896 # # . prologue + 897 # 55/push-ebp + 898 # 89/<- %ebp 4/r32/esp + 899 # { + 900 # 8b/-> *(ebp+8) 3/r32/ebx + 901 # 03/add-to 3/r32/ebx *(ebp+0xc) + 902 # } + 903 # # . epilogue + 904 # 89/<- %esp 5/r32/ebp + 905 # 5d/pop-to-ebp + 906 # c3/return + 907 # . prologue + 908 55/push-ebp + 909 89/<- %ebp 4/r32/esp + 910 # setup + 911 (clear-stream _test-input-stream) + 912 (clear-stream $_test-input-buffered-file->buffer) + 913 (clear-stream _test-output-stream) + 914 (clear-stream $_test-output-buffered-file->buffer) + 915 # + 916 (write _test-input-stream "fn main -> result/ebx: int {\n") + 917 (write _test-input-stream " result <- do-add 3 4\n") + 918 (write _test-input-stream "}\n") + 919 (write _test-input-stream "fn do-add a: int, b: int -> result/ebx: int {\n") + 920 (write _test-input-stream " result <- copy a\n") + 921 (write _test-input-stream " result <- add b\n") + 922 (write _test-input-stream "}\n") + 923 # convert + 924 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 925 (flush _test-output-buffered-file) + 926 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- + 932 # check output + 933 (check-next-stream-line-equal _test-output-stream "main:" "F - test-convert-function-call-with-literal-arg/0") + 934 (check-next-stream-line-equal _test-output-stream "# . prologue" "F - test-convert-function-call-with-literal-arg/1") + 935 (check-next-stream-line-equal _test-output-stream "55/push-ebp" "F - test-convert-function-call-with-literal-arg/2") + 936 (check-next-stream-line-equal _test-output-stream "89/<- %ebp 4/r32/esp" "F - test-convert-function-call-with-literal-arg/3") + 937 (check-next-stream-line-equal _test-output-stream "{" "F - test-convert-function-call-with-literal-arg/4") + 938 (check-next-stream-line-equal _test-output-stream "(do-add 3 4)" "F - test-convert-function-call-with-literal-arg/5") + 939 (check-next-stream-line-equal _test-output-stream "}" "F - test-convert-function-call-with-literal-arg/6") + 940 (check-next-stream-line-equal _test-output-stream "# . epilogue" "F - test-convert-function-call-with-literal-arg/7") + 941 (check-next-stream-line-equal _test-output-stream "89/<- %esp 5/r32/ebp" "F - test-convert-function-call-with-literal-arg/8") + 942 (check-next-stream-line-equal _test-output-stream "5d/pop-to-ebp" "F - test-convert-function-call-with-literal-arg/9") + 943 (check-next-stream-line-equal _test-output-stream "c3/return" "F - test-convert-function-call-with-literal-arg/10") + 944 (check-next-stream-line-equal _test-output-stream "do-add:" "F - test-convert-function-call-with-literal-arg/11") + 945 (check-next-stream-line-equal _test-output-stream "# . prologue" "F - test-convert-function-call-with-literal-arg/12") + 946 (check-next-stream-line-equal _test-output-stream "55/push-ebp" "F - test-convert-function-call-with-literal-arg/13") + 947 (check-next-stream-line-equal _test-output-stream "89/<- %ebp 4/r32/esp" "F - test-convert-function-call-with-literal-arg/14") + 948 (check-next-stream-line-equal _test-output-stream "{" "F - test-convert-function-call-with-literal-arg/15") + 949 (check-next-stream-line-equal _test-output-stream "8b/copy-from *(ebp+0x00000008) 0x00000003/r32" "F - test-convert-function-call-with-literal-arg/16") + 950 (check-next-stream-line-equal _test-output-stream "03/add *(ebp+0x0000000c) 0x00000003/r32" "F - test-convert-function-call-with-literal-arg/17") + 951 (check-next-stream-line-equal _test-output-stream "}" "F - test-convert-function-call-with-literal-arg/18") + 952 (check-next-stream-line-equal _test-output-stream "# . epilogue" "F - test-convert-function-call-with-literal-arg/19") + 953 (check-next-stream-line-equal _test-output-stream "89/<- %esp 5/r32/ebp" "F - test-convert-function-call-with-literal-arg/20") + 954 (check-next-stream-line-equal _test-output-stream "5d/pop-to-ebp" "F - test-convert-function-call-with-literal-arg/21") + 955 (check-next-stream-line-equal _test-output-stream "c3/return" "F - test-convert-function-call-with-literal-arg/22") + 956 # . epilogue + 957 89/<- %esp 5/r32/ebp + 958 5d/pop-to-ebp + 959 c3/return + 960 + 961 ####################################################### + 962 # Parsing + 963 ####################################################### + 964 + 965 parse-mu: # in : (addr buffered-file) + 966 # pseudocode + 967 # var curr-function : (addr (handle function)) = Program + 968 # var line : (stream byte 512) + 969 # var word-slice : slice + 970 # while true # line loop + 971 # clear-stream(line) + 972 # read-line-buffered(in, line) + 973 # if (line->write == 0) break # end of file + 974 # word-slice = next-word-or-string(line) + 975 # if slice-empty?(word-slice) # end of line + 976 # continue + 977 # else if slice-starts-with?(word-slice, "#") # comment + 978 # continue # end of line + 979 # else if slice-equal(word-slice, "fn") + 980 # var new-function : (handle function) = allocate(function) + 981 # var vars : (stack (addr var) 256) + 982 # populate-mu-function-header(in, new-function, vars) + 983 # populate-mu-function-body(in, new-function, vars) + 984 # assert(vars->top == 0) + 985 # *curr-function = new-function + 986 # curr-function = &new-function->next + 987 # else + 988 # abort() + 989 # + 990 # . prologue + 991 55/push-ebp + 992 89/<- %ebp 4/r32/esp + 993 # . save registers + 994 50/push-eax + 995 51/push-ecx + 996 52/push-edx + 997 53/push-ebx + 998 57/push-edi + 999 # var line/ecx : (stream byte 512) +1000 81 5/subop/subtract %esp 0x200/imm32 +1001 68/push 0x200/imm32/length +1002 68/push 0/imm32/read +1003 68/push 0/imm32/write +1004 89/<- %ecx 4/r32/esp +1005 # var word-slice/edx : slice +1006 68/push 0/imm32/end +1007 68/push 0/imm32/start +1008 89/<- %edx 4/r32/esp +1009 # var curr-function/edi : (addr (handle function)) = Program +1010 bf/copy-to-edi Program/imm32 +1011 # var vars/ebx : (stack (addr var) 256) +1012 81 5/subop/subtract %esp 0x400/imm32 +1013 68/push 0x400/imm32/length +1014 68/push 0/imm32/top +1015 89/<- %ebx 4/r32/esp +1016 { +1017 $parse-mu:line-loop: +1018 (clear-stream %ecx) +1019 (read-line-buffered *(ebp+8) %ecx) +1020 # if (line->write == 0) break +1021 81 7/subop/compare *ecx 0/imm32 +1022 0f 84/jump-if-= break/disp32 +1023 +-- 6 lines: #? # dump line --------------------------------------------------------------------------------------------------------------------------- +1029 (next-word-or-string %ecx %edx) +1030 # if slice-empty?(word-slice) continue +1031 (slice-empty? %edx) +1032 3d/compare-eax-and 0/imm32 +1033 0f 85/jump-if-!= loop/disp32 +1034 # if (*word-slice->start == "#") continue +1035 # . eax = *word-slice->start +1036 8b/-> *edx 0/r32/eax +1037 8a/copy-byte *eax 0/r32/AL +1038 81 4/subop/and %eax 0xff/imm32 +1039 # . if (eax == '#') continue +1040 3d/compare-eax-and 0x23/imm32/hash +1041 0f 84/jump-if-= loop/disp32 +1042 # if (slice-equal?(word-slice, "fn")) parse a function +1043 { +1044 $parse-mu:fn: +1045 (slice-equal? %edx "fn") +1046 3d/compare-eax-and 0/imm32 +1047 0f 84/jump-if-= break/disp32 +1048 # var new-function/eax : (handle function) = populate-mu-function(in, new-function, vars) +1049 (allocate Heap *Function-size) # => eax +1050 (zero-out %eax *Function-size) +1051 (clear-stack %ebx) +1052 (populate-mu-function-header %ecx %eax %ebx) +1053 (populate-mu-function-body *(ebp+8) %eax %ebx) +1054 # *curr-function = new-function +1055 89/<- *edi 0/r32/eax +1056 # curr-function = &new-function->next +1057 8d/address-> *(eax+0x14) 7/r32/edi # Function-next +1058 e9/jump $parse-mu:line-loop/disp32 +1059 } +1060 # otherwise abort +1061 e9/jump $parse-mu:error1/disp32 +1062 } # end line loop +1063 $parse-mu:end: +1064 # . reclaim locals +1065 81 0/subop/add %esp 0x630/imm32 +1066 # . restore registers +1067 5f/pop-to-edi +1068 5b/pop-to-ebx +1069 5a/pop-to-edx +1070 59/pop-to-ecx +1071 58/pop-to-eax +1072 # . epilogue +1073 89/<- %esp 5/r32/ebp +1074 5d/pop-to-ebp +1075 c3/return +1076 +1077 $parse-mu:error1: +1078 # error("unexpected top-level command: " word-slice "\n") +1079 (write-buffered Stderr "unexpected top-level command: ") +1080 (write-slice-buffered Stderr %edx) +1081 (write-buffered Stderr "\n") +1082 (flush Stderr) +1083 # . syscall(exit, 1) +1084 bb/copy-to-ebx 1/imm32 +1085 b8/copy-to-eax 1/imm32/exit +1086 cd/syscall 0x80/imm8 +1087 # never gets here +1088 +1089 $parse-mu:error2: +1090 # error(vars->top " vars not reclaimed after fn '" new-function->name "'\n") +1091 (print-int32-buffered Stderr *ebx) +1092 (write-buffered Stderr " vars not reclaimed after fn '") +1093 (write-slice-buffered Stderr *eax) # Function-name +1094 (write-buffered Stderr "'\n") +1095 (flush Stderr) +1096 # . syscall(exit, 1) +1097 bb/copy-to-ebx 1/imm32 +1098 b8/copy-to-eax 1/imm32/exit +1099 cd/syscall 0x80/imm8 +1100 # never gets here +1101 +1102 # scenarios considered: +1103 # ✗ fn foo # no block +1104 # ✓ fn foo { +1105 # ✗ fn foo { { +1106 # ✗ fn foo { } +1107 # ✗ fn foo { } { +1108 # ✗ fn foo x { +1109 # ✗ fn foo x : { +1110 # ✓ fn foo x : int { +1111 # ✓ fn foo x: int { +1112 # ✓ fn foo x: int -> y/eax: int { +1113 populate-mu-function-header: # first-line : (addr stream byte), out : (handle function), vars : (addr stack (handle var)) +1114 # pseudocode: +1115 # var name : slice +1116 # next-word(first-line, name) +1117 # assert(name not in '{' '}' '->') +1118 # out->name = slice-to-string(name) +1119 # var next-offset : int = 8 +1120 # ## inouts +1121 # while true +1122 # ## name +1123 # name = next-word(first-line) +1124 # if (name == '{') goto done +1125 # if (name == '->') break +1126 # assert(name != '}') +1127 # var v : (handle var) = parse-var-with-type(name, first-line) +1128 # assert(v->register == null) +1129 # v->stack-offset = next-offset +1130 # next-offset += size-of(v) +1131 # out->inouts = append(out->inouts, v) +1132 # push(vars, v) +1133 # ## outputs +1134 # while true +1135 # ## name +1136 # name = next-word(first-line) +1137 # assert(name not in '{' '}' '->') +1138 # var v : (handle var) = parse-var-with-type(name, first-line) +1139 # assert(v->register != null) +1140 # out->outputs = append(out->outputs, v) +1141 # done: +1142 # +1143 # . prologue +1144 55/push-ebp +1145 89/<- %ebp 4/r32/esp +1146 # . save registers +1147 50/push-eax +1148 51/push-ecx +1149 52/push-edx +1150 53/push-ebx +1151 57/push-edi +1152 # edi = out +1153 8b/-> *(ebp+0xc) 7/r32/edi +1154 # var word-slice/ecx : slice +1155 68/push 0/imm32/end +1156 68/push 0/imm32/start +1157 89/<- %ecx 4/r32/esp +1158 # var next-offset/edx = 8 +1159 ba/copy-to-edx 8/imm32 +1160 # read function name +1161 (next-word *(ebp+8) %ecx) +1162 # error checking +1163 # if (word-slice == '{') abort +1164 (slice-equal? %ecx "{") # => eax +1165 3d/compare-eax-and 0/imm32 +1166 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 +1167 # if (word-slice == '->') abort +1168 (slice-equal? %ecx "->") # => eax +1169 3d/compare-eax-and 0/imm32 +1170 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 +1171 # if (word-slice == '}') abort +1172 (slice-equal? %ecx "}") # => eax +1173 3d/compare-eax-and 0/imm32 +1174 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 +1175 # save function name +1176 (slice-to-string Heap %ecx) # => eax +1177 89/<- *edi 0/r32/eax # Function-name +1178 # initialize default subx-name as well +1179 89/<- *(edi+4) 0/r32/eax # Function-subx-name +1180 # save function inouts +1181 { +1182 $populate-mu-function-header:check-for-inout: +1183 (next-word *(ebp+8) %ecx) +1184 # if (word-slice == '{') goto done +1185 (slice-equal? %ecx "{") # => eax +1186 3d/compare-eax-and 0/imm32 +1187 0f 85/jump-if-!= $populate-mu-function-header:done/disp32 +1188 # if (word-slice == '->') break +1189 (slice-equal? %ecx "->") # => eax +1190 3d/compare-eax-and 0/imm32 +1191 0f 85/jump-if-!= break/disp32 +1192 # if (word-slice == '}') abort +1193 (slice-equal? %ecx "}") # => eax +1194 3d/compare-eax-and 0/imm32 +1195 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 +1196 # var v/ebx : (handle var) = parse-var-with-type(word-slice, first-line) +1197 (parse-var-with-type %ecx *(ebp+8)) # => eax +1198 89/<- %ebx 0/r32/eax +1199 # assert(v->register == null) +1200 81 7/subop/compare *(ebx+0x10) 0/imm32 # Var-register +1201 0f 85/jump-if-!= $populate-mu-function-header:error2/disp32 +1202 # v->stack-offset = next-offset +1203 89/<- *(ebx+0xc) 2/r32/edx # Var-stack-offset +1204 # next-offset += size-of(v) +1205 (size-of %ebx) # => eax +1206 01/add %edx 0/r32/eax +1207 # +1208 (append-list Heap %ebx *(edi+8)) # Function-inouts => eax +1209 89/<- *(edi+8) 0/r32/eax # Function-inouts +1210 (push *(ebp+0x10) %ebx) +1211 # +1212 e9/jump loop/disp32 +1213 } +1214 # save function outputs +1215 { +1216 $parse-var-with-type:check-for-out: +1217 (next-word *(ebp+8) %ecx) +1218 # if (word-slice == '{') break +1219 (slice-equal? %ecx "{") # => eax +1220 3d/compare-eax-and 0/imm32 +1221 0f 85/jump-if-!= break/disp32 +1222 # if (word-slice == '->') abort +1223 (slice-equal? %ecx "->") # => eax +1224 3d/compare-eax-and 0/imm32 +1225 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 +1226 # if (word-slice == '}') abort +1227 (slice-equal? %ecx "}") # => eax +1228 3d/compare-eax-and 0/imm32 +1229 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 +1230 # +1231 (parse-var-with-type %ecx *(ebp+8)) # => eax +1232 89/<- %ebx 0/r32/eax +1233 # assert(var->register != null) +1234 81 7/subop/compare *(ebx+0x10) 0/imm32 # Var-register +1235 0f 84/jump-if-= $populate-mu-function-header:error3/disp32 +1236 (append-list Heap %ebx *(edi+0xc)) # Function-outputs => eax +1237 89/<- *(edi+0xc) 0/r32/eax # Function-outputs +1238 e9/jump loop/disp32 +1239 } +1240 $populate-mu-function-header:done: +1241 (check-no-tokens-left *(ebp+8)) +1242 $populate-mu-function-header:end: +1243 # . reclaim locals +1244 81 0/subop/add %esp 8/imm32 +1245 # . restore registers +1246 5f/pop-to-edi +1247 5b/pop-to-ebx +1248 5a/pop-to-edx +1249 59/pop-to-ecx +1250 58/pop-to-eax +1251 # . epilogue +1252 89/<- %esp 5/r32/ebp +1253 5d/pop-to-ebp +1254 c3/return +1255 +1256 $populate-mu-function-header:error1: +1257 # error("function header not in form 'fn <name> {'") +1258 (write-buffered Stderr "function header not in form 'fn <name> [inouts] [-> outputs] {' -- '") +1259 (flush Stderr) +1260 (rewind-stream *(ebp+8)) +1261 (write-stream 2 *(ebp+8)) +1262 (write-buffered Stderr "'\n") +1263 (flush Stderr) +1264 # . syscall(exit, 1) +1265 bb/copy-to-ebx 1/imm32 +1266 b8/copy-to-eax 1/imm32/exit +1267 cd/syscall 0x80/imm8 +1268 # never gets here +1269 +1270 $populate-mu-function-header:error2: +1271 # error("function input '" var "' cannot be in a register") +1272 (write-buffered Stderr "function input '") +1273 (write-buffered Stderr *ebx) # Var-name +1274 (write-buffered Stderr "' cannot be in a register") +1275 (flush Stderr) +1276 # . syscall(exit, 1) +1277 bb/copy-to-ebx 1/imm32 +1278 b8/copy-to-eax 1/imm32/exit +1279 cd/syscall 0x80/imm8 +1280 # never gets here +1281 +1282 $populate-mu-function-header:error3: +1283 # error("function input '" var "' must be in a register") +1284 (write-buffered Stderr "function input '") +1285 (write-buffered Stderr *eax) # Var-name +1286 (write-buffered Stderr " must be in a register'") +1287 (flush Stderr) +1288 (rewind-stream *(ebp+8)) +1289 (write-stream 2 *(ebp+8)) +1290 (write-buffered Stderr "'\n") +1291 (flush Stderr) +1292 # . syscall(exit, 1) +1293 bb/copy-to-ebx 1/imm32 +1294 b8/copy-to-eax 1/imm32/exit +1295 cd/syscall 0x80/imm8 +1296 # never gets here +1297 +1298 test-function-header-with-arg: +1299 # 'foo n : int {' +1300 # . prologue +1301 55/push-ebp +1302 89/<- %ebp 4/r32/esp +1303 # setup +1304 (clear-stream _test-input-stream) +1305 (write _test-input-stream "foo n : int {\n") +1306 # result/ecx : function +1307 2b/subtract-> *Function-size 4/r32/esp +1308 89/<- %ecx 4/r32/esp +1309 (zero-out %ecx *Function-size) +1310 # var vars/ebx : (stack (addr var) 16) +1311 81 5/subop/subtract %esp 0x10/imm32 +1312 68/push 0x10/imm32/length +1313 68/push 0/imm32/top +1314 89/<- %ebx 4/r32/esp +1315 # convert +1316 (populate-mu-function-header _test-input-stream %ecx %ebx) +1317 # check result +1318 (check-strings-equal *ecx "foo" "F - test-function-header-with-arg/name") # Function-name +1319 # edx : (handle list var) = result->inouts +1320 8b/-> *(ecx+8) 2/r32/edx # Function-inouts +1321 # ebx : (handle var) = result->inouts->value +1322 8b/-> *edx 3/r32/ebx # List-value +1323 (check-strings-equal *ebx "n" "F - test-function-header-with-arg/inout:0") # Var-name +1324 8b/-> *(ebx+4) 3/r32/ebx # Var-type +1325 (check-ints-equal *ebx 1 "F - test-function-header-with-arg/inout:0/type:0") # Tree-left +1326 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-arg/inout:0/type:1") # Tree-right +1327 # . epilogue +1328 89/<- %esp 5/r32/ebp +1329 5d/pop-to-ebp +1330 c3/return +1331 +1332 test-function-header-with-multiple-args: +1333 # 'fn foo a: int, b: int, c: int {' +1334 # . prologue +1335 55/push-ebp +1336 89/<- %ebp 4/r32/esp +1337 # setup +1338 (clear-stream _test-input-stream) +1339 (write _test-input-stream "foo a: int, b: int c: int {\n") +1340 # result/ecx : (handle function) +1341 2b/subtract-> *Function-size 4/r32/esp +1342 89/<- %ecx 4/r32/esp +1343 (zero-out %ecx *Function-size) +1344 # var vars/ebx : (stack (addr var) 16) +1345 81 5/subop/subtract %esp 0x10/imm32 +1346 68/push 0x10/imm32/length +1347 68/push 0/imm32/top +1348 89/<- %ebx 4/r32/esp +1349 # convert +1350 (populate-mu-function-header _test-input-stream %ecx %ebx) +1351 # check result +1352 (check-strings-equal *ecx "foo") # Function-name +1353 # edx : (handle list var) = result->inouts +1354 8b/-> *(ecx+8) 2/r32/edx # Function-inouts +1355 $test-function-header-with-multiple-args:inout0: +1356 # ebx : (handle var) = result->inouts->value +1357 8b/-> *edx 3/r32/ebx # List-value +1358 (check-strings-equal *ebx "a" "F - test-function-header-with-multiple-args/inout:0") # Var-name +1359 8b/-> *(ebx+4) 3/r32/ebx # Var-type +1360 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args/inout:0/type:0") # Tree-left +1361 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args/inout:0/type:1") # Tree-right +1362 # edx = result->inouts->next +1363 8b/-> *(edx+4) 2/r32/edx # List-next +1364 $test-function-header-with-multiple-args:inout1: +1365 # ebx = result->inouts->next->value +1366 8b/-> *edx 3/r32/ebx # List-value +1367 (check-strings-equal *ebx "b" "F - test-function-header-with-multiple-args/inout:1") # Var-name +1368 8b/-> *(ebx+4) 3/r32/ebx # Var-type +1369 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args/inout:1/type:0") # Tree-left +1370 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args/inout:1/type:1") # Tree-right +1371 # edx = result->inouts->next->next +1372 8b/-> *(edx+4) 2/r32/edx # List-next +1373 $test-function-header-with-multiple-args:inout2: +1374 # ebx = result->inouts->next->next->value +1375 8b/-> *edx 3/r32/ebx # List-value +1376 (check-strings-equal *ebx "c" "F - test-function-header-with-multiple-args/inout:2") # Var-name +1377 8b/-> *(ebx+4) 3/r32/ebx # Var-type +1378 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args/inout:2/type:0") # Tree-left +1379 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args/inout:2/type:1") # Tree-right +1380 # . epilogue +1381 89/<- %esp 5/r32/ebp +1382 5d/pop-to-ebp +1383 c3/return +1384 +1385 test-function-with-multiple-args-and-outputs: +1386 # fn foo a: int, b: int, c: int -> x: int, y: int { +1387 # . prologue +1388 55/push-ebp +1389 89/<- %ebp 4/r32/esp +1390 # setup +1391 (clear-stream _test-input-stream) +1392 (write _test-input-stream "foo a: int, b: int, c: int -> x/ecx: int y/edx : int {\n") +1393 # result/ecx : (handle function) +1394 2b/subtract-> *Function-size 4/r32/esp +1395 89/<- %ecx 4/r32/esp +1396 (zero-out %ecx *Function-size) +1397 # var vars/ebx : (stack (addr var) 16) +1398 81 5/subop/subtract %esp 0x10/imm32 +1399 68/push 0x10/imm32/length +1400 68/push 0/imm32/top +1401 89/<- %ebx 4/r32/esp +1402 # convert +1403 (populate-mu-function-header _test-input-stream %ecx %ebx) +1404 # check result +1405 (check-strings-equal *ecx "foo") # Function-name +1406 # edx : (handle list var) = result->inouts +1407 8b/-> *(ecx+8) 2/r32/edx # Function-inouts +1408 # ebx : (handle var) = result->inouts->value +1409 8b/-> *edx 3/r32/ebx # List-value +1410 (check-strings-equal *ebx "a" "F - test-function-header-with-multiple-args-and-outputs/inout:0") # Var-name +1411 8b/-> *(ebx+4) 3/r32/ebx # Var-type +1412 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:0") # Tree-left +1413 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:1") # Tree-right +1414 # edx = result->inouts->next +1415 8b/-> *(edx+4) 2/r32/edx # List-next +1416 # ebx = result->inouts->next->value +1417 8b/-> *edx 3/r32/ebx # List-value +1418 (check-strings-equal *ebx "b" "F - test-function-header-with-multiple-args-and-outputs/inout:1") # Var-name +1419 8b/-> *(ebx+4) 3/r32/ebx # Var-type +1420 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:0") # Tree-left +1421 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:1") # Tree-right +1422 # edx = result->inouts->next->next +1423 8b/-> *(edx+4) 2/r32/edx # List-next +1424 # ebx = result->inouts->next->next->value +1425 8b/-> *edx 3/r32/ebx # List-value +1426 (check-strings-equal *ebx "c" "F - test-function-header-with-multiple-args-and-outputs/inout:2") # Var-name +1427 8b/-> *(ebx+4) 3/r32/ebx # Var-type +1428 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:0") # Tree-left +1429 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:1") # Tree-right +1430 # edx : (handle list var) = result->outputs +1431 8b/-> *(ecx+0xc) 2/r32/edx # Function-outputs +1432 # ebx : (handle var) = result->outputs->value +1433 8b/-> *edx 3/r32/ebx # List-value +1434 (check-strings-equal *ebx "x" "F - test-function-header-with-multiple-args-and-outputs/output:0") # Var-name +1435 (check-strings-equal *(ebx+0x10) "ecx" "F - test-function-header-with-multiple-args-and-outputs/output:0/register") # Var-register +1436 8b/-> *(ebx+4) 3/r32/ebx # Var-type +1437 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:1") # Tree-left +1438 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:1") # Tree-right +1439 # edx = result->outputs->next +1440 8b/-> *(edx+4) 2/r32/edx # List-next +1441 # ebx = result->outputs->next->value +1442 8b/-> *edx 3/r32/ebx # List-value +1443 (check-strings-equal *ebx "y" "F - test-function-header-with-multiple-args-and-outputs/output:1") # Var-name +1444 (check-strings-equal *(ebx+0x10) "edx" "F - test-function-header-with-multiple-args-and-outputs/output:0/register") # Var-register +1445 8b/-> *(ebx+4) 3/r32/ebx # Var-type +1446 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:1") # Tree-left +1447 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:1") # Tree-right +1448 # . epilogue +1449 89/<- %esp 5/r32/ebp +1450 5d/pop-to-ebp +1451 c3/return +1452 +1453 # format for variables with types +1454 # x : int +1455 # x: int +1456 # x: int, +1457 # ignores at most one trailing colon or comma +1458 parse-var-with-type: # name: (addr slice), first-line: (addr stream byte) -> result/eax: (handle var) +1459 # pseudocode: +1460 # var v : (handle var) = allocate(Heap, Var-size) +1461 # var s : slice +1462 # next-token-from-slice(name->start, name->end, '/', s) +1463 # var end : (addr byte) = s->end +1464 # if (slice-ends-with(s, ":")) +1465 # decrement s->end +1466 # if (slice-ends-with(s, ",")) +1467 # decrement s->end +1468 # v->name = slice-to-string(s) +1469 # ## register +1470 # next-token-from-slice(end, name->end, '/', s) +1471 # if (slice-ends-with(s, ":")) +1472 # decrement s->end +1473 # if (slice-ends-with(s, ",")) +1474 # decrement s->end +1475 # if (!slice-empty?(s)) +1476 # v->register = slice-to-string(s) +1477 # ## type +1478 # var type : (handle tree type-id) = parse-type(first-line) +1479 # v->type = type +1480 # return v +1481 # +1482 # . prologue +1483 55/push-ebp +1484 89/<- %ebp 4/r32/esp +1485 # . save registers +1486 51/push-ecx +1487 52/push-edx +1488 53/push-ebx +1489 56/push-esi +1490 57/push-edi +1491 # var result/edi : (handle var) = allocate(Heap, Var-size) +1492 (allocate Heap *Var-size) # => eax +1493 (zero-out %eax *Var-size) +1494 89/<- %edi 0/r32/eax +1495 # esi = name +1496 8b/-> *(ebp+8) 6/r32/esi +1497 # var s/ecx : slice +1498 68/push 0/imm32/end +1499 68/push 0/imm32/start +1500 89/<- %ecx 4/r32/esp +1501 $parse-var-with-type:save-name: +1502 # save v->name +1503 (next-token-from-slice *esi *(esi+4) 0x2f %ecx) # Slice-start, Slice-end, '/' +1504 # . end/edx = s->end +1505 8b/-> *(ecx+4) 2/r32/edx +1506 # . if s ends with ':', decrement s->end +1507 { +1508 8b/-> *(ecx+4) 0/r32/eax +1509 48/decrement-eax +1510 8a/copy-byte *eax 3/r32/BL +1511 81 4/subop/and %ebx 0xff/imm32 +1512 81 7/subop/compare %ebx 0x3a/imm32/colon +1513 75/jump-if-!= break/disp8 +1514 89/<- *(ecx+4) 0/r32/eax +1515 } +1516 # . if s ends with ',', decrement s->end +1517 { +1518 8b/-> *(ecx+4) 0/r32/eax +1519 48/decrement-eax +1520 8a/copy-byte *eax 3/r32/BL +1521 81 4/subop/and %ebx 0xff/imm32 +1522 81 7/subop/compare %ebx 0x2c/imm32/comma +1523 75/jump-if-!= break/disp8 +1524 89/<- *(ecx+4) 0/r32/eax +1525 } +1526 $parse-var-with-type:write-name: +1527 (slice-to-string Heap %ecx) # => eax +1528 89/<- *edi 0/r32/eax # Var-name +1529 # save v->register +1530 $parse-var-with-type:save-register: +1531 (next-token-from-slice %edx *(esi+4) 0x2f %ecx) # end, name->end, '/' +1532 # . if s ends with ':', decrement s->end +1533 { +1534 8b/-> *(ecx+4) 0/r32/eax +1535 48/decrement-eax +1536 8a/copy-byte *eax 3/r32/BL +1537 81 4/subop/and %ebx 0xff/imm32 +1538 81 7/subop/compare %ebx 0x3a/imm32/colon +1539 75/jump-if-!= break/disp8 +1540 89/<- *(ecx+4) 0/r32/eax +1541 } +1542 # . if s ends with ',', decrement s->end +1543 { +1544 8b/-> *(ecx+4) 0/r32/eax +1545 48/decrement-eax +1546 8a/copy-byte *eax 3/r32/BL +1547 81 4/subop/and %ebx 0xff/imm32 +1548 81 7/subop/compare %ebx 0x2c/imm32/comma +1549 75/jump-if-!= break/disp8 +1550 89/<- *(ecx+4) 0/r32/eax +1551 } +1552 # if (!slice-empty?(s)) v->register = slice-to-string(s) +1553 { +1554 $parse-var-with-type:write-register: +1555 # HACK: s->end can be less than s->start with all the decrements above +1556 # That's probably a sign we have the wrong algorithm for this function. +1557 8b/-> *ecx 0/r32/eax +1558 39/compare 0/r32/eax *(ecx+4) +1559 76/jump-if-<= break/disp8 +1560 (slice-to-string Heap %ecx) +1561 89/<- *(edi+0x10) 0/r32/eax # Var-register +1562 } +1563 $parse-var-with-type:save-type: +1564 (parse-type Heap *(ebp+0xc)) # => eax +1565 89/<- *(edi+4) 0/r32/eax # Var-type +1566 $parse-var-with-type:end: +1567 # return result +1568 89/<- %eax 7/r32/edi +1569 # . reclaim locals +1570 81 0/subop/add %esp 8/imm32 +1571 # . restore registers +1572 5f/pop-to-edi +1573 5e/pop-to-esi +1574 5b/pop-to-ebx +1575 5a/pop-to-edx +1576 59/pop-to-ecx +1577 # . epilogue +1578 89/<- %esp 5/r32/ebp +1579 5d/pop-to-ebp +1580 c3/return +1581 +1582 $parse-var-with-type:abort: +1583 # error("function header not in form 'fn <name> {'") +1584 (write-buffered Stderr "var should have form 'name: type' in '") +1585 (flush Stderr) +1586 (rewind-stream *(ebp+0xc)) +1587 (write-stream 2 *(ebp+0xc)) +1588 (write-buffered Stderr "'\n") +1589 (flush Stderr) +1590 # . syscall(exit, 1) +1591 bb/copy-to-ebx 1/imm32 +1592 b8/copy-to-eax 1/imm32/exit +1593 cd/syscall 0x80/imm8 +1594 # never gets here +1595 +1596 parse-type: # ad: (address allocation-descriptor), in: (addr stream byte) -> result/eax: (handle tree type-id) +1597 # pseudocode: +1598 # var s: slice = next-mu-token(in) +1599 # assert s != "" +1600 # assert s != "->" +1601 # assert s != "{" +1602 # assert s != "}" +1603 # if s == ")" +1604 # return 0 +1605 # result = allocate(Tree) +1606 # zero-out(result, *Tree-size) +1607 # if s != "(" +1608 # result->left = pos-slice(Type-id, s) +1609 # return +1610 # result->left = parse-type(ad, in) +1611 # result->right = parse-type-tree(ad, in) +1612 # +1613 # . prologue +1614 55/push-ebp +1615 89/<- %ebp 4/r32/esp +1616 # . save registers +1617 51/push-ecx +1618 52/push-edx +1619 # var s/ecx: slice +1620 68/push 0/imm32 +1621 68/push 0/imm32 +1622 89/<- %ecx 4/r32/esp +1623 # s = next-mu-token(in) +1624 (next-mu-token *(ebp+0xc) %ecx) +1625 #? (write-buffered Stderr "tok: ") +1626 #? (write-slice-buffered Stderr %ecx) +1627 #? (write-buffered Stderr "$\n") +1628 #? (flush Stderr) +1629 # assert s != "" +1630 (slice-equal? %ecx "") +1631 3d/compare-eax-and 0/imm32 +1632 0f 85/jump-if-not-equal $parse-type:abort/disp32 +1633 # assert s != "{" +1634 (slice-equal? %ecx "{") +1635 3d/compare-eax-and 0/imm32 +1636 0f 85/jump-if-not-equal $parse-type:abort/disp32 +1637 # assert s != "}" +1638 (slice-equal? %ecx "}") +1639 3d/compare-eax-and 0/imm32 +1640 0f 85/jump-if-not-equal $parse-type:abort/disp32 +1641 # assert s != "->" +1642 (slice-equal? %ecx "->") +1643 3d/compare-eax-and 0/imm32 +1644 0f 85/jump-if-not-equal $parse-type:abort/disp32 +1645 # if (s == ")") return 0 +1646 (slice-equal? %ecx ")") +1647 3d/compare-eax-and 0/imm32 +1648 b8/copy-to-eax 0/imm32 +1649 0f 85/jump-if-not-equal $parse-type:end/disp32 +1650 # var result/edx: (handle tree type-id) +1651 (allocate *(ebp+8) *Tree-size) # => eax +1652 (zero-out %eax *Tree-size) +1653 89/<- %edx 0/r32/eax +1654 { +1655 # if (s != "(") break +1656 (slice-equal? %ecx "(") +1657 3d/compare-eax-and 0/imm32 +1658 75/jump-if-not-equal break/disp8 +1659 # result->left = pos-slice(Type-id, s) +1660 (pos-slice Type-id %ecx) +1661 #? (write-buffered Stderr "=> {") +1662 #? (print-int32-buffered Stderr %eax) +1663 #? (write-buffered Stderr ", 0}\n") +1664 #? (flush Stderr) +1665 89/<- *edx 0/r32/eax # Tree-left +1666 e9/jump $parse-type:return-edx/disp32 +1667 } +1668 # otherwise s == "(" +1669 # result->left = parse-type(ad, in) +1670 (parse-type *(ebp+8) *(ebp+0xc)) +1671 #? (write-buffered Stderr "=> {") +1672 #? (print-int32-buffered Stderr %eax) +1673 89/<- *edx 0/r32/eax # Tree-left +1674 # result->right = parse-type-tree(ad, in) +1675 (parse-type-tree *(ebp+8) *(ebp+0xc)) +1676 #? (write-buffered Stderr Space) +1677 #? (print-int32-buffered Stderr %eax) +1678 #? (write-buffered Stderr "}\n") +1679 #? (flush Stderr) +1680 89/<- *(edx+4) 0/r32/eax # Tree-right +1681 $parse-type:return-edx: +1682 89/<- %eax 2/r32/edx +1683 $parse-type:end: +1684 # . reclaim locals +1685 81 0/subop/add %esp 8/imm32 +1686 # . restore registers +1687 5a/pop-to-edx +1688 59/pop-to-ecx +1689 # . epilogue +1690 89/<- %esp 5/r32/ebp +1691 5d/pop-to-ebp +1692 c3/return +1693 +1694 $parse-type:abort: +1695 # error("unexpected token when parsing type: '" s "'\n") +1696 (write-buffered Stderr "unexpected token when parsing type: '") +1697 (write-slice-buffered Stderr %ecx) +1698 (write-buffered Stderr "'\n") +1699 (flush Stderr) +1700 # . syscall(exit, 1) +1701 bb/copy-to-ebx 1/imm32 +1702 b8/copy-to-eax 1/imm32/exit +1703 cd/syscall 0x80/imm8 +1704 # never gets here +1705 +1706 parse-type-tree: # ad: (address allocation-descriptor), in: (addr stream byte) -> result/eax: (handle tree type-id) +1707 # pseudocode: +1708 # var tmp: (handle tree type-id) = parse-type(ad, in) +1709 # if tmp == 0 +1710 # return 0 +1711 # result = allocate(Tree) +1712 # zero-out(result, *Tree-size) +1713 # result->left = tmp +1714 # result->right = parse-type-tree(ad, in) +1715 # +1716 # . prologue +1717 55/push-ebp +1718 89/<- %ebp 4/r32/esp +1719 # . save registers +1720 51/push-ecx +1721 52/push-edx +1722 # var tmp/eax: (handle tree type-id) = parse-type(ad, in) +1723 (parse-type *(ebp+8) *(ebp+0xc)) +1724 # if (tmp == 0) return tmp +1725 3d/compare-eax-and 0/imm32 +1726 74/jump-if-equal $parse-type-tree:end/disp8 +1727 # var tmp2/ecx = tmp +1728 89/<- %ecx 0/r32/eax +1729 # var result/edx: (handle tree type-id) +1730 (allocate *(ebp+8) *Tree-size) # => eax +1731 (zero-out %eax *Tree-size) +1732 89/<- %edx 0/r32/eax +1733 # result->left = tmp2 +1734 89/<- *edx 1/r32/ecx # Tree-left +1735 # result->right = parse-type-tree(ad, in) +1736 (parse-type-tree *(ebp+8) *(ebp+0xc)) +1737 89/<- *(edx+4) 0/r32/eax # Tree-right +1738 $parse-type-tree:return-edx: +1739 89/<- %eax 2/r32/edx +1740 $parse-type-tree:end: +1741 # . restore registers +1742 5a/pop-to-edx +1743 59/pop-to-ecx +1744 # . epilogue +1745 89/<- %esp 5/r32/ebp +1746 5d/pop-to-ebp +1747 c3/return +1748 +1749 next-mu-token: # in: (addr stream byte), out: (addr slice) +1750 # pseudocode: +1751 # start: +1752 # skip-chars-matching-whitespace(in) +1753 # if in->read >= in->write # end of in +1754 # out = {0, 0} +1755 # return +1756 # out->start = &in->data[in->read] +1757 # var curr-byte/eax: byte = in->data[in->read] +1758 # if curr->byte == ':' # comment token +1759 # ++in->read +1760 # goto start +1761 # if curr->byte == ',' # comment token +1762 # ++in->read +1763 # goto start +1764 # if curr-byte == '#' # comment +1765 # in->read = in->write # skip to end of in +1766 # goto done +1767 # if curr-byte == '"' # string literal +1768 # skip-string(in) +1769 # goto done # no metadata +1770 # if curr-byte == '(' +1771 # ++in->read 1772 # goto done -1773 # if curr-byte == '"' # string literal -1774 # skip-string(in) -1775 # goto done # no metadata -1776 # if curr-byte == '(' -1777 # ++in->read -1778 # goto done -1779 # if curr-byte == ')' -1780 # ++in->read -1781 # goto done -1782 # # read a word -1783 # while true -1784 # if in->read >= in->write -1785 # break -1786 # curr-byte = in->data[in->read] -1787 # if curr-byte == ' ' +1773 # if curr-byte == ')' +1774 # ++in->read +1775 # goto done +1776 # # read a word +1777 # while true +1778 # if in->read >= in->write +1779 # break +1780 # curr-byte = in->data[in->read] +1781 # if curr-byte == ' ' +1782 # break +1783 # if curr-byte == '\r' +1784 # break +1785 # if curr-byte == '\n' +1786 # break +1787 # if curr-byte == '(' 1788 # break -1789 # if curr-byte == '(' +1789 # if curr-byte == ')' 1790 # break -1791 # if curr-byte == ')' +1791 # if curr-byte == ':' 1792 # break -1793 # if curr-byte == ':' +1793 # if curr-byte == ',' 1794 # break -1795 # if curr-byte == ',' -1796 # break -1797 # ++in->read -1798 # done: -1799 # out->end = &in->data[in->read] -1800 # # hack: skip a few trailing delimiters, because we don't always use -1801 # # this correct tokenizer in later tokens -1802 # while true -1803 # if in->read >= in->write -1804 # break -1805 # curr-byte = in->data[in->read] -1806 # if curr-byte == ':' +1795 # ++in->read +1796 # done: +1797 # out->end = &in->data[in->read] +1798 # # hack: skip a few trailing delimiters, because we don't always use +1799 # # this correct tokenizer in later tokens +1800 # while true +1801 # if in->read >= in->write +1802 # break +1803 # curr-byte = in->data[in->read] +1804 # if curr-byte == ':' +1805 # ++in->read +1806 # else if curr-byte == ',' 1807 # ++in->read -1808 # else if curr-byte == ',' -1809 # ++in->read -1810 # else -1811 # break -1812 # -1813 # . prologue -1814 55/push-ebp -1815 89/<- %ebp 4/r32/esp -1816 # . save registers -1817 50/push-eax -1818 51/push-ecx -1819 56/push-esi -1820 57/push-edi -1821 # esi = in -1822 8b/-> *(ebp+8) 6/r32/esi -1823 # edi = out -1824 8b/-> *(ebp+0xc) 7/r32/edi -1825 $next-mu-token:start: -1826 # skip-chars-matching(in, ' ') -1827 (skip-chars-matching %esi 0x20) # ' ' -1828 $next-mu-token:check0: -1829 # if (in->read >= in->write) return out = {0, 0} -1830 # . ecx = in->read -1831 8b/-> *(esi+4) 1/r32/ecx -1832 # . if (ecx >= in->write) return out = {0, 0} -1833 3b/compare 1/r32/ecx *esi -1834 c7 0/subop/copy *edi 0/imm32 -1835 c7 0/subop/copy *(edi+4) 0/imm32 -1836 0f 8d/jump-if->= $next-mu-token:end/disp32 -1837 # out->start = &in->data[in->read] -1838 8d/copy-address *(esi+ecx+0xc) 0/r32/eax -1839 89/<- *edi 0/r32/eax -1840 # var curr-byte/eax : byte = in->data[in->read] -1841 31/xor %eax 0/r32/eax -1842 8a/copy-byte *(esi+ecx+0xc) 0/r32/AL -1843 { -1844 $next-mu-token:check-for-colon: -1845 # if (curr-byte != ':') break -1846 3d/compare-eax-and 0x3a/imm32/colon -1847 75/jump-if-!= break/disp8 -1848 # ++in->read -1849 ff 0/subop/increment *(esi+4) -1850 # restart -1851 e9/jump $next-mu-token:start/disp32 -1852 } -1853 { -1854 $next-mu-token:check-for-comma: -1855 # if (curr-byte != ',') break -1856 3d/compare-eax-and 0x2c/imm32/comma -1857 75/jump-if-!= break/disp8 -1858 # ++in->read -1859 ff 0/subop/increment *(esi+4) -1860 # restart -1861 e9/jump $next-mu-token:start/disp32 -1862 } -1863 { -1864 $next-mu-token:check-for-comment: -1865 # if (curr-byte != '#') break -1866 3d/compare-eax-and 0x23/imm32/pound -1867 75/jump-if-!= break/disp8 -1868 # in->read = in->write # skip rest of in -1869 8b/-> *esi 0/r32/eax -1870 89/<- *(esi+4) 0/r32/eax -1871 # return -1872 e9/jump $next-mu-token:done/disp32 -1873 } -1874 { -1875 $next-mu-token:check-for-string-literal: -1876 # if (curr-byte != '"') break -1877 3d/compare-eax-and 0x22/imm32/dquote -1878 75/jump-if-!= break/disp8 -1879 (skip-string %esi) -1880 # return -1881 e9/jump $next-mu-token:done/disp32 -1882 } -1883 { -1884 $next-mu-token:check-for-open-paren: -1885 # if (curr-byte != '(') break -1886 3d/compare-eax-and 0x28/imm32/open-paren -1887 75/jump-if-!= break/disp8 -1888 # ++in->read -1889 ff 0/subop/increment *(esi+4) -1890 # return -1891 e9/jump $next-mu-token:done/disp32 -1892 } -1893 { -1894 $next-mu-token:check-for-close-paren: -1895 # if (curr-byte != ')') break -1896 3d/compare-eax-and 0x29/imm32/close-paren -1897 75/jump-if-!= break/disp8 -1898 # ++in->read -1899 ff 0/subop/increment *(esi+4) -1900 # return -1901 e9/jump $next-mu-token:done/disp32 -1902 } -1903 { -1904 $next-mu-token:regular-word-without-metadata: -1905 # if (in->read >= in->write) break -1906 # . ecx = in->read -1907 8b/-> *(esi+4) 1/r32/ecx -1908 # . if (ecx >= in->write) break -1909 3b/compare *esi 1/r32/ecx -1910 7d/jump-if->= break/disp8 -1911 # var c/eax: byte = in->data[in->read] -1912 31/xor %eax 0/r32/eax -1913 8a/copy-byte *(esi+ecx+0xc) 0/r32/AL -1914 # if (c == ' ') break -1915 3d/compare-eax-and 0x20/imm32/space +1808 # else +1809 # break +1810 # +1811 # . prologue +1812 55/push-ebp +1813 89/<- %ebp 4/r32/esp +1814 # . save registers +1815 50/push-eax +1816 51/push-ecx +1817 56/push-esi +1818 57/push-edi +1819 # esi = in +1820 8b/-> *(ebp+8) 6/r32/esi +1821 # edi = out +1822 8b/-> *(ebp+0xc) 7/r32/edi +1823 $next-mu-token:start: +1824 (skip-chars-matching-whitespace %esi) +1825 $next-mu-token:check0: +1826 # if (in->read >= in->write) return out = {0, 0} +1827 # . ecx = in->read +1828 8b/-> *(esi+4) 1/r32/ecx +1829 # . if (ecx >= in->write) return out = {0, 0} +1830 3b/compare 1/r32/ecx *esi +1831 c7 0/subop/copy *edi 0/imm32 +1832 c7 0/subop/copy *(edi+4) 0/imm32 +1833 0f 8d/jump-if->= $next-mu-token:end/disp32 +1834 # out->start = &in->data[in->read] +1835 8d/copy-address *(esi+ecx+0xc) 0/r32/eax +1836 89/<- *edi 0/r32/eax +1837 # var curr-byte/eax : byte = in->data[in->read] +1838 31/xor %eax 0/r32/eax +1839 8a/copy-byte *(esi+ecx+0xc) 0/r32/AL +1840 { +1841 $next-mu-token:check-for-colon: +1842 # if (curr-byte != ':') break +1843 3d/compare-eax-and 0x3a/imm32/colon +1844 75/jump-if-!= break/disp8 +1845 # ++in->read +1846 ff 0/subop/increment *(esi+4) +1847 # restart +1848 e9/jump $next-mu-token:start/disp32 +1849 } +1850 { +1851 $next-mu-token:check-for-comma: +1852 # if (curr-byte != ',') break +1853 3d/compare-eax-and 0x2c/imm32/comma +1854 75/jump-if-!= break/disp8 +1855 # ++in->read +1856 ff 0/subop/increment *(esi+4) +1857 # restart +1858 e9/jump $next-mu-token:start/disp32 +1859 } +1860 { +1861 $next-mu-token:check-for-comment: +1862 # if (curr-byte != '#') break +1863 3d/compare-eax-and 0x23/imm32/pound +1864 75/jump-if-!= break/disp8 +1865 # in->read = in->write # skip rest of in +1866 8b/-> *esi 0/r32/eax +1867 89/<- *(esi+4) 0/r32/eax +1868 # return +1869 e9/jump $next-mu-token:done/disp32 +1870 } +1871 { +1872 $next-mu-token:check-for-string-literal: +1873 # if (curr-byte != '"') break +1874 3d/compare-eax-and 0x22/imm32/dquote +1875 75/jump-if-!= break/disp8 +1876 (skip-string %esi) +1877 # return +1878 e9/jump $next-mu-token:done/disp32 +1879 } +1880 { +1881 $next-mu-token:check-for-open-paren: +1882 # if (curr-byte != '(') break +1883 3d/compare-eax-and 0x28/imm32/open-paren +1884 75/jump-if-!= break/disp8 +1885 # ++in->read +1886 ff 0/subop/increment *(esi+4) +1887 # return +1888 e9/jump $next-mu-token:done/disp32 +1889 } +1890 { +1891 $next-mu-token:check-for-close-paren: +1892 # if (curr-byte != ')') break +1893 3d/compare-eax-and 0x29/imm32/close-paren +1894 75/jump-if-!= break/disp8 +1895 # ++in->read +1896 ff 0/subop/increment *(esi+4) +1897 # return +1898 e9/jump $next-mu-token:done/disp32 +1899 } +1900 { +1901 $next-mu-token:regular-word-without-metadata: +1902 # if (in->read >= in->write) break +1903 # . ecx = in->read +1904 8b/-> *(esi+4) 1/r32/ecx +1905 # . if (ecx >= in->write) break +1906 3b/compare *esi 1/r32/ecx +1907 7d/jump-if->= break/disp8 +1908 # var c/eax: byte = in->data[in->read] +1909 31/xor %eax 0/r32/eax +1910 8a/copy-byte *(esi+ecx+0xc) 0/r32/AL +1911 # if (c == ' ') break +1912 3d/compare-eax-and 0x20/imm32/space +1913 74/jump-if-= break/disp8 +1914 # if (c == '\r') break +1915 3d/compare-eax-and 0xd/imm32/carriage-return 1916 74/jump-if-= break/disp8 -1917 # if (c == '(') break -1918 3d/compare-eax-and 0x28/imm32/open-paren -1919 0f 84/jump-if-= break/disp32 -1920 # if (c == ')') break -1921 3d/compare-eax-and 0x29/imm32/close-paren +1917 # if (c == '\n') break +1918 3d/compare-eax-and 0xa/imm32/newline +1919 74/jump-if-= break/disp8 +1920 # if (c == '(') break +1921 3d/compare-eax-and 0x28/imm32/open-paren 1922 0f 84/jump-if-= break/disp32 -1923 # if (c == ':') break -1924 3d/compare-eax-and 0x3a/imm32/colon +1923 # if (c == ')') break +1924 3d/compare-eax-and 0x29/imm32/close-paren 1925 0f 84/jump-if-= break/disp32 -1926 # if (c == ',') break -1927 3d/compare-eax-and 0x2c/imm32/comma +1926 # if (c == ':') break +1927 3d/compare-eax-and 0x3a/imm32/colon 1928 0f 84/jump-if-= break/disp32 -1929 # ++in->read -1930 ff 0/subop/increment *(esi+4) -1931 # -1932 e9/jump loop/disp32 -1933 } -1934 $next-mu-token:done: -1935 # out->end = &in->data[in->read] -1936 8b/-> *(esi+4) 1/r32/ecx -1937 8d/copy-address *(esi+ecx+0xc) 0/r32/eax -1938 89/<- *(edi+4) 0/r32/eax -1939 { -1940 $next-mu-token:skip-trailing-delimiters: -1941 # if (in->read >= in->write) break -1942 # . ecx = in->read -1943 8b/-> *(esi+4) 1/r32/ecx -1944 # . if (ecx >= in->write) break -1945 3b/compare *esi 1/r32/ecx -1946 7d/jump-if->= break/disp8 -1947 # var c/eax: byte = in->data[in->read] -1948 31/xor %eax 0/r32/eax -1949 8a/copy-byte *(esi+ecx+0xc) 0/r32/AL -1950 # if (c == ':') ++in->read and loop -1951 { -1952 3d/compare-eax-and 0x3a/imm32/colon -1953 75/jump-if-!= break/disp8 -1954 # ++in->read -1955 ff 0/subop/increment *(esi+4) -1956 # -1957 eb/jump $next-mu-token:skip-trailing-delimiters/disp8 -1958 } -1959 # if (c == ',') ++in->read and loop -1960 { -1961 3d/compare-eax-and 0x2c/imm32/comma -1962 75/jump-if-!= break/disp8 -1963 # ++in->read -1964 ff 0/subop/increment *(esi+4) -1965 # -1966 eb/jump $next-mu-token:skip-trailing-delimiters/disp8 -1967 } -1968 # else break -1969 } -1970 $next-mu-token:end: -1971 # . restore registers -1972 5f/pop-to-edi -1973 5e/pop-to-esi -1974 59/pop-to-ecx -1975 58/pop-to-eax -1976 # . epilogue -1977 89/<- %esp 5/r32/ebp -1978 5d/pop-to-ebp -1979 c3/return -1980 -1981 # return the index in an array of strings matching 's' -1982 # index is denominated in elements, not bytes -1983 pos-slice: # arr: (addr stream (handle array byte)), s: (addr slice) -> index/eax: int -1984 # . prologue -1985 55/push-ebp -1986 89/<- %ebp 4/r32/esp -1987 # . save registers -1988 51/push-ecx -1989 52/push-edx -1990 53/push-ebx -1991 56/push-esi -1992 #? (write-buffered Stderr "pos-slice: ") -1993 #? (write-slice-buffered Stderr *(ebp+0xc)) -1994 #? (write-buffered Stderr "\n") -1995 #? (flush Stderr) -1996 # esi = arr -1997 8b/-> *(ebp+8) 6/r32/esi -1998 # var index/ecx: int = 0 -1999 b9/copy-to-ecx 0/imm32 -2000 # var curr/edx: (addr (addr array byte)) = arr->data -2001 8d/copy-address *(esi+0xc) 2/r32/edx -2002 # var max/ebx: (addr (addr array byte)) = &arr->data[arr->write] -2003 8b/-> *esi 3/r32/ebx -2004 8d/copy-address *(esi+ebx+0xc) 3/r32/ebx -2005 { -2006 #? (write-buffered Stderr " ") -2007 #? (print-int32-buffered Stderr %ecx) -2008 #? (write-buffered Stderr "\n") -2009 #? (flush Stderr) -2010 # if (curr >= max) return -1 -2011 39/compare %edx 3/r32/ebx -2012 b8/copy-to-eax -1/imm32 -2013 73/jump-if-addr>= $pos-slice:end/disp8 -2014 # if (slice-equal?(s, *curr)) break -2015 (slice-equal? *(ebp+0xc) *edx) # => eax -2016 3d/compare-eax-and 0/imm32 -2017 75/jump-if-!= break/disp8 -2018 # ++index -2019 41/increment-ecx -2020 # curr += 4 -2021 81 0/subop/add %edx 4/imm32 -2022 # -2023 eb/jump loop/disp8 -2024 } -2025 # return index -2026 89/<- %eax 1/r32/ecx -2027 $pos-slice:end: -2028 #? (write-buffered Stderr "=> ") -2029 #? (print-int32-buffered Stderr %eax) -2030 #? (write-buffered Stderr "\n") -2031 # . restore registers -2032 5e/pop-to-esi -2033 5b/pop-to-ebx -2034 5a/pop-to-edx -2035 59/pop-to-ecx -2036 # . epilogue -2037 89/<- %esp 5/r32/ebp -2038 5d/pop-to-ebp -2039 c3/return -2040 -2041 == data -2042 -2043 Type-id: # (stream (address array byte)) -2044 0x18/imm32/write -2045 0/imm32/read -2046 0x100/imm32/length -2047 # data -2048 "literal"/imm32 # 0 -2049 "int"/imm32 # 1 -2050 "addr"/imm32 # 2 -2051 "array"/imm32 # 3 -2052 "handle"/imm32 # 4 -2053 "bool"/imm32 # 5 -2054 0/imm32 -2055 0/imm32 -2056 # 0x20 -2057 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 -2058 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 -2059 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +1929 # if (c == ',') break +1930 3d/compare-eax-and 0x2c/imm32/comma +1931 0f 84/jump-if-= break/disp32 +1932 # ++in->read +1933 ff 0/subop/increment *(esi+4) +1934 # +1935 e9/jump loop/disp32 +1936 } +1937 $next-mu-token:done: +1938 # out->end = &in->data[in->read] +1939 8b/-> *(esi+4) 1/r32/ecx +1940 8d/copy-address *(esi+ecx+0xc) 0/r32/eax +1941 89/<- *(edi+4) 0/r32/eax +1942 { +1943 $next-mu-token:skip-trailing-delimiters: +1944 # if (in->read >= in->write) break +1945 # . ecx = in->read +1946 8b/-> *(esi+4) 1/r32/ecx +1947 # . if (ecx >= in->write) break +1948 3b/compare *esi 1/r32/ecx +1949 7d/jump-if->= break/disp8 +1950 # var c/eax: byte = in->data[in->read] +1951 31/xor %eax 0/r32/eax +1952 8a/copy-byte *(esi+ecx+0xc) 0/r32/AL +1953 # if (c == ':') ++in->read and loop +1954 { +1955 3d/compare-eax-and 0x3a/imm32/colon +1956 75/jump-if-!= break/disp8 +1957 # ++in->read +1958 ff 0/subop/increment *(esi+4) +1959 # +1960 eb/jump $next-mu-token:skip-trailing-delimiters/disp8 +1961 } +1962 # if (c == ',') ++in->read and loop +1963 { +1964 3d/compare-eax-and 0x2c/imm32/comma +1965 75/jump-if-!= break/disp8 +1966 # ++in->read +1967 ff 0/subop/increment *(esi+4) +1968 # +1969 eb/jump $next-mu-token:skip-trailing-delimiters/disp8 +1970 } +1971 # else break +1972 } +1973 $next-mu-token:end: +1974 # . restore registers +1975 5f/pop-to-edi +1976 5e/pop-to-esi +1977 59/pop-to-ecx +1978 58/pop-to-eax +1979 # . epilogue +1980 89/<- %esp 5/r32/ebp +1981 5d/pop-to-ebp +1982 c3/return +1983 +1984 # return the index in an array of strings matching 's' +1985 # index is denominated in elements, not bytes +1986 pos-slice: # arr: (addr stream (handle array byte)), s: (addr slice) -> index/eax: int +1987 # . prologue +1988 55/push-ebp +1989 89/<- %ebp 4/r32/esp +1990 # . save registers +1991 51/push-ecx +1992 52/push-edx +1993 53/push-ebx +1994 56/push-esi +1995 #? (write-buffered Stderr "pos-slice: ") +1996 #? (write-slice-buffered Stderr *(ebp+0xc)) +1997 #? (write-buffered Stderr "\n") +1998 #? (flush Stderr) +1999 # esi = arr +2000 8b/-> *(ebp+8) 6/r32/esi +2001 # var index/ecx: int = 0 +2002 b9/copy-to-ecx 0/imm32 +2003 # var curr/edx: (addr (addr array byte)) = arr->data +2004 8d/copy-address *(esi+0xc) 2/r32/edx +2005 # var max/ebx: (addr (addr array byte)) = &arr->data[arr->write] +2006 8b/-> *esi 3/r32/ebx +2007 8d/copy-address *(esi+ebx+0xc) 3/r32/ebx +2008 { +2009 #? (write-buffered Stderr " ") +2010 #? (print-int32-buffered Stderr %ecx) +2011 #? (write-buffered Stderr "\n") +2012 #? (flush Stderr) +2013 # if (curr >= max) return -1 +2014 39/compare %edx 3/r32/ebx +2015 b8/copy-to-eax -1/imm32 +2016 73/jump-if-addr>= $pos-slice:end/disp8 +2017 # if (slice-equal?(s, *curr)) break +2018 (slice-equal? *(ebp+0xc) *edx) # => eax +2019 3d/compare-eax-and 0/imm32 +2020 75/jump-if-!= break/disp8 +2021 # ++index +2022 41/increment-ecx +2023 # curr += 4 +2024 81 0/subop/add %edx 4/imm32 +2025 # +2026 eb/jump loop/disp8 +2027 } +2028 # return index +2029 89/<- %eax 1/r32/ecx +2030 $pos-slice:end: +2031 #? (write-buffered Stderr "=> ") +2032 #? (print-int32-buffered Stderr %eax) +2033 #? (write-buffered Stderr "\n") +2034 # . restore registers +2035 5e/pop-to-esi +2036 5b/pop-to-ebx +2037 5a/pop-to-edx +2038 59/pop-to-ecx +2039 # . epilogue +2040 89/<- %esp 5/r32/ebp +2041 5d/pop-to-ebp +2042 c3/return +2043 +2044 == data +2045 +2046 Type-id: # (stream (address array byte)) +2047 0x18/imm32/write +2048 0/imm32/read +2049 0x100/imm32/length +2050 # data +2051 "literal"/imm32 # 0 +2052 "int"/imm32 # 1 +2053 "addr"/imm32 # 2 +2054 "array"/imm32 # 3 +2055 "handle"/imm32 # 4 +2056 "bool"/imm32 # 5 +2057 0/imm32 +2058 0/imm32 +2059 # 0x20 2060 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 2061 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 2062 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 2063 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 -2064 -2065 == code -2066 -2067 test-parse-var-with-type: -2068 # . prologue -2069 55/push-ebp -2070 89/<- %ebp 4/r32/esp -2071 # (eax..ecx) = "x:" -2072 b8/copy-to-eax "x:"/imm32 -2073 8b/-> *eax 1/r32/ecx -2074 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2075 05/add-to-eax 4/imm32 -2076 # var slice/ecx : slice = {eax, ecx} -2077 51/push-ecx -2078 50/push-eax -2079 89/<- %ecx 4/r32/esp -2080 # _test-input-stream contains "int" -2081 (clear-stream _test-input-stream) -2082 (write _test-input-stream "int") -2083 # -2084 (parse-var-with-type %ecx _test-input-stream) -2085 8b/-> *eax 2/r32/edx # Var-name -2086 (check-strings-equal %edx "x" "F - test-var-with-type/name") -2087 8b/-> *(eax+4) 2/r32/edx # Var-type -2088 (check-ints-equal *edx 1 "F - test-var-with-type/type") -2089 (check-ints-equal *(edx+4) 0 "F - test-var-with-type/type") -2090 # . epilogue -2091 89/<- %esp 5/r32/ebp -2092 5d/pop-to-ebp -2093 c3/return -2094 -2095 test-parse-var-with-type-and-register: -2096 # . prologue -2097 55/push-ebp -2098 89/<- %ebp 4/r32/esp -2099 # (eax..ecx) = "x/eax" -2100 b8/copy-to-eax "x/eax"/imm32 -2101 8b/-> *eax 1/r32/ecx -2102 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2103 05/add-to-eax 4/imm32 -2104 # var slice/ecx : slice = {eax, ecx} -2105 51/push-ecx -2106 50/push-eax -2107 89/<- %ecx 4/r32/esp -2108 # _test-input-stream contains ": int" -2109 (clear-stream _test-input-stream) -2110 (write _test-input-stream ": int") -2111 # -2112 (parse-var-with-type %ecx _test-input-stream) -2113 8b/-> *eax 2/r32/edx # Var-name -2114 (check-strings-equal %edx "x" "F - test-var-with-type-and-register/name") -2115 8b/-> *(eax+0x10) 2/r32/edx # Var-register -2116 (check-strings-equal %edx "eax" "F - test-var-with-type-and-register/register") -2117 8b/-> *(eax+4) 2/r32/edx # Var-type -2118 (check-ints-equal *edx 1 "F - test-var-with-type-and-register/type") -2119 (check-ints-equal *(edx+4) 0 "F - test-var-with-type-and-register/type") -2120 # . epilogue -2121 89/<- %esp 5/r32/ebp -2122 5d/pop-to-ebp -2123 c3/return -2124 -2125 test-parse-var-with-trailing-characters: -2126 # . prologue -2127 55/push-ebp -2128 89/<- %ebp 4/r32/esp -2129 # (eax..ecx) = "x:" -2130 b8/copy-to-eax "x:"/imm32 -2131 8b/-> *eax 1/r32/ecx -2132 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2133 05/add-to-eax 4/imm32 -2134 # var slice/ecx : slice = {eax, ecx} -2135 51/push-ecx -2136 50/push-eax -2137 89/<- %ecx 4/r32/esp -2138 # _test-input-stream contains "int," -2139 (clear-stream _test-input-stream) -2140 (write _test-input-stream "int,") -2141 # -2142 (parse-var-with-type %ecx _test-input-stream) -2143 8b/-> *eax 2/r32/edx # Var-name -2144 (check-strings-equal %edx "x" "F - test-var-with-trailing-characters/name") -2145 8b/-> *(eax+0x10) 2/r32/edx # Var-register -2146 (check-ints-equal %edx 0 "F - test-var-with-trailing-characters/register") -2147 8b/-> *(eax+4) 2/r32/edx # Var-type -2148 (check-ints-equal *edx 1 "F - test-var-with-trailing-characters/type") -2149 (check-ints-equal *(edx+4) 0 "F - test-var-with-trailing-characters/type") -2150 # . epilogue -2151 89/<- %esp 5/r32/ebp -2152 5d/pop-to-ebp -2153 c3/return -2154 -2155 test-parse-var-with-register-and-trailing-characters: -2156 # . prologue -2157 55/push-ebp -2158 89/<- %ebp 4/r32/esp -2159 # (eax..ecx) = "x/eax:" -2160 b8/copy-to-eax "x/eax:"/imm32 -2161 8b/-> *eax 1/r32/ecx -2162 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2163 05/add-to-eax 4/imm32 -2164 # var slice/ecx : slice = {eax, ecx} -2165 51/push-ecx -2166 50/push-eax -2167 89/<- %ecx 4/r32/esp -2168 # _test-input-stream contains "int," -2169 (clear-stream _test-input-stream) -2170 (write _test-input-stream "int,") -2171 # -2172 (parse-var-with-type %ecx _test-input-stream) -2173 8b/-> *eax 2/r32/edx # Var-name -2174 (check-strings-equal %edx "x" "F - test-var-with-register-and-trailing-characters/name") -2175 8b/-> *(eax+0x10) 2/r32/edx # Var-register -2176 (check-strings-equal %edx "eax" "F - test-var-with-register-and-trailing-characters/register") -2177 8b/-> *(eax+4) 2/r32/edx # Var-type -2178 (check-ints-equal *edx 1 "F - test-var-with-register-and-trailing-characters/type") -2179 (check-ints-equal *(edx+4) 0 "F - test-var-with-register-and-trailing-characters/type") -2180 # . epilogue -2181 89/<- %esp 5/r32/ebp -2182 5d/pop-to-ebp -2183 c3/return -2184 -2185 test-parse-var-with-compound-type: -2186 # . prologue -2187 55/push-ebp -2188 89/<- %ebp 4/r32/esp -2189 # (eax..ecx) = "x:" -2190 b8/copy-to-eax "x:"/imm32 -2191 8b/-> *eax 1/r32/ecx -2192 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2193 05/add-to-eax 4/imm32 -2194 # var slice/ecx : slice = {eax, ecx} -2195 51/push-ecx -2196 50/push-eax -2197 89/<- %ecx 4/r32/esp -2198 # _test-input-stream contains "(addr int)" -2199 (clear-stream _test-input-stream) -2200 (write _test-input-stream "(addr int)") -2201 # -2202 (parse-var-with-type %ecx _test-input-stream) -2203 8b/-> *eax 2/r32/edx # Var-name -2204 (check-strings-equal %edx "x" "F - test-var-with-compound-type/name") -2205 8b/-> *(eax+0x10) 2/r32/edx # Var-register -2206 (check-ints-equal %edx 0 "F - test-var-with-compound-type/register") -2207 # var type/edx: (handle tree type-id) = var->type -2208 8b/-> *(eax+4) 2/r32/edx # Var-type -2209 # type->left == atom(addr) -2210 8b/-> *edx 0/r32/eax # Atom-value -2211 (check-ints-equal *eax 2 "F - test-var-with-compound-type/type:0") # Tree-left -2212 # type->right->left == atom(int) -2213 8b/-> *(edx+4) 2/r32/edx # Tree-right -2214 8b/-> *edx 0/r32/eax # Tree-left -2215 (check-ints-equal *eax 1 "F - test-var-with-compound-type/type:1") # Atom-value -2216 # type->right->right == null -2217 (check-ints-equal *(edx+4) 0 "F - test-var-with-compound-type/type:2") # Tree-right -2218 # . epilogue -2219 89/<- %esp 5/r32/ebp -2220 5d/pop-to-ebp -2221 c3/return -2222 -2223 # identifier starts with a letter or '$' or '_' -2224 # no constraints at the moment on later letters -2225 # all we really want to do so far is exclude '{', '}' and '->' -2226 is-identifier?: # in : (addr slice) -> result/eax : boolean -2227 # . prologue -2228 55/push-ebp -2229 89/<- %ebp 4/r32/esp -2230 # if (slice-empty?(in)) return false -2231 (slice-empty? *(ebp+8)) # => eax -2232 3d/compare-eax-and 0/imm32 -2233 75/jump-if-!= $is-identifier?:false/disp8 -2234 # var c/eax : byte = *in->start -2235 8b/-> *(ebp+8) 0/r32/eax -2236 8b/-> *eax 0/r32/eax -2237 8a/copy-byte *eax 0/r32/AL -2238 81 4/subop/and %eax 0xff/imm32 -2239 # if (c == '$') return true -2240 3d/compare-eax-and 0x24/imm32/$ -2241 74/jump-if-= $is-identifier?:true/disp8 -2242 # if (c == '_') return true -2243 3d/compare-eax-and 0x5f/imm32/_ +2064 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +2065 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +2066 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +2067 +2068 == code +2069 +2070 test-parse-var-with-type: +2071 # . prologue +2072 55/push-ebp +2073 89/<- %ebp 4/r32/esp +2074 # (eax..ecx) = "x:" +2075 b8/copy-to-eax "x:"/imm32 +2076 8b/-> *eax 1/r32/ecx +2077 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2078 05/add-to-eax 4/imm32 +2079 # var slice/ecx : slice = {eax, ecx} +2080 51/push-ecx +2081 50/push-eax +2082 89/<- %ecx 4/r32/esp +2083 # _test-input-stream contains "int" +2084 (clear-stream _test-input-stream) +2085 (write _test-input-stream "int") +2086 # +2087 (parse-var-with-type %ecx _test-input-stream) +2088 8b/-> *eax 2/r32/edx # Var-name +2089 (check-strings-equal %edx "x" "F - test-var-with-type/name") +2090 8b/-> *(eax+4) 2/r32/edx # Var-type +2091 (check-ints-equal *edx 1 "F - test-var-with-type/type") +2092 (check-ints-equal *(edx+4) 0 "F - test-var-with-type/type") +2093 # . epilogue +2094 89/<- %esp 5/r32/ebp +2095 5d/pop-to-ebp +2096 c3/return +2097 +2098 test-parse-var-with-type-and-register: +2099 # . prologue +2100 55/push-ebp +2101 89/<- %ebp 4/r32/esp +2102 # (eax..ecx) = "x/eax" +2103 b8/copy-to-eax "x/eax"/imm32 +2104 8b/-> *eax 1/r32/ecx +2105 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2106 05/add-to-eax 4/imm32 +2107 # var slice/ecx : slice = {eax, ecx} +2108 51/push-ecx +2109 50/push-eax +2110 89/<- %ecx 4/r32/esp +2111 # _test-input-stream contains ": int" +2112 (clear-stream _test-input-stream) +2113 (write _test-input-stream ": int") +2114 # +2115 (parse-var-with-type %ecx _test-input-stream) +2116 8b/-> *eax 2/r32/edx # Var-name +2117 (check-strings-equal %edx "x" "F - test-var-with-type-and-register/name") +2118 8b/-> *(eax+0x10) 2/r32/edx # Var-register +2119 (check-strings-equal %edx "eax" "F - test-var-with-type-and-register/register") +2120 8b/-> *(eax+4) 2/r32/edx # Var-type +2121 (check-ints-equal *edx 1 "F - test-var-with-type-and-register/type") +2122 (check-ints-equal *(edx+4) 0 "F - test-var-with-type-and-register/type") +2123 # . epilogue +2124 89/<- %esp 5/r32/ebp +2125 5d/pop-to-ebp +2126 c3/return +2127 +2128 test-parse-var-with-trailing-characters: +2129 # . prologue +2130 55/push-ebp +2131 89/<- %ebp 4/r32/esp +2132 # (eax..ecx) = "x:" +2133 b8/copy-to-eax "x:"/imm32 +2134 8b/-> *eax 1/r32/ecx +2135 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2136 05/add-to-eax 4/imm32 +2137 # var slice/ecx : slice = {eax, ecx} +2138 51/push-ecx +2139 50/push-eax +2140 89/<- %ecx 4/r32/esp +2141 # _test-input-stream contains "int," +2142 (clear-stream _test-input-stream) +2143 (write _test-input-stream "int,") +2144 # +2145 (parse-var-with-type %ecx _test-input-stream) +2146 8b/-> *eax 2/r32/edx # Var-name +2147 (check-strings-equal %edx "x" "F - test-var-with-trailing-characters/name") +2148 8b/-> *(eax+0x10) 2/r32/edx # Var-register +2149 (check-ints-equal %edx 0 "F - test-var-with-trailing-characters/register") +2150 8b/-> *(eax+4) 2/r32/edx # Var-type +2151 (check-ints-equal *edx 1 "F - test-var-with-trailing-characters/type") +2152 (check-ints-equal *(edx+4) 0 "F - test-var-with-trailing-characters/type") +2153 # . epilogue +2154 89/<- %esp 5/r32/ebp +2155 5d/pop-to-ebp +2156 c3/return +2157 +2158 test-parse-var-with-register-and-trailing-characters: +2159 # . prologue +2160 55/push-ebp +2161 89/<- %ebp 4/r32/esp +2162 # (eax..ecx) = "x/eax:" +2163 b8/copy-to-eax "x/eax:"/imm32 +2164 8b/-> *eax 1/r32/ecx +2165 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2166 05/add-to-eax 4/imm32 +2167 # var slice/ecx : slice = {eax, ecx} +2168 51/push-ecx +2169 50/push-eax +2170 89/<- %ecx 4/r32/esp +2171 # _test-input-stream contains "int," +2172 (clear-stream _test-input-stream) +2173 (write _test-input-stream "int,") +2174 # +2175 (parse-var-with-type %ecx _test-input-stream) +2176 8b/-> *eax 2/r32/edx # Var-name +2177 (check-strings-equal %edx "x" "F - test-var-with-register-and-trailing-characters/name") +2178 8b/-> *(eax+0x10) 2/r32/edx # Var-register +2179 (check-strings-equal %edx "eax" "F - test-var-with-register-and-trailing-characters/register") +2180 8b/-> *(eax+4) 2/r32/edx # Var-type +2181 (check-ints-equal *edx 1 "F - test-var-with-register-and-trailing-characters/type") +2182 (check-ints-equal *(edx+4) 0 "F - test-var-with-register-and-trailing-characters/type") +2183 # . epilogue +2184 89/<- %esp 5/r32/ebp +2185 5d/pop-to-ebp +2186 c3/return +2187 +2188 test-parse-var-with-compound-type: +2189 # . prologue +2190 55/push-ebp +2191 89/<- %ebp 4/r32/esp +2192 # (eax..ecx) = "x:" +2193 b8/copy-to-eax "x:"/imm32 +2194 8b/-> *eax 1/r32/ecx +2195 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2196 05/add-to-eax 4/imm32 +2197 # var slice/ecx : slice = {eax, ecx} +2198 51/push-ecx +2199 50/push-eax +2200 89/<- %ecx 4/r32/esp +2201 # _test-input-stream contains "(addr int)" +2202 (clear-stream _test-input-stream) +2203 (write _test-input-stream "(addr int)") +2204 # +2205 (parse-var-with-type %ecx _test-input-stream) +2206 8b/-> *eax 2/r32/edx # Var-name +2207 (check-strings-equal %edx "x" "F - test-var-with-compound-type/name") +2208 8b/-> *(eax+0x10) 2/r32/edx # Var-register +2209 (check-ints-equal %edx 0 "F - test-var-with-compound-type/register") +2210 # var type/edx: (handle tree type-id) = var->type +2211 8b/-> *(eax+4) 2/r32/edx # Var-type +2212 # type->left == atom(addr) +2213 8b/-> *edx 0/r32/eax # Atom-value +2214 (check-ints-equal *eax 2 "F - test-var-with-compound-type/type:0") # Tree-left +2215 # type->right->left == atom(int) +2216 8b/-> *(edx+4) 2/r32/edx # Tree-right +2217 8b/-> *edx 0/r32/eax # Tree-left +2218 (check-ints-equal *eax 1 "F - test-var-with-compound-type/type:1") # Atom-value +2219 # type->right->right == null +2220 (check-ints-equal *(edx+4) 0 "F - test-var-with-compound-type/type:2") # Tree-right +2221 # . epilogue +2222 89/<- %esp 5/r32/ebp +2223 5d/pop-to-ebp +2224 c3/return +2225 +2226 # identifier starts with a letter or '$' or '_' +2227 # no constraints at the moment on later letters +2228 # all we really want to do so far is exclude '{', '}' and '->' +2229 is-identifier?: # in : (addr slice) -> result/eax : boolean +2230 # . prologue +2231 55/push-ebp +2232 89/<- %ebp 4/r32/esp +2233 # if (slice-empty?(in)) return false +2234 (slice-empty? *(ebp+8)) # => eax +2235 3d/compare-eax-and 0/imm32 +2236 75/jump-if-!= $is-identifier?:false/disp8 +2237 # var c/eax : byte = *in->start +2238 8b/-> *(ebp+8) 0/r32/eax +2239 8b/-> *eax 0/r32/eax +2240 8a/copy-byte *eax 0/r32/AL +2241 81 4/subop/and %eax 0xff/imm32 +2242 # if (c == '$') return true +2243 3d/compare-eax-and 0x24/imm32/$ 2244 74/jump-if-= $is-identifier?:true/disp8 -2245 # drop case -2246 25/and-eax-with 0x5f/imm32 -2247 # if (c < 'A') return false -2248 3d/compare-eax-and 0x41/imm32/A -2249 7c/jump-if-< $is-identifier?:false/disp8 -2250 # if (c > 'Z') return false -2251 3d/compare-eax-and 0x5a/imm32/Z -2252 7f/jump-if-> $is-identifier?:false/disp8 -2253 # otherwise return true -2254 $is-identifier?:true: -2255 b8/copy-to-eax 1/imm32/true -2256 eb/jump $is-identifier?:end/disp8 -2257 $is-identifier?:false: -2258 b8/copy-to-eax 0/imm32/false -2259 $is-identifier?:end: -2260 # . epilogue -2261 89/<- %esp 5/r32/ebp -2262 5d/pop-to-ebp -2263 c3/return -2264 -2265 test-is-identifier-dollar: -2266 # . prologue -2267 55/push-ebp -2268 89/<- %ebp 4/r32/esp -2269 # (eax..ecx) = "$a" -2270 b8/copy-to-eax "$a"/imm32 -2271 8b/-> *eax 1/r32/ecx -2272 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2273 05/add-to-eax 4/imm32 -2274 # var slice/ecx : slice = {eax, ecx} -2275 51/push-ecx -2276 50/push-eax -2277 89/<- %ecx 4/r32/esp -2278 # -2279 (is-identifier? %ecx) -2280 (check-ints-equal %eax 1 "F - test-is-identifier-dollar") -2281 # . epilogue -2282 89/<- %esp 5/r32/ebp -2283 5d/pop-to-ebp -2284 c3/return -2285 -2286 test-is-identifier-underscore: -2287 # . prologue -2288 55/push-ebp -2289 89/<- %ebp 4/r32/esp -2290 # (eax..ecx) = "_a" -2291 b8/copy-to-eax "_a"/imm32 -2292 8b/-> *eax 1/r32/ecx -2293 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2294 05/add-to-eax 4/imm32 -2295 # var slice/ecx : slice = {eax, ecx} -2296 51/push-ecx -2297 50/push-eax -2298 89/<- %ecx 4/r32/esp -2299 # -2300 (is-identifier? %ecx) -2301 (check-ints-equal %eax 1 "F - test-is-identifier-underscore") -2302 # . epilogue -2303 89/<- %esp 5/r32/ebp -2304 5d/pop-to-ebp -2305 c3/return -2306 -2307 test-is-identifier-a: -2308 # . prologue -2309 55/push-ebp -2310 89/<- %ebp 4/r32/esp -2311 # (eax..ecx) = "a$" -2312 b8/copy-to-eax "a$"/imm32 -2313 8b/-> *eax 1/r32/ecx -2314 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2315 05/add-to-eax 4/imm32 -2316 # var slice/ecx : slice = {eax, ecx} -2317 51/push-ecx -2318 50/push-eax -2319 89/<- %ecx 4/r32/esp -2320 # -2321 (is-identifier? %ecx) -2322 (check-ints-equal %eax 1 "F - test-is-identifier-a") -2323 # . epilogue -2324 89/<- %esp 5/r32/ebp -2325 5d/pop-to-ebp -2326 c3/return -2327 -2328 test-is-identifier-z: -2329 # . prologue -2330 55/push-ebp -2331 89/<- %ebp 4/r32/esp -2332 # (eax..ecx) = "z$" -2333 b8/copy-to-eax "z$"/imm32 -2334 8b/-> *eax 1/r32/ecx -2335 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2336 05/add-to-eax 4/imm32 -2337 # var slice/ecx : slice = {eax, ecx} -2338 51/push-ecx -2339 50/push-eax -2340 89/<- %ecx 4/r32/esp -2341 # -2342 (is-identifier? %ecx) -2343 (check-ints-equal %eax 1 "F - test-is-identifier-z") -2344 # . epilogue -2345 89/<- %esp 5/r32/ebp -2346 5d/pop-to-ebp -2347 c3/return -2348 -2349 test-is-identifier-A: -2350 # . prologue -2351 55/push-ebp -2352 89/<- %ebp 4/r32/esp -2353 # (eax..ecx) = "A$" -2354 b8/copy-to-eax "A$"/imm32 -2355 8b/-> *eax 1/r32/ecx -2356 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2357 05/add-to-eax 4/imm32 -2358 # var slice/ecx : slice = {eax, ecx} -2359 51/push-ecx -2360 50/push-eax -2361 89/<- %ecx 4/r32/esp -2362 # -2363 (is-identifier? %ecx) -2364 (check-ints-equal %eax 1 "F - test-is-identifier-A") -2365 # . epilogue -2366 89/<- %esp 5/r32/ebp -2367 5d/pop-to-ebp -2368 c3/return -2369 -2370 test-is-identifier-Z: -2371 # . prologue -2372 55/push-ebp -2373 89/<- %ebp 4/r32/esp -2374 # (eax..ecx) = "Z$" -2375 b8/copy-to-eax "Z$"/imm32 -2376 8b/-> *eax 1/r32/ecx -2377 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2378 05/add-to-eax 4/imm32 -2379 # var slice/ecx : slice = {eax, ecx} -2380 51/push-ecx -2381 50/push-eax -2382 89/<- %ecx 4/r32/esp -2383 # -2384 (is-identifier? %ecx) -2385 (check-ints-equal %eax 1 "F - test-is-identifier-Z") -2386 # . epilogue -2387 89/<- %esp 5/r32/ebp -2388 5d/pop-to-ebp -2389 c3/return -2390 -2391 test-is-identifier-@: -2392 # character before 'A' is invalid -2393 # . prologue -2394 55/push-ebp -2395 89/<- %ebp 4/r32/esp -2396 # (eax..ecx) = "@a" -2397 b8/copy-to-eax "@a"/imm32 -2398 8b/-> *eax 1/r32/ecx -2399 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2400 05/add-to-eax 4/imm32 -2401 # var slice/ecx : slice = {eax, ecx} -2402 51/push-ecx -2403 50/push-eax -2404 89/<- %ecx 4/r32/esp -2405 # -2406 (is-identifier? %ecx) -2407 (check-ints-equal %eax 0 "F - test-is-identifier-@") -2408 # . epilogue -2409 89/<- %esp 5/r32/ebp -2410 5d/pop-to-ebp -2411 c3/return -2412 -2413 test-is-identifier-square-bracket: -2414 # character after 'Z' is invalid -2415 # . prologue -2416 55/push-ebp -2417 89/<- %ebp 4/r32/esp -2418 # (eax..ecx) = "[a" -2419 b8/copy-to-eax "[a"/imm32 -2420 8b/-> *eax 1/r32/ecx -2421 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2422 05/add-to-eax 4/imm32 -2423 # var slice/ecx : slice = {eax, ecx} -2424 51/push-ecx -2425 50/push-eax -2426 89/<- %ecx 4/r32/esp -2427 # -2428 (is-identifier? %ecx) -2429 (check-ints-equal %eax 0 "F - test-is-identifier-@") -2430 # . epilogue -2431 89/<- %esp 5/r32/ebp -2432 5d/pop-to-ebp -2433 c3/return -2434 -2435 test-is-identifier-backtick: -2436 # character before 'a' is invalid -2437 # . prologue -2438 55/push-ebp -2439 89/<- %ebp 4/r32/esp -2440 # (eax..ecx) = "`a" -2441 b8/copy-to-eax "`a"/imm32 -2442 8b/-> *eax 1/r32/ecx -2443 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2444 05/add-to-eax 4/imm32 -2445 # var slice/ecx : slice = {eax, ecx} -2446 51/push-ecx -2447 50/push-eax -2448 89/<- %ecx 4/r32/esp -2449 # -2450 (is-identifier? %ecx) -2451 (check-ints-equal %eax 0 "F - test-is-identifier-backtick") -2452 # . epilogue -2453 89/<- %esp 5/r32/ebp -2454 5d/pop-to-ebp -2455 c3/return -2456 -2457 test-is-identifier-curly-brace-open: -2458 # character after 'z' is invalid; also used for blocks -2459 # . prologue -2460 55/push-ebp -2461 89/<- %ebp 4/r32/esp -2462 # (eax..ecx) = "{a" -2463 b8/copy-to-eax "{a"/imm32 -2464 8b/-> *eax 1/r32/ecx -2465 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2466 05/add-to-eax 4/imm32 -2467 # var slice/ecx : slice = {eax, ecx} -2468 51/push-ecx -2469 50/push-eax -2470 89/<- %ecx 4/r32/esp -2471 # -2472 (is-identifier? %ecx) -2473 (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-open") -2474 # . epilogue -2475 89/<- %esp 5/r32/ebp -2476 5d/pop-to-ebp -2477 c3/return -2478 -2479 test-is-identifier-curly-brace-close: -2480 # . prologue -2481 55/push-ebp -2482 89/<- %ebp 4/r32/esp -2483 # (eax..ecx) = "}a" -2484 b8/copy-to-eax "}a"/imm32 -2485 8b/-> *eax 1/r32/ecx -2486 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2487 05/add-to-eax 4/imm32 -2488 # var slice/ecx : slice = {eax, ecx} -2489 51/push-ecx -2490 50/push-eax -2491 89/<- %ecx 4/r32/esp -2492 # -2493 (is-identifier? %ecx) -2494 (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-close") -2495 # . epilogue -2496 89/<- %esp 5/r32/ebp -2497 5d/pop-to-ebp -2498 c3/return -2499 -2500 test-is-identifier-hyphen: -2501 # disallow leading '-' since '->' has special meaning -2502 # . prologue -2503 55/push-ebp -2504 89/<- %ebp 4/r32/esp -2505 # (eax..ecx) = "-a" -2506 b8/copy-to-eax "-a"/imm32 -2507 8b/-> *eax 1/r32/ecx -2508 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2509 05/add-to-eax 4/imm32 -2510 # var slice/ecx : slice = {eax, ecx} -2511 51/push-ecx -2512 50/push-eax -2513 89/<- %ecx 4/r32/esp -2514 # -2515 (is-identifier? %ecx) -2516 (check-ints-equal %eax 0 "F - test-is-identifier-hyphen") -2517 # . epilogue -2518 89/<- %esp 5/r32/ebp -2519 5d/pop-to-ebp -2520 c3/return -2521 -2522 populate-mu-function-body: # in : (addr buffered-file), out : (handle function), vars : (addr stack (handle var)) -2523 # . prologue -2524 55/push-ebp -2525 89/<- %ebp 4/r32/esp -2526 # . save registers -2527 50/push-eax -2528 56/push-esi -2529 57/push-edi -2530 # esi = in -2531 8b/-> *(ebp+8) 6/r32/esi -2532 # edi = out -2533 8b/-> *(ebp+0xc) 7/r32/edi -2534 # var eax : (handle block) = parse-mu-block(in, vars) -2535 (parse-mu-block %esi *(ebp+0x10) %edi) # => eax -2536 # out->body = eax -2537 89/<- *(edi+0x10) 0/r32/eax # Function-body -2538 $populate-mu-function-body:end: -2539 # . restore registers -2540 5f/pop-to-edi -2541 5e/pop-to-esi -2542 58/pop-to-eax -2543 # . epilogue -2544 89/<- %esp 5/r32/ebp -2545 5d/pop-to-ebp -2546 c3/return -2547 -2548 # parses a block, assuming that the leading '{' has already been read by the caller -2549 parse-mu-block: # in : (addr buffered-file), vars : (addr stack (handle var)), fn : (handle function) -> result/eax : (handle block) -2550 # pseudocode: -2551 # var line : (stream byte 512) -2552 # var word-slice : slice -2553 # result/eax = allocate(Heap, Stmt-size) -2554 # result->tag = 0/Block -2555 # while true # line loop -2556 # clear-stream(line) -2557 # read-line-buffered(in, line) -2558 # if (line->write == 0) break # end of file -2559 # word-slice = next-word(line) -2560 # if slice-empty?(word-slice) # end of line -2561 # continue -2562 # else if slice-starts-with?(word-slice, "#") -2563 # continue -2564 # else if slice-equal?(word-slice, "{") -2565 # assert(no-tokens-in(line)) -2566 # block = parse-mu-block(in, vars, fn) -2567 # append-to-block(result, block) -2568 # else if slice-equal?(word-slice, "}") -2569 # break -2570 # else if slice-ends-with?(word-slice, ":") -2571 # named-block = parse-mu-named-block(word-slice, line, in, vars, fn) -2572 # append-to-block(result, named-block) -2573 # else if slice-equal?(word-slice, "var") -2574 # var-def = parse-mu-var-def(line, vars) -2575 # append-to-block(result, var-def) -2576 # else -2577 # stmt = parse-mu-stmt(line, vars, fn) -2578 # append-to-block(result, stmt) -2579 # return result -2580 # -2581 # . prologue -2582 55/push-ebp -2583 89/<- %ebp 4/r32/esp -2584 # . save registers -2585 51/push-ecx -2586 52/push-edx -2587 53/push-ebx -2588 57/push-edi -2589 # var line/ecx : (stream byte 512) -2590 81 5/subop/subtract %esp 0x200/imm32 -2591 68/push 0x200/imm32/length -2592 68/push 0/imm32/read -2593 68/push 0/imm32/write -2594 89/<- %ecx 4/r32/esp -2595 # var word-slice/edx : slice -2596 68/push 0/imm32/end -2597 68/push 0/imm32/start -2598 89/<- %edx 4/r32/esp -2599 # edi = result -2600 (allocate Heap *Stmt-size) # => eax -2601 (zero-out %eax *Stmt-size) -2602 89/<- %edi 0/r32/eax -2603 { # line loop -2604 $parse-mu-block:line-loop: -2605 # line = read-line-buffered(in) -2606 (clear-stream %ecx) -2607 (read-line-buffered *(ebp+8) %ecx) -2608 #? (write-buffered Stderr "line: ") -2609 #? (write-stream-data Stderr %ecx) -2610 #? (write-buffered Stderr Newline) -2611 #? (flush Stderr) -2612 # if (line->write == 0) break -2613 81 7/subop/compare *ecx 0/imm32 -2614 0f 84/jump-if-= break/disp32 -2615 # word-slice = next-word(line) -2616 (next-word %ecx %edx) -2617 #? (write-buffered Stderr "word: ") -2618 #? (write-slice-buffered Stderr %edx) -2619 #? (write-buffered Stderr Newline) -2620 #? (flush Stderr) -2621 # if slice-empty?(word-slice) continue -2622 (slice-empty? %edx) -2623 3d/compare-eax-and 0/imm32 -2624 0f 85/jump-if-!= loop/disp32 -2625 # if (slice-starts-with?(word-slice, '#') continue -2626 # . eax = *word-slice->start -2627 8b/-> *edx 0/r32/eax -2628 8a/copy-byte *eax 0/r32/AL -2629 81 4/subop/and %eax 0xff/imm32 -2630 # . if (eax == '#') continue -2631 3d/compare-eax-and 0x23/imm32/hash -2632 0f 84/jump-if-= loop/disp32 -2633 # if slice-equal?(word-slice, "{") -2634 { -2635 $parse-mu-block:check-for-block: -2636 (slice-equal? %edx "{") -2637 3d/compare-eax-and 0/imm32 -2638 74/jump-if-= break/disp8 -2639 (check-no-tokens-left %ecx) -2640 # parse new block and append -2641 (parse-mu-block *(ebp+8) *(ebp+0xc) *(ebp+0x10)) # => eax -2642 (append-to-block Heap %edi %eax) -2643 e9/jump $parse-mu-block:line-loop/disp32 -2644 } -2645 # if slice-equal?(word-slice, "}") break -2646 $parse-mu-block:check-for-end: -2647 (slice-equal? %edx "}") -2648 3d/compare-eax-and 0/imm32 -2649 0f 85/jump-if-!= break/disp32 -2650 # if slice-ends-with?(word-slice, ":") parse named block and append -2651 { -2652 $parse-mu-block:check-for-named-block: -2653 # . eax = *word-slice->end -2654 8b/-> *(edx+4) 0/r32/eax -2655 8a/copy-byte *eax 0/r32/AL -2656 81 4/subop/and %eax 0xff/imm32 -2657 # . if (eax != ':') break -2658 3d/compare-eax-and 0x23/imm32/hash -2659 0f 85/jump-if-!= break/disp32 -2660 # -2661 (parse-mu-named-block %edx %ecx *(ebp+8) *(ebp+0xc) *(ebp+0x10)) # => eax -2662 (append-to-block Heap %edi %eax) -2663 e9/jump $parse-mu-block:line-loop/disp32 -2664 } -2665 # if slice-equal?(word-slice, "var") -2666 { -2667 $parse-mu-block:check-for-var: -2668 (slice-equal? %edx "var") -2669 3d/compare-eax-and 0/imm32 -2670 74/jump-if-= break/disp8 -2671 # -2672 (parse-mu-var-def %ecx *(ebp+0xc)) # => eax -2673 (append-to-block Heap %edi %eax) -2674 e9/jump $parse-mu-block:line-loop/disp32 -2675 } -2676 $parse-mu-block:regular-stmt: -2677 # otherwise -2678 (parse-mu-stmt %ecx *(ebp+0xc) *(ebp+0x10)) # => eax -2679 (append-to-block Heap %edi %eax) -2680 e9/jump loop/disp32 -2681 } # end line loop -2682 # return result -2683 89/<- %eax 7/r32/edi -2684 $parse-mu-block:end: -2685 # . reclaim locals -2686 81 0/subop/add %esp 0x214/imm32 -2687 # . restore registers -2688 5f/pop-to-edi -2689 5b/pop-to-ebx -2690 5a/pop-to-edx -2691 59/pop-to-ecx -2692 # . epilogue -2693 89/<- %esp 5/r32/ebp -2694 5d/pop-to-ebp -2695 c3/return -2696 -2697 $parse-mu-block:abort: -2698 # error("'{' or '}' should be on its own line, but got '") -2699 (write-buffered Stderr "'{' or '}' should be on its own line, but got '") -2700 (rewind-stream %ecx) -2701 (write-stream 2 %ecx) -2702 (write-buffered Stderr "'\n") -2703 (flush Stderr) -2704 # . syscall(exit, 1) -2705 bb/copy-to-ebx 1/imm32 -2706 b8/copy-to-eax 1/imm32/exit -2707 cd/syscall 0x80/imm8 -2708 # never gets here -2709 -2710 check-no-tokens-left: # line : (addr stream byte) -2711 # . prologue -2712 55/push-ebp -2713 89/<- %ebp 4/r32/esp -2714 # . save registers -2715 50/push-eax -2716 51/push-ecx -2717 # var s/ecx : slice -2718 68/push 0/imm32/end -2719 68/push 0/imm32/start -2720 89/<- %ecx 4/r32/esp -2721 # -2722 (next-word *(ebp+8) %ecx) -2723 # if slice-empty?(s) return -2724 (slice-empty? %ecx) -2725 3d/compare-eax-and 0/imm32 -2726 75/jump-if-!= $check-no-tokens-left:end/disp8 -2727 # if (slice-starts-with?(s, '#') return -2728 # . eax = *s->start -2729 8b/-> *edx 0/r32/eax -2730 8a/copy-byte *eax 0/r32/AL -2731 81 4/subop/and %eax 0xff/imm32 -2732 # . if (eax == '#') continue -2733 3d/compare-eax-and 0x23/imm32/hash -2734 74/jump-if-= $check-no-tokens-left:end/disp8 -2735 # abort -2736 (write-buffered Stderr "'{' or '}' should be on its own line, but got '") -2737 (rewind-stream %ecx) -2738 (write-stream 2 %ecx) -2739 (write-buffered Stderr "'\n") -2740 (flush Stderr) -2741 # . syscall(exit, 1) -2742 bb/copy-to-ebx 1/imm32 -2743 b8/copy-to-eax 1/imm32/exit -2744 cd/syscall 0x80/imm8 -2745 # never gets here -2746 $check-no-tokens-left:end: -2747 # . reclaim locals -2748 81 0/subop/add %esp 8/imm32 -2749 # . restore registers -2750 59/pop-to-ecx -2751 58/pop-to-eax -2752 # . epilogue -2753 89/<- %esp 5/r32/ebp -2754 5d/pop-to-ebp -2755 c3/return -2756 -2757 parse-mu-named-block: # name : (addr slice), first-line : (addr stream byte), in : (addr buffered-file), vars : (addr stack (handle var)) -> result/eax : (handle stmt) -2758 # pseudocode: -2759 # var line : (stream byte 512) -2760 # var word-slice : slice -2761 # result/eax = allocate(Heap, Stmt-size) -2762 # result->tag = 4/Named-block -2763 # result->name = name -2764 # assert(next-word(first-line) == "{") -2765 # assert(no-tokens-in(first-line)) -2766 # while true # line loop -2767 # clear-stream(line) -2768 # read-line-buffered(in, line) -2769 # if (line->write == 0) break # end of file -2770 # word-slice = next-word(line) -2771 # if slice-empty?(word-slice) # end of line -2772 # break -2773 # else if slice-equal?(word-slice, "{") -2774 # block = parse-mu-block(in, vars) -2775 # append-to-block(result, block) -2776 # else if slice-equal?(word-slice, "}") -2777 # break -2778 # else if slice-ends-with?(word-slice, ":") -2779 # named-block = parse-mu-named-block(word-slice, in, vars) -2780 # append-to-block(result, named-block) -2781 # else if slice-equal?(word-slice, "var") -2782 # var-def = parse-mu-var-def(line, vars) -2783 # append-to-block(result, var-def) -2784 # else -2785 # stmt = parse-mu-stmt(line, vars, fn) -2786 # append-to-block(result, stmt) -2787 # return result -2788 # -2789 # . prologue -2790 55/push-ebp -2791 89/<- %ebp 4/r32/esp -2792 # . save registers -2793 $parse-mu-named-block:end: -2794 # . reclaim locals -2795 # . restore registers -2796 # . epilogue -2797 89/<- %esp 5/r32/ebp -2798 5d/pop-to-ebp -2799 c3/return -2800 -2801 parse-mu-var-def: # line : (addr stream byte), vars : (addr stack (handle var)) -> result/eax : (handle stmt) -2802 # pseudocode: -2803 # -2804 # . prologue -2805 55/push-ebp -2806 89/<- %ebp 4/r32/esp -2807 # . save registers -2808 $parse-mu-var-def:end: -2809 # . reclaim locals -2810 # . restore registers -2811 # . epilogue -2812 89/<- %esp 5/r32/ebp -2813 5d/pop-to-ebp -2814 c3/return -2815 -2816 parse-mu-stmt: # line : (addr stream byte), vars : (addr stack (handle var)), fn : (handle function) -> result/eax : (handle stmt) -2817 # pseudocode: -2818 # var name : slice -2819 # result = allocate(Heap, Stmt-size) -2820 # if stmt-has-outputs?(line) -2821 # while true -2822 # name = next-word(line) -2823 # if (name == '<-') break -2824 # assert(is-identifier?(name)) -2825 # var v : (handle var) = lookup-or-define-var(name, vars) -2826 # result->outputs = append(result->outputs, v) -2827 # result->name = slice-to-string(next-word(line)) -2828 # while true -2829 # name = next-word-or-string(line) -2830 # v = lookup-var-or-literal(name) -2831 # result->inouts = append(result->inouts, v) -2832 # -2833 # . prologue -2834 55/push-ebp -2835 89/<- %ebp 4/r32/esp -2836 # . save registers -2837 51/push-ecx -2838 57/push-edi -2839 # var name/ecx : slice -2840 68/push 0/imm32/end -2841 68/push 0/imm32/start -2842 89/<- %ecx 4/r32/esp -2843 # result/edi : (handle stmt) -2844 (allocate Heap *Stmt-size) # => eax -2845 (zero-out %eax *Stmt-size) -2846 89/<- %edi 0/r32/eax -2847 # result->tag = 1/stmt -2848 c7 0/subop/copy *edi 1/imm32/stmt1 # Stmt-tag -2849 { -2850 (stmt-has-outputs? *(ebp+8)) -2851 3d/compare-eax-and 0/imm32 -2852 0f 84/jump-if-= break/disp32 -2853 { -2854 $parse-mu-stmt:read-outputs: -2855 # name = next-word(line) -2856 (next-word *(ebp+8) %ecx) -2857 # if slice-empty?(word-slice) break -2858 (slice-empty? %ecx) -2859 3d/compare-eax-and 0/imm32 -2860 0f 85/jump-if-!= break/disp32 -2861 # if (name == "<-") break -2862 (slice-equal? %ecx "<-") -2863 3d/compare-eax-and 0/imm32 -2864 75/jump-if-!= break/disp8 -2865 # assert(is-identifier?(name)) -2866 (is-identifier? %ecx) -2867 3d/compare-eax-and 0/imm32 -2868 0f 84/jump-if-= $parse-mu-stmt:abort/disp32 -2869 # -2870 (lookup-or-define-var %ecx *(ebp+0xc) *(ebp+0x10)) # => eax -2871 (append-list Heap %eax *(edi+0xc)) # Stmt1-outputs => eax -2872 89/<- *(edi+0xc) 0/r32/eax # Stmt1-outputs -2873 e9/jump loop/disp32 -2874 } -2875 } -2876 $parse-mu-stmt:read-operation: -2877 (next-word *(ebp+8) %ecx) -2878 (slice-to-string Heap %ecx) -2879 89/<- *(edi+4) 0/r32/eax # Stmt1-operation -2880 { -2881 $parse-mu-stmt:read-inouts: -2882 # name = next-word-or-string(line) -2883 (next-word-or-string *(ebp+8) %ecx) -2884 # if slice-empty?(word-slice) break -2885 (slice-empty? %ecx) -2886 3d/compare-eax-and 0/imm32 -2887 0f 85/jump-if-!= break/disp32 -2888 # if (name == "<-") abort -2889 (slice-equal? %ecx "<-") -2890 3d/compare-eax-and 0/imm32 -2891 0f 85/jump-if-!= $parse-mu-stmt:abort2/disp32 -2892 # -2893 (lookup-var-or-literal %ecx *(ebp+0xc)) # => eax -2894 (append-list Heap %eax *(edi+8)) # Stmt1-inouts => eax -2895 89/<- *(edi+8) 0/r32/eax # Stmt1-inouts -2896 e9/jump loop/disp32 -2897 } -2898 $parse-mu-stmt:end: -2899 # return result -2900 89/<- %eax 7/r32/edi -2901 # . reclaim locals -2902 81 0/subop/add %esp 8/imm32 -2903 # . restore registers -2904 5f/pop-to-edi -2905 59/pop-to-ecx -2906 # . epilogue -2907 89/<- %esp 5/r32/ebp -2908 5d/pop-to-ebp -2909 c3/return -2910 -2911 $parse-mu-stmt:abort: -2912 # error("invalid identifier '" name "'\n") -2913 (write-buffered Stderr "invalid identifier '") -2914 (write-slice-buffered Stderr %ecx) -2915 (write-buffered Stderr "'\n") -2916 (flush Stderr) -2917 # . syscall(exit, 1) -2918 bb/copy-to-ebx 1/imm32 -2919 b8/copy-to-eax 1/imm32/exit -2920 cd/syscall 0x80/imm8 -2921 # never gets here -2922 -2923 $parse-mu-stmt:abort2: -2924 # error("invalid statement '" line "'\n") -2925 (rewind-stream *(ebp+8)) -2926 (write-buffered Stderr "invalid identifier '") -2927 (write-stream Stderr *(ebp+8)) -2928 (write-buffered Stderr "'\n") -2929 (flush Stderr) -2930 # . syscall(exit, 1) -2931 bb/copy-to-ebx 1/imm32 -2932 b8/copy-to-eax 1/imm32/exit -2933 cd/syscall 0x80/imm8 -2934 # never gets here -2935 -2936 stmt-has-outputs?: # line : (addr stream byte) -> result/eax : boolean -2937 # . prologue -2938 55/push-ebp -2939 89/<- %ebp 4/r32/esp -2940 # . save registers -2941 51/push-ecx -2942 # var word-slice/ecx : slice -2943 68/push 0/imm32/end -2944 68/push 0/imm32/start -2945 89/<- %ecx 4/r32/esp -2946 # result = false -2947 b8/copy-to-eax 0/imm32/false -2948 (rewind-stream *(ebp+8)) -2949 { -2950 (next-word-or-string *(ebp+8) %ecx) -2951 # if slice-empty?(word-slice) break -2952 (slice-empty? %ecx) -2953 3d/compare-eax-and 0/imm32 -2954 b8/copy-to-eax 0/imm32/false/result # restore result (if we're here it's still false) -2955 0f 85/jump-if-!= break/disp32 -2956 # if slice-starts-with?(word-slice, '#') break -2957 # . eax = *word-slice->start -2958 8b/-> *ecx 0/r32/eax -2959 8a/copy-byte *eax 0/r32/AL -2960 81 4/subop/and %eax 0xff/imm32 -2961 # . if (eax == '#') break -2962 3d/compare-eax-and 0x23/imm32/hash -2963 b8/copy-to-eax 0/imm32/false/result # restore result (if we're here it's still false) -2964 0f 84/jump-if-= break/disp32 -2965 # if slice-equal?(word-slice, '<-') return true -2966 (slice-equal? %ecx "<-") -2967 3d/compare-eax-and 0/imm32 -2968 74/jump-if-= loop/disp8 -2969 b8/copy-to-eax 1/imm32/true -2970 } -2971 $stmt-has-outputs:end: -2972 (rewind-stream *(ebp+8)) -2973 # . reclaim locals -2974 81 0/subop/add %esp 8/imm32 -2975 # . restore registers -2976 59/pop-to-ecx -2977 # . epilogue -2978 89/<- %esp 5/r32/ebp -2979 5d/pop-to-ebp -2980 c3/return -2981 -2982 # if 'name' starts with a digit, create a new literal var for it -2983 # otherwise return first 'name' from the top (back) of 'vars' and abort if not found -2984 lookup-var-or-literal: # name: (addr slice), vars : (addr stack (handle var)) -> result/eax: (handle var) -2985 # . prologue -2986 55/push-ebp -2987 89/<- %ebp 4/r32/esp -2988 # . save registers -2989 51/push-ecx -2990 56/push-esi -2991 # esi = name -2992 8b/-> *(ebp+8) 6/r32/esi -2993 # if slice-empty?(name) abort -2994 (slice-empty? %esi) # => eax -2995 3d/compare-eax-and 0/imm32 -2996 0f 85/jump-if-!= $lookup-var-or-literal:abort/disp32 -2997 # var ecx : byte = *name->start -2998 8b/-> *esi 1/r32/ecx -2999 8a/copy-byte *ecx 1/r32/CL -3000 81 4/subop/and %ecx 0xff/imm32 -3001 # if is-decimal-digit?(*name->start) return new var(name) -3002 (is-decimal-digit? %ecx) # => eax -3003 81 7/subop/compare %eax 0/imm32 -3004 { -3005 74/jump-if-= break/disp8 -3006 (new-literal-integer Heap %esi) # => eax -3007 } -3008 # otherwise return lookup-var(name, vars) -3009 { -3010 75/jump-if-!= break/disp8 -3011 (lookup-var %esi *(ebp+0xc)) # => eax -3012 } -3013 $lookup-var-or-literal:end: -3014 # . restore registers -3015 5e/pop-to-esi -3016 59/pop-to-ecx -3017 # . epilogue -3018 89/<- %esp 5/r32/ebp -3019 5d/pop-to-ebp -3020 c3/return -3021 -3022 $lookup-var-or-literal:abort: -3023 (write-buffered Stderr "empty variable!") -3024 (flush Stderr) -3025 # . syscall(exit, 1) -3026 bb/copy-to-ebx 1/imm32 -3027 b8/copy-to-eax 1/imm32/exit -3028 cd/syscall 0x80/imm8 -3029 # never gets here -3030 -3031 # return first 'name' from the top (back) of 'vars' and abort if not found -3032 lookup-var: # name: (addr slice), vars : (addr stack (handle var)) -> result/eax: (handle var) -3033 # . prologue -3034 55/push-ebp -3035 89/<- %ebp 4/r32/esp -3036 # var target/eax : (handle array byte) = slice-to-string(name) -3037 (slice-to-string Heap *(ebp+8)) # => eax -3038 # -3039 (lookup-var-helper %eax *(ebp+0xc)) # => eax -3040 # if (result == 0) abort -3041 3d/compare-eax-and 0/imm32 -3042 74/jump-if-= $lookup-var:abort/disp8 -3043 $lookup-var:end: -3044 # . epilogue -3045 89/<- %esp 5/r32/ebp -3046 5d/pop-to-ebp -3047 c3/return -3048 -3049 $lookup-var:abort: -3050 (write-buffered Stderr "unknown variable '") -3051 (write-slice-buffered Stderr *(ebp+8)) -3052 (write-buffered Stderr "'\n") -3053 (flush Stderr) -3054 # . syscall(exit, 1) -3055 bb/copy-to-ebx 1/imm32 -3056 b8/copy-to-eax 1/imm32/exit -3057 cd/syscall 0x80/imm8 -3058 # never gets here -3059 -3060 # return first 'name' from the top (back) of 'vars', and 0/null if not found -3061 lookup-var-helper: # name: (addr array byte), vars : (addr stack (handle var)) -> result/eax: (handle var) -3062 # pseudocode: -3063 # var curr : (addr handle var) = &vars->data[vars->top - 4] -3064 # var min = vars->data -3065 # while curr >= min -3066 # var v : (handle var) = *curr -3067 # if v->name == name -3068 # return v -3069 # return 0 -3070 # -3071 # . prologue -3072 55/push-ebp -3073 89/<- %ebp 4/r32/esp -3074 # . save registers -3075 52/push-edx -3076 53/push-ebx -3077 56/push-esi -3078 # esi = vars -3079 8b/-> *(ebp+0xc) 6/r32/esi -3080 # ebx = vars->top -3081 8b/-> *esi 3/r32/ebx -3082 # if (vars->top > vars->length) abort -3083 3b/compare 0/r32/eax *(esi+4) -3084 0f 8f/jump-if-> $lookup-var-helper:error1/disp32 -3085 # var min/edx : (addr handle var) = vars->data -3086 8d/copy-address *(esi+8) 2/r32/edx -3087 # var curr/ebx : (addr handle var) = &vars->data[vars->top - 4] -3088 81 5/subop/subtract %ebx 4/imm32 -3089 8d/copy-address *(esi+ebx+8) 3/r32/ebx -3090 { -3091 # if (curr < min) return 0 -3092 39/compare %ebx 2/r32/edx -3093 b8/copy-to-eax 0/imm32 -3094 0f 82/jump-if-addr< break/disp32 -3095 # var v/eax : (handle var) = *curr -3096 8b/-> *ebx 0/r32/eax -3097 # if (v->name == name) return v -3098 (string-equal? *eax *(ebp+8)) # Var-name +2245 # if (c == '_') return true +2246 3d/compare-eax-and 0x5f/imm32/_ +2247 74/jump-if-= $is-identifier?:true/disp8 +2248 # drop case +2249 25/and-eax-with 0x5f/imm32 +2250 # if (c < 'A') return false +2251 3d/compare-eax-and 0x41/imm32/A +2252 7c/jump-if-< $is-identifier?:false/disp8 +2253 # if (c > 'Z') return false +2254 3d/compare-eax-and 0x5a/imm32/Z +2255 7f/jump-if-> $is-identifier?:false/disp8 +2256 # otherwise return true +2257 $is-identifier?:true: +2258 b8/copy-to-eax 1/imm32/true +2259 eb/jump $is-identifier?:end/disp8 +2260 $is-identifier?:false: +2261 b8/copy-to-eax 0/imm32/false +2262 $is-identifier?:end: +2263 # . epilogue +2264 89/<- %esp 5/r32/ebp +2265 5d/pop-to-ebp +2266 c3/return +2267 +2268 test-is-identifier-dollar: +2269 # . prologue +2270 55/push-ebp +2271 89/<- %ebp 4/r32/esp +2272 # (eax..ecx) = "$a" +2273 b8/copy-to-eax "$a"/imm32 +2274 8b/-> *eax 1/r32/ecx +2275 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2276 05/add-to-eax 4/imm32 +2277 # var slice/ecx : slice = {eax, ecx} +2278 51/push-ecx +2279 50/push-eax +2280 89/<- %ecx 4/r32/esp +2281 # +2282 (is-identifier? %ecx) +2283 (check-ints-equal %eax 1 "F - test-is-identifier-dollar") +2284 # . epilogue +2285 89/<- %esp 5/r32/ebp +2286 5d/pop-to-ebp +2287 c3/return +2288 +2289 test-is-identifier-underscore: +2290 # . prologue +2291 55/push-ebp +2292 89/<- %ebp 4/r32/esp +2293 # (eax..ecx) = "_a" +2294 b8/copy-to-eax "_a"/imm32 +2295 8b/-> *eax 1/r32/ecx +2296 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2297 05/add-to-eax 4/imm32 +2298 # var slice/ecx : slice = {eax, ecx} +2299 51/push-ecx +2300 50/push-eax +2301 89/<- %ecx 4/r32/esp +2302 # +2303 (is-identifier? %ecx) +2304 (check-ints-equal %eax 1 "F - test-is-identifier-underscore") +2305 # . epilogue +2306 89/<- %esp 5/r32/ebp +2307 5d/pop-to-ebp +2308 c3/return +2309 +2310 test-is-identifier-a: +2311 # . prologue +2312 55/push-ebp +2313 89/<- %ebp 4/r32/esp +2314 # (eax..ecx) = "a$" +2315 b8/copy-to-eax "a$"/imm32 +2316 8b/-> *eax 1/r32/ecx +2317 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2318 05/add-to-eax 4/imm32 +2319 # var slice/ecx : slice = {eax, ecx} +2320 51/push-ecx +2321 50/push-eax +2322 89/<- %ecx 4/r32/esp +2323 # +2324 (is-identifier? %ecx) +2325 (check-ints-equal %eax 1 "F - test-is-identifier-a") +2326 # . epilogue +2327 89/<- %esp 5/r32/ebp +2328 5d/pop-to-ebp +2329 c3/return +2330 +2331 test-is-identifier-z: +2332 # . prologue +2333 55/push-ebp +2334 89/<- %ebp 4/r32/esp +2335 # (eax..ecx) = "z$" +2336 b8/copy-to-eax "z$"/imm32 +2337 8b/-> *eax 1/r32/ecx +2338 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2339 05/add-to-eax 4/imm32 +2340 # var slice/ecx : slice = {eax, ecx} +2341 51/push-ecx +2342 50/push-eax +2343 89/<- %ecx 4/r32/esp +2344 # +2345 (is-identifier? %ecx) +2346 (check-ints-equal %eax 1 "F - test-is-identifier-z") +2347 # . epilogue +2348 89/<- %esp 5/r32/ebp +2349 5d/pop-to-ebp +2350 c3/return +2351 +2352 test-is-identifier-A: +2353 # . prologue +2354 55/push-ebp +2355 89/<- %ebp 4/r32/esp +2356 # (eax..ecx) = "A$" +2357 b8/copy-to-eax "A$"/imm32 +2358 8b/-> *eax 1/r32/ecx +2359 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2360 05/add-to-eax 4/imm32 +2361 # var slice/ecx : slice = {eax, ecx} +2362 51/push-ecx +2363 50/push-eax +2364 89/<- %ecx 4/r32/esp +2365 # +2366 (is-identifier? %ecx) +2367 (check-ints-equal %eax 1 "F - test-is-identifier-A") +2368 # . epilogue +2369 89/<- %esp 5/r32/ebp +2370 5d/pop-to-ebp +2371 c3/return +2372 +2373 test-is-identifier-Z: +2374 # . prologue +2375 55/push-ebp +2376 89/<- %ebp 4/r32/esp +2377 # (eax..ecx) = "Z$" +2378 b8/copy-to-eax "Z$"/imm32 +2379 8b/-> *eax 1/r32/ecx +2380 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2381 05/add-to-eax 4/imm32 +2382 # var slice/ecx : slice = {eax, ecx} +2383 51/push-ecx +2384 50/push-eax +2385 89/<- %ecx 4/r32/esp +2386 # +2387 (is-identifier? %ecx) +2388 (check-ints-equal %eax 1 "F - test-is-identifier-Z") +2389 # . epilogue +2390 89/<- %esp 5/r32/ebp +2391 5d/pop-to-ebp +2392 c3/return +2393 +2394 test-is-identifier-@: +2395 # character before 'A' is invalid +2396 # . prologue +2397 55/push-ebp +2398 89/<- %ebp 4/r32/esp +2399 # (eax..ecx) = "@a" +2400 b8/copy-to-eax "@a"/imm32 +2401 8b/-> *eax 1/r32/ecx +2402 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2403 05/add-to-eax 4/imm32 +2404 # var slice/ecx : slice = {eax, ecx} +2405 51/push-ecx +2406 50/push-eax +2407 89/<- %ecx 4/r32/esp +2408 # +2409 (is-identifier? %ecx) +2410 (check-ints-equal %eax 0 "F - test-is-identifier-@") +2411 # . epilogue +2412 89/<- %esp 5/r32/ebp +2413 5d/pop-to-ebp +2414 c3/return +2415 +2416 test-is-identifier-square-bracket: +2417 # character after 'Z' is invalid +2418 # . prologue +2419 55/push-ebp +2420 89/<- %ebp 4/r32/esp +2421 # (eax..ecx) = "[a" +2422 b8/copy-to-eax "[a"/imm32 +2423 8b/-> *eax 1/r32/ecx +2424 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2425 05/add-to-eax 4/imm32 +2426 # var slice/ecx : slice = {eax, ecx} +2427 51/push-ecx +2428 50/push-eax +2429 89/<- %ecx 4/r32/esp +2430 # +2431 (is-identifier? %ecx) +2432 (check-ints-equal %eax 0 "F - test-is-identifier-@") +2433 # . epilogue +2434 89/<- %esp 5/r32/ebp +2435 5d/pop-to-ebp +2436 c3/return +2437 +2438 test-is-identifier-backtick: +2439 # character before 'a' is invalid +2440 # . prologue +2441 55/push-ebp +2442 89/<- %ebp 4/r32/esp +2443 # (eax..ecx) = "`a" +2444 b8/copy-to-eax "`a"/imm32 +2445 8b/-> *eax 1/r32/ecx +2446 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2447 05/add-to-eax 4/imm32 +2448 # var slice/ecx : slice = {eax, ecx} +2449 51/push-ecx +2450 50/push-eax +2451 89/<- %ecx 4/r32/esp +2452 # +2453 (is-identifier? %ecx) +2454 (check-ints-equal %eax 0 "F - test-is-identifier-backtick") +2455 # . epilogue +2456 89/<- %esp 5/r32/ebp +2457 5d/pop-to-ebp +2458 c3/return +2459 +2460 test-is-identifier-curly-brace-open: +2461 # character after 'z' is invalid; also used for blocks +2462 # . prologue +2463 55/push-ebp +2464 89/<- %ebp 4/r32/esp +2465 # (eax..ecx) = "{a" +2466 b8/copy-to-eax "{a"/imm32 +2467 8b/-> *eax 1/r32/ecx +2468 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2469 05/add-to-eax 4/imm32 +2470 # var slice/ecx : slice = {eax, ecx} +2471 51/push-ecx +2472 50/push-eax +2473 89/<- %ecx 4/r32/esp +2474 # +2475 (is-identifier? %ecx) +2476 (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-open") +2477 # . epilogue +2478 89/<- %esp 5/r32/ebp +2479 5d/pop-to-ebp +2480 c3/return +2481 +2482 test-is-identifier-curly-brace-close: +2483 # . prologue +2484 55/push-ebp +2485 89/<- %ebp 4/r32/esp +2486 # (eax..ecx) = "}a" +2487 b8/copy-to-eax "}a"/imm32 +2488 8b/-> *eax 1/r32/ecx +2489 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2490 05/add-to-eax 4/imm32 +2491 # var slice/ecx : slice = {eax, ecx} +2492 51/push-ecx +2493 50/push-eax +2494 89/<- %ecx 4/r32/esp +2495 # +2496 (is-identifier? %ecx) +2497 (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-close") +2498 # . epilogue +2499 89/<- %esp 5/r32/ebp +2500 5d/pop-to-ebp +2501 c3/return +2502 +2503 test-is-identifier-hyphen: +2504 # disallow leading '-' since '->' has special meaning +2505 # . prologue +2506 55/push-ebp +2507 89/<- %ebp 4/r32/esp +2508 # (eax..ecx) = "-a" +2509 b8/copy-to-eax "-a"/imm32 +2510 8b/-> *eax 1/r32/ecx +2511 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2512 05/add-to-eax 4/imm32 +2513 # var slice/ecx : slice = {eax, ecx} +2514 51/push-ecx +2515 50/push-eax +2516 89/<- %ecx 4/r32/esp +2517 # +2518 (is-identifier? %ecx) +2519 (check-ints-equal %eax 0 "F - test-is-identifier-hyphen") +2520 # . epilogue +2521 89/<- %esp 5/r32/ebp +2522 5d/pop-to-ebp +2523 c3/return +2524 +2525 populate-mu-function-body: # in : (addr buffered-file), out : (handle function), vars : (addr stack (handle var)) +2526 # . prologue +2527 55/push-ebp +2528 89/<- %ebp 4/r32/esp +2529 # . save registers +2530 50/push-eax +2531 56/push-esi +2532 57/push-edi +2533 # esi = in +2534 8b/-> *(ebp+8) 6/r32/esi +2535 # edi = out +2536 8b/-> *(ebp+0xc) 7/r32/edi +2537 # var eax : (handle block) = parse-mu-block(in, vars) +2538 (parse-mu-block %esi *(ebp+0x10) %edi) # => eax +2539 # out->body = eax +2540 89/<- *(edi+0x10) 0/r32/eax # Function-body +2541 $populate-mu-function-body:end: +2542 # . restore registers +2543 5f/pop-to-edi +2544 5e/pop-to-esi +2545 58/pop-to-eax +2546 # . epilogue +2547 89/<- %esp 5/r32/ebp +2548 5d/pop-to-ebp +2549 c3/return +2550 +2551 # parses a block, assuming that the leading '{' has already been read by the caller +2552 parse-mu-block: # in : (addr buffered-file), vars : (addr stack (handle var)), fn : (handle function) -> result/eax : (handle block) +2553 # pseudocode: +2554 # var line : (stream byte 512) +2555 # var word-slice : slice +2556 # result/eax = allocate(Heap, Stmt-size) +2557 # result->tag = 0/Block +2558 # while true # line loop +2559 # clear-stream(line) +2560 # read-line-buffered(in, line) +2561 # if (line->write == 0) break # end of file +2562 # word-slice = next-word(line) +2563 # if slice-empty?(word-slice) # end of line +2564 # continue +2565 # else if slice-starts-with?(word-slice, "#") +2566 # continue +2567 # else if slice-equal?(word-slice, "{") +2568 # assert(no-tokens-in(line)) +2569 # block = parse-mu-block(in, vars, fn) +2570 # append-to-block(result, block) +2571 # else if slice-equal?(word-slice, "}") +2572 # break +2573 # else if slice-ends-with?(word-slice, ":") +2574 # named-block = parse-mu-named-block(word-slice, line, in, vars, fn) +2575 # append-to-block(result, named-block) +2576 # else if slice-equal?(word-slice, "var") +2577 # var-def = parse-mu-var-def(line, vars) +2578 # append-to-block(result, var-def) +2579 # else +2580 # stmt = parse-mu-stmt(line, vars, fn) +2581 # append-to-block(result, stmt) +2582 # return result +2583 # +2584 # . prologue +2585 55/push-ebp +2586 89/<- %ebp 4/r32/esp +2587 # . save registers +2588 51/push-ecx +2589 52/push-edx +2590 53/push-ebx +2591 57/push-edi +2592 # var line/ecx : (stream byte 512) +2593 81 5/subop/subtract %esp 0x200/imm32 +2594 68/push 0x200/imm32/length +2595 68/push 0/imm32/read +2596 68/push 0/imm32/write +2597 89/<- %ecx 4/r32/esp +2598 # var word-slice/edx : slice +2599 68/push 0/imm32/end +2600 68/push 0/imm32/start +2601 89/<- %edx 4/r32/esp +2602 # edi = result +2603 (allocate Heap *Stmt-size) # => eax +2604 (zero-out %eax *Stmt-size) +2605 89/<- %edi 0/r32/eax +2606 { # line loop +2607 $parse-mu-block:line-loop: +2608 # line = read-line-buffered(in) +2609 (clear-stream %ecx) +2610 (read-line-buffered *(ebp+8) %ecx) +2611 #? (write-buffered Stderr "line: ") +2612 #? (write-stream-data Stderr %ecx) +2613 #? (write-buffered Stderr Newline) +2614 #? (flush Stderr) +2615 # if (line->write == 0) break +2616 81 7/subop/compare *ecx 0/imm32 +2617 0f 84/jump-if-= break/disp32 +2618 # word-slice = next-word(line) +2619 (next-word %ecx %edx) +2620 #? (write-buffered Stderr "word: ") +2621 #? (write-slice-buffered Stderr %edx) +2622 #? (write-buffered Stderr Newline) +2623 #? (flush Stderr) +2624 # if slice-empty?(word-slice) continue +2625 (slice-empty? %edx) +2626 3d/compare-eax-and 0/imm32 +2627 0f 85/jump-if-!= loop/disp32 +2628 # if (slice-starts-with?(word-slice, '#') continue +2629 # . eax = *word-slice->start +2630 8b/-> *edx 0/r32/eax +2631 8a/copy-byte *eax 0/r32/AL +2632 81 4/subop/and %eax 0xff/imm32 +2633 # . if (eax == '#') continue +2634 3d/compare-eax-and 0x23/imm32/hash +2635 0f 84/jump-if-= loop/disp32 +2636 # if slice-equal?(word-slice, "{") +2637 { +2638 $parse-mu-block:check-for-block: +2639 (slice-equal? %edx "{") +2640 3d/compare-eax-and 0/imm32 +2641 74/jump-if-= break/disp8 +2642 (check-no-tokens-left %ecx) +2643 # parse new block and append +2644 (parse-mu-block *(ebp+8) *(ebp+0xc) *(ebp+0x10)) # => eax +2645 (append-to-block Heap %edi %eax) +2646 e9/jump $parse-mu-block:line-loop/disp32 +2647 } +2648 # if slice-equal?(word-slice, "}") break +2649 $parse-mu-block:check-for-end: +2650 (slice-equal? %edx "}") +2651 3d/compare-eax-and 0/imm32 +2652 0f 85/jump-if-!= break/disp32 +2653 # if slice-ends-with?(word-slice, ":") parse named block and append +2654 { +2655 $parse-mu-block:check-for-named-block: +2656 # . eax = *word-slice->end +2657 8b/-> *(edx+4) 0/r32/eax +2658 8a/copy-byte *eax 0/r32/AL +2659 81 4/subop/and %eax 0xff/imm32 +2660 # . if (eax != ':') break +2661 3d/compare-eax-and 0x23/imm32/hash +2662 0f 85/jump-if-!= break/disp32 +2663 # +2664 (parse-mu-named-block %edx %ecx *(ebp+8) *(ebp+0xc) *(ebp+0x10)) # => eax +2665 (append-to-block Heap %edi %eax) +2666 e9/jump $parse-mu-block:line-loop/disp32 +2667 } +2668 # if slice-equal?(word-slice, "var") +2669 { +2670 $parse-mu-block:check-for-var: +2671 (slice-equal? %edx "var") +2672 3d/compare-eax-and 0/imm32 +2673 74/jump-if-= break/disp8 +2674 # +2675 (parse-mu-var-def %ecx *(ebp+0xc)) # => eax +2676 (append-to-block Heap %edi %eax) +2677 e9/jump $parse-mu-block:line-loop/disp32 +2678 } +2679 $parse-mu-block:regular-stmt: +2680 # otherwise +2681 (parse-mu-stmt %ecx *(ebp+0xc) *(ebp+0x10)) # => eax +2682 (append-to-block Heap %edi %eax) +2683 e9/jump loop/disp32 +2684 } # end line loop +2685 # return result +2686 89/<- %eax 7/r32/edi +2687 $parse-mu-block:end: +2688 # . reclaim locals +2689 81 0/subop/add %esp 0x214/imm32 +2690 # . restore registers +2691 5f/pop-to-edi +2692 5b/pop-to-ebx +2693 5a/pop-to-edx +2694 59/pop-to-ecx +2695 # . epilogue +2696 89/<- %esp 5/r32/ebp +2697 5d/pop-to-ebp +2698 c3/return +2699 +2700 $parse-mu-block:abort: +2701 # error("'{' or '}' should be on its own line, but got '") +2702 (write-buffered Stderr "'{' or '}' should be on its own line, but got '") +2703 (rewind-stream %ecx) +2704 (write-stream 2 %ecx) +2705 (write-buffered Stderr "'\n") +2706 (flush Stderr) +2707 # . syscall(exit, 1) +2708 bb/copy-to-ebx 1/imm32 +2709 b8/copy-to-eax 1/imm32/exit +2710 cd/syscall 0x80/imm8 +2711 # never gets here +2712 +2713 check-no-tokens-left: # line : (addr stream byte) +2714 # . prologue +2715 55/push-ebp +2716 89/<- %ebp 4/r32/esp +2717 # . save registers +2718 50/push-eax +2719 51/push-ecx +2720 # var s/ecx : slice +2721 68/push 0/imm32/end +2722 68/push 0/imm32/start +2723 89/<- %ecx 4/r32/esp +2724 # +2725 (next-word *(ebp+8) %ecx) +2726 # if slice-empty?(s) return +2727 (slice-empty? %ecx) +2728 3d/compare-eax-and 0/imm32 +2729 75/jump-if-!= $check-no-tokens-left:end/disp8 +2730 # if (slice-starts-with?(s, '#') return +2731 # . eax = *s->start +2732 8b/-> *edx 0/r32/eax +2733 8a/copy-byte *eax 0/r32/AL +2734 81 4/subop/and %eax 0xff/imm32 +2735 # . if (eax == '#') continue +2736 3d/compare-eax-and 0x23/imm32/hash +2737 74/jump-if-= $check-no-tokens-left:end/disp8 +2738 # abort +2739 (write-buffered Stderr "'{' or '}' should be on its own line, but got '") +2740 (rewind-stream %ecx) +2741 (write-stream 2 %ecx) +2742 (write-buffered Stderr "'\n") +2743 (flush Stderr) +2744 # . syscall(exit, 1) +2745 bb/copy-to-ebx 1/imm32 +2746 b8/copy-to-eax 1/imm32/exit +2747 cd/syscall 0x80/imm8 +2748 # never gets here +2749 $check-no-tokens-left:end: +2750 # . reclaim locals +2751 81 0/subop/add %esp 8/imm32 +2752 # . restore registers +2753 59/pop-to-ecx +2754 58/pop-to-eax +2755 # . epilogue +2756 89/<- %esp 5/r32/ebp +2757 5d/pop-to-ebp +2758 c3/return +2759 +2760 parse-mu-named-block: # name : (addr slice), first-line : (addr stream byte), in : (addr buffered-file), vars : (addr stack (handle var)) -> result/eax : (handle stmt) +2761 # pseudocode: +2762 # var line : (stream byte 512) +2763 # var word-slice : slice +2764 # result/eax = allocate(Heap, Stmt-size) +2765 # result->tag = 4/Named-block +2766 # result->name = name +2767 # assert(next-word(first-line) == "{") +2768 # assert(no-tokens-in(first-line)) +2769 # while true # line loop +2770 # clear-stream(line) +2771 # read-line-buffered(in, line) +2772 # if (line->write == 0) break # end of file +2773 # word-slice = next-word(line) +2774 # if slice-empty?(word-slice) # end of line +2775 # break +2776 # else if slice-equal?(word-slice, "{") +2777 # block = parse-mu-block(in, vars) +2778 # append-to-block(result, block) +2779 # else if slice-equal?(word-slice, "}") +2780 # break +2781 # else if slice-ends-with?(word-slice, ":") +2782 # named-block = parse-mu-named-block(word-slice, in, vars) +2783 # append-to-block(result, named-block) +2784 # else if slice-equal?(word-slice, "var") +2785 # var-def = parse-mu-var-def(line, vars) +2786 # append-to-block(result, var-def) +2787 # else +2788 # stmt = parse-mu-stmt(line, vars, fn) +2789 # append-to-block(result, stmt) +2790 # return result +2791 # +2792 # . prologue +2793 55/push-ebp +2794 89/<- %ebp 4/r32/esp +2795 # . save registers +2796 $parse-mu-named-block:end: +2797 # . reclaim locals +2798 # . restore registers +2799 # . epilogue +2800 89/<- %esp 5/r32/ebp +2801 5d/pop-to-ebp +2802 c3/return +2803 +2804 parse-mu-var-def: # line : (addr stream byte), vars : (addr stack (handle var)) -> result/eax : (handle stmt) +2805 # pseudocode: +2806 # +2807 # . prologue +2808 55/push-ebp +2809 89/<- %ebp 4/r32/esp +2810 # . save registers +2811 51/push-ecx +2812 52/push-edx +2813 # var word-slice/ecx : slice +2814 68/push 0/imm32/end +2815 68/push 0/imm32/start +2816 89/<- %ecx 4/r32/esp +2817 # var v/edx : (handle var) = parse-var-with-type(line) +2818 (next-word *(ebp+8) %ecx) +2819 (parse-var-with-type %ecx *(ebp+8)) # => eax +2820 89/<- %edx 0/r32/eax +2821 # either v has no register and there's no more to this line +2822 8b/-> *(edx+0x10) 0/r32/eax # Var-register +2823 3d/compare-eax-and 0/imm32 +2824 { +2825 75/jump-if-not-equal break/disp8 +2826 # TODO: ensure that there's nothing else on this line +2827 (new-vardef Heap %edx) # => eax +2828 eb/jump $parse-mu-var-def:end/disp8 +2829 } +2830 # or v has a register and there's more to this line +2831 { +2832 74/jump-if-equal break/disp8 +2833 # ensure that the next word is '<-' +2834 (next-word *(ebp+8) %ecx) +2835 (slice-equal? %ecx "<-") # => eax +2836 3d/compare-eax-and 0/imm32 +2837 74/jump-if-equal $parse-mu-var-def:abort/disp8 +2838 # +2839 (new-regvardef Heap %edx) # => eax +2840 (add-operation-and-inputs-to-stmt %eax *(ebp+8) *(ebp+0xc)) +2841 } +2842 $parse-mu-var-def:end: +2843 # . reclaim locals +2844 81 0/subop/add %esp 8/imm32 +2845 # . restore registers +2846 5a/pop-to-edx +2847 59/pop-to-ecx +2848 # . epilogue +2849 89/<- %esp 5/r32/ebp +2850 5d/pop-to-ebp +2851 c3/return +2852 +2853 $parse-mu-var-def:abort: +2854 (rewind-stream *(ebp+8)) +2855 # error("register variable requires a valid instruction to initialize but got '" line "'\n") +2856 (write-buffered Stderr "register variable requires a valid instruction to initialize but got '") +2857 (flush Stderr) +2858 (write-stream 2 *(ebp+8)) +2859 (write-buffered Stderr "'\n") +2860 (flush Stderr) +2861 # . syscall(exit, 1) +2862 bb/copy-to-ebx 1/imm32 +2863 b8/copy-to-eax 1/imm32/exit +2864 cd/syscall 0x80/imm8 +2865 # never gets here +2866 +2867 test-parse-mu-var-def: +2868 # 'var n: int' +2869 # . prologue +2870 55/push-ebp +2871 89/<- %ebp 4/r32/esp +2872 # setup +2873 (clear-stream _test-input-stream) +2874 (write _test-input-stream "n: int\n") # caller has consumed the 'var' +2875 # var vars/ecx : (stack (addr var) 4) +2876 81 5/subop/subtract %esp 0x10/imm32 +2877 68/push 0x10/imm32/length +2878 68/push 0/imm32/top +2879 89/<- %ecx 4/r32/esp +2880 (clear-stack %ecx) +2881 # convert +2882 (parse-mu-var-def _test-input-stream %ecx) # => eax +2883 # check result +2884 (check-ints-equal *eax 2 "F - test-parse-mu-var-def/tag") # Stmt-tag is vardef +2885 8b/-> *(eax+4) 0/r32/eax # Vardef-var +2886 (check-strings-equal *eax "n" "F - test-parse-mu-var-def/var-name") # Var-name +2887 (check-ints-equal *(eax+0x10) 0 "F - test-parse-mu-var-def/var-register") # Var-register +2888 # TODO: ensure stack-offset is -4 +2889 # TODO: ensure block-depth is 1 +2890 # ensure type is int +2891 8b/-> *(eax+4) 0/r32/eax # Var-type +2892 (check-ints-equal *eax 1 "F - test-parse-mu-var-def/var-type:0") # Tree-left +2893 (check-ints-equal *(eax+4) 0 "F - test-parse-mu-var-def/var-type:0") # Tree-right +2894 # . epilogue +2895 89/<- %esp 5/r32/ebp +2896 5d/pop-to-ebp +2897 c3/return +2898 +2899 test-parse-mu-reg-var-def: +2900 # 'var n/eax: int <- copy 0' +2901 # . prologue +2902 55/push-ebp +2903 89/<- %ebp 4/r32/esp +2904 # setup +2905 (clear-stream _test-input-stream) +2906 (write _test-input-stream "n/eax: int <- copy 0\n") # caller has consumed the 'var' +2907 # var vars/ecx : (stack (addr var) 4) +2908 81 5/subop/subtract %esp 0x10/imm32 +2909 68/push 0x10/imm32/length +2910 68/push 0/imm32/top +2911 89/<- %ecx 4/r32/esp +2912 (clear-stack %ecx) +2913 # convert +2914 (parse-mu-var-def _test-input-stream %ecx) # => eax +2915 # check result +2916 (check-ints-equal *eax 3 "F - test-parse-mu-reg-var-def/tag") # Stmt-tag is regvardef +2917 8b/-> *(eax+0xc) 0/r32/eax # Regvardef-var +2918 (check-strings-equal *eax "n" "F - test-parse-mu-reg-var-def/var-name") # Var-name +2919 (check-strings-equal *(eax+0x10) "eax" "F - test-parse-mu-reg-var-def/var-register") # Var-register +2920 # TODO: ensure stack-offset is -4 +2921 # TODO: ensure block-depth is 1 +2922 # ensure type is int +2923 8b/-> *(eax+4) 0/r32/eax # Var-type +2924 (check-ints-equal *eax 1 "F - test-parse-mu-reg-var-def/var-type:0") # Tree-left +2925 (check-ints-equal *(eax+4) 0 "F - test-parse-mu-reg-var-def/var-type:0") # Tree-right +2926 # . epilogue +2927 89/<- %esp 5/r32/ebp +2928 5d/pop-to-ebp +2929 c3/return +2930 +2931 parse-mu-stmt: # line : (addr stream byte), vars : (addr stack (handle var)), fn : (handle function) -> result/eax : (handle stmt) +2932 # pseudocode: +2933 # var name : slice +2934 # result = allocate(Heap, Stmt-size) +2935 # if stmt-has-outputs?(line) +2936 # while true +2937 # name = next-word(line) +2938 # if (name == '<-') break +2939 # assert(is-identifier?(name)) +2940 # var v : (handle var) = lookup-or-define-var(name, vars, fn) # regular stmts may define vars in fn outputs +2941 # result->outputs = append(result->outputs, v) +2942 # add-operation-and-inputs-to-stmt(result, line, vars) +2943 # +2944 # . prologue +2945 55/push-ebp +2946 89/<- %ebp 4/r32/esp +2947 # . save registers +2948 51/push-ecx +2949 57/push-edi +2950 # var name/ecx : slice +2951 68/push 0/imm32/end +2952 68/push 0/imm32/start +2953 89/<- %ecx 4/r32/esp +2954 # result/edi : (handle stmt) +2955 (allocate Heap *Stmt-size) # => eax +2956 (zero-out %eax *Stmt-size) +2957 89/<- %edi 0/r32/eax +2958 # result->tag = 1/stmt +2959 c7 0/subop/copy *edi 1/imm32/stmt1 # Stmt-tag +2960 { +2961 (stmt-has-outputs? *(ebp+8)) +2962 3d/compare-eax-and 0/imm32 +2963 0f 84/jump-if-= break/disp32 +2964 { +2965 $parse-mu-stmt:read-outputs: +2966 # name = next-word(line) +2967 (next-word *(ebp+8) %ecx) +2968 # if slice-empty?(word-slice) break +2969 (slice-empty? %ecx) +2970 3d/compare-eax-and 0/imm32 +2971 0f 85/jump-if-!= break/disp32 +2972 # if (name == "<-") break +2973 (slice-equal? %ecx "<-") +2974 3d/compare-eax-and 0/imm32 +2975 75/jump-if-!= break/disp8 +2976 # assert(is-identifier?(name)) +2977 (is-identifier? %ecx) +2978 3d/compare-eax-and 0/imm32 +2979 0f 84/jump-if-= $parse-mu-stmt:abort/disp32 +2980 # +2981 (lookup-or-define-var %ecx *(ebp+0xc) *(ebp+0x10)) # => eax +2982 (append-list Heap %eax *(edi+0xc)) # Stmt1-outputs => eax +2983 89/<- *(edi+0xc) 0/r32/eax # Stmt1-outputs +2984 e9/jump loop/disp32 +2985 } +2986 } +2987 (add-operation-and-inputs-to-stmt %edi *(ebp+8) *(ebp+0xc)) +2988 $parse-mu-stmt:end: +2989 # return result +2990 89/<- %eax 7/r32/edi +2991 # . reclaim locals +2992 81 0/subop/add %esp 8/imm32 +2993 # . restore registers +2994 5f/pop-to-edi +2995 59/pop-to-ecx +2996 # . epilogue +2997 89/<- %esp 5/r32/ebp +2998 5d/pop-to-ebp +2999 c3/return +3000 +3001 $parse-mu-stmt:abort: +3002 # error("invalid identifier '" name "'\n") +3003 (write-buffered Stderr "invalid identifier '") +3004 (write-slice-buffered Stderr %ecx) +3005 (write-buffered Stderr "'\n") +3006 (flush Stderr) +3007 # . syscall(exit, 1) +3008 bb/copy-to-ebx 1/imm32 +3009 b8/copy-to-eax 1/imm32/exit +3010 cd/syscall 0x80/imm8 +3011 # never gets here +3012 +3013 add-operation-and-inputs-to-stmt: # stmt : (handle stmt), line : (addr stream byte) +3014 # pseudocode: +3015 # stmt->name = slice-to-string(next-word(line)) +3016 # while true +3017 # name = next-word-or-string(line) +3018 # v = lookup-var-or-literal(name) +3019 # stmt->inouts = append(stmt->inouts, v) +3020 # +3021 # . prologue +3022 55/push-ebp +3023 89/<- %ebp 4/r32/esp +3024 # . save registers +3025 50/push-eax +3026 51/push-ecx +3027 57/push-edi +3028 # edi = stmt +3029 8b/-> *(ebp+8) 7/r32/edi +3030 # var name/ecx : slice +3031 68/push 0/imm32/end +3032 68/push 0/imm32/start +3033 89/<- %ecx 4/r32/esp +3034 $add-operation-and-inputs-to-stmt:read-operation: +3035 (next-word *(ebp+0xc) %ecx) +3036 (slice-to-string Heap %ecx) # => eax +3037 89/<- *(edi+4) 0/r32/eax # Stmt1-operation or Regvardef-operation +3038 { +3039 $add-operation-and-inputs-to-stmt:read-inouts: +3040 # name = next-word-or-string(line) +3041 (next-word-or-string *(ebp+0xc) %ecx) +3042 # if slice-empty?(word-slice) break +3043 (slice-empty? %ecx) # => eax +3044 3d/compare-eax-and 0/imm32 +3045 0f 85/jump-if-!= break/disp32 +3046 # if (name == "<-") abort +3047 (slice-equal? %ecx "<-") +3048 3d/compare-eax-and 0/imm32 +3049 0f 85/jump-if-!= $add-operation-and-inputs-to-stmt:abort/disp32 +3050 # +3051 (lookup-var-or-literal %ecx *(ebp+0x10)) # => eax +3052 (append-list Heap %eax *(edi+8)) # Stmt1-inouts or Regvardef-inouts => eax +3053 89/<- *(edi+8) 0/r32/eax # Stmt1-inouts or Regvardef-inouts +3054 e9/jump loop/disp32 +3055 } +3056 $add-operation-and-inputs-to-stmt:end: +3057 # . reclaim locals +3058 81 0/subop/add %esp 8/imm32 +3059 # . restore registers +3060 5f/pop-to-edi +3061 59/pop-to-ecx +3062 58/pop-to-eax +3063 # . epilogue +3064 89/<- %esp 5/r32/ebp +3065 5d/pop-to-ebp +3066 c3/return +3067 +3068 $add-operation-and-inputs-to-stmt:abort: +3069 # error("invalid statement '" line "'\n") +3070 (rewind-stream *(ebp+8)) +3071 (write-buffered Stderr "invalid identifier '") +3072 (flush Stderr) +3073 (write-stream 2 *(ebp+8)) +3074 (write-buffered Stderr "'\n") +3075 (flush Stderr) +3076 # . syscall(exit, 1) +3077 bb/copy-to-ebx 1/imm32 +3078 b8/copy-to-eax 1/imm32/exit +3079 cd/syscall 0x80/imm8 +3080 # never gets here +3081 +3082 stmt-has-outputs?: # line : (addr stream byte) -> result/eax : boolean +3083 # . prologue +3084 55/push-ebp +3085 89/<- %ebp 4/r32/esp +3086 # . save registers +3087 51/push-ecx +3088 # var word-slice/ecx : slice +3089 68/push 0/imm32/end +3090 68/push 0/imm32/start +3091 89/<- %ecx 4/r32/esp +3092 # result = false +3093 b8/copy-to-eax 0/imm32/false +3094 (rewind-stream *(ebp+8)) +3095 { +3096 (next-word-or-string *(ebp+8) %ecx) +3097 # if slice-empty?(word-slice) break +3098 (slice-empty? %ecx) 3099 3d/compare-eax-and 0/imm32 -3100 8b/-> *ebx 0/r32/eax -3101 75/jump-if-!= break/disp8 -3102 # curr -= 4 -3103 81 5/subop/subtract %ebx 4/imm32 -3104 e9/jump loop/disp32 -3105 } -3106 $lookup-var-helper:end: -3107 # . restore registers -3108 5e/pop-to-esi -3109 5b/pop-to-ebx -3110 5a/pop-to-edx -3111 # . epilogue -3112 89/<- %esp 5/r32/ebp -3113 5d/pop-to-ebp -3114 c3/return -3115 -3116 $lookup-var-helper:error1: -3117 (write-buffered Stderr "malformed stack when looking up '") -3118 (write-slice-buffered Stderr *(ebp+8)) -3119 (write-buffered Stderr "'\n") -3120 (flush Stderr) -3121 # . syscall(exit, 1) -3122 bb/copy-to-ebx 1/imm32 -3123 b8/copy-to-eax 1/imm32/exit -3124 cd/syscall 0x80/imm8 -3125 # never gets here -3126 -3127 # return first 'name' from the top (back) of 'vars' and create a new var for a fn output if not found -3128 lookup-or-define-var: # name: (addr slice), vars : (addr stack (handle var)), fn : (handle function) -> result/eax: (handle var) -3129 # . prologue -3130 55/push-ebp -3131 89/<- %ebp 4/r32/esp -3132 # . save registers -3133 51/push-ecx -3134 # var target/ecx : (handle array byte) = slice-to-string(name) -3135 (slice-to-string Heap *(ebp+8)) # => eax -3136 89/<- %ecx 0/r32/eax -3137 # -3138 (lookup-var-helper *(ebp+8) *(ebp+0xc)) # => eax -3139 { -3140 # if (result != 0) return -3141 3d/compare-eax-and 0/imm32 -3142 75/jump-if-!= break/disp8 -3143 # if name is one of fn's outputs, return it -3144 { -3145 (find-in-function-outputs *(ebp+0x10) %ecx) # => eax -3146 3d/compare-eax-and 0/imm32 -3147 # otherwise abort -3148 0f 84/jump-if-!= $lookup-var:abort/disp32 -3149 } -3150 } -3151 $lookup-or-define-var:end: -3152 # . restore registers -3153 59/pop-to-ecx -3154 # . epilogue -3155 89/<- %esp 5/r32/ebp -3156 5d/pop-to-ebp -3157 c3/return -3158 -3159 find-in-function-outputs: # fn : (handle function), name : (handle array byte) => result/eax : (handle var) -3160 # . prologue -3161 55/push-ebp -3162 89/<- %ebp 4/r32/esp -3163 # . save registers -3164 51/push-ecx -3165 # var curr/ecx : (handle list var) = fn->outputs -3166 8b/-> *(ebp+8) 1/r32/ecx -3167 8b/-> *(ecx+0xc) 1/r32/ecx -3168 # while curr != null -3169 { -3170 81 7/subop/compare %ecx 0/imm32 -3171 74/jump-if-= break/disp8 -3172 # var v : (handle var) = *curr -3173 8b/-> *ecx 0/r32/eax # List-value -3174 # if (curr->name == name) return curr -3175 50/push-eax -3176 (string-equal? *eax *(ebp+0xc)) -3177 3d/compare-eax-and 0/imm32 -3178 58/pop-to-eax -3179 75/jump-if-!= $find-in-function-outputs:end/disp8 -3180 # curr = curr->next -3181 8b/-> *(ecx+4) 1/r32/ecx # List-next -3182 eb/jump loop/disp8 -3183 } -3184 b8/copy-to-eax 0/imm32 -3185 $find-in-function-outputs:end: -3186 # . restore registers -3187 59/pop-to-ecx -3188 # . epilogue -3189 89/<- %esp 5/r32/ebp -3190 5d/pop-to-ebp -3191 c3/return -3192 -3193 test-parse-mu-stmt: -3194 # 'increment n' -3195 # . prologue -3196 55/push-ebp -3197 89/<- %ebp 4/r32/esp -3198 # setup -3199 (clear-stream _test-input-stream) -3200 (write _test-input-stream "increment n\n") -3201 # var vars/ecx : (stack (addr var) 4) -3202 81 5/subop/subtract %esp 0x10/imm32 -3203 68/push 0x10/imm32/length -3204 68/push 0/imm32/top -3205 89/<- %ecx 4/r32/esp -3206 (clear-stack %ecx) -3207 # var v/edx : var -3208 81 5/subop/subtract %esp 0x14/imm32 # Var-size -3209 89/<- %edx 4/r32/esp -3210 (zero-out %edx 0x14) -3211 # v->name = "n" -3212 c7 0/subop/copy *edx "n"/imm32 # Var-name -3213 # -3214 (push %ecx %edx) -3215 # convert -3216 (parse-mu-stmt _test-input-stream %ecx) -3217 # check result -3218 (check-strings-equal *(eax+4) "increment" "F - test-parse-mu-stmt/name") # Stmt1-operation -3219 # edx : (handle list var) = result->inouts -3220 8b/-> *(eax+8) 2/r32/edx # Stmt1-inouts -3221 # ebx : (handle var) = result->inouts->value -3222 8b/-> *edx 3/r32/ebx # List-value -3223 (check-strings-equal *ebx "n" "F - test-parse-mu-stmt/inout:0") # Var-name -3224 # . epilogue -3225 89/<- %esp 5/r32/ebp -3226 5d/pop-to-ebp -3227 c3/return -3228 -3229 new-function: # ad: (addr allocation-descriptor), name: (addr array byte), subx-name: (addr array byte), inouts: (handle list var), outputs: (handle list var), body: (handle block), next: (handle function) -> result/eax: (handle function) -3230 # . prologue -3231 55/push-ebp -3232 89/<- %ebp 4/r32/esp -3233 # . save registers -3234 51/push-ecx -3235 # -3236 (allocate *(ebp+8) *Function-size) # => eax -3237 8b/-> *(ebp+0xc) 1/r32/ecx -3238 89/<- *eax 1/r32/ecx # Function-name -3239 8b/-> *(ebp+0x10) 1/r32/ecx -3240 89/<- *(eax+4) 1/r32/ecx # Function-subx-name -3241 8b/-> *(ebp+0x14) 1/r32/ecx -3242 89/<- *(eax+8) 1/r32/ecx # Function-inouts -3243 8b/-> *(ebp+0x18) 1/r32/ecx -3244 89/<- *(eax+0xc) 1/r32/ecx # Function-outputs -3245 8b/-> *(ebp+0x1c) 1/r32/ecx -3246 89/<- *(eax+0x10) 1/r32/ecx # Function-body -3247 8b/-> *(ebp+0x20) 1/r32/ecx -3248 89/<- *(eax+0x14) 1/r32/ecx # Function-next -3249 $new-function:end: -3250 # . restore registers -3251 59/pop-to-ecx -3252 # . epilogue -3253 89/<- %esp 5/r32/ebp -3254 5d/pop-to-ebp -3255 c3/return -3256 -3257 new-var: # ad: (addr allocation-descriptor), name: (addr array byte), type: int, block: int, stack-offset: int, register: (addr array byte) -> result/eax: (handle var) -3258 # . prologue -3259 55/push-ebp -3260 89/<- %ebp 4/r32/esp -3261 # . save registers -3262 51/push-ecx -3263 # -3264 (allocate *(ebp+8) *Var-size) # => eax -3265 8b/-> *(ebp+0xc) 1/r32/ecx -3266 89/<- *eax 1/r32/ecx # Var-name -3267 8b/-> *(ebp+0x10) 1/r32/ecx -3268 89/<- *(eax+4) 1/r32/ecx # Var-type -3269 8b/-> *(ebp+0x14) 1/r32/ecx -3270 89/<- *(eax+8) 1/r32/ecx # Var-block -3271 8b/-> *(ebp+0x18) 1/r32/ecx -3272 89/<- *(eax+0xc) 1/r32/ecx # Var-stack-offset -3273 8b/-> *(ebp+0x1c) 1/r32/ecx -3274 89/<- *(eax+0x10) 1/r32/ecx # Var-register -3275 $new-var:end: -3276 # . restore registers -3277 59/pop-to-ecx -3278 # . epilogue -3279 89/<- %esp 5/r32/ebp -3280 5d/pop-to-ebp -3281 c3/return -3282 -3283 new-literal-integer: # ad: (addr allocation-descriptor), name: (addr slice) -> result/eax: (handle var) -3284 # . prologue -3285 55/push-ebp -3286 89/<- %ebp 4/r32/esp -3287 # . save registers -3288 51/push-ecx -3289 # if (!is-hex-int?(name)) abort -3290 (is-hex-int? *(ebp+0xc)) # => eax -3291 3d/compare-eax-and 0/imm32 -3292 0f 84/jump-if-= $new-literal-integer:abort/disp32 -3293 # var s/ecx : (addr array byte) -3294 (slice-to-string Heap *(ebp+0xc)) # => eax -3295 89/<- %ecx 0/r32/eax -3296 # -3297 (allocate *(ebp+8) *Var-size) # => eax -3298 89/<- *eax 1/r32/ecx # Var-name -3299 89/<- %ecx 0/r32/eax -3300 (allocate *(ebp+8) *Tree-size) # => eax -3301 89/<- *(ecx+4) 0/r32/eax # Var-type -3302 89/<- %eax 1/r32/ecx -3303 c7 0/subop/copy *(eax+8) 0/imm32 # Var-block -3304 c7 0/subop/copy *(eax+0xc) 0/imm32 # Var-stack-offset -3305 c7 0/subop/copy *(eax+0x10) 0/imm32 # Var-register -3306 $new-literal-integer:end: -3307 # . restore registers -3308 59/pop-to-ecx -3309 # . epilogue -3310 89/<- %esp 5/r32/ebp -3311 5d/pop-to-ebp -3312 c3/return -3313 -3314 $new-literal-integer:abort: -3315 (write-buffered Stderr "variable cannot begin with a digit '") -3316 (write-slice-buffered Stderr *(ebp+0xc)) -3317 (write-buffered Stderr "'\n") -3318 (flush Stderr) -3319 # . syscall(exit, 1) -3320 bb/copy-to-ebx 1/imm32 -3321 b8/copy-to-eax 1/imm32/exit -3322 cd/syscall 0x80/imm8 -3323 # never gets here -3324 -3325 new-block: # ad: (addr allocation-descriptor), data: (handle list statement) -> result/eax: (handle statement) -3326 # . prologue -3327 55/push-ebp -3328 89/<- %ebp 4/r32/esp -3329 # . save registers -3330 51/push-ecx -3331 # -3332 (allocate *(ebp+8) *Stmt-size) # => eax -3333 (zero-out %eax *Stmt-size) -3334 c7 0/subop/copy *eax 0/imm32/tag/block # Stmt-tag -3335 8b/-> *(ebp+0xc) 1/r32/ecx -3336 89/<- *(eax+4) 1/r32/ecx # Block-statements -3337 $new-block:end: -3338 # . restore registers -3339 59/pop-to-ecx -3340 # . epilogue -3341 89/<- %esp 5/r32/ebp -3342 5d/pop-to-ebp -3343 c3/return -3344 -3345 new-stmt: # ad: (addr allocation-descriptor), operation: (addr array byte), inouts: (handle list var), outputs: (handle list var) -> result/eax: (handle statement) -3346 # . prologue -3347 55/push-ebp -3348 89/<- %ebp 4/r32/esp -3349 # . save registers -3350 51/push-ecx -3351 # -3352 (allocate *(ebp+8) *Stmt-size) # => eax -3353 (zero-out %eax *Stmt-size) -3354 c7 0/subop/copy *eax 1/imm32/tag/regular-stmt # Stmt-tag -3355 8b/-> *(ebp+0xc) 1/r32/ecx -3356 89/<- *(eax+4) 1/r32/ecx # Stmt1-operation -3357 8b/-> *(ebp+0x10) 1/r32/ecx -3358 89/<- *(eax+8) 1/r32/ecx # Stmt1-inouts -3359 8b/-> *(ebp+0x14) 1/r32/ecx -3360 89/<- *(eax+0xc) 1/r32/ecx # Stmt1-outputs -3361 $new-stmt:end: -3362 # . restore registers -3363 59/pop-to-ecx -3364 # . epilogue -3365 89/<- %esp 5/r32/ebp -3366 5d/pop-to-ebp -3367 c3/return -3368 -3369 new-vardef: # ad: (addr allocation-descriptor), name: (addr array byte), type: int -> result/eax: (handle statement) -3370 # . prologue -3371 55/push-ebp -3372 89/<- %ebp 4/r32/esp -3373 # . save registers -3374 51/push-ecx -3375 # -3376 (allocate *(ebp+8) *Stmt-size) # => eax -3377 (zero-out %eax *Stmt-size) -3378 c7 0/subop/copy *eax 2/imm32/tag/var-on-stack # Stmt-tag -3379 8b/-> *(ebp+0xc) 1/r32/ecx -3380 89/<- *(eax+4) 1/r32/ecx # Vardef-name -3381 8b/-> *(ebp+0x10) 1/r32/ecx -3382 89/<- *(eax+8) 1/r32/ecx # Vardef-type -3383 $new-vardef:end: -3384 # . restore registers -3385 59/pop-to-ecx -3386 # . epilogue -3387 89/<- %esp 5/r32/ebp -3388 5d/pop-to-ebp -3389 c3/return -3390 -3391 new-regvardef: # ad: (addr allocation-descriptor), name: (addr array byte), type: int, register: (addr array byte) -> result/eax: (handle statement) -3392 # . prologue -3393 55/push-ebp -3394 89/<- %ebp 4/r32/esp -3395 # . save registers -3396 51/push-ecx -3397 # -3398 (allocate *(ebp+8) *Stmt-size) # => eax -3399 (zero-out %eax *Stmt-size) -3400 c7 0/subop/copy *eax 3/imm32/tag/var-in-register -3401 8b/-> *(ebp+0xc) 1/r32/ecx -3402 89/<- *(eax+4) 1/r32/ecx # Regvardef-name -3403 8b/-> *(ebp+0x10) 1/r32/ecx -3404 89/<- *(eax+8) 1/r32/ecx # Regvardef-type -3405 8b/-> *(ebp+0x14) 1/r32/ecx -3406 89/<- *(eax+0xc) 1/r32/ecx # Regvardef-register -3407 $new-regvardef:end: -3408 # . restore registers -3409 59/pop-to-ecx -3410 # . epilogue -3411 89/<- %esp 5/r32/ebp -3412 5d/pop-to-ebp -3413 c3/return -3414 -3415 new-named-block: # ad: (addr allocation-descriptor), name: (addr array byte), data: (handle list statement) -> result/eax: (handle statement) -3416 # . prologue -3417 55/push-ebp -3418 89/<- %ebp 4/r32/esp -3419 # . save registers -3420 51/push-ecx -3421 # -3422 (allocate *(ebp+8) *Stmt-size) # => eax -3423 (zero-out %eax *Stmt-size) -3424 c7 0/subop/copy *eax 4/imm32/tag/named-block -3425 8b/-> *(ebp+0xc) 1/r32/ecx -3426 89/<- *(eax+4) 1/r32/ecx # Named-block-name -3427 8b/-> *(ebp+0x10) 1/r32/ecx -3428 89/<- *(eax+8) 1/r32/ecx # Named-block-statements -3429 $new-named-block:end: -3430 # . restore registers -3431 59/pop-to-ecx -3432 # . epilogue -3433 89/<- %esp 5/r32/ebp -3434 5d/pop-to-ebp -3435 c3/return -3436 -3437 new-list: # ad: (addr allocation-descriptor), value: _type, next: (handle list _type) -> result/eax : (handle list _type) -3438 # . prologue -3439 55/push-ebp -3440 89/<- %ebp 4/r32/esp -3441 # . save registers -3442 51/push-ecx +3100 b8/copy-to-eax 0/imm32/false/result # restore result (if we're here it's still false) +3101 0f 85/jump-if-!= break/disp32 +3102 # if slice-starts-with?(word-slice, '#') break +3103 # . eax = *word-slice->start +3104 8b/-> *ecx 0/r32/eax +3105 8a/copy-byte *eax 0/r32/AL +3106 81 4/subop/and %eax 0xff/imm32 +3107 # . if (eax == '#') break +3108 3d/compare-eax-and 0x23/imm32/hash +3109 b8/copy-to-eax 0/imm32/false/result # restore result (if we're here it's still false) +3110 0f 84/jump-if-= break/disp32 +3111 # if slice-equal?(word-slice, '<-') return true +3112 (slice-equal? %ecx "<-") +3113 3d/compare-eax-and 0/imm32 +3114 74/jump-if-= loop/disp8 +3115 b8/copy-to-eax 1/imm32/true +3116 } +3117 $stmt-has-outputs:end: +3118 (rewind-stream *(ebp+8)) +3119 # . reclaim locals +3120 81 0/subop/add %esp 8/imm32 +3121 # . restore registers +3122 59/pop-to-ecx +3123 # . epilogue +3124 89/<- %esp 5/r32/ebp +3125 5d/pop-to-ebp +3126 c3/return +3127 +3128 # if 'name' starts with a digit, create a new literal var for it +3129 # otherwise return first 'name' from the top (back) of 'vars' and abort if not found +3130 lookup-var-or-literal: # name: (addr slice), vars : (addr stack (handle var)) -> result/eax: (handle var) +3131 # . prologue +3132 55/push-ebp +3133 89/<- %ebp 4/r32/esp +3134 # . save registers +3135 51/push-ecx +3136 56/push-esi +3137 # esi = name +3138 8b/-> *(ebp+8) 6/r32/esi +3139 # if slice-empty?(name) abort +3140 (slice-empty? %esi) # => eax +3141 3d/compare-eax-and 0/imm32 +3142 0f 85/jump-if-!= $lookup-var-or-literal:abort/disp32 +3143 # var ecx : byte = *name->start +3144 8b/-> *esi 1/r32/ecx +3145 8a/copy-byte *ecx 1/r32/CL +3146 81 4/subop/and %ecx 0xff/imm32 +3147 # if is-decimal-digit?(*name->start) return new var(name) +3148 (is-decimal-digit? %ecx) # => eax +3149 81 7/subop/compare %eax 0/imm32 +3150 { +3151 74/jump-if-= break/disp8 +3152 (new-literal-integer Heap %esi) # => eax +3153 } +3154 # otherwise return lookup-var(name, vars) +3155 { +3156 75/jump-if-!= break/disp8 +3157 (lookup-var %esi *(ebp+0xc)) # => eax +3158 } +3159 $lookup-var-or-literal:end: +3160 # . restore registers +3161 5e/pop-to-esi +3162 59/pop-to-ecx +3163 # . epilogue +3164 89/<- %esp 5/r32/ebp +3165 5d/pop-to-ebp +3166 c3/return +3167 +3168 $lookup-var-or-literal:abort: +3169 (write-buffered Stderr "empty variable!") +3170 (flush Stderr) +3171 # . syscall(exit, 1) +3172 bb/copy-to-ebx 1/imm32 +3173 b8/copy-to-eax 1/imm32/exit +3174 cd/syscall 0x80/imm8 +3175 # never gets here +3176 +3177 # return first 'name' from the top (back) of 'vars' and abort if not found +3178 lookup-var: # name: (addr slice), vars : (addr stack (handle var)) -> result/eax: (handle var) +3179 # . prologue +3180 55/push-ebp +3181 89/<- %ebp 4/r32/esp +3182 # var target/eax : (handle array byte) = slice-to-string(name) +3183 (slice-to-string Heap *(ebp+8)) # => eax +3184 # +3185 (lookup-var-helper %eax *(ebp+0xc)) # => eax +3186 # if (result == 0) abort +3187 3d/compare-eax-and 0/imm32 +3188 74/jump-if-= $lookup-var:abort/disp8 +3189 $lookup-var:end: +3190 # . epilogue +3191 89/<- %esp 5/r32/ebp +3192 5d/pop-to-ebp +3193 c3/return +3194 +3195 $lookup-var:abort: +3196 (write-buffered Stderr "unknown variable '") +3197 (write-slice-buffered Stderr *(ebp+8)) +3198 (write-buffered Stderr "'\n") +3199 (flush Stderr) +3200 # . syscall(exit, 1) +3201 bb/copy-to-ebx 1/imm32 +3202 b8/copy-to-eax 1/imm32/exit +3203 cd/syscall 0x80/imm8 +3204 # never gets here +3205 +3206 # return first 'name' from the top (back) of 'vars', and 0/null if not found +3207 lookup-var-helper: # name: (addr array byte), vars : (addr stack (handle var)) -> result/eax: (handle var) +3208 # pseudocode: +3209 # var curr : (addr handle var) = &vars->data[vars->top - 4] +3210 # var min = vars->data +3211 # while curr >= min +3212 # var v : (handle var) = *curr +3213 # if v->name == name +3214 # return v +3215 # return 0 +3216 # +3217 # . prologue +3218 55/push-ebp +3219 89/<- %ebp 4/r32/esp +3220 # . save registers +3221 52/push-edx +3222 53/push-ebx +3223 56/push-esi +3224 # esi = vars +3225 8b/-> *(ebp+0xc) 6/r32/esi +3226 # ebx = vars->top +3227 8b/-> *esi 3/r32/ebx +3228 # if (vars->top > vars->length) abort +3229 3b/compare 0/r32/eax *(esi+4) +3230 0f 8f/jump-if-> $lookup-var-helper:error1/disp32 +3231 # var min/edx : (addr handle var) = vars->data +3232 8d/copy-address *(esi+8) 2/r32/edx +3233 # var curr/ebx : (addr handle var) = &vars->data[vars->top - 4] +3234 81 5/subop/subtract %ebx 4/imm32 +3235 8d/copy-address *(esi+ebx+8) 3/r32/ebx +3236 { +3237 # if (curr < min) return 0 +3238 39/compare %ebx 2/r32/edx +3239 b8/copy-to-eax 0/imm32 +3240 0f 82/jump-if-addr< break/disp32 +3241 # var v/eax : (handle var) = *curr +3242 8b/-> *ebx 0/r32/eax +3243 # if (v->name == name) return v +3244 (string-equal? *eax *(ebp+8)) # Var-name +3245 3d/compare-eax-and 0/imm32 +3246 8b/-> *ebx 0/r32/eax +3247 75/jump-if-!= break/disp8 +3248 # curr -= 4 +3249 81 5/subop/subtract %ebx 4/imm32 +3250 e9/jump loop/disp32 +3251 } +3252 $lookup-var-helper:end: +3253 # . restore registers +3254 5e/pop-to-esi +3255 5b/pop-to-ebx +3256 5a/pop-to-edx +3257 # . epilogue +3258 89/<- %esp 5/r32/ebp +3259 5d/pop-to-ebp +3260 c3/return +3261 +3262 $lookup-var-helper:error1: +3263 (write-buffered Stderr "malformed stack when looking up '") +3264 (write-slice-buffered Stderr *(ebp+8)) +3265 (write-buffered Stderr "'\n") +3266 (flush Stderr) +3267 # . syscall(exit, 1) +3268 bb/copy-to-ebx 1/imm32 +3269 b8/copy-to-eax 1/imm32/exit +3270 cd/syscall 0x80/imm8 +3271 # never gets here +3272 +3273 # return first 'name' from the top (back) of 'vars' and create a new var for a fn output if not found +3274 lookup-or-define-var: # name: (addr slice), vars : (addr stack (handle var)), fn : (handle function) -> result/eax: (handle var) +3275 # . prologue +3276 55/push-ebp +3277 89/<- %ebp 4/r32/esp +3278 # . save registers +3279 51/push-ecx +3280 # var target/ecx : (handle array byte) = slice-to-string(name) +3281 (slice-to-string Heap *(ebp+8)) # => eax +3282 89/<- %ecx 0/r32/eax +3283 # +3284 (lookup-var-helper *(ebp+8) *(ebp+0xc)) # => eax +3285 { +3286 # if (result != 0) return +3287 3d/compare-eax-and 0/imm32 +3288 75/jump-if-!= break/disp8 +3289 # if name is one of fn's outputs, return it +3290 { +3291 (find-in-function-outputs *(ebp+0x10) %ecx) # => eax +3292 3d/compare-eax-and 0/imm32 +3293 # otherwise abort +3294 0f 84/jump-if-!= $lookup-var:abort/disp32 +3295 } +3296 } +3297 $lookup-or-define-var:end: +3298 # . restore registers +3299 59/pop-to-ecx +3300 # . epilogue +3301 89/<- %esp 5/r32/ebp +3302 5d/pop-to-ebp +3303 c3/return +3304 +3305 find-in-function-outputs: # fn : (handle function), name : (handle array byte) => result/eax : (handle var) +3306 # . prologue +3307 55/push-ebp +3308 89/<- %ebp 4/r32/esp +3309 # . save registers +3310 51/push-ecx +3311 # var curr/ecx : (handle list var) = fn->outputs +3312 8b/-> *(ebp+8) 1/r32/ecx +3313 8b/-> *(ecx+0xc) 1/r32/ecx +3314 # while curr != null +3315 { +3316 81 7/subop/compare %ecx 0/imm32 +3317 74/jump-if-= break/disp8 +3318 # var v : (handle var) = *curr +3319 8b/-> *ecx 0/r32/eax # List-value +3320 # if (curr->name == name) return curr +3321 50/push-eax +3322 (string-equal? *eax *(ebp+0xc)) +3323 3d/compare-eax-and 0/imm32 +3324 58/pop-to-eax +3325 75/jump-if-!= $find-in-function-outputs:end/disp8 +3326 # curr = curr->next +3327 8b/-> *(ecx+4) 1/r32/ecx # List-next +3328 eb/jump loop/disp8 +3329 } +3330 b8/copy-to-eax 0/imm32 +3331 $find-in-function-outputs:end: +3332 # . restore registers +3333 59/pop-to-ecx +3334 # . epilogue +3335 89/<- %esp 5/r32/ebp +3336 5d/pop-to-ebp +3337 c3/return +3338 +3339 test-parse-mu-stmt: +3340 # 'increment n' +3341 # . prologue +3342 55/push-ebp +3343 89/<- %ebp 4/r32/esp +3344 # setup +3345 (clear-stream _test-input-stream) +3346 (write _test-input-stream "increment n\n") +3347 # var vars/ecx : (stack (addr var) 4) +3348 81 5/subop/subtract %esp 0x10/imm32 +3349 68/push 0x10/imm32/length +3350 68/push 0/imm32/top +3351 89/<- %ecx 4/r32/esp +3352 (clear-stack %ecx) +3353 # var v/edx : var +3354 81 5/subop/subtract %esp 0x14/imm32 # Var-size +3355 89/<- %edx 4/r32/esp +3356 (zero-out %edx 0x14) +3357 # v->name = "n" +3358 c7 0/subop/copy *edx "n"/imm32 # Var-name +3359 # +3360 (push %ecx %edx) +3361 # convert +3362 (parse-mu-stmt _test-input-stream %ecx) # => eax +3363 # check result +3364 (check-ints-equal *eax 1 "F - test-parse-mu-stmt/tag") # Stmt-tag is Stmt1 +3365 (check-strings-equal *(eax+4) "increment" "F - test-parse-mu-stmt/name") # Stmt1-operation +3366 # edx : (handle list var) = result->inouts +3367 8b/-> *(eax+8) 2/r32/edx # Stmt1-inouts +3368 # ebx : (handle var) = result->inouts->value +3369 8b/-> *edx 3/r32/ebx # List-value +3370 (check-strings-equal *ebx "n" "F - test-parse-mu-stmt/inout:0") # Var-name +3371 # . epilogue +3372 89/<- %esp 5/r32/ebp +3373 5d/pop-to-ebp +3374 c3/return +3375 +3376 new-function: # ad: (addr allocation-descriptor), name: (addr array byte), subx-name: (addr array byte), inouts: (handle list var), outputs: (handle list var), body: (handle block), next: (handle function) -> result/eax: (handle function) +3377 # . prologue +3378 55/push-ebp +3379 89/<- %ebp 4/r32/esp +3380 # . save registers +3381 51/push-ecx +3382 # +3383 (allocate *(ebp+8) *Function-size) # => eax +3384 8b/-> *(ebp+0xc) 1/r32/ecx +3385 89/<- *eax 1/r32/ecx # Function-name +3386 8b/-> *(ebp+0x10) 1/r32/ecx +3387 89/<- *(eax+4) 1/r32/ecx # Function-subx-name +3388 8b/-> *(ebp+0x14) 1/r32/ecx +3389 89/<- *(eax+8) 1/r32/ecx # Function-inouts +3390 8b/-> *(ebp+0x18) 1/r32/ecx +3391 89/<- *(eax+0xc) 1/r32/ecx # Function-outputs +3392 8b/-> *(ebp+0x1c) 1/r32/ecx +3393 89/<- *(eax+0x10) 1/r32/ecx # Function-body +3394 8b/-> *(ebp+0x20) 1/r32/ecx +3395 89/<- *(eax+0x14) 1/r32/ecx # Function-next +3396 $new-function:end: +3397 # . restore registers +3398 59/pop-to-ecx +3399 # . epilogue +3400 89/<- %esp 5/r32/ebp +3401 5d/pop-to-ebp +3402 c3/return +3403 +3404 new-var: # ad: (addr allocation-descriptor), name: (addr array byte), type: int, block: int, stack-offset: int, register: (addr array byte) -> result/eax: (handle var) +3405 # . prologue +3406 55/push-ebp +3407 89/<- %ebp 4/r32/esp +3408 # . save registers +3409 51/push-ecx +3410 # +3411 (allocate *(ebp+8) *Var-size) # => eax +3412 8b/-> *(ebp+0xc) 1/r32/ecx +3413 89/<- *eax 1/r32/ecx # Var-name +3414 8b/-> *(ebp+0x10) 1/r32/ecx +3415 89/<- *(eax+4) 1/r32/ecx # Var-type +3416 8b/-> *(ebp+0x14) 1/r32/ecx +3417 89/<- *(eax+8) 1/r32/ecx # Var-block +3418 8b/-> *(ebp+0x18) 1/r32/ecx +3419 89/<- *(eax+0xc) 1/r32/ecx # Var-stack-offset +3420 8b/-> *(ebp+0x1c) 1/r32/ecx +3421 89/<- *(eax+0x10) 1/r32/ecx # Var-register +3422 $new-var:end: +3423 # . restore registers +3424 59/pop-to-ecx +3425 # . epilogue +3426 89/<- %esp 5/r32/ebp +3427 5d/pop-to-ebp +3428 c3/return +3429 +3430 new-literal-integer: # ad: (addr allocation-descriptor), name: (addr slice) -> result/eax: (handle var) +3431 # . prologue +3432 55/push-ebp +3433 89/<- %ebp 4/r32/esp +3434 # . save registers +3435 51/push-ecx +3436 # if (!is-hex-int?(name)) abort +3437 (is-hex-int? *(ebp+0xc)) # => eax +3438 3d/compare-eax-and 0/imm32 +3439 0f 84/jump-if-= $new-literal-integer:abort/disp32 +3440 # var s/ecx : (addr array byte) +3441 (slice-to-string Heap *(ebp+0xc)) # => eax +3442 89/<- %ecx 0/r32/eax 3443 # -3444 (allocate *(ebp+8) *List-size) # => eax -3445 8b/-> *(ebp+0xc) 1/r32/ecx -3446 89/<- *eax 1/r32/ecx # List-value -3447 8b/-> *(ebp+0x10) 1/r32/ecx -3448 89/<- *(eax+4) 1/r32/ecx # List-next -3449 $new-list:end: -3450 # . restore registers -3451 59/pop-to-ecx -3452 # . epilogue -3453 89/<- %esp 5/r32/ebp -3454 5d/pop-to-ebp -3455 c3/return -3456 -3457 append-list: # ad: (addr allocation-descriptor), value: _type, list: (handle list _type) -> result/eax : (handle list _type) -3458 # . prologue -3459 55/push-ebp -3460 89/<- %ebp 4/r32/esp -3461 # . save registers -3462 51/push-ecx -3463 # -3464 (allocate *(ebp+8) *List-size) # => eax -3465 8b/-> *(ebp+0xc) 1/r32/ecx -3466 89/<- *eax 1/r32/ecx # List-value -3467 # if (list == null) return result -3468 81 7/subop/compare *(ebp+0x10) 0/imm32 -3469 74/jump-if-= $new-list:end/disp8 -3470 # otherwise append -3471 # var curr/ecx = list -3472 8b/-> *(ebp+0x10) 1/r32/ecx -3473 # while (curr->next != null) curr = curr->next -3474 { -3475 81 7/subop/compare *(ecx+4) 0/imm32 # List-next -3476 74/jump-if-= break/disp8 -3477 # curr = curr->next -3478 8b/-> *(ecx+4) 1/r32/ecx -3479 eb/jump loop/disp8 -3480 } -3481 # curr->next = result -3482 89/<- *(ecx+4) 0/r32/eax -3483 # return list -3484 8b/-> *(ebp+0x10) 0/r32/eax -3485 $append-list:end: -3486 # . restore registers -3487 59/pop-to-ecx -3488 # . epilogue -3489 89/<- %esp 5/r32/ebp -3490 5d/pop-to-ebp -3491 c3/return -3492 -3493 append-to-block: # ad: (addr allocation-descriptor), block: (handle block), x: (handle stmt) -3494 # . prologue -3495 55/push-ebp -3496 89/<- %ebp 4/r32/esp -3497 # . save registers -3498 56/push-esi -3499 # esi = block -3500 8b/-> *(ebp+0xc) 6/r32/esi -3501 (append-list *(ebp+8) *(ebp+0x10) *(esi+4)) # ad, x, Block-statements -3502 89/<- *(esi+4) 0/r32/eax # Block-statements -3503 $append-to-block:end: -3504 # . restore registers -3505 5e/pop-to-esi -3506 # . epilogue -3507 89/<- %esp 5/r32/ebp -3508 5d/pop-to-ebp -3509 c3/return -3510 -3511 ####################################################### -3512 # Type-checking -3513 ####################################################### -3514 -3515 check-mu-types: -3516 # . prologue -3517 55/push-ebp -3518 89/<- %ebp 4/r32/esp +3444 (allocate *(ebp+8) *Var-size) # => eax +3445 89/<- *eax 1/r32/ecx # Var-name +3446 89/<- %ecx 0/r32/eax +3447 (allocate *(ebp+8) *Tree-size) # => eax +3448 89/<- *(ecx+4) 0/r32/eax # Var-type +3449 89/<- %eax 1/r32/ecx +3450 c7 0/subop/copy *(eax+8) 0/imm32 # Var-block +3451 c7 0/subop/copy *(eax+0xc) 0/imm32 # Var-stack-offset +3452 c7 0/subop/copy *(eax+0x10) 0/imm32 # Var-register +3453 $new-literal-integer:end: +3454 # . restore registers +3455 59/pop-to-ecx +3456 # . epilogue +3457 89/<- %esp 5/r32/ebp +3458 5d/pop-to-ebp +3459 c3/return +3460 +3461 $new-literal-integer:abort: +3462 (write-buffered Stderr "variable cannot begin with a digit '") +3463 (write-slice-buffered Stderr *(ebp+0xc)) +3464 (write-buffered Stderr "'\n") +3465 (flush Stderr) +3466 # . syscall(exit, 1) +3467 bb/copy-to-ebx 1/imm32 +3468 b8/copy-to-eax 1/imm32/exit +3469 cd/syscall 0x80/imm8 +3470 # never gets here +3471 +3472 new-block: # ad: (addr allocation-descriptor), data: (handle list statement) -> result/eax: (handle statement) +3473 # . prologue +3474 55/push-ebp +3475 89/<- %ebp 4/r32/esp +3476 # . save registers +3477 51/push-ecx +3478 # +3479 (allocate *(ebp+8) *Stmt-size) # => eax +3480 (zero-out %eax *Stmt-size) +3481 c7 0/subop/copy *eax 0/imm32/tag/block # Stmt-tag +3482 8b/-> *(ebp+0xc) 1/r32/ecx +3483 89/<- *(eax+4) 1/r32/ecx # Block-statements +3484 $new-block:end: +3485 # . restore registers +3486 59/pop-to-ecx +3487 # . epilogue +3488 89/<- %esp 5/r32/ebp +3489 5d/pop-to-ebp +3490 c3/return +3491 +3492 new-vardef: # ad: (addr allocation-descriptor), var: (handle var) -> result/eax: (handle statement) +3493 # . prologue +3494 55/push-ebp +3495 89/<- %ebp 4/r32/esp +3496 # . save registers +3497 51/push-ecx +3498 # +3499 (allocate *(ebp+8) *Stmt-size) # => eax +3500 (zero-out %eax *Stmt-size) +3501 c7 0/subop/copy *eax 2/imm32/tag/var-on-stack # Stmt-tag +3502 # result->var = var +3503 8b/-> *(ebp+0xc) 1/r32/ecx +3504 89/<- *(eax+4) 1/r32/ecx # Vardef-var +3505 $new-vardef:end: +3506 # . restore registers +3507 59/pop-to-ecx +3508 # . epilogue +3509 89/<- %esp 5/r32/ebp +3510 5d/pop-to-ebp +3511 c3/return +3512 +3513 new-regvardef: # ad: (addr allocation-descriptor), var: (handle var) -> result/eax: (handle statement) +3514 # . prologue +3515 55/push-ebp +3516 89/<- %ebp 4/r32/esp +3517 # . save registers +3518 51/push-ecx 3519 # -3520 $check-mu-types:end: -3521 # . epilogue -3522 89/<- %esp 5/r32/ebp -3523 5d/pop-to-ebp -3524 c3/return -3525 -3526 size-of: # n : (addr var) -3527 # . prologue -3528 55/push-ebp -3529 89/<- %ebp 4/r32/esp -3530 # hard-coded since we only support 'int' types for now -3531 b8/copy-to-eax 4/imm32 -3532 $size-of:end: -3533 # . epilogue -3534 89/<- %esp 5/r32/ebp -3535 5d/pop-to-ebp -3536 c3/return -3537 -3538 ####################################################### -3539 # Code-generation -3540 ####################################################### -3541 -3542 emit-subx: # out : (addr buffered-file) -3543 # . prologue -3544 55/push-ebp -3545 89/<- %ebp 4/r32/esp -3546 # . save registers -3547 50/push-eax -3548 51/push-ecx -3549 57/push-edi -3550 # edi = out -3551 8b/-> *(ebp+8) 7/r32/edi -3552 # var curr/ecx : (handle function) = *Program -3553 8b/-> *Program 1/r32/ecx -3554 { -3555 # if (curr == null) break -3556 81 7/subop/compare %ecx 0/imm32 -3557 0f 84/jump-if-= break/disp32 -3558 (emit-subx-function %edi %ecx) -3559 # curr = curr->next -3560 8b/-> *(ecx+0x14) 1/r32/ecx # Function-next -3561 e9/jump loop/disp32 -3562 } -3563 $emit-subx:end: -3564 # . restore registers -3565 5f/pop-to-edi -3566 59/pop-to-ecx -3567 58/pop-to-eax -3568 # . epilogue -3569 89/<- %esp 5/r32/ebp -3570 5d/pop-to-ebp -3571 c3/return -3572 -3573 emit-subx-function: # out : (addr buffered-file), f : (handle function) -3574 # . prologue -3575 55/push-ebp -3576 89/<- %ebp 4/r32/esp -3577 # . save registers -3578 50/push-eax -3579 51/push-ecx -3580 57/push-edi -3581 # edi = out -3582 8b/-> *(ebp+8) 7/r32/edi -3583 # ecx = f -3584 8b/-> *(ebp+0xc) 1/r32/ecx -3585 # -3586 (write-buffered %edi *ecx) -3587 (write-buffered %edi ":\n") -3588 (emit-subx-prologue %edi) -3589 (emit-subx-block %edi *(ecx+0x10)) # Function-body -3590 (emit-subx-epilogue %edi) -3591 $emit-subx-function:end: -3592 # . restore registers -3593 5f/pop-to-edi -3594 59/pop-to-ecx -3595 58/pop-to-eax -3596 # . epilogue -3597 89/<- %esp 5/r32/ebp -3598 5d/pop-to-ebp -3599 c3/return -3600 -3601 emit-subx-block: # out : (addr buffered-file), block : (handle block) -3602 # . prologue -3603 55/push-ebp -3604 89/<- %ebp 4/r32/esp -3605 # curr/esi : (handle list statement) = block->statements -3606 8b/-> *(ebp+0xc) 6/r32/esi -3607 8b/-> *(esi+4) 6/r32/esi # Block-statements -3608 # -3609 { -3610 $emit-subx-block:check-empty: -3611 81 7/subop/compare %esi 0/imm32 -3612 0f 84/jump-if-= break/disp32 -3613 (write-buffered *(ebp+8) "{\n") -3614 { -3615 $emit-subx-block:stmt: -3616 81 7/subop/compare %esi 0/imm32 -3617 74/jump-if-= break/disp8 -3618 (emit-subx-statement *(ebp+8) *esi Primitives *Program) -3619 (write-buffered *(ebp+8) Newline) -3620 8b/-> *(esi+4) 6/r32/esi # List-next -3621 eb/jump loop/disp8 -3622 } -3623 (write-buffered *(ebp+8) "}\n") -3624 } -3625 $emit-subx-block:end: -3626 # . epilogue -3627 89/<- %esp 5/r32/ebp -3628 5d/pop-to-ebp -3629 c3/return -3630 -3631 emit-subx-statement: # out : (addr buffered-file), stmt : (handle statement), primitives : (handle primitive), functions : (handle function) -3632 # . prologue -3633 55/push-ebp -3634 89/<- %ebp 4/r32/esp -3635 # . save registers -3636 50/push-eax -3637 51/push-ecx -3638 # if stmt matches a primitive, emit it -3639 { -3640 $emit-subx-statement:primitive: -3641 (find-matching-primitive *(ebp+0x10) *(ebp+0xc)) # primitives, stmt => curr/eax -3642 3d/compare-eax-and 0/imm32 -3643 74/jump-if-= break/disp8 -3644 (emit-subx-primitive *(ebp+8) *(ebp+0xc) %eax) # out, stmt, curr -3645 e9/jump $emit-subx-statement:end/disp32 -3646 } -3647 # else if stmt matches a function, emit a call to it -3648 { -3649 $emit-subx-statement:call: -3650 (find-matching-function *(ebp+0x14) *(ebp+0xc)) # functions, stmt => curr/eax -3651 3d/compare-eax-and 0/imm32 -3652 74/jump-if-= break/disp8 -3653 (emit-subx-call *(ebp+8) *(ebp+0xc) %eax) # out, stmt, curr -3654 e9/jump $emit-subx-statement:end/disp32 -3655 } -3656 # else abort -3657 e9/jump $emit-subx-statement:abort/disp32 -3658 $emit-subx-statement:end: -3659 # . restore registers -3660 59/pop-to-ecx -3661 58/pop-to-eax -3662 # . epilogue -3663 89/<- %esp 5/r32/ebp -3664 5d/pop-to-ebp -3665 c3/return -3666 -3667 $emit-subx-statement:abort: -3668 # error("couldn't translate '" stmt "'\n") -3669 (write-buffered Stderr "couldn't translate '") -3670 #? (emit-string Stderr *(ebp+0xc)) # TODO -3671 (write-buffered Stderr "'\n") -3672 (flush Stderr) -3673 # . syscall(exit, 1) -3674 bb/copy-to-ebx 1/imm32 -3675 b8/copy-to-eax 1/imm32/exit -3676 cd/syscall 0x80/imm8 -3677 # never gets here -3678 -3679 # Primitives supported -3680 # For each operation, put variants with hard-coded registers before flexible ones. -3681 == data -3682 Primitives: -3683 # - increment/decrement -3684 _Primitive-inc-eax: -3685 # var/eax <- increment => 40/increment-eax -3686 "increment"/imm32/name -3687 0/imm32/no-inouts -3688 Single-int-var-in-eax/imm32/outputs -3689 "40/increment-eax"/imm32/subx-name -3690 0/imm32/no-rm32 -3691 0/imm32/no-r32 -3692 0/imm32/no-imm32 -3693 0/imm32/output-is-write-only -3694 _Primitive-inc-ecx/imm32/next -3695 _Primitive-inc-ecx: -3696 # var/ecx <- increment => 41/increment-ecx -3697 "increment"/imm32/name -3698 0/imm32/no-inouts -3699 Single-int-var-in-ecx/imm32/outputs -3700 "41/increment-ecx"/imm32/subx-name -3701 0/imm32/no-rm32 -3702 0/imm32/no-r32 -3703 0/imm32/no-imm32 -3704 0/imm32/output-is-write-only -3705 _Primitive-inc-edx/imm32/next -3706 _Primitive-inc-edx: -3707 # var/edx <- increment => 42/increment-edx -3708 "increment"/imm32/name -3709 0/imm32/no-inouts -3710 Single-int-var-in-edx/imm32/outputs -3711 "42/increment-edx"/imm32/subx-name -3712 0/imm32/no-rm32 -3713 0/imm32/no-r32 -3714 0/imm32/no-imm32 -3715 0/imm32/output-is-write-only -3716 _Primitive-inc-ebx/imm32/next -3717 _Primitive-inc-ebx: -3718 # var/ebx <- increment => 43/increment-ebx -3719 "increment"/imm32/name -3720 0/imm32/no-inouts -3721 Single-int-var-in-ebx/imm32/outputs -3722 "43/increment-ebx"/imm32/subx-name -3723 0/imm32/no-rm32 -3724 0/imm32/no-r32 -3725 0/imm32/no-imm32 -3726 0/imm32/output-is-write-only -3727 _Primitive-inc-esi/imm32/next -3728 _Primitive-inc-esi: -3729 # var/esi <- increment => 46/increment-esi -3730 "increment"/imm32/name -3731 0/imm32/no-inouts -3732 Single-int-var-in-esi/imm32/outputs -3733 "46/increment-esi"/imm32/subx-name -3734 0/imm32/no-rm32 -3735 0/imm32/no-r32 -3736 0/imm32/no-imm32 -3737 0/imm32/output-is-write-only -3738 _Primitive-inc-edi/imm32/next -3739 _Primitive-inc-edi: -3740 # var/edi <- increment => 47/increment-edi -3741 "increment"/imm32/name -3742 0/imm32/no-inouts -3743 Single-int-var-in-edi/imm32/outputs -3744 "47/increment-edi"/imm32/subx-name -3745 0/imm32/no-rm32 -3746 0/imm32/no-r32 -3747 0/imm32/no-imm32 -3748 0/imm32/output-is-write-only -3749 _Primitive-dec-eax/imm32/next -3750 _Primitive-dec-eax: -3751 # var/eax <- decrement => 48/decrement-eax -3752 "decrement"/imm32/name -3753 0/imm32/no-inouts -3754 Single-int-var-in-eax/imm32/outputs -3755 "48/decrement-eax"/imm32/subx-name -3756 0/imm32/no-rm32 -3757 0/imm32/no-r32 -3758 0/imm32/no-imm32 -3759 0/imm32/output-is-write-only -3760 _Primitive-dec-ecx/imm32/next -3761 _Primitive-dec-ecx: -3762 # var/ecx <- decrement => 49/decrement-ecx -3763 "decrement"/imm32/name -3764 0/imm32/no-inouts -3765 Single-int-var-in-ecx/imm32/outputs -3766 "49/decrement-ecx"/imm32/subx-name -3767 0/imm32/no-rm32 -3768 0/imm32/no-r32 -3769 0/imm32/no-imm32 -3770 0/imm32/output-is-write-only -3771 _Primitive-dec-edx/imm32/next -3772 _Primitive-dec-edx: -3773 # var/edx <- decrement => 4a/decrement-edx -3774 "decrement"/imm32/name -3775 0/imm32/no-inouts -3776 Single-int-var-in-edx/imm32/outputs -3777 "4a/decrement-edx"/imm32/subx-name -3778 0/imm32/no-rm32 -3779 0/imm32/no-r32 -3780 0/imm32/no-imm32 -3781 0/imm32/output-is-write-only -3782 _Primitive-dec-ebx/imm32/next -3783 _Primitive-dec-ebx: -3784 # var/ebx <- decrement => 4b/decrement-ebx -3785 "decrement"/imm32/name -3786 0/imm32/no-inouts -3787 Single-int-var-in-ebx/imm32/outputs -3788 "4b/decrement-ebx"/imm32/subx-name -3789 0/imm32/no-rm32 -3790 0/imm32/no-r32 -3791 0/imm32/no-imm32 -3792 0/imm32/output-is-write-only -3793 _Primitive-dec-esi/imm32/next -3794 _Primitive-dec-esi: -3795 # var/esi <- decrement => 4e/decrement-esi -3796 "decrement"/imm32/name -3797 0/imm32/no-inouts -3798 Single-int-var-in-esi/imm32/outputs -3799 "4e/decrement-esi"/imm32/subx-name -3800 0/imm32/no-rm32 -3801 0/imm32/no-r32 -3802 0/imm32/no-imm32 -3803 0/imm32/output-is-write-only -3804 _Primitive-dec-edi/imm32/next -3805 _Primitive-dec-edi: -3806 # var/edi <- decrement => 4f/decrement-edi -3807 "decrement"/imm32/name -3808 0/imm32/no-inouts -3809 Single-int-var-in-edi/imm32/outputs -3810 "4f/decrement-edi"/imm32/subx-name -3811 0/imm32/no-rm32 -3812 0/imm32/no-r32 -3813 0/imm32/no-imm32 -3814 0/imm32/output-is-write-only -3815 _Primitive-inc-mem/imm32/next -3816 _Primitive-inc-mem: -3817 # increment var => ff 0/subop/increment *(ebp+__) -3818 "increment"/imm32/name -3819 Single-int-var-on-stack/imm32/inouts -3820 0/imm32/no-outputs -3821 "ff 0/subop/increment"/imm32/subx-name -3822 1/imm32/rm32-is-first-inout -3823 0/imm32/no-r32 -3824 0/imm32/no-imm32 -3825 0/imm32/output-is-write-only -3826 _Primitive-inc-reg/imm32/next -3827 _Primitive-inc-reg: -3828 # var/reg <- increment => ff 0/subop/increment %__ -3829 "increment"/imm32/name -3830 0/imm32/no-inouts -3831 Single-int-var-in-some-register/imm32/outputs -3832 "ff 0/subop/increment"/imm32/subx-name -3833 3/imm32/rm32-is-first-output -3834 0/imm32/no-r32 -3835 0/imm32/no-imm32 -3836 0/imm32/output-is-write-only -3837 _Primitive-dec-mem/imm32/next -3838 _Primitive-dec-mem: -3839 # decrement var => ff 1/subop/decrement *(ebp+__) -3840 "decrement"/imm32/name -3841 Single-int-var-on-stack/imm32/inouts -3842 0/imm32/no-outputs -3843 "ff 1/subop/decrement"/imm32/subx-name -3844 1/imm32/rm32-is-first-inout -3845 0/imm32/no-r32 -3846 0/imm32/no-imm32 -3847 0/imm32/output-is-write-only -3848 _Primitive-dec-reg/imm32/next -3849 _Primitive-dec-reg: -3850 # var/reg <- decrement => ff 1/subop/decrement %__ -3851 "decrement"/imm32/name -3852 0/imm32/no-inouts -3853 Single-int-var-in-some-register/imm32/outputs -3854 "ff 1/subop/decrement"/imm32/subx-name -3855 3/imm32/rm32-is-first-output -3856 0/imm32/no-r32 -3857 0/imm32/no-imm32 -3858 0/imm32/output-is-write-only -3859 _Primitive-add-to-eax/imm32/next -3860 # - add -3861 _Primitive-add-to-eax: -3862 # var/eax <- add lit => 05/add-to-eax lit/imm32 -3863 "add"/imm32/name -3864 Single-lit-var/imm32/inouts -3865 Single-int-var-in-eax/imm32/outputs -3866 "05/add-to-eax"/imm32/subx-name -3867 0/imm32/no-rm32 -3868 0/imm32/no-r32 -3869 1/imm32/imm32-is-first-inout -3870 0/imm32/output-is-write-only -3871 _Primitive-add-reg-to-reg/imm32/next -3872 _Primitive-add-reg-to-reg: -3873 # var1/reg <- add var2/reg => 01/add-to var1/rm32 var2/r32 -3874 "add"/imm32/name -3875 Single-int-var-in-some-register/imm32/inouts -3876 Single-int-var-in-some-register/imm32/outputs -3877 "01/add-to"/imm32/subx-name -3878 3/imm32/rm32-is-first-output -3879 1/imm32/r32-is-first-inout -3880 0/imm32/no-imm32 -3881 0/imm32/output-is-write-only -3882 _Primitive-add-reg-to-mem/imm32/next -3883 _Primitive-add-reg-to-mem: -3884 # add-to var1 var2/reg => 01/add-to var1 var2/r32 -3885 "add-to"/imm32/name -3886 Int-var-and-second-int-var-in-some-register/imm32/inouts -3887 0/imm32/outputs -3888 "01/add-to"/imm32/subx-name -3889 1/imm32/rm32-is-first-inout -3890 2/imm32/r32-is-second-inout -3891 0/imm32/no-imm32 -3892 0/imm32/output-is-write-only -3893 _Primitive-add-mem-to-reg/imm32/next -3894 _Primitive-add-mem-to-reg: -3895 # var1/reg <- add var2 => 03/add var2/rm32 var1/r32 -3896 "add"/imm32/name -3897 Single-int-var-on-stack/imm32/inouts -3898 Single-int-var-in-some-register/imm32/outputs -3899 "03/add"/imm32/subx-name -3900 1/imm32/rm32-is-first-inout -3901 3/imm32/r32-is-first-output -3902 0/imm32/no-imm32 -3903 0/imm32/output-is-write-only -3904 _Primitive-add-lit-to-reg/imm32/next -3905 _Primitive-add-lit-to-reg: -3906 # var1/reg <- add lit => 81 0/subop/add var1/rm32 lit/imm32 -3907 "add"/imm32/name -3908 Single-lit-var/imm32/inouts -3909 Single-int-var-in-some-register/imm32/outputs -3910 "81 0/subop/add"/imm32/subx-name -3911 3/imm32/rm32-is-first-output -3912 0/imm32/no-r32 -3913 1/imm32/imm32-is-first-inout -3914 0/imm32/output-is-write-only -3915 _Primitive-add-lit-to-mem/imm32/next -3916 _Primitive-add-lit-to-mem: -3917 # add-to var1, lit => 81 0/subop/add var1/rm32 lit/imm32 -3918 "add-to"/imm32/name -3919 Int-var-and-literal/imm32/inouts -3920 0/imm32/outputs -3921 "81 0/subop/add"/imm32/subx-name -3922 1/imm32/rm32-is-first-inout -3923 0/imm32/no-r32 -3924 2/imm32/imm32-is-first-inout -3925 0/imm32/output-is-write-only -3926 _Primitive-subtract-from-eax/imm32/next -3927 # - subtract -3928 _Primitive-subtract-from-eax: -3929 # var/eax <- subtract lit => 2d/subtract-from-eax lit/imm32 -3930 "subtract"/imm32/name -3931 Single-lit-var/imm32/inouts -3932 Single-int-var-in-eax/imm32/outputs -3933 "2d/subtract-from-eax"/imm32/subx-name -3934 0/imm32/no-rm32 -3935 0/imm32/no-r32 -3936 1/imm32/imm32-is-first-inout -3937 0/imm32/output-is-write-only -3938 _Primitive-subtract-reg-from-reg/imm32/next -3939 _Primitive-subtract-reg-from-reg: -3940 # var1/reg <- subtract var2/reg => 29/subtract-from var1/rm32 var2/r32 -3941 "subtract"/imm32/name -3942 Single-int-var-in-some-register/imm32/inouts -3943 Single-int-var-in-some-register/imm32/outputs -3944 "29/subtract-from"/imm32/subx-name -3945 3/imm32/rm32-is-first-output -3946 1/imm32/r32-is-first-inout -3947 0/imm32/no-imm32 -3948 0/imm32/output-is-write-only -3949 _Primitive-subtract-reg-from-mem/imm32/next -3950 _Primitive-subtract-reg-from-mem: -3951 # subtract-from var1 var2/reg => 29/subtract-from var1 var2/r32 -3952 "subtract-from"/imm32/name -3953 Int-var-and-second-int-var-in-some-register/imm32/inouts -3954 0/imm32/outputs -3955 "29/subtract-from"/imm32/subx-name -3956 1/imm32/rm32-is-first-inout -3957 2/imm32/r32-is-second-inout -3958 0/imm32/no-imm32 -3959 0/imm32/output-is-write-only -3960 _Primitive-subtract-mem-from-reg/imm32/next -3961 _Primitive-subtract-mem-from-reg: -3962 # var1/reg <- subtract var2 => 2b/subtract var2/rm32 var1/r32 -3963 "subtract"/imm32/name -3964 Single-int-var-on-stack/imm32/inouts -3965 Single-int-var-in-some-register/imm32/outputs -3966 "2b/subtract"/imm32/subx-name -3967 1/imm32/rm32-is-first-inout -3968 3/imm32/r32-is-first-output -3969 0/imm32/no-imm32 -3970 0/imm32/output-is-write-only -3971 _Primitive-subtract-lit-from-reg/imm32/next -3972 _Primitive-subtract-lit-from-reg: -3973 # var1/reg <- subtract lit => 81 5/subop/subtract var1/rm32 lit/imm32 -3974 "subtract"/imm32/name -3975 Single-lit-var/imm32/inouts -3976 Single-int-var-in-some-register/imm32/outputs -3977 "81 5/subop/subtract"/imm32/subx-name -3978 3/imm32/rm32-is-first-output -3979 0/imm32/no-r32 -3980 1/imm32/imm32-is-first-inout -3981 0/imm32/output-is-write-only -3982 _Primitive-subtract-lit-from-mem/imm32/next -3983 _Primitive-subtract-lit-from-mem: -3984 # subtract-from var1, lit => 81 5/subop/subtract var1/rm32 lit/imm32 -3985 "subtract-from"/imm32/name -3986 Int-var-and-literal/imm32/inouts -3987 0/imm32/outputs -3988 "81 5/subop/subtract"/imm32/subx-name -3989 1/imm32/rm32-is-first-inout -3990 0/imm32/no-r32 -3991 2/imm32/imm32-is-first-inout -3992 0/imm32/output-is-write-only -3993 _Primitive-and-with-eax/imm32/next -3994 # - and -3995 _Primitive-and-with-eax: -3996 # var/eax <- and lit => 25/and-with-eax lit/imm32 -3997 "and"/imm32/name -3998 Single-lit-var/imm32/inouts -3999 Single-int-var-in-eax/imm32/outputs -4000 "25/and-with-eax"/imm32/subx-name -4001 0/imm32/no-rm32 -4002 0/imm32/no-r32 -4003 1/imm32/imm32-is-first-inout -4004 0/imm32/output-is-write-only -4005 _Primitive-and-reg-with-reg/imm32/next -4006 _Primitive-and-reg-with-reg: -4007 # var1/reg <- and var2/reg => 21/and-with var1/rm32 var2/r32 -4008 "and"/imm32/name -4009 Single-int-var-in-some-register/imm32/inouts -4010 Single-int-var-in-some-register/imm32/outputs -4011 "21/and-with"/imm32/subx-name -4012 3/imm32/rm32-is-first-output -4013 1/imm32/r32-is-first-inout -4014 0/imm32/no-imm32 -4015 0/imm32/output-is-write-only -4016 _Primitive-and-reg-with-mem/imm32/next -4017 _Primitive-and-reg-with-mem: -4018 # and-with var1 var2/reg => 21/and-with var1 var2/r32 -4019 "and-with"/imm32/name -4020 Int-var-and-second-int-var-in-some-register/imm32/inouts -4021 0/imm32/outputs -4022 "21/and-with"/imm32/subx-name -4023 1/imm32/rm32-is-first-inout -4024 2/imm32/r32-is-second-inout -4025 0/imm32/no-imm32 -4026 0/imm32/output-is-write-only -4027 _Primitive-and-mem-with-reg/imm32/next -4028 _Primitive-and-mem-with-reg: -4029 # var1/reg <- and var2 => 23/and var2/rm32 var1/r32 -4030 "and"/imm32/name -4031 Single-int-var-on-stack/imm32/inouts -4032 Single-int-var-in-some-register/imm32/outputs -4033 "23/and"/imm32/subx-name -4034 1/imm32/rm32-is-first-inout -4035 3/imm32/r32-is-first-output -4036 0/imm32/no-imm32 -4037 0/imm32/output-is-write-only -4038 _Primitive-and-lit-with-reg/imm32/next -4039 _Primitive-and-lit-with-reg: -4040 # var1/reg <- and lit => 81 4/subop/and var1/rm32 lit/imm32 -4041 "and"/imm32/name -4042 Single-lit-var/imm32/inouts -4043 Single-int-var-in-some-register/imm32/outputs -4044 "81 4/subop/and"/imm32/subx-name -4045 3/imm32/rm32-is-first-output -4046 0/imm32/no-r32 -4047 1/imm32/imm32-is-first-inout -4048 0/imm32/output-is-write-only -4049 _Primitive-and-lit-with-mem/imm32/next -4050 _Primitive-and-lit-with-mem: -4051 # and-with var1, lit => 81 4/subop/and var1/rm32 lit/imm32 -4052 "and-with"/imm32/name -4053 Int-var-and-literal/imm32/inouts -4054 0/imm32/outputs -4055 "81 4/subop/and"/imm32/subx-name -4056 1/imm32/rm32-is-first-inout -4057 0/imm32/no-r32 -4058 2/imm32/imm32-is-first-inout -4059 0/imm32/output-is-write-only -4060 _Primitive-or-with-eax/imm32/next -4061 # - or -4062 _Primitive-or-with-eax: -4063 # var/eax <- or lit => 0d/or-with-eax lit/imm32 -4064 "or"/imm32/name -4065 Single-lit-var/imm32/inouts -4066 Single-int-var-in-eax/imm32/outputs -4067 "0d/or-with-eax"/imm32/subx-name -4068 0/imm32/no-rm32 -4069 0/imm32/no-r32 -4070 1/imm32/imm32-is-first-inout -4071 0/imm32/output-is-write-only -4072 _Primitive-or-reg-with-reg/imm32/next -4073 _Primitive-or-reg-with-reg: -4074 # var1/reg <- or var2/reg => 09/or-with var1/rm32 var2/r32 -4075 "or"/imm32/name -4076 Single-int-var-in-some-register/imm32/inouts -4077 Single-int-var-in-some-register/imm32/outputs -4078 "09/or-with"/imm32/subx-name -4079 3/imm32/rm32-is-first-output -4080 1/imm32/r32-is-first-inout -4081 0/imm32/no-imm32 -4082 0/imm32/output-is-write-only -4083 _Primitive-or-reg-with-mem/imm32/next -4084 _Primitive-or-reg-with-mem: -4085 # or-with var1 var2/reg => 09/or-with var1 var2/r32 -4086 "or-with"/imm32/name -4087 Int-var-and-second-int-var-in-some-register/imm32/inouts -4088 0/imm32/outputs -4089 "09/or-with"/imm32/subx-name -4090 1/imm32/rm32-is-first-inout -4091 2/imm32/r32-is-second-inout -4092 0/imm32/no-imm32 -4093 0/imm32/output-is-write-only -4094 _Primitive-or-mem-with-reg/imm32/next -4095 _Primitive-or-mem-with-reg: -4096 # var1/reg <- or var2 => 0b/or var2/rm32 var1/r32 -4097 "or"/imm32/name -4098 Single-int-var-on-stack/imm32/inouts -4099 Single-int-var-in-some-register/imm32/outputs -4100 "0b/or"/imm32/subx-name -4101 1/imm32/rm32-is-first-inout -4102 3/imm32/r32-is-first-output -4103 0/imm32/no-imm32 -4104 0/imm32/output-is-write-only -4105 _Primitive-or-lit-with-reg/imm32/next -4106 _Primitive-or-lit-with-reg: -4107 # var1/reg <- or lit => 81 1/subop/or var1/rm32 lit/imm32 -4108 "or"/imm32/name -4109 Single-lit-var/imm32/inouts -4110 Single-int-var-in-some-register/imm32/outputs -4111 "81 4/subop/or"/imm32/subx-name -4112 3/imm32/rm32-is-first-output -4113 0/imm32/no-r32 -4114 1/imm32/imm32-is-first-inout -4115 0/imm32/output-is-write-only -4116 _Primitive-or-lit-with-mem/imm32/next -4117 _Primitive-or-lit-with-mem: -4118 # or-with var1, lit => 81 1/subop/or var1/rm32 lit/imm32 -4119 "or-with"/imm32/name -4120 Int-var-and-literal/imm32/inouts -4121 0/imm32/outputs -4122 "81 4/subop/or"/imm32/subx-name -4123 1/imm32/rm32-is-first-inout -4124 0/imm32/no-r32 -4125 2/imm32/imm32-is-first-inout -4126 0/imm32/output-is-write-only -4127 _Primitive-xor-with-eax/imm32/next -4128 # - xor -4129 _Primitive-xor-with-eax: -4130 # var/eax <- xor lit => 35/xor-with-eax lit/imm32 -4131 "xor"/imm32/name -4132 Single-lit-var/imm32/inouts -4133 Single-int-var-in-eax/imm32/outputs -4134 "35/xor-with-eax"/imm32/subx-name -4135 0/imm32/no-rm32 -4136 0/imm32/no-r32 -4137 1/imm32/imm32-is-first-inout -4138 0/imm32/output-is-write-only -4139 _Primitive-xor-reg-with-reg/imm32/next -4140 _Primitive-xor-reg-with-reg: -4141 # var1/reg <- xor var2/reg => 31/xor-with var1/rm32 var2/r32 -4142 "xor"/imm32/name -4143 Single-int-var-in-some-register/imm32/inouts -4144 Single-int-var-in-some-register/imm32/outputs -4145 "31/xor-with"/imm32/subx-name -4146 3/imm32/rm32-is-first-output -4147 1/imm32/r32-is-first-inout -4148 0/imm32/no-imm32 -4149 0/imm32/output-is-write-only -4150 _Primitive-xor-reg-with-mem/imm32/next -4151 _Primitive-xor-reg-with-mem: -4152 # xor-with var1 var2/reg => 31/xor-with var1 var2/r32 -4153 "xor-with"/imm32/name -4154 Int-var-and-second-int-var-in-some-register/imm32/inouts -4155 0/imm32/outputs -4156 "31/xor-with"/imm32/subx-name -4157 1/imm32/rm32-is-first-inout -4158 2/imm32/r32-is-second-inout -4159 0/imm32/no-imm32 -4160 0/imm32/output-is-write-only -4161 _Primitive-xor-mem-with-reg/imm32/next -4162 _Primitive-xor-mem-with-reg: -4163 # var1/reg <- xor var2 => 33/xor var2/rm32 var1/r32 -4164 "xor"/imm32/name -4165 Single-int-var-on-stack/imm32/inouts -4166 Single-int-var-in-some-register/imm32/outputs -4167 "33/xor"/imm32/subx-name -4168 1/imm32/rm32-is-first-inout -4169 3/imm32/r32-is-first-output -4170 0/imm32/no-imm32 -4171 0/imm32/output-is-write-only -4172 _Primitive-xor-lit-with-reg/imm32/next -4173 _Primitive-xor-lit-with-reg: -4174 # var1/reg <- xor lit => 81 6/subop/xor var1/rm32 lit/imm32 -4175 "xor"/imm32/name -4176 Single-lit-var/imm32/inouts -4177 Single-int-var-in-some-register/imm32/outputs -4178 "81 4/subop/xor"/imm32/subx-name -4179 3/imm32/rm32-is-first-output -4180 0/imm32/no-r32 -4181 1/imm32/imm32-is-first-inout -4182 0/imm32/output-is-write-only -4183 _Primitive-xor-lit-with-mem/imm32/next -4184 _Primitive-xor-lit-with-mem: -4185 # xor-with var1, lit => 81 6/subop/xor var1/rm32 lit/imm32 -4186 "xor-with"/imm32/name -4187 Int-var-and-literal/imm32/inouts -4188 0/imm32/outputs -4189 "81 4/subop/xor"/imm32/subx-name -4190 1/imm32/rm32-is-first-inout -4191 0/imm32/no-r32 -4192 2/imm32/imm32-is-first-inout -4193 0/imm32/output-is-write-only -4194 _Primitive-copy-to-eax/imm32/next -4195 # - copy -4196 _Primitive-copy-to-eax: -4197 # var/eax <- copy lit => b8/copy-to-eax lit/imm32 -4198 "copy"/imm32/name -4199 Single-lit-var/imm32/inouts -4200 Single-int-var-in-eax/imm32/outputs -4201 "b8/copy-to-eax"/imm32/subx-name -4202 0/imm32/no-rm32 -4203 0/imm32/no-r32 -4204 1/imm32/imm32-is-first-inout -4205 1/imm32/output-is-write-only -4206 _Primitive-copy-to-ecx/imm32/next -4207 _Primitive-copy-to-ecx: -4208 # var/ecx <- copy lit => b9/copy-to-ecx lit/imm32 -4209 "copy"/imm32/name -4210 Single-lit-var/imm32/inouts -4211 Single-int-var-in-ecx/imm32/outputs -4212 "b9/copy-to-ecx"/imm32/subx-name -4213 0/imm32/no-rm32 -4214 0/imm32/no-r32 -4215 1/imm32/imm32-is-first-inout -4216 1/imm32/output-is-write-only -4217 _Primitive-copy-to-edx/imm32/next -4218 _Primitive-copy-to-edx: -4219 # var/edx <- copy lit => ba/copy-to-edx lit/imm32 -4220 "copy"/imm32/name -4221 Single-lit-var/imm32/inouts -4222 Single-int-var-in-edx/imm32/outputs -4223 "ba/copy-to-edx"/imm32/subx-name -4224 0/imm32/no-rm32 -4225 0/imm32/no-r32 -4226 1/imm32/imm32-is-first-inout -4227 1/imm32/output-is-write-only -4228 _Primitive-copy-to-ebx/imm32/next -4229 _Primitive-copy-to-ebx: -4230 # var/ebx <- copy lit => bb/copy-to-ebx lit/imm32 -4231 "copy"/imm32/name -4232 Single-lit-var/imm32/inouts -4233 Single-int-var-in-ebx/imm32/outputs -4234 "bb/copy-to-ebx"/imm32/subx-name -4235 0/imm32/no-rm32 -4236 0/imm32/no-r32 -4237 1/imm32/imm32-is-first-inout -4238 1/imm32/output-is-write-only -4239 _Primitive-copy-to-esi/imm32/next -4240 _Primitive-copy-to-esi: -4241 # var/esi <- copy lit => be/copy-to-esi lit/imm32 -4242 "copy"/imm32/name -4243 Single-lit-var/imm32/inouts -4244 Single-int-var-in-esi/imm32/outputs -4245 "be/copy-to-esi"/imm32/subx-name -4246 0/imm32/no-rm32 -4247 0/imm32/no-r32 -4248 1/imm32/imm32-is-first-inout -4249 1/imm32/output-is-write-only -4250 _Primitive-copy-to-edi/imm32/next -4251 _Primitive-copy-to-edi: -4252 # var/edi <- copy lit => bf/copy-to-edi lit/imm32 -4253 "copy"/imm32/name -4254 Single-lit-var/imm32/inouts -4255 Single-int-var-in-edi/imm32/outputs -4256 "bf/copy-to-edi"/imm32/subx-name -4257 0/imm32/no-rm32 -4258 0/imm32/no-r32 -4259 1/imm32/imm32-is-first-inout -4260 1/imm32/output-is-write-only -4261 _Primitive-copy-reg-to-reg/imm32/next -4262 _Primitive-copy-reg-to-reg: -4263 # var1/reg <- copy var2/reg => 89/copy-to var1/rm32 var2/r32 -4264 "copy"/imm32/name -4265 Single-int-var-in-some-register/imm32/inouts -4266 Single-int-var-in-some-register/imm32/outputs -4267 "89/copy-to"/imm32/subx-name -4268 3/imm32/rm32-is-first-output -4269 1/imm32/r32-is-first-inout -4270 0/imm32/no-imm32 -4271 1/imm32/output-is-write-only -4272 _Primitive-copy-reg-to-mem/imm32/next -4273 _Primitive-copy-reg-to-mem: -4274 # copy-to var1 var2/reg => 89/copy-to var1 var2/r32 -4275 "copy-to"/imm32/name -4276 Int-var-and-second-int-var-in-some-register/imm32/inouts -4277 0/imm32/outputs -4278 "89/copy-to"/imm32/subx-name -4279 1/imm32/rm32-is-first-inout -4280 2/imm32/r32-is-second-inout -4281 0/imm32/no-imm32 -4282 1/imm32/output-is-write-only -4283 _Primitive-copy-mem-to-reg/imm32/next -4284 _Primitive-copy-mem-to-reg: -4285 # var1/reg <- copy var2 => 8b/copy-from var2/rm32 var1/r32 -4286 "copy"/imm32/name -4287 Single-int-var-on-stack/imm32/inouts -4288 Single-int-var-in-some-register/imm32/outputs -4289 "8b/copy-from"/imm32/subx-name -4290 1/imm32/rm32-is-first-inout -4291 3/imm32/r32-is-first-output -4292 0/imm32/no-imm32 -4293 1/imm32/output-is-write-only -4294 _Primitive-copy-lit-to-reg/imm32/next -4295 _Primitive-copy-lit-to-reg: -4296 # var1/reg <- copy lit => c7 0/subop/copy var1/rm32 lit/imm32 -4297 "copy"/imm32/name -4298 Single-lit-var/imm32/inouts -4299 Single-int-var-in-some-register/imm32/outputs -4300 "c7 0/subop/copy"/imm32/subx-name -4301 3/imm32/rm32-is-first-output -4302 0/imm32/no-r32 -4303 1/imm32/imm32-is-first-inout -4304 1/imm32/output-is-write-only -4305 _Primitive-copy-lit-to-mem/imm32/next -4306 _Primitive-copy-lit-to-mem: -4307 # copy-to var1, lit => c7 0/subop/copy var1/rm32 lit/imm32 -4308 "copy-to"/imm32/name -4309 Int-var-and-literal/imm32/inouts -4310 0/imm32/outputs -4311 "c7 0/subop/copy"/imm32/subx-name -4312 1/imm32/rm32-is-first-inout -4313 0/imm32/no-r32 -4314 2/imm32/imm32-is-first-inout -4315 1/imm32/output-is-write-only -4316 0/imm32/next -4317 -4318 Single-int-var-on-stack: -4319 Int-var-on-stack/imm32 -4320 0/imm32/next -4321 -4322 Int-var-on-stack: -4323 "arg1"/imm32/name -4324 Type-int/imm32 -4325 1/imm32/some-block-depth -4326 1/imm32/some-stack-offset -4327 0/imm32/no-register -4328 -4329 Int-var-and-second-int-var-in-some-register: -4330 Int-var-on-stack/imm32 -4331 Single-int-var-in-some-register/imm32/next -4332 -4333 Int-var-and-literal: -4334 Int-var-on-stack/imm32 -4335 Single-lit-var/imm32/next -4336 -4337 Single-int-var-in-some-register: -4338 Int-var-in-some-register/imm32 -4339 0/imm32/next -4340 -4341 Int-var-in-some-register: -4342 "arg1"/imm32/name -4343 Type-int/imm32 -4344 1/imm32/some-block-depth -4345 0/imm32/no-stack-offset -4346 "*"/imm32/register -4347 -4348 Single-int-var-in-eax: -4349 Int-var-in-eax/imm32 -4350 0/imm32/next -4351 -4352 Int-var-in-eax: -4353 "arg1"/imm32/name -4354 Type-int/imm32 -4355 1/imm32/some-block-depth -4356 0/imm32/no-stack-offset -4357 "eax"/imm32/register -4358 -4359 Single-int-var-in-ecx: -4360 Int-var-in-ecx/imm32 -4361 0/imm32/next -4362 -4363 Int-var-in-ecx: -4364 "arg1"/imm32/name -4365 Type-int/imm32 -4366 1/imm32/some-block-depth -4367 0/imm32/no-stack-offset -4368 "ecx"/imm32/register -4369 -4370 Single-int-var-in-edx: -4371 Int-var-in-edx/imm32 -4372 0/imm32/next -4373 -4374 Int-var-in-edx: -4375 "arg1"/imm32/name -4376 Type-int/imm32 -4377 1/imm32/some-block-depth -4378 0/imm32/no-stack-offset -4379 "edx"/imm32/register -4380 -4381 Single-int-var-in-ebx: -4382 Int-var-in-ebx/imm32 -4383 0/imm32/next -4384 -4385 Int-var-in-ebx: -4386 "arg1"/imm32/name -4387 Type-int/imm32 -4388 1/imm32/some-block-depth -4389 0/imm32/no-stack-offset -4390 "ebx"/imm32/register -4391 -4392 Single-int-var-in-esi: -4393 Int-var-in-esi/imm32 -4394 0/imm32/next -4395 -4396 Int-var-in-esi: -4397 "arg1"/imm32/name -4398 Type-int/imm32 -4399 1/imm32/some-block-depth -4400 0/imm32/no-stack-offset -4401 "esi"/imm32/register -4402 -4403 Single-int-var-in-edi: -4404 Int-var-in-edi/imm32 -4405 0/imm32/next -4406 -4407 Int-var-in-edi: -4408 "arg1"/imm32/name -4409 Type-int/imm32 -4410 1/imm32/some-block-depth -4411 0/imm32/no-stack-offset -4412 "edi"/imm32/register -4413 -4414 Single-lit-var: -4415 Lit-var/imm32 -4416 0/imm32/next -4417 -4418 Lit-var: -4419 "literal"/imm32/name -4420 Type-literal/imm32 -4421 1/imm32/some-block-depth -4422 0/imm32/no-stack-offset -4423 0/imm32/no-register -4424 -4425 Type-int: -4426 1/imm32/left/int -4427 0/imm32/right/null -4428 -4429 Type-literal: -4430 0/imm32/left/literal -4431 0/imm32/right/null -4432 -4433 == code -4434 emit-subx-primitive: # out : (addr buffered-file), stmt : (handle statement), primitive : (handle function) -4435 # . prologue -4436 55/push-ebp -4437 89/<- %ebp 4/r32/esp -4438 # . save registers -4439 50/push-eax -4440 51/push-ecx -4441 # ecx = primitive -4442 8b/-> *(ebp+0x10) 1/r32/ecx -4443 # emit primitive name -4444 (write-buffered *(ebp+8) *(ecx+0xc)) # Primitive-subx-name -4445 # emit rm32 if necessary -4446 (emit-subx-rm32 *(ebp+8) *(ecx+0x10) *(ebp+0xc)) # out, Primitive-subx-rm32, stmt -4447 # emit r32 if necessary -4448 (emit-subx-r32 *(ebp+8) *(ecx+0x14) *(ebp+0xc)) # out, Primitive-subx-r32, stmt -4449 # emit imm32 if necessary -4450 (emit-subx-imm32 *(ebp+8) *(ecx+0x18) *(ebp+0xc)) # out, Primitive-subx-imm32, stmt -4451 $emit-subx-primitive:end: -4452 # . restore registers -4453 59/pop-to-ecx -4454 58/pop-to-eax -4455 # . epilogue -4456 89/<- %esp 5/r32/ebp -4457 5d/pop-to-ebp -4458 c3/return -4459 -4460 emit-subx-rm32: # out : (addr buffered-file), l : arg-location, stmt : (handle statement) -4461 # . prologue -4462 55/push-ebp -4463 89/<- %ebp 4/r32/esp -4464 # . save registers -4465 50/push-eax -4466 # if (l == 0) return -4467 81 7/subop/compare *(ebp+0xc) 0/imm32 -4468 74/jump-if-= $emit-subx-rm32:end/disp8 -4469 # -4470 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax -4471 (emit-subx-var-as-rm32 *(ebp+8) %eax) # out, var -4472 $emit-subx-rm32:end: -4473 # . restore registers -4474 58/pop-to-eax -4475 # . epilogue -4476 89/<- %esp 5/r32/ebp -4477 5d/pop-to-ebp -4478 c3/return -4479 -4480 get-stmt-operand-from-arg-location: # stmt : (handle statement), l : arg-location -> var/eax : (handle variable) -4481 # . prologue -4482 55/push-ebp -4483 89/<- %ebp 4/r32/esp -4484 # . save registers -4485 51/push-ecx -4486 # eax = l -4487 8b/-> *(ebp+0xc) 0/r32/eax -4488 # ecx = stmt -4489 8b/-> *(ebp+8) 1/r32/ecx -4490 # if (l == 1) return stmt->inouts->var -4491 { -4492 3d/compare-eax-and 1/imm32 -4493 75/jump-if-!= break/disp8 -4494 $get-stmt-operand-from-arg-location:1: -4495 8b/-> *(ecx+8) 0/r32/eax # Stmt1-inouts -4496 8b/-> *eax 0/r32/eax # Operand-var -4497 eb/jump $get-stmt-operand-from-arg-location:end/disp8 -4498 } -4499 # if (l == 2) return stmt->inouts->next->var -4500 { -4501 3d/compare-eax-and 2/imm32 -4502 75/jump-if-!= break/disp8 -4503 $get-stmt-operand-from-arg-location:2: -4504 8b/-> *(ecx+8) 0/r32/eax # Stmt1-inouts -4505 8b/-> *(eax+4) 0/r32/eax # Operand-next -4506 8b/-> *eax 0/r32/eax # Operand-var -4507 eb/jump $get-stmt-operand-from-arg-location:end/disp8 -4508 } -4509 # if (l == 3) return stmt->outputs -4510 { -4511 3d/compare-eax-and 3/imm32 -4512 75/jump-if-!= break/disp8 -4513 $get-stmt-operand-from-arg-location:3: -4514 8b/-> *(ecx+0xc) 0/r32/eax # Stmt1-outputs -4515 8b/-> *eax 0/r32/eax # Operand-var -4516 eb/jump $get-stmt-operand-from-arg-location:end/disp8 -4517 } -4518 # abort -4519 e9/jump $get-stmt-operand-from-arg-location:abort/disp32 -4520 $get-stmt-operand-from-arg-location:end: -4521 # . restore registers -4522 59/pop-to-ecx -4523 # . epilogue -4524 89/<- %esp 5/r32/ebp -4525 5d/pop-to-ebp -4526 c3/return -4527 -4528 $get-stmt-operand-from-arg-location:abort: -4529 # error("invalid arg-location " eax) -4530 (write-buffered Stderr "invalid arg-location ") -4531 (print-int32-buffered Stderr %eax) -4532 (write-buffered Stderr "\n") -4533 (flush Stderr) -4534 # . syscall(exit, 1) -4535 bb/copy-to-ebx 1/imm32 -4536 b8/copy-to-eax 1/imm32/exit -4537 cd/syscall 0x80/imm8 -4538 # never gets here -4539 -4540 emit-subx-r32: # out : (addr buffered-file), l : arg-location, stmt : (handle statement) -4541 # . prologue -4542 55/push-ebp -4543 89/<- %ebp 4/r32/esp -4544 # . save registers -4545 50/push-eax -4546 51/push-ecx -4547 # if (location == 0) return -4548 81 7/subop/compare *(ebp+0xc) 0/imm32 -4549 0f 84/jump-if-= $emit-subx-r32:end/disp32 -4550 # -4551 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax -4552 (maybe-get Registers *(eax+0x10) 8) # Var-register => eax : (addr register-index) -4553 (write-buffered *(ebp+8) Space) -4554 (print-int32-buffered *(ebp+8) *eax) -4555 (write-buffered *(ebp+8) "/r32") -4556 $emit-subx-r32:end: -4557 # . restore registers -4558 59/pop-to-ecx -4559 58/pop-to-eax -4560 # . epilogue -4561 89/<- %esp 5/r32/ebp -4562 5d/pop-to-ebp -4563 c3/return -4564 -4565 emit-subx-imm32: # out : (addr buffered-file), l : arg-location, stmt : (handle statement) -4566 # . prologue -4567 55/push-ebp -4568 89/<- %ebp 4/r32/esp -4569 # . save registers -4570 50/push-eax -4571 51/push-ecx -4572 # if (location == 0) return -4573 81 7/subop/compare *(ebp+0xc) 0/imm32 -4574 74/jump-if-= $emit-subx-imm32:end/disp8 -4575 # -4576 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax -4577 (write-buffered *(ebp+8) Space) -4578 (write-buffered *(ebp+8) *eax) # Var-name -4579 (write-buffered *(ebp+8) "/imm32") -4580 $emit-subx-imm32:end: -4581 # . restore registers -4582 59/pop-to-ecx -4583 58/pop-to-eax -4584 # . epilogue -4585 89/<- %esp 5/r32/ebp -4586 5d/pop-to-ebp -4587 c3/return -4588 -4589 emit-subx-call: # out : (addr buffered-file), stmt : (handle statement), callee : (handle function) -4590 # . prologue -4591 55/push-ebp -4592 89/<- %ebp 4/r32/esp -4593 # . save registers -4594 50/push-eax -4595 51/push-ecx -4596 # -4597 (write-buffered *(ebp+8) "(") -4598 # - emit function name -4599 8b/-> *(ebp+0x10) 1/r32/ecx -4600 (write-buffered *(ebp+8) *(ecx+4)) # Function-subx-name -4601 # - emit arguments -4602 # var curr/ecx : (handle list var) = stmt->inouts -4603 8b/-> *(ebp+0xc) 1/r32/ecx -4604 8b/-> *(ecx+8) 1/r32/ecx # Stmt1-inouts -4605 { -4606 # if (curr == null) break -4607 81 7/subop/compare %ecx 0/imm32 -4608 74/jump-if-= break/disp8 -4609 # -4610 (emit-subx-call-operand *(ebp+8) *ecx) -4611 # curr = curr->next -4612 8b/-> *(ecx+4) 1/r32/ecx -4613 eb/jump loop/disp8 -4614 } -4615 # -4616 (write-buffered *(ebp+8) ")") -4617 $emit-subx-call:end: -4618 # . restore registers -4619 59/pop-to-ecx -4620 58/pop-to-eax -4621 # . epilogue -4622 89/<- %esp 5/r32/ebp -4623 5d/pop-to-ebp -4624 c3/return -4625 -4626 emit-subx-call-operand: # out : (addr buffered-file), operand : (handle variable) -4627 # . prologue -4628 55/push-ebp -4629 89/<- %ebp 4/r32/esp -4630 # . save registers -4631 50/push-eax -4632 # eax = operand -4633 8b/-> *(ebp+0xc) 0/r32/eax -4634 # if (operand->register) emit "%__" -4635 { -4636 81 7/subop/compare *(eax+0x10) 0/imm32 # Var-register -4637 74/jump-if-= break/disp8 -4638 $emit-subx-call-operand:register: -4639 (write-buffered *(ebp+8) " %") -4640 (write-buffered *(ebp+8) *(eax+0x10)) # Var-register -4641 e9/jump $emit-subx-call-operand:end/disp32 -4642 } -4643 # else if (operand->stack-offset) emit "*(ebp+__)" -4644 { -4645 81 7/subop/compare *(eax+0xc) 0/imm32 # Var-stack-offset -4646 74/jump-if-= break/disp8 -4647 $emit-subx-call-operand:stack: -4648 (write-buffered *(ebp+8) Space) -4649 (write-buffered *(ebp+8) "*(ebp+") -4650 8b/-> *(ebp+0xc) 0/r32/eax -4651 (print-int32-buffered *(ebp+8) *(eax+0xc)) # Var-stack-offset -4652 (write-buffered *(ebp+8) ")") -4653 e9/jump $emit-subx-call-operand:end/disp32 -4654 } -4655 # else if (operand->type == literal) emit "__" -4656 { -4657 50/push-eax -4658 8b/-> *(eax+4) 0/r32/eax # Var-type -4659 81 7/subop/compare *eax 0/imm32 # Tree-left -4660 58/pop-to-eax -4661 75/jump-if-!= break/disp8 -4662 $emit-subx-call-operand:literal: -4663 (write-buffered *(ebp+8) Space) -4664 (write-buffered *(ebp+8) *eax) -4665 } -4666 $emit-subx-call-operand:end: -4667 # . restore registers -4668 58/pop-to-eax -4669 # . epilogue -4670 89/<- %esp 5/r32/ebp -4671 5d/pop-to-ebp -4672 c3/return -4673 -4674 emit-subx-var-as-rm32: # out : (addr buffered-file), operand : (handle variable) -4675 # . prologue -4676 55/push-ebp -4677 89/<- %ebp 4/r32/esp -4678 # . save registers -4679 50/push-eax -4680 # eax = operand -4681 8b/-> *(ebp+0xc) 0/r32/eax -4682 # if (operand->register) emit "%__" -4683 { -4684 81 7/subop/compare *(eax+0x10) 0/imm32 # Var-register -4685 74/jump-if-= break/disp8 -4686 $emit-subx-var-as-rm32:register: -4687 (write-buffered *(ebp+8) " %") -4688 (write-buffered *(ebp+8) *(eax+0x10)) # Var-register -4689 } -4690 # else if (operand->stack-offset) emit "*(ebp+__)" -4691 { -4692 81 7/subop/compare *(eax+0xc) 0/imm32 # Var-stack-offset -4693 74/jump-if-= break/disp8 -4694 $emit-subx-var-as-rm32:stack: -4695 (write-buffered *(ebp+8) Space) -4696 (write-buffered *(ebp+8) "*(ebp+") -4697 8b/-> *(ebp+0xc) 0/r32/eax -4698 (print-int32-buffered *(ebp+8) *(eax+0xc)) # Var-stack-offset -4699 (write-buffered *(ebp+8) ")") -4700 } -4701 $emit-subx-var-as-rm32:end: -4702 # . restore registers -4703 58/pop-to-eax -4704 # . epilogue -4705 89/<- %esp 5/r32/ebp -4706 5d/pop-to-ebp -4707 c3/return -4708 -4709 find-matching-function: # functions : (addr function), stmt : (handle statement) -> result/eax : (handle function) -4710 # . prologue -4711 55/push-ebp -4712 89/<- %ebp 4/r32/esp -4713 # . save registers -4714 51/push-ecx -4715 # var curr/ecx : (handle function) = functions -4716 8b/-> *(ebp+8) 1/r32/ecx -4717 { -4718 # if (curr == null) break -4719 81 7/subop/compare %ecx 0/imm32 -4720 74/jump-if-= break/disp8 -4721 # if match(stmt, curr) return curr -4722 { -4723 (mu-stmt-matches-function? *(ebp+0xc) %ecx) # => eax -4724 3d/compare-eax-and 0/imm32 -4725 74/jump-if-= break/disp8 -4726 89/<- %eax 1/r32/ecx -4727 eb/jump $find-matching-function:end/disp8 -4728 } +3520 (allocate *(ebp+8) *Stmt-size) # => eax +3521 (zero-out %eax *Stmt-size) +3522 c7 0/subop/copy *eax 3/imm32/tag/var-in-register # Stmt-tag +3523 8b/-> *(ebp+0xc) 1/r32/ecx +3524 89/<- *(eax+0xc) 1/r32/ecx # Regvardef-var +3525 $new-regvardef:end: +3526 # . restore registers +3527 59/pop-to-ecx +3528 # . epilogue +3529 89/<- %esp 5/r32/ebp +3530 5d/pop-to-ebp +3531 c3/return +3532 +3533 new-named-block: # ad: (addr allocation-descriptor), name: (addr array byte), data: (handle list statement) -> result/eax: (handle statement) +3534 # . prologue +3535 55/push-ebp +3536 89/<- %ebp 4/r32/esp +3537 # . save registers +3538 51/push-ecx +3539 # +3540 (allocate *(ebp+8) *Stmt-size) # => eax +3541 (zero-out %eax *Stmt-size) +3542 c7 0/subop/copy *eax 4/imm32/tag/named-block +3543 8b/-> *(ebp+0xc) 1/r32/ecx +3544 89/<- *(eax+4) 1/r32/ecx # Named-block-name +3545 8b/-> *(ebp+0x10) 1/r32/ecx +3546 89/<- *(eax+8) 1/r32/ecx # Named-block-statements +3547 $new-named-block:end: +3548 # . restore registers +3549 59/pop-to-ecx +3550 # . epilogue +3551 89/<- %esp 5/r32/ebp +3552 5d/pop-to-ebp +3553 c3/return +3554 +3555 new-list: # ad: (addr allocation-descriptor), value: _type, next: (handle list _type) -> result/eax : (handle list _type) +3556 # . prologue +3557 55/push-ebp +3558 89/<- %ebp 4/r32/esp +3559 # . save registers +3560 51/push-ecx +3561 # +3562 (allocate *(ebp+8) *List-size) # => eax +3563 8b/-> *(ebp+0xc) 1/r32/ecx +3564 89/<- *eax 1/r32/ecx # List-value +3565 8b/-> *(ebp+0x10) 1/r32/ecx +3566 89/<- *(eax+4) 1/r32/ecx # List-next +3567 $new-list:end: +3568 # . restore registers +3569 59/pop-to-ecx +3570 # . epilogue +3571 89/<- %esp 5/r32/ebp +3572 5d/pop-to-ebp +3573 c3/return +3574 +3575 append-list: # ad: (addr allocation-descriptor), value: _type, list: (handle list _type) -> result/eax : (handle list _type) +3576 # . prologue +3577 55/push-ebp +3578 89/<- %ebp 4/r32/esp +3579 # . save registers +3580 51/push-ecx +3581 # +3582 (allocate *(ebp+8) *List-size) # => eax +3583 8b/-> *(ebp+0xc) 1/r32/ecx +3584 89/<- *eax 1/r32/ecx # List-value +3585 # if (list == null) return result +3586 81 7/subop/compare *(ebp+0x10) 0/imm32 +3587 74/jump-if-= $new-list:end/disp8 +3588 # otherwise append +3589 # var curr/ecx = list +3590 8b/-> *(ebp+0x10) 1/r32/ecx +3591 # while (curr->next != null) curr = curr->next +3592 { +3593 81 7/subop/compare *(ecx+4) 0/imm32 # List-next +3594 74/jump-if-= break/disp8 +3595 # curr = curr->next +3596 8b/-> *(ecx+4) 1/r32/ecx +3597 eb/jump loop/disp8 +3598 } +3599 # curr->next = result +3600 89/<- *(ecx+4) 0/r32/eax +3601 # return list +3602 8b/-> *(ebp+0x10) 0/r32/eax +3603 $append-list:end: +3604 # . restore registers +3605 59/pop-to-ecx +3606 # . epilogue +3607 89/<- %esp 5/r32/ebp +3608 5d/pop-to-ebp +3609 c3/return +3610 +3611 append-to-block: # ad: (addr allocation-descriptor), block: (handle block), x: (handle stmt) +3612 # . prologue +3613 55/push-ebp +3614 89/<- %ebp 4/r32/esp +3615 # . save registers +3616 56/push-esi +3617 # esi = block +3618 8b/-> *(ebp+0xc) 6/r32/esi +3619 (append-list *(ebp+8) *(ebp+0x10) *(esi+4)) # ad, x, Block-statements +3620 89/<- *(esi+4) 0/r32/eax # Block-statements +3621 $append-to-block:end: +3622 # . restore registers +3623 5e/pop-to-esi +3624 # . epilogue +3625 89/<- %esp 5/r32/ebp +3626 5d/pop-to-ebp +3627 c3/return +3628 +3629 ####################################################### +3630 # Type-checking +3631 ####################################################### +3632 +3633 check-mu-types: +3634 # . prologue +3635 55/push-ebp +3636 89/<- %ebp 4/r32/esp +3637 # +3638 $check-mu-types:end: +3639 # . epilogue +3640 89/<- %esp 5/r32/ebp +3641 5d/pop-to-ebp +3642 c3/return +3643 +3644 size-of: # n : (addr var) +3645 # . prologue +3646 55/push-ebp +3647 89/<- %ebp 4/r32/esp +3648 # hard-coded since we only support 'int' types for now +3649 b8/copy-to-eax 4/imm32 +3650 $size-of:end: +3651 # . epilogue +3652 89/<- %esp 5/r32/ebp +3653 5d/pop-to-ebp +3654 c3/return +3655 +3656 ####################################################### +3657 # Code-generation +3658 ####################################################### +3659 +3660 emit-subx: # out : (addr buffered-file) +3661 # . prologue +3662 55/push-ebp +3663 89/<- %ebp 4/r32/esp +3664 # . save registers +3665 50/push-eax +3666 51/push-ecx +3667 57/push-edi +3668 # edi = out +3669 8b/-> *(ebp+8) 7/r32/edi +3670 # var curr/ecx : (handle function) = *Program +3671 8b/-> *Program 1/r32/ecx +3672 { +3673 # if (curr == null) break +3674 81 7/subop/compare %ecx 0/imm32 +3675 0f 84/jump-if-= break/disp32 +3676 (emit-subx-function %edi %ecx) +3677 # curr = curr->next +3678 8b/-> *(ecx+0x14) 1/r32/ecx # Function-next +3679 e9/jump loop/disp32 +3680 } +3681 $emit-subx:end: +3682 # . restore registers +3683 5f/pop-to-edi +3684 59/pop-to-ecx +3685 58/pop-to-eax +3686 # . epilogue +3687 89/<- %esp 5/r32/ebp +3688 5d/pop-to-ebp +3689 c3/return +3690 +3691 emit-subx-function: # out : (addr buffered-file), f : (handle function) +3692 # . prologue +3693 55/push-ebp +3694 89/<- %ebp 4/r32/esp +3695 # . save registers +3696 50/push-eax +3697 51/push-ecx +3698 57/push-edi +3699 # edi = out +3700 8b/-> *(ebp+8) 7/r32/edi +3701 # ecx = f +3702 8b/-> *(ebp+0xc) 1/r32/ecx +3703 # +3704 (write-buffered %edi *ecx) +3705 (write-buffered %edi ":\n") +3706 (emit-subx-prologue %edi) +3707 (emit-subx-block %edi *(ecx+0x10)) # Function-body +3708 (emit-subx-epilogue %edi) +3709 $emit-subx-function:end: +3710 # . restore registers +3711 5f/pop-to-edi +3712 59/pop-to-ecx +3713 58/pop-to-eax +3714 # . epilogue +3715 89/<- %esp 5/r32/ebp +3716 5d/pop-to-ebp +3717 c3/return +3718 +3719 emit-subx-block: # out : (addr buffered-file), block : (handle block) +3720 # . prologue +3721 55/push-ebp +3722 89/<- %ebp 4/r32/esp +3723 # curr/esi : (handle list statement) = block->statements +3724 8b/-> *(ebp+0xc) 6/r32/esi +3725 8b/-> *(esi+4) 6/r32/esi # Block-statements +3726 # +3727 { +3728 $emit-subx-block:check-empty: +3729 81 7/subop/compare %esi 0/imm32 +3730 0f 84/jump-if-= break/disp32 +3731 (write-buffered *(ebp+8) "{\n") +3732 { +3733 $emit-subx-block:stmt: +3734 81 7/subop/compare %esi 0/imm32 +3735 74/jump-if-= break/disp8 +3736 (emit-subx-statement *(ebp+8) *esi Primitives *Program) +3737 (write-buffered *(ebp+8) Newline) +3738 8b/-> *(esi+4) 6/r32/esi # List-next +3739 eb/jump loop/disp8 +3740 } +3741 (write-buffered *(ebp+8) "}\n") +3742 } +3743 $emit-subx-block:end: +3744 # . epilogue +3745 89/<- %esp 5/r32/ebp +3746 5d/pop-to-ebp +3747 c3/return +3748 +3749 emit-subx-statement: # out : (addr buffered-file), stmt : (handle statement), primitives : (handle primitive), functions : (handle function) +3750 # . prologue +3751 55/push-ebp +3752 89/<- %ebp 4/r32/esp +3753 # . save registers +3754 50/push-eax +3755 51/push-ecx +3756 # if stmt matches a primitive, emit it +3757 { +3758 $emit-subx-statement:primitive: +3759 (find-matching-primitive *(ebp+0x10) *(ebp+0xc)) # primitives, stmt => curr/eax +3760 3d/compare-eax-and 0/imm32 +3761 74/jump-if-= break/disp8 +3762 (emit-subx-primitive *(ebp+8) *(ebp+0xc) %eax) # out, stmt, curr +3763 e9/jump $emit-subx-statement:end/disp32 +3764 } +3765 # else if stmt matches a function, emit a call to it +3766 { +3767 $emit-subx-statement:call: +3768 (find-matching-function *(ebp+0x14) *(ebp+0xc)) # functions, stmt => curr/eax +3769 3d/compare-eax-and 0/imm32 +3770 74/jump-if-= break/disp8 +3771 (emit-subx-call *(ebp+8) *(ebp+0xc) %eax) # out, stmt, curr +3772 e9/jump $emit-subx-statement:end/disp32 +3773 } +3774 # else abort +3775 e9/jump $emit-subx-statement:abort/disp32 +3776 $emit-subx-statement:end: +3777 # . restore registers +3778 59/pop-to-ecx +3779 58/pop-to-eax +3780 # . epilogue +3781 89/<- %esp 5/r32/ebp +3782 5d/pop-to-ebp +3783 c3/return +3784 +3785 $emit-subx-statement:abort: +3786 # error("couldn't translate '" stmt "'\n") +3787 (write-buffered Stderr "couldn't translate '") +3788 #? (emit-string Stderr *(ebp+0xc)) # TODO +3789 (write-buffered Stderr "'\n") +3790 (flush Stderr) +3791 # . syscall(exit, 1) +3792 bb/copy-to-ebx 1/imm32 +3793 b8/copy-to-eax 1/imm32/exit +3794 cd/syscall 0x80/imm8 +3795 # never gets here +3796 +3797 # Primitives supported +3798 # For each operation, put variants with hard-coded registers before flexible ones. +3799 == data +3800 Primitives: +3801 # - increment/decrement +3802 _Primitive-inc-eax: +3803 # var/eax <- increment => 40/increment-eax +3804 "increment"/imm32/name +3805 0/imm32/no-inouts +3806 Single-int-var-in-eax/imm32/outputs +3807 "40/increment-eax"/imm32/subx-name +3808 0/imm32/no-rm32 +3809 0/imm32/no-r32 +3810 0/imm32/no-imm32 +3811 0/imm32/output-is-write-only +3812 _Primitive-inc-ecx/imm32/next +3813 _Primitive-inc-ecx: +3814 # var/ecx <- increment => 41/increment-ecx +3815 "increment"/imm32/name +3816 0/imm32/no-inouts +3817 Single-int-var-in-ecx/imm32/outputs +3818 "41/increment-ecx"/imm32/subx-name +3819 0/imm32/no-rm32 +3820 0/imm32/no-r32 +3821 0/imm32/no-imm32 +3822 0/imm32/output-is-write-only +3823 _Primitive-inc-edx/imm32/next +3824 _Primitive-inc-edx: +3825 # var/edx <- increment => 42/increment-edx +3826 "increment"/imm32/name +3827 0/imm32/no-inouts +3828 Single-int-var-in-edx/imm32/outputs +3829 "42/increment-edx"/imm32/subx-name +3830 0/imm32/no-rm32 +3831 0/imm32/no-r32 +3832 0/imm32/no-imm32 +3833 0/imm32/output-is-write-only +3834 _Primitive-inc-ebx/imm32/next +3835 _Primitive-inc-ebx: +3836 # var/ebx <- increment => 43/increment-ebx +3837 "increment"/imm32/name +3838 0/imm32/no-inouts +3839 Single-int-var-in-ebx/imm32/outputs +3840 "43/increment-ebx"/imm32/subx-name +3841 0/imm32/no-rm32 +3842 0/imm32/no-r32 +3843 0/imm32/no-imm32 +3844 0/imm32/output-is-write-only +3845 _Primitive-inc-esi/imm32/next +3846 _Primitive-inc-esi: +3847 # var/esi <- increment => 46/increment-esi +3848 "increment"/imm32/name +3849 0/imm32/no-inouts +3850 Single-int-var-in-esi/imm32/outputs +3851 "46/increment-esi"/imm32/subx-name +3852 0/imm32/no-rm32 +3853 0/imm32/no-r32 +3854 0/imm32/no-imm32 +3855 0/imm32/output-is-write-only +3856 _Primitive-inc-edi/imm32/next +3857 _Primitive-inc-edi: +3858 # var/edi <- increment => 47/increment-edi +3859 "increment"/imm32/name +3860 0/imm32/no-inouts +3861 Single-int-var-in-edi/imm32/outputs +3862 "47/increment-edi"/imm32/subx-name +3863 0/imm32/no-rm32 +3864 0/imm32/no-r32 +3865 0/imm32/no-imm32 +3866 0/imm32/output-is-write-only +3867 _Primitive-dec-eax/imm32/next +3868 _Primitive-dec-eax: +3869 # var/eax <- decrement => 48/decrement-eax +3870 "decrement"/imm32/name +3871 0/imm32/no-inouts +3872 Single-int-var-in-eax/imm32/outputs +3873 "48/decrement-eax"/imm32/subx-name +3874 0/imm32/no-rm32 +3875 0/imm32/no-r32 +3876 0/imm32/no-imm32 +3877 0/imm32/output-is-write-only +3878 _Primitive-dec-ecx/imm32/next +3879 _Primitive-dec-ecx: +3880 # var/ecx <- decrement => 49/decrement-ecx +3881 "decrement"/imm32/name +3882 0/imm32/no-inouts +3883 Single-int-var-in-ecx/imm32/outputs +3884 "49/decrement-ecx"/imm32/subx-name +3885 0/imm32/no-rm32 +3886 0/imm32/no-r32 +3887 0/imm32/no-imm32 +3888 0/imm32/output-is-write-only +3889 _Primitive-dec-edx/imm32/next +3890 _Primitive-dec-edx: +3891 # var/edx <- decrement => 4a/decrement-edx +3892 "decrement"/imm32/name +3893 0/imm32/no-inouts +3894 Single-int-var-in-edx/imm32/outputs +3895 "4a/decrement-edx"/imm32/subx-name +3896 0/imm32/no-rm32 +3897 0/imm32/no-r32 +3898 0/imm32/no-imm32 +3899 0/imm32/output-is-write-only +3900 _Primitive-dec-ebx/imm32/next +3901 _Primitive-dec-ebx: +3902 # var/ebx <- decrement => 4b/decrement-ebx +3903 "decrement"/imm32/name +3904 0/imm32/no-inouts +3905 Single-int-var-in-ebx/imm32/outputs +3906 "4b/decrement-ebx"/imm32/subx-name +3907 0/imm32/no-rm32 +3908 0/imm32/no-r32 +3909 0/imm32/no-imm32 +3910 0/imm32/output-is-write-only +3911 _Primitive-dec-esi/imm32/next +3912 _Primitive-dec-esi: +3913 # var/esi <- decrement => 4e/decrement-esi +3914 "decrement"/imm32/name +3915 0/imm32/no-inouts +3916 Single-int-var-in-esi/imm32/outputs +3917 "4e/decrement-esi"/imm32/subx-name +3918 0/imm32/no-rm32 +3919 0/imm32/no-r32 +3920 0/imm32/no-imm32 +3921 0/imm32/output-is-write-only +3922 _Primitive-dec-edi/imm32/next +3923 _Primitive-dec-edi: +3924 # var/edi <- decrement => 4f/decrement-edi +3925 "decrement"/imm32/name +3926 0/imm32/no-inouts +3927 Single-int-var-in-edi/imm32/outputs +3928 "4f/decrement-edi"/imm32/subx-name +3929 0/imm32/no-rm32 +3930 0/imm32/no-r32 +3931 0/imm32/no-imm32 +3932 0/imm32/output-is-write-only +3933 _Primitive-inc-mem/imm32/next +3934 _Primitive-inc-mem: +3935 # increment var => ff 0/subop/increment *(ebp+__) +3936 "increment"/imm32/name +3937 Single-int-var-on-stack/imm32/inouts +3938 0/imm32/no-outputs +3939 "ff 0/subop/increment"/imm32/subx-name +3940 1/imm32/rm32-is-first-inout +3941 0/imm32/no-r32 +3942 0/imm32/no-imm32 +3943 0/imm32/output-is-write-only +3944 _Primitive-inc-reg/imm32/next +3945 _Primitive-inc-reg: +3946 # var/reg <- increment => ff 0/subop/increment %__ +3947 "increment"/imm32/name +3948 0/imm32/no-inouts +3949 Single-int-var-in-some-register/imm32/outputs +3950 "ff 0/subop/increment"/imm32/subx-name +3951 3/imm32/rm32-is-first-output +3952 0/imm32/no-r32 +3953 0/imm32/no-imm32 +3954 0/imm32/output-is-write-only +3955 _Primitive-dec-mem/imm32/next +3956 _Primitive-dec-mem: +3957 # decrement var => ff 1/subop/decrement *(ebp+__) +3958 "decrement"/imm32/name +3959 Single-int-var-on-stack/imm32/inouts +3960 0/imm32/no-outputs +3961 "ff 1/subop/decrement"/imm32/subx-name +3962 1/imm32/rm32-is-first-inout +3963 0/imm32/no-r32 +3964 0/imm32/no-imm32 +3965 0/imm32/output-is-write-only +3966 _Primitive-dec-reg/imm32/next +3967 _Primitive-dec-reg: +3968 # var/reg <- decrement => ff 1/subop/decrement %__ +3969 "decrement"/imm32/name +3970 0/imm32/no-inouts +3971 Single-int-var-in-some-register/imm32/outputs +3972 "ff 1/subop/decrement"/imm32/subx-name +3973 3/imm32/rm32-is-first-output +3974 0/imm32/no-r32 +3975 0/imm32/no-imm32 +3976 0/imm32/output-is-write-only +3977 _Primitive-add-to-eax/imm32/next +3978 # - add +3979 _Primitive-add-to-eax: +3980 # var/eax <- add lit => 05/add-to-eax lit/imm32 +3981 "add"/imm32/name +3982 Single-lit-var/imm32/inouts +3983 Single-int-var-in-eax/imm32/outputs +3984 "05/add-to-eax"/imm32/subx-name +3985 0/imm32/no-rm32 +3986 0/imm32/no-r32 +3987 1/imm32/imm32-is-first-inout +3988 0/imm32/output-is-write-only +3989 _Primitive-add-reg-to-reg/imm32/next +3990 _Primitive-add-reg-to-reg: +3991 # var1/reg <- add var2/reg => 01/add-to var1/rm32 var2/r32 +3992 "add"/imm32/name +3993 Single-int-var-in-some-register/imm32/inouts +3994 Single-int-var-in-some-register/imm32/outputs +3995 "01/add-to"/imm32/subx-name +3996 3/imm32/rm32-is-first-output +3997 1/imm32/r32-is-first-inout +3998 0/imm32/no-imm32 +3999 0/imm32/output-is-write-only +4000 _Primitive-add-reg-to-mem/imm32/next +4001 _Primitive-add-reg-to-mem: +4002 # add-to var1 var2/reg => 01/add-to var1 var2/r32 +4003 "add-to"/imm32/name +4004 Int-var-and-second-int-var-in-some-register/imm32/inouts +4005 0/imm32/outputs +4006 "01/add-to"/imm32/subx-name +4007 1/imm32/rm32-is-first-inout +4008 2/imm32/r32-is-second-inout +4009 0/imm32/no-imm32 +4010 0/imm32/output-is-write-only +4011 _Primitive-add-mem-to-reg/imm32/next +4012 _Primitive-add-mem-to-reg: +4013 # var1/reg <- add var2 => 03/add var2/rm32 var1/r32 +4014 "add"/imm32/name +4015 Single-int-var-on-stack/imm32/inouts +4016 Single-int-var-in-some-register/imm32/outputs +4017 "03/add"/imm32/subx-name +4018 1/imm32/rm32-is-first-inout +4019 3/imm32/r32-is-first-output +4020 0/imm32/no-imm32 +4021 0/imm32/output-is-write-only +4022 _Primitive-add-lit-to-reg/imm32/next +4023 _Primitive-add-lit-to-reg: +4024 # var1/reg <- add lit => 81 0/subop/add var1/rm32 lit/imm32 +4025 "add"/imm32/name +4026 Single-lit-var/imm32/inouts +4027 Single-int-var-in-some-register/imm32/outputs +4028 "81 0/subop/add"/imm32/subx-name +4029 3/imm32/rm32-is-first-output +4030 0/imm32/no-r32 +4031 1/imm32/imm32-is-first-inout +4032 0/imm32/output-is-write-only +4033 _Primitive-add-lit-to-mem/imm32/next +4034 _Primitive-add-lit-to-mem: +4035 # add-to var1, lit => 81 0/subop/add var1/rm32 lit/imm32 +4036 "add-to"/imm32/name +4037 Int-var-and-literal/imm32/inouts +4038 0/imm32/outputs +4039 "81 0/subop/add"/imm32/subx-name +4040 1/imm32/rm32-is-first-inout +4041 0/imm32/no-r32 +4042 2/imm32/imm32-is-first-inout +4043 0/imm32/output-is-write-only +4044 _Primitive-subtract-from-eax/imm32/next +4045 # - subtract +4046 _Primitive-subtract-from-eax: +4047 # var/eax <- subtract lit => 2d/subtract-from-eax lit/imm32 +4048 "subtract"/imm32/name +4049 Single-lit-var/imm32/inouts +4050 Single-int-var-in-eax/imm32/outputs +4051 "2d/subtract-from-eax"/imm32/subx-name +4052 0/imm32/no-rm32 +4053 0/imm32/no-r32 +4054 1/imm32/imm32-is-first-inout +4055 0/imm32/output-is-write-only +4056 _Primitive-subtract-reg-from-reg/imm32/next +4057 _Primitive-subtract-reg-from-reg: +4058 # var1/reg <- subtract var2/reg => 29/subtract-from var1/rm32 var2/r32 +4059 "subtract"/imm32/name +4060 Single-int-var-in-some-register/imm32/inouts +4061 Single-int-var-in-some-register/imm32/outputs +4062 "29/subtract-from"/imm32/subx-name +4063 3/imm32/rm32-is-first-output +4064 1/imm32/r32-is-first-inout +4065 0/imm32/no-imm32 +4066 0/imm32/output-is-write-only +4067 _Primitive-subtract-reg-from-mem/imm32/next +4068 _Primitive-subtract-reg-from-mem: +4069 # subtract-from var1 var2/reg => 29/subtract-from var1 var2/r32 +4070 "subtract-from"/imm32/name +4071 Int-var-and-second-int-var-in-some-register/imm32/inouts +4072 0/imm32/outputs +4073 "29/subtract-from"/imm32/subx-name +4074 1/imm32/rm32-is-first-inout +4075 2/imm32/r32-is-second-inout +4076 0/imm32/no-imm32 +4077 0/imm32/output-is-write-only +4078 _Primitive-subtract-mem-from-reg/imm32/next +4079 _Primitive-subtract-mem-from-reg: +4080 # var1/reg <- subtract var2 => 2b/subtract var2/rm32 var1/r32 +4081 "subtract"/imm32/name +4082 Single-int-var-on-stack/imm32/inouts +4083 Single-int-var-in-some-register/imm32/outputs +4084 "2b/subtract"/imm32/subx-name +4085 1/imm32/rm32-is-first-inout +4086 3/imm32/r32-is-first-output +4087 0/imm32/no-imm32 +4088 0/imm32/output-is-write-only +4089 _Primitive-subtract-lit-from-reg/imm32/next +4090 _Primitive-subtract-lit-from-reg: +4091 # var1/reg <- subtract lit => 81 5/subop/subtract var1/rm32 lit/imm32 +4092 "subtract"/imm32/name +4093 Single-lit-var/imm32/inouts +4094 Single-int-var-in-some-register/imm32/outputs +4095 "81 5/subop/subtract"/imm32/subx-name +4096 3/imm32/rm32-is-first-output +4097 0/imm32/no-r32 +4098 1/imm32/imm32-is-first-inout +4099 0/imm32/output-is-write-only +4100 _Primitive-subtract-lit-from-mem/imm32/next +4101 _Primitive-subtract-lit-from-mem: +4102 # subtract-from var1, lit => 81 5/subop/subtract var1/rm32 lit/imm32 +4103 "subtract-from"/imm32/name +4104 Int-var-and-literal/imm32/inouts +4105 0/imm32/outputs +4106 "81 5/subop/subtract"/imm32/subx-name +4107 1/imm32/rm32-is-first-inout +4108 0/imm32/no-r32 +4109 2/imm32/imm32-is-first-inout +4110 0/imm32/output-is-write-only +4111 _Primitive-and-with-eax/imm32/next +4112 # - and +4113 _Primitive-and-with-eax: +4114 # var/eax <- and lit => 25/and-with-eax lit/imm32 +4115 "and"/imm32/name +4116 Single-lit-var/imm32/inouts +4117 Single-int-var-in-eax/imm32/outputs +4118 "25/and-with-eax"/imm32/subx-name +4119 0/imm32/no-rm32 +4120 0/imm32/no-r32 +4121 1/imm32/imm32-is-first-inout +4122 0/imm32/output-is-write-only +4123 _Primitive-and-reg-with-reg/imm32/next +4124 _Primitive-and-reg-with-reg: +4125 # var1/reg <- and var2/reg => 21/and-with var1/rm32 var2/r32 +4126 "and"/imm32/name +4127 Single-int-var-in-some-register/imm32/inouts +4128 Single-int-var-in-some-register/imm32/outputs +4129 "21/and-with"/imm32/subx-name +4130 3/imm32/rm32-is-first-output +4131 1/imm32/r32-is-first-inout +4132 0/imm32/no-imm32 +4133 0/imm32/output-is-write-only +4134 _Primitive-and-reg-with-mem/imm32/next +4135 _Primitive-and-reg-with-mem: +4136 # and-with var1 var2/reg => 21/and-with var1 var2/r32 +4137 "and-with"/imm32/name +4138 Int-var-and-second-int-var-in-some-register/imm32/inouts +4139 0/imm32/outputs +4140 "21/and-with"/imm32/subx-name +4141 1/imm32/rm32-is-first-inout +4142 2/imm32/r32-is-second-inout +4143 0/imm32/no-imm32 +4144 0/imm32/output-is-write-only +4145 _Primitive-and-mem-with-reg/imm32/next +4146 _Primitive-and-mem-with-reg: +4147 # var1/reg <- and var2 => 23/and var2/rm32 var1/r32 +4148 "and"/imm32/name +4149 Single-int-var-on-stack/imm32/inouts +4150 Single-int-var-in-some-register/imm32/outputs +4151 "23/and"/imm32/subx-name +4152 1/imm32/rm32-is-first-inout +4153 3/imm32/r32-is-first-output +4154 0/imm32/no-imm32 +4155 0/imm32/output-is-write-only +4156 _Primitive-and-lit-with-reg/imm32/next +4157 _Primitive-and-lit-with-reg: +4158 # var1/reg <- and lit => 81 4/subop/and var1/rm32 lit/imm32 +4159 "and"/imm32/name +4160 Single-lit-var/imm32/inouts +4161 Single-int-var-in-some-register/imm32/outputs +4162 "81 4/subop/and"/imm32/subx-name +4163 3/imm32/rm32-is-first-output +4164 0/imm32/no-r32 +4165 1/imm32/imm32-is-first-inout +4166 0/imm32/output-is-write-only +4167 _Primitive-and-lit-with-mem/imm32/next +4168 _Primitive-and-lit-with-mem: +4169 # and-with var1, lit => 81 4/subop/and var1/rm32 lit/imm32 +4170 "and-with"/imm32/name +4171 Int-var-and-literal/imm32/inouts +4172 0/imm32/outputs +4173 "81 4/subop/and"/imm32/subx-name +4174 1/imm32/rm32-is-first-inout +4175 0/imm32/no-r32 +4176 2/imm32/imm32-is-first-inout +4177 0/imm32/output-is-write-only +4178 _Primitive-or-with-eax/imm32/next +4179 # - or +4180 _Primitive-or-with-eax: +4181 # var/eax <- or lit => 0d/or-with-eax lit/imm32 +4182 "or"/imm32/name +4183 Single-lit-var/imm32/inouts +4184 Single-int-var-in-eax/imm32/outputs +4185 "0d/or-with-eax"/imm32/subx-name +4186 0/imm32/no-rm32 +4187 0/imm32/no-r32 +4188 1/imm32/imm32-is-first-inout +4189 0/imm32/output-is-write-only +4190 _Primitive-or-reg-with-reg/imm32/next +4191 _Primitive-or-reg-with-reg: +4192 # var1/reg <- or var2/reg => 09/or-with var1/rm32 var2/r32 +4193 "or"/imm32/name +4194 Single-int-var-in-some-register/imm32/inouts +4195 Single-int-var-in-some-register/imm32/outputs +4196 "09/or-with"/imm32/subx-name +4197 3/imm32/rm32-is-first-output +4198 1/imm32/r32-is-first-inout +4199 0/imm32/no-imm32 +4200 0/imm32/output-is-write-only +4201 _Primitive-or-reg-with-mem/imm32/next +4202 _Primitive-or-reg-with-mem: +4203 # or-with var1 var2/reg => 09/or-with var1 var2/r32 +4204 "or-with"/imm32/name +4205 Int-var-and-second-int-var-in-some-register/imm32/inouts +4206 0/imm32/outputs +4207 "09/or-with"/imm32/subx-name +4208 1/imm32/rm32-is-first-inout +4209 2/imm32/r32-is-second-inout +4210 0/imm32/no-imm32 +4211 0/imm32/output-is-write-only +4212 _Primitive-or-mem-with-reg/imm32/next +4213 _Primitive-or-mem-with-reg: +4214 # var1/reg <- or var2 => 0b/or var2/rm32 var1/r32 +4215 "or"/imm32/name +4216 Single-int-var-on-stack/imm32/inouts +4217 Single-int-var-in-some-register/imm32/outputs +4218 "0b/or"/imm32/subx-name +4219 1/imm32/rm32-is-first-inout +4220 3/imm32/r32-is-first-output +4221 0/imm32/no-imm32 +4222 0/imm32/output-is-write-only +4223 _Primitive-or-lit-with-reg/imm32/next +4224 _Primitive-or-lit-with-reg: +4225 # var1/reg <- or lit => 81 1/subop/or var1/rm32 lit/imm32 +4226 "or"/imm32/name +4227 Single-lit-var/imm32/inouts +4228 Single-int-var-in-some-register/imm32/outputs +4229 "81 4/subop/or"/imm32/subx-name +4230 3/imm32/rm32-is-first-output +4231 0/imm32/no-r32 +4232 1/imm32/imm32-is-first-inout +4233 0/imm32/output-is-write-only +4234 _Primitive-or-lit-with-mem/imm32/next +4235 _Primitive-or-lit-with-mem: +4236 # or-with var1, lit => 81 1/subop/or var1/rm32 lit/imm32 +4237 "or-with"/imm32/name +4238 Int-var-and-literal/imm32/inouts +4239 0/imm32/outputs +4240 "81 4/subop/or"/imm32/subx-name +4241 1/imm32/rm32-is-first-inout +4242 0/imm32/no-r32 +4243 2/imm32/imm32-is-first-inout +4244 0/imm32/output-is-write-only +4245 _Primitive-xor-with-eax/imm32/next +4246 # - xor +4247 _Primitive-xor-with-eax: +4248 # var/eax <- xor lit => 35/xor-with-eax lit/imm32 +4249 "xor"/imm32/name +4250 Single-lit-var/imm32/inouts +4251 Single-int-var-in-eax/imm32/outputs +4252 "35/xor-with-eax"/imm32/subx-name +4253 0/imm32/no-rm32 +4254 0/imm32/no-r32 +4255 1/imm32/imm32-is-first-inout +4256 0/imm32/output-is-write-only +4257 _Primitive-xor-reg-with-reg/imm32/next +4258 _Primitive-xor-reg-with-reg: +4259 # var1/reg <- xor var2/reg => 31/xor-with var1/rm32 var2/r32 +4260 "xor"/imm32/name +4261 Single-int-var-in-some-register/imm32/inouts +4262 Single-int-var-in-some-register/imm32/outputs +4263 "31/xor-with"/imm32/subx-name +4264 3/imm32/rm32-is-first-output +4265 1/imm32/r32-is-first-inout +4266 0/imm32/no-imm32 +4267 0/imm32/output-is-write-only +4268 _Primitive-xor-reg-with-mem/imm32/next +4269 _Primitive-xor-reg-with-mem: +4270 # xor-with var1 var2/reg => 31/xor-with var1 var2/r32 +4271 "xor-with"/imm32/name +4272 Int-var-and-second-int-var-in-some-register/imm32/inouts +4273 0/imm32/outputs +4274 "31/xor-with"/imm32/subx-name +4275 1/imm32/rm32-is-first-inout +4276 2/imm32/r32-is-second-inout +4277 0/imm32/no-imm32 +4278 0/imm32/output-is-write-only +4279 _Primitive-xor-mem-with-reg/imm32/next +4280 _Primitive-xor-mem-with-reg: +4281 # var1/reg <- xor var2 => 33/xor var2/rm32 var1/r32 +4282 "xor"/imm32/name +4283 Single-int-var-on-stack/imm32/inouts +4284 Single-int-var-in-some-register/imm32/outputs +4285 "33/xor"/imm32/subx-name +4286 1/imm32/rm32-is-first-inout +4287 3/imm32/r32-is-first-output +4288 0/imm32/no-imm32 +4289 0/imm32/output-is-write-only +4290 _Primitive-xor-lit-with-reg/imm32/next +4291 _Primitive-xor-lit-with-reg: +4292 # var1/reg <- xor lit => 81 6/subop/xor var1/rm32 lit/imm32 +4293 "xor"/imm32/name +4294 Single-lit-var/imm32/inouts +4295 Single-int-var-in-some-register/imm32/outputs +4296 "81 4/subop/xor"/imm32/subx-name +4297 3/imm32/rm32-is-first-output +4298 0/imm32/no-r32 +4299 1/imm32/imm32-is-first-inout +4300 0/imm32/output-is-write-only +4301 _Primitive-xor-lit-with-mem/imm32/next +4302 _Primitive-xor-lit-with-mem: +4303 # xor-with var1, lit => 81 6/subop/xor var1/rm32 lit/imm32 +4304 "xor-with"/imm32/name +4305 Int-var-and-literal/imm32/inouts +4306 0/imm32/outputs +4307 "81 4/subop/xor"/imm32/subx-name +4308 1/imm32/rm32-is-first-inout +4309 0/imm32/no-r32 +4310 2/imm32/imm32-is-first-inout +4311 0/imm32/output-is-write-only +4312 _Primitive-copy-to-eax/imm32/next +4313 # - copy +4314 _Primitive-copy-to-eax: +4315 # var/eax <- copy lit => b8/copy-to-eax lit/imm32 +4316 "copy"/imm32/name +4317 Single-lit-var/imm32/inouts +4318 Single-int-var-in-eax/imm32/outputs +4319 "b8/copy-to-eax"/imm32/subx-name +4320 0/imm32/no-rm32 +4321 0/imm32/no-r32 +4322 1/imm32/imm32-is-first-inout +4323 1/imm32/output-is-write-only +4324 _Primitive-copy-to-ecx/imm32/next +4325 _Primitive-copy-to-ecx: +4326 # var/ecx <- copy lit => b9/copy-to-ecx lit/imm32 +4327 "copy"/imm32/name +4328 Single-lit-var/imm32/inouts +4329 Single-int-var-in-ecx/imm32/outputs +4330 "b9/copy-to-ecx"/imm32/subx-name +4331 0/imm32/no-rm32 +4332 0/imm32/no-r32 +4333 1/imm32/imm32-is-first-inout +4334 1/imm32/output-is-write-only +4335 _Primitive-copy-to-edx/imm32/next +4336 _Primitive-copy-to-edx: +4337 # var/edx <- copy lit => ba/copy-to-edx lit/imm32 +4338 "copy"/imm32/name +4339 Single-lit-var/imm32/inouts +4340 Single-int-var-in-edx/imm32/outputs +4341 "ba/copy-to-edx"/imm32/subx-name +4342 0/imm32/no-rm32 +4343 0/imm32/no-r32 +4344 1/imm32/imm32-is-first-inout +4345 1/imm32/output-is-write-only +4346 _Primitive-copy-to-ebx/imm32/next +4347 _Primitive-copy-to-ebx: +4348 # var/ebx <- copy lit => bb/copy-to-ebx lit/imm32 +4349 "copy"/imm32/name +4350 Single-lit-var/imm32/inouts +4351 Single-int-var-in-ebx/imm32/outputs +4352 "bb/copy-to-ebx"/imm32/subx-name +4353 0/imm32/no-rm32 +4354 0/imm32/no-r32 +4355 1/imm32/imm32-is-first-inout +4356 1/imm32/output-is-write-only +4357 _Primitive-copy-to-esi/imm32/next +4358 _Primitive-copy-to-esi: +4359 # var/esi <- copy lit => be/copy-to-esi lit/imm32 +4360 "copy"/imm32/name +4361 Single-lit-var/imm32/inouts +4362 Single-int-var-in-esi/imm32/outputs +4363 "be/copy-to-esi"/imm32/subx-name +4364 0/imm32/no-rm32 +4365 0/imm32/no-r32 +4366 1/imm32/imm32-is-first-inout +4367 1/imm32/output-is-write-only +4368 _Primitive-copy-to-edi/imm32/next +4369 _Primitive-copy-to-edi: +4370 # var/edi <- copy lit => bf/copy-to-edi lit/imm32 +4371 "copy"/imm32/name +4372 Single-lit-var/imm32/inouts +4373 Single-int-var-in-edi/imm32/outputs +4374 "bf/copy-to-edi"/imm32/subx-name +4375 0/imm32/no-rm32 +4376 0/imm32/no-r32 +4377 1/imm32/imm32-is-first-inout +4378 1/imm32/output-is-write-only +4379 _Primitive-copy-reg-to-reg/imm32/next +4380 _Primitive-copy-reg-to-reg: +4381 # var1/reg <- copy var2/reg => 89/copy-to var1/rm32 var2/r32 +4382 "copy"/imm32/name +4383 Single-int-var-in-some-register/imm32/inouts +4384 Single-int-var-in-some-register/imm32/outputs +4385 "89/copy-to"/imm32/subx-name +4386 3/imm32/rm32-is-first-output +4387 1/imm32/r32-is-first-inout +4388 0/imm32/no-imm32 +4389 1/imm32/output-is-write-only +4390 _Primitive-copy-reg-to-mem/imm32/next +4391 _Primitive-copy-reg-to-mem: +4392 # copy-to var1 var2/reg => 89/copy-to var1 var2/r32 +4393 "copy-to"/imm32/name +4394 Int-var-and-second-int-var-in-some-register/imm32/inouts +4395 0/imm32/outputs +4396 "89/copy-to"/imm32/subx-name +4397 1/imm32/rm32-is-first-inout +4398 2/imm32/r32-is-second-inout +4399 0/imm32/no-imm32 +4400 1/imm32/output-is-write-only +4401 _Primitive-copy-mem-to-reg/imm32/next +4402 _Primitive-copy-mem-to-reg: +4403 # var1/reg <- copy var2 => 8b/copy-from var2/rm32 var1/r32 +4404 "copy"/imm32/name +4405 Single-int-var-on-stack/imm32/inouts +4406 Single-int-var-in-some-register/imm32/outputs +4407 "8b/copy-from"/imm32/subx-name +4408 1/imm32/rm32-is-first-inout +4409 3/imm32/r32-is-first-output +4410 0/imm32/no-imm32 +4411 1/imm32/output-is-write-only +4412 _Primitive-copy-lit-to-reg/imm32/next +4413 _Primitive-copy-lit-to-reg: +4414 # var1/reg <- copy lit => c7 0/subop/copy var1/rm32 lit/imm32 +4415 "copy"/imm32/name +4416 Single-lit-var/imm32/inouts +4417 Single-int-var-in-some-register/imm32/outputs +4418 "c7 0/subop/copy"/imm32/subx-name +4419 3/imm32/rm32-is-first-output +4420 0/imm32/no-r32 +4421 1/imm32/imm32-is-first-inout +4422 1/imm32/output-is-write-only +4423 _Primitive-copy-lit-to-mem/imm32/next +4424 _Primitive-copy-lit-to-mem: +4425 # copy-to var1, lit => c7 0/subop/copy var1/rm32 lit/imm32 +4426 "copy-to"/imm32/name +4427 Int-var-and-literal/imm32/inouts +4428 0/imm32/outputs +4429 "c7 0/subop/copy"/imm32/subx-name +4430 1/imm32/rm32-is-first-inout +4431 0/imm32/no-r32 +4432 2/imm32/imm32-is-first-inout +4433 1/imm32/output-is-write-only +4434 0/imm32/next +4435 +4436 Single-int-var-on-stack: +4437 Int-var-on-stack/imm32 +4438 0/imm32/next +4439 +4440 Int-var-on-stack: +4441 "arg1"/imm32/name +4442 Type-int/imm32 +4443 1/imm32/some-block-depth +4444 1/imm32/some-stack-offset +4445 0/imm32/no-register +4446 +4447 Int-var-and-second-int-var-in-some-register: +4448 Int-var-on-stack/imm32 +4449 Single-int-var-in-some-register/imm32/next +4450 +4451 Int-var-and-literal: +4452 Int-var-on-stack/imm32 +4453 Single-lit-var/imm32/next +4454 +4455 Single-int-var-in-some-register: +4456 Int-var-in-some-register/imm32 +4457 0/imm32/next +4458 +4459 Int-var-in-some-register: +4460 "arg1"/imm32/name +4461 Type-int/imm32 +4462 1/imm32/some-block-depth +4463 0/imm32/no-stack-offset +4464 "*"/imm32/register +4465 +4466 Single-int-var-in-eax: +4467 Int-var-in-eax/imm32 +4468 0/imm32/next +4469 +4470 Int-var-in-eax: +4471 "arg1"/imm32/name +4472 Type-int/imm32 +4473 1/imm32/some-block-depth +4474 0/imm32/no-stack-offset +4475 "eax"/imm32/register +4476 +4477 Single-int-var-in-ecx: +4478 Int-var-in-ecx/imm32 +4479 0/imm32/next +4480 +4481 Int-var-in-ecx: +4482 "arg1"/imm32/name +4483 Type-int/imm32 +4484 1/imm32/some-block-depth +4485 0/imm32/no-stack-offset +4486 "ecx"/imm32/register +4487 +4488 Single-int-var-in-edx: +4489 Int-var-in-edx/imm32 +4490 0/imm32/next +4491 +4492 Int-var-in-edx: +4493 "arg1"/imm32/name +4494 Type-int/imm32 +4495 1/imm32/some-block-depth +4496 0/imm32/no-stack-offset +4497 "edx"/imm32/register +4498 +4499 Single-int-var-in-ebx: +4500 Int-var-in-ebx/imm32 +4501 0/imm32/next +4502 +4503 Int-var-in-ebx: +4504 "arg1"/imm32/name +4505 Type-int/imm32 +4506 1/imm32/some-block-depth +4507 0/imm32/no-stack-offset +4508 "ebx"/imm32/register +4509 +4510 Single-int-var-in-esi: +4511 Int-var-in-esi/imm32 +4512 0/imm32/next +4513 +4514 Int-var-in-esi: +4515 "arg1"/imm32/name +4516 Type-int/imm32 +4517 1/imm32/some-block-depth +4518 0/imm32/no-stack-offset +4519 "esi"/imm32/register +4520 +4521 Single-int-var-in-edi: +4522 Int-var-in-edi/imm32 +4523 0/imm32/next +4524 +4525 Int-var-in-edi: +4526 "arg1"/imm32/name +4527 Type-int/imm32 +4528 1/imm32/some-block-depth +4529 0/imm32/no-stack-offset +4530 "edi"/imm32/register +4531 +4532 Single-lit-var: +4533 Lit-var/imm32 +4534 0/imm32/next +4535 +4536 Lit-var: +4537 "literal"/imm32/name +4538 Type-literal/imm32 +4539 1/imm32/some-block-depth +4540 0/imm32/no-stack-offset +4541 0/imm32/no-register +4542 +4543 Type-int: +4544 1/imm32/left/int +4545 0/imm32/right/null +4546 +4547 Type-literal: +4548 0/imm32/left/literal +4549 0/imm32/right/null +4550 +4551 == code +4552 emit-subx-primitive: # out : (addr buffered-file), stmt : (handle statement), primitive : (handle function) +4553 # . prologue +4554 55/push-ebp +4555 89/<- %ebp 4/r32/esp +4556 # . save registers +4557 50/push-eax +4558 51/push-ecx +4559 # ecx = primitive +4560 8b/-> *(ebp+0x10) 1/r32/ecx +4561 # emit primitive name +4562 (write-buffered *(ebp+8) *(ecx+0xc)) # Primitive-subx-name +4563 # emit rm32 if necessary +4564 (emit-subx-rm32 *(ebp+8) *(ecx+0x10) *(ebp+0xc)) # out, Primitive-subx-rm32, stmt +4565 # emit r32 if necessary +4566 (emit-subx-r32 *(ebp+8) *(ecx+0x14) *(ebp+0xc)) # out, Primitive-subx-r32, stmt +4567 # emit imm32 if necessary +4568 (emit-subx-imm32 *(ebp+8) *(ecx+0x18) *(ebp+0xc)) # out, Primitive-subx-imm32, stmt +4569 $emit-subx-primitive:end: +4570 # . restore registers +4571 59/pop-to-ecx +4572 58/pop-to-eax +4573 # . epilogue +4574 89/<- %esp 5/r32/ebp +4575 5d/pop-to-ebp +4576 c3/return +4577 +4578 emit-subx-rm32: # out : (addr buffered-file), l : arg-location, stmt : (handle statement) +4579 # . prologue +4580 55/push-ebp +4581 89/<- %ebp 4/r32/esp +4582 # . save registers +4583 50/push-eax +4584 # if (l == 0) return +4585 81 7/subop/compare *(ebp+0xc) 0/imm32 +4586 74/jump-if-= $emit-subx-rm32:end/disp8 +4587 # +4588 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax +4589 (emit-subx-var-as-rm32 *(ebp+8) %eax) # out, var +4590 $emit-subx-rm32:end: +4591 # . restore registers +4592 58/pop-to-eax +4593 # . epilogue +4594 89/<- %esp 5/r32/ebp +4595 5d/pop-to-ebp +4596 c3/return +4597 +4598 get-stmt-operand-from-arg-location: # stmt : (handle statement), l : arg-location -> var/eax : (handle variable) +4599 # . prologue +4600 55/push-ebp +4601 89/<- %ebp 4/r32/esp +4602 # . save registers +4603 51/push-ecx +4604 # eax = l +4605 8b/-> *(ebp+0xc) 0/r32/eax +4606 # ecx = stmt +4607 8b/-> *(ebp+8) 1/r32/ecx +4608 # if (l == 1) return stmt->inouts->var +4609 { +4610 3d/compare-eax-and 1/imm32 +4611 75/jump-if-!= break/disp8 +4612 $get-stmt-operand-from-arg-location:1: +4613 8b/-> *(ecx+8) 0/r32/eax # Stmt1-inouts +4614 8b/-> *eax 0/r32/eax # Operand-var +4615 eb/jump $get-stmt-operand-from-arg-location:end/disp8 +4616 } +4617 # if (l == 2) return stmt->inouts->next->var +4618 { +4619 3d/compare-eax-and 2/imm32 +4620 75/jump-if-!= break/disp8 +4621 $get-stmt-operand-from-arg-location:2: +4622 8b/-> *(ecx+8) 0/r32/eax # Stmt1-inouts +4623 8b/-> *(eax+4) 0/r32/eax # Operand-next +4624 8b/-> *eax 0/r32/eax # Operand-var +4625 eb/jump $get-stmt-operand-from-arg-location:end/disp8 +4626 } +4627 # if (l == 3) return stmt->outputs +4628 { +4629 3d/compare-eax-and 3/imm32 +4630 75/jump-if-!= break/disp8 +4631 $get-stmt-operand-from-arg-location:3: +4632 8b/-> *(ecx+0xc) 0/r32/eax # Stmt1-outputs +4633 8b/-> *eax 0/r32/eax # Operand-var +4634 eb/jump $get-stmt-operand-from-arg-location:end/disp8 +4635 } +4636 # abort +4637 e9/jump $get-stmt-operand-from-arg-location:abort/disp32 +4638 $get-stmt-operand-from-arg-location:end: +4639 # . restore registers +4640 59/pop-to-ecx +4641 # . epilogue +4642 89/<- %esp 5/r32/ebp +4643 5d/pop-to-ebp +4644 c3/return +4645 +4646 $get-stmt-operand-from-arg-location:abort: +4647 # error("invalid arg-location " eax) +4648 (write-buffered Stderr "invalid arg-location ") +4649 (print-int32-buffered Stderr %eax) +4650 (write-buffered Stderr "\n") +4651 (flush Stderr) +4652 # . syscall(exit, 1) +4653 bb/copy-to-ebx 1/imm32 +4654 b8/copy-to-eax 1/imm32/exit +4655 cd/syscall 0x80/imm8 +4656 # never gets here +4657 +4658 emit-subx-r32: # out : (addr buffered-file), l : arg-location, stmt : (handle statement) +4659 # . prologue +4660 55/push-ebp +4661 89/<- %ebp 4/r32/esp +4662 # . save registers +4663 50/push-eax +4664 51/push-ecx +4665 # if (location == 0) return +4666 81 7/subop/compare *(ebp+0xc) 0/imm32 +4667 0f 84/jump-if-= $emit-subx-r32:end/disp32 +4668 # +4669 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax +4670 (maybe-get Registers *(eax+0x10) 8) # Var-register => eax : (addr register-index) +4671 (write-buffered *(ebp+8) Space) +4672 (print-int32-buffered *(ebp+8) *eax) +4673 (write-buffered *(ebp+8) "/r32") +4674 $emit-subx-r32:end: +4675 # . restore registers +4676 59/pop-to-ecx +4677 58/pop-to-eax +4678 # . epilogue +4679 89/<- %esp 5/r32/ebp +4680 5d/pop-to-ebp +4681 c3/return +4682 +4683 emit-subx-imm32: # out : (addr buffered-file), l : arg-location, stmt : (handle statement) +4684 # . prologue +4685 55/push-ebp +4686 89/<- %ebp 4/r32/esp +4687 # . save registers +4688 50/push-eax +4689 51/push-ecx +4690 # if (location == 0) return +4691 81 7/subop/compare *(ebp+0xc) 0/imm32 +4692 74/jump-if-= $emit-subx-imm32:end/disp8 +4693 # +4694 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax +4695 (write-buffered *(ebp+8) Space) +4696 (write-buffered *(ebp+8) *eax) # Var-name +4697 (write-buffered *(ebp+8) "/imm32") +4698 $emit-subx-imm32:end: +4699 # . restore registers +4700 59/pop-to-ecx +4701 58/pop-to-eax +4702 # . epilogue +4703 89/<- %esp 5/r32/ebp +4704 5d/pop-to-ebp +4705 c3/return +4706 +4707 emit-subx-call: # out : (addr buffered-file), stmt : (handle statement), callee : (handle function) +4708 # . prologue +4709 55/push-ebp +4710 89/<- %ebp 4/r32/esp +4711 # . save registers +4712 50/push-eax +4713 51/push-ecx +4714 # +4715 (write-buffered *(ebp+8) "(") +4716 # - emit function name +4717 8b/-> *(ebp+0x10) 1/r32/ecx +4718 (write-buffered *(ebp+8) *(ecx+4)) # Function-subx-name +4719 # - emit arguments +4720 # var curr/ecx : (handle list var) = stmt->inouts +4721 8b/-> *(ebp+0xc) 1/r32/ecx +4722 8b/-> *(ecx+8) 1/r32/ecx # Stmt1-inouts +4723 { +4724 # if (curr == null) break +4725 81 7/subop/compare %ecx 0/imm32 +4726 74/jump-if-= break/disp8 +4727 # +4728 (emit-subx-call-operand *(ebp+8) *ecx) 4729 # curr = curr->next -4730 8b/-> *(ecx+0x14) 1/r32/ecx # Function-next +4730 8b/-> *(ecx+4) 1/r32/ecx 4731 eb/jump loop/disp8 4732 } -4733 # return null -4734 b8/copy-to-eax 0/imm32 -4735 $find-matching-function:end: +4733 # +4734 (write-buffered *(ebp+8) ")") +4735 $emit-subx-call:end: 4736 # . restore registers 4737 59/pop-to-ecx -4738 # . epilogue -4739 89/<- %esp 5/r32/ebp -4740 5d/pop-to-ebp -4741 c3/return -4742 -4743 find-matching-primitive: # primitives : (handle primitive), stmt : (handle statement) -> result/eax : (handle primitive) -4744 # . prologue -4745 55/push-ebp -4746 89/<- %ebp 4/r32/esp -4747 # . save registers -4748 51/push-ecx -4749 # var curr/ecx : (handle primitive) = primitives -4750 8b/-> *(ebp+8) 1/r32/ecx -4751 { -4752 $find-matching-primitive:loop: -4753 # if (curr == null) break -4754 81 7/subop/compare %ecx 0/imm32 -4755 0f 84/jump-if-= break/disp32 -4756 #? (write-buffered Stderr "prim: ") -4757 #? (write-buffered Stderr *ecx) # Primitive-name -4758 #? (write-buffered Stderr " => ") -4759 #? (write-buffered Stderr *(ecx+0xc)) # Primitive-subx-name -4760 #? (write-buffered Stderr "\n") -4761 #? (flush Stderr) -4762 # if match(curr, stmt) return curr -4763 { -4764 (mu-stmt-matches-primitive? *(ebp+0xc) %ecx) # => eax -4765 3d/compare-eax-and 0/imm32 -4766 74/jump-if-= break/disp8 -4767 89/<- %eax 1/r32/ecx -4768 eb/jump $find-matching-primitive:end/disp8 -4769 } -4770 $find-matching-primitive:next-primitive: -4771 # curr = curr->next -4772 8b/-> *(ecx+0x20) 1/r32/ecx # Primitive-next -4773 e9/jump loop/disp32 -4774 } -4775 # return null -4776 b8/copy-to-eax 0/imm32 -4777 $find-matching-primitive:end: -4778 # . restore registers -4779 59/pop-to-ecx -4780 # . epilogue -4781 89/<- %esp 5/r32/ebp -4782 5d/pop-to-ebp -4783 c3/return -4784 -4785 mu-stmt-matches-function?: # stmt : (handle statement), function : (handle function) => result/eax : boolean -4786 # . prologue -4787 55/push-ebp -4788 89/<- %ebp 4/r32/esp -4789 # . save registers -4790 51/push-ecx -4791 # return function->name == stmt->operation -4792 8b/-> *(ebp+8) 1/r32/ecx -4793 8b/-> *(ebp+0xc) 0/r32/eax -4794 (string-equal? *(ecx+4) *eax) # Stmt1-operation, Function-name => eax -4795 $mu-stmt-matches-function?:end: -4796 # . restore registers -4797 59/pop-to-ecx -4798 # . epilogue -4799 89/<- %esp 5/r32/ebp -4800 5d/pop-to-ebp -4801 c3/return -4802 -4803 mu-stmt-matches-primitive?: # stmt : (handle statement), primitive : (handle primitive) => result/eax : boolean -4804 # A mu stmt matches a primitive if the name matches, all the inout vars -4805 # match, and all the output vars match. -4806 # Vars match if types match and registers match. -4807 # In addition, a stmt output matches a primitive's output if types match -4808 # and the primitive has a wildcard register. -4809 # . prologue -4810 55/push-ebp -4811 89/<- %ebp 4/r32/esp -4812 # . save registers -4813 51/push-ecx -4814 52/push-edx -4815 53/push-ebx -4816 56/push-esi -4817 57/push-edi -4818 # ecx = stmt -4819 8b/-> *(ebp+8) 1/r32/ecx -4820 # edx = primitive -4821 8b/-> *(ebp+0xc) 2/r32/edx -4822 { -4823 $mu-stmt-matches-primitive?:check-name: -4824 # if (primitive->name != stmt->operation) return false -4825 (string-equal? *(ecx+4) *edx) # Stmt1-operation, Primitive-name => eax -4826 3d/compare-eax-and 0/imm32 -4827 75/jump-if-!= break/disp8 -4828 b8/copy-to-eax 0/imm32 -4829 e9/jump $mu-stmt-matches-primitive?:end/disp32 -4830 } -4831 $mu-stmt-matches-primitive?:check-inouts: -4832 # for (curr/esi in stmt->inouts, curr2/edi in primitive->inouts) -4833 8b/-> *(ecx+8) 6/r32/esi # Stmt1-inouts -4834 8b/-> *(edx+4) 7/r32/edi # Primitive-inouts +4738 58/pop-to-eax +4739 # . epilogue +4740 89/<- %esp 5/r32/ebp +4741 5d/pop-to-ebp +4742 c3/return +4743 +4744 emit-subx-call-operand: # out : (addr buffered-file), operand : (handle variable) +4745 # . prologue +4746 55/push-ebp +4747 89/<- %ebp 4/r32/esp +4748 # . save registers +4749 50/push-eax +4750 # eax = operand +4751 8b/-> *(ebp+0xc) 0/r32/eax +4752 # if (operand->register) emit "%__" +4753 { +4754 81 7/subop/compare *(eax+0x10) 0/imm32 # Var-register +4755 74/jump-if-= break/disp8 +4756 $emit-subx-call-operand:register: +4757 (write-buffered *(ebp+8) " %") +4758 (write-buffered *(ebp+8) *(eax+0x10)) # Var-register +4759 e9/jump $emit-subx-call-operand:end/disp32 +4760 } +4761 # else if (operand->stack-offset) emit "*(ebp+__)" +4762 { +4763 81 7/subop/compare *(eax+0xc) 0/imm32 # Var-stack-offset +4764 74/jump-if-= break/disp8 +4765 $emit-subx-call-operand:stack: +4766 (write-buffered *(ebp+8) Space) +4767 (write-buffered *(ebp+8) "*(ebp+") +4768 8b/-> *(ebp+0xc) 0/r32/eax +4769 (print-int32-buffered *(ebp+8) *(eax+0xc)) # Var-stack-offset +4770 (write-buffered *(ebp+8) ")") +4771 e9/jump $emit-subx-call-operand:end/disp32 +4772 } +4773 # else if (operand->type == literal) emit "__" +4774 { +4775 50/push-eax +4776 8b/-> *(eax+4) 0/r32/eax # Var-type +4777 81 7/subop/compare *eax 0/imm32 # Tree-left +4778 58/pop-to-eax +4779 75/jump-if-!= break/disp8 +4780 $emit-subx-call-operand:literal: +4781 (write-buffered *(ebp+8) Space) +4782 (write-buffered *(ebp+8) *eax) +4783 } +4784 $emit-subx-call-operand:end: +4785 # . restore registers +4786 58/pop-to-eax +4787 # . epilogue +4788 89/<- %esp 5/r32/ebp +4789 5d/pop-to-ebp +4790 c3/return +4791 +4792 emit-subx-var-as-rm32: # out : (addr buffered-file), operand : (handle variable) +4793 # . prologue +4794 55/push-ebp +4795 89/<- %ebp 4/r32/esp +4796 # . save registers +4797 50/push-eax +4798 # eax = operand +4799 8b/-> *(ebp+0xc) 0/r32/eax +4800 # if (operand->register) emit "%__" +4801 { +4802 81 7/subop/compare *(eax+0x10) 0/imm32 # Var-register +4803 74/jump-if-= break/disp8 +4804 $emit-subx-var-as-rm32:register: +4805 (write-buffered *(ebp+8) " %") +4806 (write-buffered *(ebp+8) *(eax+0x10)) # Var-register +4807 } +4808 # else if (operand->stack-offset) emit "*(ebp+__)" +4809 { +4810 81 7/subop/compare *(eax+0xc) 0/imm32 # Var-stack-offset +4811 74/jump-if-= break/disp8 +4812 $emit-subx-var-as-rm32:stack: +4813 (write-buffered *(ebp+8) Space) +4814 (write-buffered *(ebp+8) "*(ebp+") +4815 8b/-> *(ebp+0xc) 0/r32/eax +4816 (print-int32-buffered *(ebp+8) *(eax+0xc)) # Var-stack-offset +4817 (write-buffered *(ebp+8) ")") +4818 } +4819 $emit-subx-var-as-rm32:end: +4820 # . restore registers +4821 58/pop-to-eax +4822 # . epilogue +4823 89/<- %esp 5/r32/ebp +4824 5d/pop-to-ebp +4825 c3/return +4826 +4827 find-matching-function: # functions : (addr function), stmt : (handle statement) -> result/eax : (handle function) +4828 # . prologue +4829 55/push-ebp +4830 89/<- %ebp 4/r32/esp +4831 # . save registers +4832 51/push-ecx +4833 # var curr/ecx : (handle function) = functions +4834 8b/-> *(ebp+8) 1/r32/ecx 4835 { -4836 # if (curr == 0 && curr2 == 0) move on to check outputs -4837 { -4838 81 7/subop/compare %esi 0/imm32 -4839 75/jump-if-!= break/disp8 -4840 $mu-stmt-matches-primitive?:stmt-inout-is-null: -4841 { -4842 81 7/subop/compare %edi 0/imm32 -4843 75/jump-if-!= break/disp8 -4844 # -4845 e9/jump $mu-stmt-matches-primitive?:check-outputs/disp32 -4846 } -4847 # return false -4848 b8/copy-to-eax 0/imm32/false -4849 e9/jump $mu-stmt-matches-primitive?:end/disp32 -4850 } -4851 # if (curr2 == 0) return false -4852 { -4853 81 7/subop/compare %edi 0/imm32 -4854 75/jump-if-!= break/disp8 -4855 $mu-stmt-matches-primitive?:prim-inout-is-null: -4856 b8/copy-to-eax 0/imm32/false -4857 e9/jump $mu-stmt-matches-primitive?:end/disp32 -4858 } -4859 # if (curr != curr2) return false -4860 { -4861 (operand-matches-primitive? *esi *edi) # => eax -4862 3d/compare-eax-and 0/imm32 -4863 75/jump-if-!= break/disp8 -4864 b8/copy-to-eax 0/imm32/false -4865 e9/jump $mu-stmt-matches-primitive?:end/disp32 -4866 } -4867 # curr=curr->next -4868 8b/-> *(esi+4) 6/r32/esi # Operand-next -4869 # curr2=curr2->next -4870 8b/-> *(edi+4) 7/r32/edi # Operand-next -4871 eb/jump loop/disp8 -4872 } -4873 $mu-stmt-matches-primitive?:check-outputs: -4874 # for (curr/esi in stmt->outputs, curr2/edi in primitive->outputs) -4875 8b/-> *(ecx+0xc) 6/r32/esi # Stmt1-outputs -4876 8b/-> *(edx+8) 7/r32/edi # Primitive-outputs -4877 { -4878 # if (curr == 0) return (curr2 == 0) -4879 { -4880 $mu-stmt-matches-primitive?:check-output: -4881 81 7/subop/compare %esi 0/imm32 -4882 75/jump-if-!= break/disp8 -4883 { -4884 81 7/subop/compare %edi 0/imm32 -4885 75/jump-if-!= break/disp8 -4886 # return true -4887 b8/copy-to-eax 1/imm32 -4888 e9/jump $mu-stmt-matches-primitive?:end/disp32 -4889 } -4890 # return false -4891 b8/copy-to-eax 0/imm32 -4892 e9/jump $mu-stmt-matches-primitive?:end/disp32 -4893 } -4894 # if (curr2 == 0) return false -4895 { -4896 81 7/subop/compare %edi 0/imm32 -4897 75/jump-if-!= break/disp8 -4898 b8/copy-to-eax 0/imm32 -4899 e9/jump $mu-stmt-matches-primitive?:end/disp32 -4900 } -4901 # if (curr != curr2) return false -4902 { -4903 (operand-matches-primitive? *esi *edi) # List-value List-value => eax -4904 3d/compare-eax-and 0/imm32 -4905 75/jump-if-!= break/disp8 -4906 b8/copy-to-eax 0/imm32 -4907 e9/jump $mu-stmt-matches-primitive?:end/disp32 -4908 } -4909 # curr=curr->next -4910 8b/-> *(esi+4) 6/r32/esi # Operand-next -4911 # curr2=curr2->next -4912 8b/-> *(edi+4) 7/r32/edi # Operand-next -4913 eb/jump loop/disp8 -4914 } -4915 $mu-stmt-matches-primitive?:return-true: -4916 b8/copy-to-eax 1/imm32 -4917 $mu-stmt-matches-primitive?:end: -4918 # . restore registers -4919 5f/pop-to-edi -4920 5e/pop-to-esi -4921 5b/pop-to-ebx -4922 5a/pop-to-edx -4923 59/pop-to-ecx -4924 # . epilogue -4925 89/<- %esp 5/r32/ebp -4926 5d/pop-to-ebp -4927 c3/return -4928 -4929 operand-matches-primitive?: # var : (handle var), prim-var : (handle var) => result/eax : boolean -4930 # . prologue -4931 55/push-ebp -4932 89/<- %ebp 4/r32/esp -4933 # . save registers +4836 # if (curr == null) break +4837 81 7/subop/compare %ecx 0/imm32 +4838 74/jump-if-= break/disp8 +4839 # if match(stmt, curr) return curr +4840 { +4841 (mu-stmt-matches-function? *(ebp+0xc) %ecx) # => eax +4842 3d/compare-eax-and 0/imm32 +4843 74/jump-if-= break/disp8 +4844 89/<- %eax 1/r32/ecx +4845 eb/jump $find-matching-function:end/disp8 +4846 } +4847 # curr = curr->next +4848 8b/-> *(ecx+0x14) 1/r32/ecx # Function-next +4849 eb/jump loop/disp8 +4850 } +4851 # return null +4852 b8/copy-to-eax 0/imm32 +4853 $find-matching-function:end: +4854 # . restore registers +4855 59/pop-to-ecx +4856 # . epilogue +4857 89/<- %esp 5/r32/ebp +4858 5d/pop-to-ebp +4859 c3/return +4860 +4861 find-matching-primitive: # primitives : (handle primitive), stmt : (handle statement) -> result/eax : (handle primitive) +4862 # . prologue +4863 55/push-ebp +4864 89/<- %ebp 4/r32/esp +4865 # . save registers +4866 51/push-ecx +4867 # var curr/ecx : (handle primitive) = primitives +4868 8b/-> *(ebp+8) 1/r32/ecx +4869 { +4870 $find-matching-primitive:loop: +4871 # if (curr == null) break +4872 81 7/subop/compare %ecx 0/imm32 +4873 0f 84/jump-if-= break/disp32 +4874 #? (write-buffered Stderr "prim: ") +4875 #? (write-buffered Stderr *ecx) # Primitive-name +4876 #? (write-buffered Stderr " => ") +4877 #? (write-buffered Stderr *(ecx+0xc)) # Primitive-subx-name +4878 #? (write-buffered Stderr "\n") +4879 #? (flush Stderr) +4880 # if match(curr, stmt) return curr +4881 { +4882 (mu-stmt-matches-primitive? *(ebp+0xc) %ecx) # => eax +4883 3d/compare-eax-and 0/imm32 +4884 74/jump-if-= break/disp8 +4885 89/<- %eax 1/r32/ecx +4886 eb/jump $find-matching-primitive:end/disp8 +4887 } +4888 $find-matching-primitive:next-primitive: +4889 # curr = curr->next +4890 8b/-> *(ecx+0x20) 1/r32/ecx # Primitive-next +4891 e9/jump loop/disp32 +4892 } +4893 # return null +4894 b8/copy-to-eax 0/imm32 +4895 $find-matching-primitive:end: +4896 # . restore registers +4897 59/pop-to-ecx +4898 # . epilogue +4899 89/<- %esp 5/r32/ebp +4900 5d/pop-to-ebp +4901 c3/return +4902 +4903 mu-stmt-matches-function?: # stmt : (handle statement), function : (handle function) => result/eax : boolean +4904 # . prologue +4905 55/push-ebp +4906 89/<- %ebp 4/r32/esp +4907 # . save registers +4908 51/push-ecx +4909 # return function->name == stmt->operation +4910 8b/-> *(ebp+8) 1/r32/ecx +4911 8b/-> *(ebp+0xc) 0/r32/eax +4912 (string-equal? *(ecx+4) *eax) # Stmt1-operation, Function-name => eax +4913 $mu-stmt-matches-function?:end: +4914 # . restore registers +4915 59/pop-to-ecx +4916 # . epilogue +4917 89/<- %esp 5/r32/ebp +4918 5d/pop-to-ebp +4919 c3/return +4920 +4921 mu-stmt-matches-primitive?: # stmt : (handle statement), primitive : (handle primitive) => result/eax : boolean +4922 # A mu stmt matches a primitive if the name matches, all the inout vars +4923 # match, and all the output vars match. +4924 # Vars match if types match and registers match. +4925 # In addition, a stmt output matches a primitive's output if types match +4926 # and the primitive has a wildcard register. +4927 # . prologue +4928 55/push-ebp +4929 89/<- %ebp 4/r32/esp +4930 # . save registers +4931 51/push-ecx +4932 52/push-edx +4933 53/push-ebx 4934 56/push-esi 4935 57/push-edi -4936 # esi = var -4937 8b/-> *(ebp+8) 6/r32/esi -4938 # edi = prim-var -4939 8b/-> *(ebp+0xc) 7/r32/edi -4940 # if (var->type != prim-var->type) return false -4941 (type-equal? *(esi+4) *(edi+4)) # Var-type, Var-type => eax -4942 3d/compare-eax-and 0/imm32 -4943 b8/copy-to-eax 0/imm32/false -4944 74/jump-if-= $operand-matches-primitive?:end/disp8 -4945 # return false if var->register doesn't match prim-var->register -4946 { -4947 # if addresses are equal, don't return here -4948 8b/-> *(esi+0x10) 0/r32/eax -4949 39/compare *(edi+0x10) 0/r32/eax -4950 74/jump-if-= break/disp8 -4951 # if either address is 0, return false -4952 3d/compare-eax-and 0/imm32 -4953 74/jump-if-= $operand-matches-primitive?:end/disp8 # eax goes from meaning var->register to result -4954 81 7/subop/compare *(edi+0x10) 0/imm32 -4955 74/jump-if-= $operand-matches-primitive?:end/disp8 # eax goes from meaning var->register to result -4956 # if prim-var->register is "*", return true -4957 (string-equal? *(edi+0x10) "*") # Var-register -4958 3d/compare-eax-and 0/imm32 -4959 b8/copy-to-eax 1/imm32/true -4960 75/jump-if-!= $operand-matches-primitive?:end/disp8 -4961 # if string contents don't match, return false -4962 (string-equal? *(esi+0x10) *(edi+0x10)) # Var-register Var-register -4963 3d/compare-eax-and 0/imm32 -4964 b8/copy-to-eax 0/imm32/false -4965 74/jump-if-= $operand-matches-primitive?:end/disp8 -4966 } -4967 # return true -4968 b8/copy-to-eax 1/imm32/true -4969 $operand-matches-primitive?:end: -4970 # . restore registers -4971 5f/pop-to-edi -4972 5e/pop-to-esi -4973 # . epilogue -4974 89/<- %esp 5/r32/ebp -4975 5d/pop-to-ebp -4976 c3/return -4977 -4978 type-equal?: # a : (handle tree type-id), b : (handle tree type-id) => result/eax : boolean -4979 # . prologue -4980 55/push-ebp -4981 89/<- %ebp 4/r32/esp -4982 # . save registers -4983 51/push-ecx -4984 52/push-edx -4985 # ecx = a -4986 8b/-> *(ebp+8) 1/r32/ecx -4987 # edx = b -4988 8b/-> *(ebp+0xc) 2/r32/edx -4989 # if (a == b) return true -4990 8b/-> %ecx 0/r32/eax # Var-type -4991 39/compare %edx 0/r32/eax # Var-type -4992 b8/copy-to-eax 1/imm32/true -4993 74/jump-if-= $type-equal?:end/disp8 -4994 # if (a < MAX_TYPE_ID) return false -4995 81 7/subop/compare %ecx 0x10000/imm32 -4996 b8/copy-to-eax 0/imm32/false -4997 72/jump-if-addr< $type-equal?:end/disp8 -4998 # if (b < MAX_TYPE_ID) return false -4999 81 7/subop/compare %edx 0x10000/imm32 -5000 b8/copy-to-eax 0/imm32/false -5001 72/jump-if-addr< $type-equal?:end/disp8 -5002 # if (!type-equal?(a->left, b->left)) return false -5003 (type-equal? *ecx *edx) # Tree-left, Tree-left => eax -5004 3d/compare-eax-and 0/imm32 -5005 74/jump-if-= $type-equal?:end/disp8 -5006 # return type-equal?(a->right, b->right) -5007 (type-equal? *(ecx+4) *(edx+4)) # Tree-right, Tree-right => eax -5008 $type-equal?:end: -5009 # . restore registers -5010 5a/pop-to-edx -5011 59/pop-to-ecx -5012 # . epilogue -5013 89/<- %esp 5/r32/ebp -5014 5d/pop-to-ebp -5015 c3/return -5016 -5017 test-emit-subx-statement-primitive: -5018 # Primitive operation on a variable on the stack. -5019 # increment foo -5020 # => -5021 # ff 0/subop/increment *(ebp-8) -5022 # -5023 # There's a variable on the var stack as follows: -5024 # name: 'foo' -5025 # type: int -5026 # stack-offset: -8 -5027 # -5028 # There's a primitive with this info: -5029 # name: 'increment' -5030 # inouts: int/mem -5031 # value: 'ff 0/subop/increment' -5032 # -5033 # There's nothing in functions. -5034 # -5035 # . prologue -5036 55/push-ebp -5037 89/<- %ebp 4/r32/esp -5038 # setup -5039 (clear-stream _test-output-stream) -5040 (clear-stream $_test-output-buffered-file->buffer) -5041 # var type/ecx : (handle tree type-id) = int -5042 68/push 0/imm32/right/null -5043 68/push 1/imm32/left/int -5044 89/<- %ecx 4/r32/esp -5045 # var var-foo/ecx : var -5046 68/push 0/imm32/no-register -5047 68/push -8/imm32/stack-offset -5048 68/push 1/imm32/block-depth -5049 51/push-ecx -5050 68/push "foo"/imm32 -5051 89/<- %ecx 4/r32/esp -5052 # var operand/ebx : (list var) -5053 68/push 0/imm32/next -5054 51/push-ecx/var-foo -5055 89/<- %ebx 4/r32/esp -5056 # var stmt/esi : statement -5057 68/push 0/imm32/next -5058 68/push 0/imm32/outputs -5059 53/push-ebx/operands -5060 68/push "increment"/imm32/operation -5061 68/push 1/imm32 -5062 89/<- %esi 4/r32/esp -5063 # var primitives/ebx : primitive -5064 68/push 0/imm32/next -5065 68/push 0/imm32/output-is-write-only -5066 68/push 0/imm32/no-imm32 -5067 68/push 0/imm32/no-r32 -5068 68/push 1/imm32/rm32-is-first-inout -5069 68/push "ff 0/subop/increment"/imm32/subx-name -5070 68/push 0/imm32/outputs -5071 53/push-ebx/inouts # hack; in practice we won't have the same var in function definition and call -5072 68/push "increment"/imm32/name -5073 89/<- %ebx 4/r32/esp -5074 # convert -5075 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) -5076 (flush _test-output-buffered-file) -5077 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -5083 # check output -5084 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment *(ebp+0xfffffff8)" "F - test-emit-subx-statement-primitive") -5085 # . epilogue -5086 89/<- %esp 5/r32/ebp -5087 5d/pop-to-ebp -5088 c3/return -5089 -5090 test-emit-subx-statement-primitive-register: -5091 # Primitive operation on a variable in a register. -5092 # foo <- increment -5093 # => -5094 # ff 0/subop/increment %eax # sub-optimal, but should suffice -5095 # -5096 # There's a variable on the var stack as follows: -5097 # name: 'foo' -5098 # type: int -5099 # register: 'eax' -5100 # -5101 # There's a primitive with this info: -5102 # name: 'increment' -5103 # out: int/reg -5104 # value: 'ff 0/subop/increment' -5105 # -5106 # There's nothing in functions. -5107 # -5108 # . prologue -5109 55/push-ebp -5110 89/<- %ebp 4/r32/esp -5111 # setup -5112 (clear-stream _test-output-stream) -5113 (clear-stream $_test-output-buffered-file->buffer) -5114 # var type/ecx : (handle tree type-id) = int -5115 68/push 0/imm32/right/null -5116 68/push 1/imm32/left/int -5117 89/<- %ecx 4/r32/esp -5118 # var var-foo/ecx : var in eax -5119 68/push "eax"/imm32/register -5120 68/push 0/imm32/no-stack-offset -5121 68/push 1/imm32/block-depth -5122 51/push-ecx -5123 68/push "foo"/imm32 -5124 89/<- %ecx 4/r32/esp -5125 # var operand/ebx : (list var) -5126 68/push 0/imm32/next -5127 51/push-ecx/var-foo -5128 89/<- %ebx 4/r32/esp -5129 # var stmt/esi : statement -5130 68/push 0/imm32/next -5131 53/push-ebx/outputs -5132 68/push 0/imm32/inouts -5133 68/push "increment"/imm32/operation -5134 68/push 1/imm32 -5135 89/<- %esi 4/r32/esp -5136 # var formal-var/ebx : var in any register -5137 68/push Any-register/imm32 -5138 68/push 0/imm32/no-stack-offset -5139 68/push 1/imm32/block-depth -5140 ff 6/subop/push *(ecx+4) # Var-type -5141 68/push "dummy"/imm32 -5142 89/<- %ebx 4/r32/esp -5143 # var operand/ebx : (list var) -5144 68/push 0/imm32/next -5145 53/push-ebx/formal-var -5146 89/<- %ebx 4/r32/esp -5147 # var primitives/ebx : primitive -5148 68/push 0/imm32/next -5149 68/push 0/imm32/output-is-write-only -5150 68/push 0/imm32/no-imm32 -5151 68/push 0/imm32/no-r32 -5152 68/push 3/imm32/rm32-in-first-output -5153 68/push "ff 0/subop/increment"/imm32/subx-name -5154 53/push-ebx/outputs -5155 68/push 0/imm32/inouts -5156 68/push "increment"/imm32/name -5157 89/<- %ebx 4/r32/esp -5158 # convert -5159 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) -5160 (flush _test-output-buffered-file) -5161 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -5167 # check output -5168 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-primitive-register") -5169 # . epilogue -5170 89/<- %esp 5/r32/ebp -5171 5d/pop-to-ebp -5172 c3/return -5173 -5174 test-emit-subx-statement-select-primitive: -5175 # Select the right primitive between overloads. -5176 # foo <- increment -5177 # => -5178 # ff 0/subop/increment %eax # sub-optimal, but should suffice -5179 # -5180 # There's a variable on the var stack as follows: -5181 # name: 'foo' -5182 # type: int -5183 # register: 'eax' -5184 # -5185 # There's two primitives, as follows: -5186 # - name: 'increment' -5187 # out: int/reg -5188 # value: 'ff 0/subop/increment' -5189 # - name: 'increment' -5190 # inout: int/mem -5191 # value: 'ff 0/subop/increment' -5192 # -5193 # There's nothing in functions. -5194 # -5195 # . prologue -5196 55/push-ebp -5197 89/<- %ebp 4/r32/esp -5198 # setup -5199 (clear-stream _test-output-stream) -5200 (clear-stream $_test-output-buffered-file->buffer) -5201 # var type/ecx : (handle tree type-id) = int -5202 68/push 0/imm32/right/null -5203 68/push 1/imm32/left/int -5204 89/<- %ecx 4/r32/esp -5205 # var var-foo/ecx : var in eax -5206 68/push "eax"/imm32/register -5207 68/push 0/imm32/no-stack-offset -5208 68/push 1/imm32/block-depth -5209 51/push-ecx -5210 68/push "foo"/imm32 -5211 89/<- %ecx 4/r32/esp -5212 # var real-outputs/edi : (list var) -5213 68/push 0/imm32/next -5214 51/push-ecx/var-foo -5215 89/<- %edi 4/r32/esp -5216 # var stmt/esi : statement -5217 68/push 0/imm32/next -5218 57/push-edi/outputs -5219 68/push 0/imm32/inouts -5220 68/push "increment"/imm32/operation -5221 68/push 1/imm32 -5222 89/<- %esi 4/r32/esp -5223 # var formal-var/ebx : var in any register -5224 68/push Any-register/imm32 -5225 68/push 0/imm32/no-stack-offset -5226 68/push 1/imm32/block-depth -5227 ff 6/subop/push *(ecx+4) # Var-type -5228 68/push "dummy"/imm32 -5229 89/<- %ebx 4/r32/esp -5230 # var formal-outputs/ebx : (list var) = {formal-var, 0} -5231 68/push 0/imm32/next -5232 53/push-ebx/formal-var -5233 89/<- %ebx 4/r32/esp -5234 # var primitive1/ebx : primitive -5235 68/push 0/imm32/next -5236 68/push 0/imm32/output-is-write-only -5237 68/push 0/imm32/no-imm32 -5238 68/push 0/imm32/no-r32 -5239 68/push 3/imm32/rm32-in-first-output -5240 68/push "ff 0/subop/increment"/imm32/subx-name -5241 53/push-ebx/outputs/formal-outputs -5242 68/push 0/imm32/inouts -5243 68/push "increment"/imm32/name -5244 89/<- %ebx 4/r32/esp -5245 # var primitives/ebx : primitive -5246 53/push-ebx/next -5247 68/push 0/imm32/output-is-write-only -5248 68/push 0/imm32/no-imm32 -5249 68/push 0/imm32/no-r32 -5250 68/push 1/imm32/rm32-is-first-inout -5251 68/push "ff 0/subop/increment"/imm32/subx-name -5252 68/push 0/imm32/outputs -5253 57/push-edi/inouts/real-outputs # hack; in practice we won't have the same var in function definition and call -5254 68/push "increment"/imm32/name -5255 89/<- %ebx 4/r32/esp -5256 # convert -5257 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) -5258 (flush _test-output-buffered-file) -5259 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -5265 # check output -5266 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-select-primitive") -5267 # . epilogue -5268 89/<- %esp 5/r32/ebp -5269 5d/pop-to-ebp -5270 c3/return -5271 -5272 test-emit-subx-statement-select-primitive-2: -5273 # Select the right primitive between overloads. -5274 # foo <- increment -5275 # => -5276 # ff 0/subop/increment %eax # sub-optimal, but should suffice -5277 # -5278 # There's a variable on the var stack as follows: -5279 # name: 'foo' -5280 # type: int -5281 # register: 'eax' -5282 # -5283 # There's two primitives, as follows: -5284 # - name: 'increment' -5285 # out: int/reg -5286 # value: 'ff 0/subop/increment' -5287 # - name: 'increment' -5288 # inout: int/mem -5289 # value: 'ff 0/subop/increment' -5290 # -5291 # There's nothing in functions. -5292 # -5293 # . prologue -5294 55/push-ebp -5295 89/<- %ebp 4/r32/esp -5296 # setup -5297 (clear-stream _test-output-stream) -5298 (clear-stream $_test-output-buffered-file->buffer) -5299 # var type/ecx : (handle tree type-id) = int -5300 68/push 0/imm32/right/null -5301 68/push 1/imm32/left/int -5302 89/<- %ecx 4/r32/esp -5303 # var var-foo/ecx : var in eax -5304 68/push "eax"/imm32/register -5305 68/push 0/imm32/no-stack-offset -5306 68/push 1/imm32/block-depth -5307 51/push-ecx -5308 68/push "foo"/imm32 -5309 89/<- %ecx 4/r32/esp -5310 # var inouts/edi : (list var) -5311 68/push 0/imm32/next -5312 51/push-ecx/var-foo -5313 89/<- %edi 4/r32/esp -5314 # var stmt/esi : statement -5315 68/push 0/imm32/next -5316 68/push 0/imm32/outputs -5317 57/push-edi/inouts -5318 68/push "increment"/imm32/operation -5319 68/push 1/imm32 -5320 89/<- %esi 4/r32/esp -5321 # var formal-var/ebx : var in any register -5322 68/push Any-register/imm32 -5323 68/push 0/imm32/no-stack-offset -5324 68/push 1/imm32/block-depth -5325 ff 6/subop/push *(ecx+4) # Var-type -5326 68/push "dummy"/imm32 -5327 89/<- %ebx 4/r32/esp -5328 # var operand/ebx : (list var) -5329 68/push 0/imm32/next -5330 53/push-ebx/formal-var -5331 89/<- %ebx 4/r32/esp -5332 # var primitive1/ebx : primitive -5333 68/push 0/imm32/next -5334 68/push 0/imm32/output-is-write-only -5335 68/push 0/imm32/no-imm32 -5336 68/push 0/imm32/no-r32 -5337 68/push 3/imm32/rm32-in-first-output -5338 68/push "ff 0/subop/increment"/imm32/subx-name -5339 53/push-ebx/outputs/formal-outputs -5340 68/push 0/imm32/inouts -5341 68/push "increment"/imm32/name -5342 89/<- %ebx 4/r32/esp -5343 # var primitives/ebx : primitive -5344 53/push-ebx/next -5345 68/push 0/imm32/output-is-write-only -5346 68/push 0/imm32/no-imm32 -5347 68/push 0/imm32/no-r32 -5348 68/push 1/imm32/rm32-is-first-inout -5349 68/push "ff 0/subop/increment"/imm32/subx-name -5350 68/push 0/imm32/outputs -5351 57/push-edi/inouts/real-outputs # hack; in practice we won't have the same var in function definition and call -5352 68/push "increment"/imm32/name -5353 89/<- %ebx 4/r32/esp -5354 # convert -5355 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) -5356 (flush _test-output-buffered-file) -5357 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -5363 # check output -5364 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-select-primitive-2") -5365 # . epilogue -5366 89/<- %esp 5/r32/ebp -5367 5d/pop-to-ebp -5368 c3/return -5369 -5370 test-increment-register: -5371 # Select the right primitive between overloads. -5372 # foo <- increment -5373 # => -5374 # 50/increment-eax -5375 # -5376 # There's a variable on the var stack as follows: -5377 # name: 'foo' -5378 # type: int -5379 # register: 'eax' -5380 # -5381 # Primitives are the global definitions. -5382 # -5383 # There are no functions defined. -5384 # -5385 # . prologue -5386 55/push-ebp -5387 89/<- %ebp 4/r32/esp -5388 # setup -5389 (clear-stream _test-output-stream) -5390 (clear-stream $_test-output-buffered-file->buffer) -5391 # var type/ecx : (handle tree type-id) = int -5392 68/push 0/imm32/right/null -5393 68/push 1/imm32/left/int -5394 89/<- %ecx 4/r32/esp -5395 # var var-foo/ecx : var in eax -5396 68/push "eax"/imm32/register -5397 68/push 0/imm32/no-stack-offset -5398 68/push 1/imm32/block-depth -5399 51/push-ecx -5400 68/push "foo"/imm32 -5401 89/<- %ecx 4/r32/esp -5402 # var real-outputs/edi : (list var) -5403 68/push 0/imm32/next -5404 51/push-ecx/var-foo -5405 89/<- %edi 4/r32/esp -5406 # var stmt/esi : statement -5407 68/push 0/imm32/next -5408 57/push-edi/outputs -5409 68/push 0/imm32/inouts -5410 68/push "increment"/imm32/operation -5411 68/push 1/imm32/regular-statement -5412 89/<- %esi 4/r32/esp -5413 # convert -5414 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -5415 (flush _test-output-buffered-file) -5416 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -5422 # check output -5423 (check-next-stream-line-equal _test-output-stream "40/increment-eax" "F - test-increment-register") -5424 # . epilogue -5425 89/<- %esp 5/r32/ebp -5426 5d/pop-to-ebp -5427 c3/return -5428 -5429 test-increment-var: -5430 # Select the right primitive between overloads. -5431 # foo <- increment -5432 # => -5433 # ff 0/subop/increment %eax # sub-optimal, but should suffice -5434 # -5435 # There's a variable on the var stack as follows: -5436 # name: 'foo' -5437 # type: int -5438 # register: 'eax' -5439 # -5440 # Primitives are the global definitions. -5441 # -5442 # There are no functions defined. -5443 # -5444 # . prologue -5445 55/push-ebp -5446 89/<- %ebp 4/r32/esp -5447 # setup -5448 (clear-stream _test-output-stream) -5449 (clear-stream $_test-output-buffered-file->buffer) -5450 # var type/ecx : (handle tree type-id) = int -5451 68/push 0/imm32/right/null -5452 68/push 1/imm32/left/int -5453 89/<- %ecx 4/r32/esp -5454 # var var-foo/ecx : var in eax -5455 68/push "eax"/imm32/register -5456 68/push 0/imm32/no-stack-offset -5457 68/push 1/imm32/block-depth -5458 51/push-ecx -5459 68/push "foo"/imm32 -5460 89/<- %ecx 4/r32/esp -5461 # var inouts/edi : (list var) -5462 68/push 0/imm32/next -5463 51/push-ecx/var-foo -5464 89/<- %edi 4/r32/esp -5465 # var stmt/esi : statement -5466 68/push 0/imm32/next -5467 68/push 0/imm32/outputs -5468 57/push-edi/inouts -5469 68/push "increment"/imm32/operation -5470 68/push 1/imm32 -5471 89/<- %esi 4/r32/esp +4936 # ecx = stmt +4937 8b/-> *(ebp+8) 1/r32/ecx +4938 # edx = primitive +4939 8b/-> *(ebp+0xc) 2/r32/edx +4940 { +4941 $mu-stmt-matches-primitive?:check-name: +4942 # if (primitive->name != stmt->operation) return false +4943 (string-equal? *(ecx+4) *edx) # Stmt1-operation, Primitive-name => eax +4944 3d/compare-eax-and 0/imm32 +4945 75/jump-if-!= break/disp8 +4946 b8/copy-to-eax 0/imm32 +4947 e9/jump $mu-stmt-matches-primitive?:end/disp32 +4948 } +4949 $mu-stmt-matches-primitive?:check-inouts: +4950 # for (curr/esi in stmt->inouts, curr2/edi in primitive->inouts) +4951 8b/-> *(ecx+8) 6/r32/esi # Stmt1-inouts +4952 8b/-> *(edx+4) 7/r32/edi # Primitive-inouts +4953 { +4954 # if (curr == 0 && curr2 == 0) move on to check outputs +4955 { +4956 81 7/subop/compare %esi 0/imm32 +4957 75/jump-if-!= break/disp8 +4958 $mu-stmt-matches-primitive?:stmt-inout-is-null: +4959 { +4960 81 7/subop/compare %edi 0/imm32 +4961 75/jump-if-!= break/disp8 +4962 # +4963 e9/jump $mu-stmt-matches-primitive?:check-outputs/disp32 +4964 } +4965 # return false +4966 b8/copy-to-eax 0/imm32/false +4967 e9/jump $mu-stmt-matches-primitive?:end/disp32 +4968 } +4969 # if (curr2 == 0) return false +4970 { +4971 81 7/subop/compare %edi 0/imm32 +4972 75/jump-if-!= break/disp8 +4973 $mu-stmt-matches-primitive?:prim-inout-is-null: +4974 b8/copy-to-eax 0/imm32/false +4975 e9/jump $mu-stmt-matches-primitive?:end/disp32 +4976 } +4977 # if (curr != curr2) return false +4978 { +4979 (operand-matches-primitive? *esi *edi) # => eax +4980 3d/compare-eax-and 0/imm32 +4981 75/jump-if-!= break/disp8 +4982 b8/copy-to-eax 0/imm32/false +4983 e9/jump $mu-stmt-matches-primitive?:end/disp32 +4984 } +4985 # curr=curr->next +4986 8b/-> *(esi+4) 6/r32/esi # Operand-next +4987 # curr2=curr2->next +4988 8b/-> *(edi+4) 7/r32/edi # Operand-next +4989 eb/jump loop/disp8 +4990 } +4991 $mu-stmt-matches-primitive?:check-outputs: +4992 # for (curr/esi in stmt->outputs, curr2/edi in primitive->outputs) +4993 8b/-> *(ecx+0xc) 6/r32/esi # Stmt1-outputs +4994 8b/-> *(edx+8) 7/r32/edi # Primitive-outputs +4995 { +4996 # if (curr == 0) return (curr2 == 0) +4997 { +4998 $mu-stmt-matches-primitive?:check-output: +4999 81 7/subop/compare %esi 0/imm32 +5000 75/jump-if-!= break/disp8 +5001 { +5002 81 7/subop/compare %edi 0/imm32 +5003 75/jump-if-!= break/disp8 +5004 # return true +5005 b8/copy-to-eax 1/imm32 +5006 e9/jump $mu-stmt-matches-primitive?:end/disp32 +5007 } +5008 # return false +5009 b8/copy-to-eax 0/imm32 +5010 e9/jump $mu-stmt-matches-primitive?:end/disp32 +5011 } +5012 # if (curr2 == 0) return false +5013 { +5014 81 7/subop/compare %edi 0/imm32 +5015 75/jump-if-!= break/disp8 +5016 b8/copy-to-eax 0/imm32 +5017 e9/jump $mu-stmt-matches-primitive?:end/disp32 +5018 } +5019 # if (curr != curr2) return false +5020 { +5021 (operand-matches-primitive? *esi *edi) # List-value List-value => eax +5022 3d/compare-eax-and 0/imm32 +5023 75/jump-if-!= break/disp8 +5024 b8/copy-to-eax 0/imm32 +5025 e9/jump $mu-stmt-matches-primitive?:end/disp32 +5026 } +5027 # curr=curr->next +5028 8b/-> *(esi+4) 6/r32/esi # Operand-next +5029 # curr2=curr2->next +5030 8b/-> *(edi+4) 7/r32/edi # Operand-next +5031 eb/jump loop/disp8 +5032 } +5033 $mu-stmt-matches-primitive?:return-true: +5034 b8/copy-to-eax 1/imm32 +5035 $mu-stmt-matches-primitive?:end: +5036 # . restore registers +5037 5f/pop-to-edi +5038 5e/pop-to-esi +5039 5b/pop-to-ebx +5040 5a/pop-to-edx +5041 59/pop-to-ecx +5042 # . epilogue +5043 89/<- %esp 5/r32/ebp +5044 5d/pop-to-ebp +5045 c3/return +5046 +5047 operand-matches-primitive?: # var : (handle var), prim-var : (handle var) => result/eax : boolean +5048 # . prologue +5049 55/push-ebp +5050 89/<- %ebp 4/r32/esp +5051 # . save registers +5052 56/push-esi +5053 57/push-edi +5054 # esi = var +5055 8b/-> *(ebp+8) 6/r32/esi +5056 # edi = prim-var +5057 8b/-> *(ebp+0xc) 7/r32/edi +5058 # if (var->type != prim-var->type) return false +5059 (type-equal? *(esi+4) *(edi+4)) # Var-type, Var-type => eax +5060 3d/compare-eax-and 0/imm32 +5061 b8/copy-to-eax 0/imm32/false +5062 74/jump-if-= $operand-matches-primitive?:end/disp8 +5063 # return false if var->register doesn't match prim-var->register +5064 { +5065 # if addresses are equal, don't return here +5066 8b/-> *(esi+0x10) 0/r32/eax +5067 39/compare *(edi+0x10) 0/r32/eax +5068 74/jump-if-= break/disp8 +5069 # if either address is 0, return false +5070 3d/compare-eax-and 0/imm32 +5071 74/jump-if-= $operand-matches-primitive?:end/disp8 # eax goes from meaning var->register to result +5072 81 7/subop/compare *(edi+0x10) 0/imm32 +5073 74/jump-if-= $operand-matches-primitive?:end/disp8 # eax goes from meaning var->register to result +5074 # if prim-var->register is "*", return true +5075 (string-equal? *(edi+0x10) "*") # Var-register +5076 3d/compare-eax-and 0/imm32 +5077 b8/copy-to-eax 1/imm32/true +5078 75/jump-if-!= $operand-matches-primitive?:end/disp8 +5079 # if string contents don't match, return false +5080 (string-equal? *(esi+0x10) *(edi+0x10)) # Var-register Var-register +5081 3d/compare-eax-and 0/imm32 +5082 b8/copy-to-eax 0/imm32/false +5083 74/jump-if-= $operand-matches-primitive?:end/disp8 +5084 } +5085 # return true +5086 b8/copy-to-eax 1/imm32/true +5087 $operand-matches-primitive?:end: +5088 # . restore registers +5089 5f/pop-to-edi +5090 5e/pop-to-esi +5091 # . epilogue +5092 89/<- %esp 5/r32/ebp +5093 5d/pop-to-ebp +5094 c3/return +5095 +5096 type-equal?: # a : (handle tree type-id), b : (handle tree type-id) => result/eax : boolean +5097 # . prologue +5098 55/push-ebp +5099 89/<- %ebp 4/r32/esp +5100 # . save registers +5101 51/push-ecx +5102 52/push-edx +5103 # ecx = a +5104 8b/-> *(ebp+8) 1/r32/ecx +5105 # edx = b +5106 8b/-> *(ebp+0xc) 2/r32/edx +5107 # if (a == b) return true +5108 8b/-> %ecx 0/r32/eax # Var-type +5109 39/compare %edx 0/r32/eax # Var-type +5110 b8/copy-to-eax 1/imm32/true +5111 74/jump-if-= $type-equal?:end/disp8 +5112 # if (a < MAX_TYPE_ID) return false +5113 81 7/subop/compare %ecx 0x10000/imm32 +5114 b8/copy-to-eax 0/imm32/false +5115 72/jump-if-addr< $type-equal?:end/disp8 +5116 # if (b < MAX_TYPE_ID) return false +5117 81 7/subop/compare %edx 0x10000/imm32 +5118 b8/copy-to-eax 0/imm32/false +5119 72/jump-if-addr< $type-equal?:end/disp8 +5120 # if (!type-equal?(a->left, b->left)) return false +5121 (type-equal? *ecx *edx) # Tree-left, Tree-left => eax +5122 3d/compare-eax-and 0/imm32 +5123 74/jump-if-= $type-equal?:end/disp8 +5124 # return type-equal?(a->right, b->right) +5125 (type-equal? *(ecx+4) *(edx+4)) # Tree-right, Tree-right => eax +5126 $type-equal?:end: +5127 # . restore registers +5128 5a/pop-to-edx +5129 59/pop-to-ecx +5130 # . epilogue +5131 89/<- %esp 5/r32/ebp +5132 5d/pop-to-ebp +5133 c3/return +5134 +5135 test-emit-subx-statement-primitive: +5136 # Primitive operation on a variable on the stack. +5137 # increment foo +5138 # => +5139 # ff 0/subop/increment *(ebp-8) +5140 # +5141 # There's a variable on the var stack as follows: +5142 # name: 'foo' +5143 # type: int +5144 # stack-offset: -8 +5145 # +5146 # There's a primitive with this info: +5147 # name: 'increment' +5148 # inouts: int/mem +5149 # value: 'ff 0/subop/increment' +5150 # +5151 # There's nothing in functions. +5152 # +5153 # . prologue +5154 55/push-ebp +5155 89/<- %ebp 4/r32/esp +5156 # setup +5157 (clear-stream _test-output-stream) +5158 (clear-stream $_test-output-buffered-file->buffer) +5159 # var type/ecx : (handle tree type-id) = int +5160 68/push 0/imm32/right/null +5161 68/push 1/imm32/left/int +5162 89/<- %ecx 4/r32/esp +5163 # var var-foo/ecx : var +5164 68/push 0/imm32/no-register +5165 68/push -8/imm32/stack-offset +5166 68/push 1/imm32/block-depth +5167 51/push-ecx +5168 68/push "foo"/imm32 +5169 89/<- %ecx 4/r32/esp +5170 # var operand/ebx : (list var) +5171 68/push 0/imm32/next +5172 51/push-ecx/var-foo +5173 89/<- %ebx 4/r32/esp +5174 # var stmt/esi : statement +5175 68/push 0/imm32/next +5176 68/push 0/imm32/outputs +5177 53/push-ebx/operands +5178 68/push "increment"/imm32/operation +5179 68/push 1/imm32 +5180 89/<- %esi 4/r32/esp +5181 # var primitives/ebx : primitive +5182 68/push 0/imm32/next +5183 68/push 0/imm32/output-is-write-only +5184 68/push 0/imm32/no-imm32 +5185 68/push 0/imm32/no-r32 +5186 68/push 1/imm32/rm32-is-first-inout +5187 68/push "ff 0/subop/increment"/imm32/subx-name +5188 68/push 0/imm32/outputs +5189 53/push-ebx/inouts # hack; in practice we won't have the same var in function definition and call +5190 68/push "increment"/imm32/name +5191 89/<- %ebx 4/r32/esp +5192 # convert +5193 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) +5194 (flush _test-output-buffered-file) +5195 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5201 # check output +5202 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment *(ebp+0xfffffff8)" "F - test-emit-subx-statement-primitive") +5203 # . epilogue +5204 89/<- %esp 5/r32/ebp +5205 5d/pop-to-ebp +5206 c3/return +5207 +5208 test-emit-subx-statement-primitive-register: +5209 # Primitive operation on a variable in a register. +5210 # foo <- increment +5211 # => +5212 # ff 0/subop/increment %eax # sub-optimal, but should suffice +5213 # +5214 # There's a variable on the var stack as follows: +5215 # name: 'foo' +5216 # type: int +5217 # register: 'eax' +5218 # +5219 # There's a primitive with this info: +5220 # name: 'increment' +5221 # out: int/reg +5222 # value: 'ff 0/subop/increment' +5223 # +5224 # There's nothing in functions. +5225 # +5226 # . prologue +5227 55/push-ebp +5228 89/<- %ebp 4/r32/esp +5229 # setup +5230 (clear-stream _test-output-stream) +5231 (clear-stream $_test-output-buffered-file->buffer) +5232 # var type/ecx : (handle tree type-id) = int +5233 68/push 0/imm32/right/null +5234 68/push 1/imm32/left/int +5235 89/<- %ecx 4/r32/esp +5236 # var var-foo/ecx : var in eax +5237 68/push "eax"/imm32/register +5238 68/push 0/imm32/no-stack-offset +5239 68/push 1/imm32/block-depth +5240 51/push-ecx +5241 68/push "foo"/imm32 +5242 89/<- %ecx 4/r32/esp +5243 # var operand/ebx : (list var) +5244 68/push 0/imm32/next +5245 51/push-ecx/var-foo +5246 89/<- %ebx 4/r32/esp +5247 # var stmt/esi : statement +5248 68/push 0/imm32/next +5249 53/push-ebx/outputs +5250 68/push 0/imm32/inouts +5251 68/push "increment"/imm32/operation +5252 68/push 1/imm32 +5253 89/<- %esi 4/r32/esp +5254 # var formal-var/ebx : var in any register +5255 68/push Any-register/imm32 +5256 68/push 0/imm32/no-stack-offset +5257 68/push 1/imm32/block-depth +5258 ff 6/subop/push *(ecx+4) # Var-type +5259 68/push "dummy"/imm32 +5260 89/<- %ebx 4/r32/esp +5261 # var operand/ebx : (list var) +5262 68/push 0/imm32/next +5263 53/push-ebx/formal-var +5264 89/<- %ebx 4/r32/esp +5265 # var primitives/ebx : primitive +5266 68/push 0/imm32/next +5267 68/push 0/imm32/output-is-write-only +5268 68/push 0/imm32/no-imm32 +5269 68/push 0/imm32/no-r32 +5270 68/push 3/imm32/rm32-in-first-output +5271 68/push "ff 0/subop/increment"/imm32/subx-name +5272 53/push-ebx/outputs +5273 68/push 0/imm32/inouts +5274 68/push "increment"/imm32/name +5275 89/<- %ebx 4/r32/esp +5276 # convert +5277 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) +5278 (flush _test-output-buffered-file) +5279 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5285 # check output +5286 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-primitive-register") +5287 # . epilogue +5288 89/<- %esp 5/r32/ebp +5289 5d/pop-to-ebp +5290 c3/return +5291 +5292 test-emit-subx-statement-select-primitive: +5293 # Select the right primitive between overloads. +5294 # foo <- increment +5295 # => +5296 # ff 0/subop/increment %eax # sub-optimal, but should suffice +5297 # +5298 # There's a variable on the var stack as follows: +5299 # name: 'foo' +5300 # type: int +5301 # register: 'eax' +5302 # +5303 # There's two primitives, as follows: +5304 # - name: 'increment' +5305 # out: int/reg +5306 # value: 'ff 0/subop/increment' +5307 # - name: 'increment' +5308 # inout: int/mem +5309 # value: 'ff 0/subop/increment' +5310 # +5311 # There's nothing in functions. +5312 # +5313 # . prologue +5314 55/push-ebp +5315 89/<- %ebp 4/r32/esp +5316 # setup +5317 (clear-stream _test-output-stream) +5318 (clear-stream $_test-output-buffered-file->buffer) +5319 # var type/ecx : (handle tree type-id) = int +5320 68/push 0/imm32/right/null +5321 68/push 1/imm32/left/int +5322 89/<- %ecx 4/r32/esp +5323 # var var-foo/ecx : var in eax +5324 68/push "eax"/imm32/register +5325 68/push 0/imm32/no-stack-offset +5326 68/push 1/imm32/block-depth +5327 51/push-ecx +5328 68/push "foo"/imm32 +5329 89/<- %ecx 4/r32/esp +5330 # var real-outputs/edi : (list var) +5331 68/push 0/imm32/next +5332 51/push-ecx/var-foo +5333 89/<- %edi 4/r32/esp +5334 # var stmt/esi : statement +5335 68/push 0/imm32/next +5336 57/push-edi/outputs +5337 68/push 0/imm32/inouts +5338 68/push "increment"/imm32/operation +5339 68/push 1/imm32 +5340 89/<- %esi 4/r32/esp +5341 # var formal-var/ebx : var in any register +5342 68/push Any-register/imm32 +5343 68/push 0/imm32/no-stack-offset +5344 68/push 1/imm32/block-depth +5345 ff 6/subop/push *(ecx+4) # Var-type +5346 68/push "dummy"/imm32 +5347 89/<- %ebx 4/r32/esp +5348 # var formal-outputs/ebx : (list var) = {formal-var, 0} +5349 68/push 0/imm32/next +5350 53/push-ebx/formal-var +5351 89/<- %ebx 4/r32/esp +5352 # var primitive1/ebx : primitive +5353 68/push 0/imm32/next +5354 68/push 0/imm32/output-is-write-only +5355 68/push 0/imm32/no-imm32 +5356 68/push 0/imm32/no-r32 +5357 68/push 3/imm32/rm32-in-first-output +5358 68/push "ff 0/subop/increment"/imm32/subx-name +5359 53/push-ebx/outputs/formal-outputs +5360 68/push 0/imm32/inouts +5361 68/push "increment"/imm32/name +5362 89/<- %ebx 4/r32/esp +5363 # var primitives/ebx : primitive +5364 53/push-ebx/next +5365 68/push 0/imm32/output-is-write-only +5366 68/push 0/imm32/no-imm32 +5367 68/push 0/imm32/no-r32 +5368 68/push 1/imm32/rm32-is-first-inout +5369 68/push "ff 0/subop/increment"/imm32/subx-name +5370 68/push 0/imm32/outputs +5371 57/push-edi/inouts/real-outputs # hack; in practice we won't have the same var in function definition and call +5372 68/push "increment"/imm32/name +5373 89/<- %ebx 4/r32/esp +5374 # convert +5375 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) +5376 (flush _test-output-buffered-file) +5377 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5383 # check output +5384 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-select-primitive") +5385 # . epilogue +5386 89/<- %esp 5/r32/ebp +5387 5d/pop-to-ebp +5388 c3/return +5389 +5390 test-emit-subx-statement-select-primitive-2: +5391 # Select the right primitive between overloads. +5392 # foo <- increment +5393 # => +5394 # ff 0/subop/increment %eax # sub-optimal, but should suffice +5395 # +5396 # There's a variable on the var stack as follows: +5397 # name: 'foo' +5398 # type: int +5399 # register: 'eax' +5400 # +5401 # There's two primitives, as follows: +5402 # - name: 'increment' +5403 # out: int/reg +5404 # value: 'ff 0/subop/increment' +5405 # - name: 'increment' +5406 # inout: int/mem +5407 # value: 'ff 0/subop/increment' +5408 # +5409 # There's nothing in functions. +5410 # +5411 # . prologue +5412 55/push-ebp +5413 89/<- %ebp 4/r32/esp +5414 # setup +5415 (clear-stream _test-output-stream) +5416 (clear-stream $_test-output-buffered-file->buffer) +5417 # var type/ecx : (handle tree type-id) = int +5418 68/push 0/imm32/right/null +5419 68/push 1/imm32/left/int +5420 89/<- %ecx 4/r32/esp +5421 # var var-foo/ecx : var in eax +5422 68/push "eax"/imm32/register +5423 68/push 0/imm32/no-stack-offset +5424 68/push 1/imm32/block-depth +5425 51/push-ecx +5426 68/push "foo"/imm32 +5427 89/<- %ecx 4/r32/esp +5428 # var inouts/edi : (list var) +5429 68/push 0/imm32/next +5430 51/push-ecx/var-foo +5431 89/<- %edi 4/r32/esp +5432 # var stmt/esi : statement +5433 68/push 0/imm32/next +5434 68/push 0/imm32/outputs +5435 57/push-edi/inouts +5436 68/push "increment"/imm32/operation +5437 68/push 1/imm32 +5438 89/<- %esi 4/r32/esp +5439 # var formal-var/ebx : var in any register +5440 68/push Any-register/imm32 +5441 68/push 0/imm32/no-stack-offset +5442 68/push 1/imm32/block-depth +5443 ff 6/subop/push *(ecx+4) # Var-type +5444 68/push "dummy"/imm32 +5445 89/<- %ebx 4/r32/esp +5446 # var operand/ebx : (list var) +5447 68/push 0/imm32/next +5448 53/push-ebx/formal-var +5449 89/<- %ebx 4/r32/esp +5450 # var primitive1/ebx : primitive +5451 68/push 0/imm32/next +5452 68/push 0/imm32/output-is-write-only +5453 68/push 0/imm32/no-imm32 +5454 68/push 0/imm32/no-r32 +5455 68/push 3/imm32/rm32-in-first-output +5456 68/push "ff 0/subop/increment"/imm32/subx-name +5457 53/push-ebx/outputs/formal-outputs +5458 68/push 0/imm32/inouts +5459 68/push "increment"/imm32/name +5460 89/<- %ebx 4/r32/esp +5461 # var primitives/ebx : primitive +5462 53/push-ebx/next +5463 68/push 0/imm32/output-is-write-only +5464 68/push 0/imm32/no-imm32 +5465 68/push 0/imm32/no-r32 +5466 68/push 1/imm32/rm32-is-first-inout +5467 68/push "ff 0/subop/increment"/imm32/subx-name +5468 68/push 0/imm32/outputs +5469 57/push-edi/inouts/real-outputs # hack; in practice we won't have the same var in function definition and call +5470 68/push "increment"/imm32/name +5471 89/<- %ebx 4/r32/esp 5472 # convert -5473 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +5473 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) 5474 (flush _test-output-buffered-file) 5475 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- 5481 # check output -5482 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-increment-var") +5482 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-select-primitive-2") 5483 # . epilogue 5484 89/<- %esp 5/r32/ebp 5485 5d/pop-to-ebp 5486 c3/return 5487 -5488 test-add-reg-to-reg: -5489 # var1/reg <- add var2/reg -5490 # => -5491 # 01/add %var1 var2 -5492 # -5493 # . prologue -5494 55/push-ebp -5495 89/<- %ebp 4/r32/esp -5496 # setup -5497 (clear-stream _test-output-stream) -5498 (clear-stream $_test-output-buffered-file->buffer) -5499 # var type/ecx : (handle tree type-id) = int -5500 68/push 0/imm32/right/null -5501 68/push 1/imm32/left/int -5502 89/<- %ecx 4/r32/esp -5503 # var var-var1/ecx : var in eax -5504 68/push "eax"/imm32/register -5505 68/push 0/imm32/no-stack-offset -5506 68/push 1/imm32/block-depth -5507 51/push-ecx -5508 68/push "var1"/imm32 -5509 89/<- %ecx 4/r32/esp -5510 # var var-var2/edx : var in ecx -5511 68/push "ecx"/imm32/register -5512 68/push 0/imm32/no-stack-offset -5513 68/push 1/imm32/block-depth -5514 ff 6/subop/push *(ecx+4) # Var-type -5515 68/push "var2"/imm32 -5516 89/<- %edx 4/r32/esp -5517 # var inouts/esi : (list var2) -5518 68/push 0/imm32/next -5519 52/push-edx/var-var2 -5520 89/<- %esi 4/r32/esp -5521 # var outputs/edi : (list var1) -5522 68/push 0/imm32/next -5523 51/push-ecx/var-var1 -5524 89/<- %edi 4/r32/esp -5525 # var stmt/esi : statement -5526 68/push 0/imm32/next -5527 57/push-edi/outputs -5528 56/push-esi/inouts -5529 68/push "add"/imm32/operation -5530 68/push 1/imm32 -5531 89/<- %esi 4/r32/esp -5532 # convert -5533 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -5534 (flush _test-output-buffered-file) -5535 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -5541 # check output -5542 (check-next-stream-line-equal _test-output-stream "01/add-to %eax 0x00000001/r32" "F - test-add-reg-to-reg") -5543 # . epilogue -5544 89/<- %esp 5/r32/ebp -5545 5d/pop-to-ebp -5546 c3/return -5547 -5548 test-add-reg-to-mem: -5549 # add-to var1 var2/reg +5488 test-increment-register: +5489 # Select the right primitive between overloads. +5490 # foo <- increment +5491 # => +5492 # 50/increment-eax +5493 # +5494 # There's a variable on the var stack as follows: +5495 # name: 'foo' +5496 # type: int +5497 # register: 'eax' +5498 # +5499 # Primitives are the global definitions. +5500 # +5501 # There are no functions defined. +5502 # +5503 # . prologue +5504 55/push-ebp +5505 89/<- %ebp 4/r32/esp +5506 # setup +5507 (clear-stream _test-output-stream) +5508 (clear-stream $_test-output-buffered-file->buffer) +5509 # var type/ecx : (handle tree type-id) = int +5510 68/push 0/imm32/right/null +5511 68/push 1/imm32/left/int +5512 89/<- %ecx 4/r32/esp +5513 # var var-foo/ecx : var in eax +5514 68/push "eax"/imm32/register +5515 68/push 0/imm32/no-stack-offset +5516 68/push 1/imm32/block-depth +5517 51/push-ecx +5518 68/push "foo"/imm32 +5519 89/<- %ecx 4/r32/esp +5520 # var real-outputs/edi : (list var) +5521 68/push 0/imm32/next +5522 51/push-ecx/var-foo +5523 89/<- %edi 4/r32/esp +5524 # var stmt/esi : statement +5525 68/push 0/imm32/next +5526 57/push-edi/outputs +5527 68/push 0/imm32/inouts +5528 68/push "increment"/imm32/operation +5529 68/push 1/imm32/regular-statement +5530 89/<- %esi 4/r32/esp +5531 # convert +5532 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +5533 (flush _test-output-buffered-file) +5534 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5540 # check output +5541 (check-next-stream-line-equal _test-output-stream "40/increment-eax" "F - test-increment-register") +5542 # . epilogue +5543 89/<- %esp 5/r32/ebp +5544 5d/pop-to-ebp +5545 c3/return +5546 +5547 test-increment-var: +5548 # Select the right primitive between overloads. +5549 # foo <- increment 5550 # => -5551 # 01/add *(ebp+__) var2 +5551 # ff 0/subop/increment %eax # sub-optimal, but should suffice 5552 # -5553 # . prologue -5554 55/push-ebp -5555 89/<- %ebp 4/r32/esp -5556 # setup -5557 (clear-stream _test-output-stream) -5558 (clear-stream $_test-output-buffered-file->buffer) -5559 # var type/ecx : (handle tree type-id) = int -5560 68/push 0/imm32/right/null -5561 68/push 1/imm32/left/int -5562 89/<- %ecx 4/r32/esp -5563 # var var-var1/ecx : var -5564 68/push 0/imm32/no-register -5565 68/push 8/imm32/stack-offset -5566 68/push 1/imm32/block-depth -5567 51/push-ecx -5568 68/push "var1"/imm32 -5569 89/<- %ecx 4/r32/esp -5570 # var var-var2/edx : var in ecx -5571 68/push "ecx"/imm32/register -5572 68/push 0/imm32/no-stack-offset -5573 68/push 1/imm32/block-depth -5574 ff 6/subop/push *(ecx+4) # Var-type -5575 68/push "var2"/imm32 -5576 89/<- %edx 4/r32/esp -5577 # var inouts/esi : (list var2) -5578 68/push 0/imm32/next -5579 52/push-edx/var-var2 -5580 89/<- %esi 4/r32/esp -5581 # var inouts = (list var1 var2) -5582 56/push-esi/next -5583 51/push-ecx/var-var1 -5584 89/<- %esi 4/r32/esp -5585 # var stmt/esi : statement -5586 68/push 0/imm32/next -5587 68/push 0/imm32/outputs -5588 56/push-esi/inouts -5589 68/push "add-to"/imm32/operation -5590 68/push 1/imm32 -5591 89/<- %esi 4/r32/esp -5592 # convert -5593 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -5594 (flush _test-output-buffered-file) -5595 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -5601 # check output -5602 (check-next-stream-line-equal _test-output-stream "01/add-to *(ebp+0x00000008) 0x00000001/r32" "F - test-add-reg-to-mem") -5603 # . epilogue -5604 89/<- %esp 5/r32/ebp -5605 5d/pop-to-ebp -5606 c3/return -5607 -5608 test-add-mem-to-reg: -5609 # var1/reg <- add var2 -5610 # => -5611 # 03/add *(ebp+__) var1 -5612 # -5613 # . prologue -5614 55/push-ebp -5615 89/<- %ebp 4/r32/esp -5616 # setup -5617 (clear-stream _test-output-stream) -5618 (clear-stream $_test-output-buffered-file->buffer) -5619 # var type/ecx : (handle tree type-id) = int -5620 68/push 0/imm32/right/null -5621 68/push 1/imm32/left/int -5622 89/<- %ecx 4/r32/esp -5623 # var var-var1/ecx : var in eax -5624 68/push "eax"/imm32/register -5625 68/push 0/imm32/no-stack-offset -5626 68/push 1/imm32/block-depth -5627 51/push-ecx -5628 68/push "var1"/imm32 -5629 89/<- %ecx 4/r32/esp -5630 # var var-var2/edx : var -5631 68/push 0/imm32/no-register -5632 68/push 8/imm32/stack-offset -5633 68/push 1/imm32/block-depth -5634 ff 6/subop/push *(ecx+4) # Var-type -5635 68/push "var2"/imm32 -5636 89/<- %edx 4/r32/esp -5637 # var inouts/esi : (list var2) -5638 68/push 0/imm32/next -5639 52/push-edx/var-var2 -5640 89/<- %esi 4/r32/esp -5641 # var outputs/edi : (list var1) -5642 68/push 0/imm32/next -5643 51/push-ecx/var-var1 -5644 89/<- %edi 4/r32/esp -5645 # var stmt/esi : statement -5646 68/push 0/imm32/next -5647 57/push-edi/outputs -5648 56/push-esi/inouts -5649 68/push "add"/imm32/operation -5650 68/push 1/imm32 -5651 89/<- %esi 4/r32/esp -5652 # convert -5653 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -5654 (flush _test-output-buffered-file) -5655 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -5661 # check output -5662 (check-next-stream-line-equal _test-output-stream "03/add *(ebp+0x00000008) 0x00000000/r32" "F - test-add-mem-to-reg") -5663 # . epilogue -5664 89/<- %esp 5/r32/ebp -5665 5d/pop-to-ebp -5666 c3/return -5667 -5668 test-add-literal-to-eax: -5669 # var1/eax <- add 0x34 -5670 # => -5671 # 05/add-to-eax 0x34/imm32 -5672 # -5673 # . prologue -5674 55/push-ebp -5675 89/<- %ebp 4/r32/esp -5676 # setup -5677 (clear-stream _test-output-stream) -5678 (clear-stream $_test-output-buffered-file->buffer) -5679 # var type/ecx : (handle tree type-id) = int -5680 68/push 0/imm32/right/null -5681 68/push 1/imm32/left/int -5682 89/<- %ecx 4/r32/esp -5683 # var var-var1/ecx : var in eax -5684 68/push "eax"/imm32/register -5685 68/push 0/imm32/no-stack-offset -5686 68/push 1/imm32/block-depth -5687 51/push-ecx -5688 68/push "var1"/imm32 -5689 89/<- %ecx 4/r32/esp -5690 # var type/edx : (handle tree type-id) = literal -5691 68/push 0/imm32/right/null -5692 68/push 0/imm32/left/literal -5693 89/<- %edx 4/r32/esp -5694 # var var-var2/edx : var literal -5695 68/push 0/imm32/no-register -5696 68/push 0/imm32/no-stack-offset -5697 68/push 1/imm32/block-depth -5698 52/push-edx -5699 68/push "0x34"/imm32 -5700 89/<- %edx 4/r32/esp -5701 # var inouts/esi : (list var2) -5702 68/push 0/imm32/next -5703 52/push-edx/var-var2 -5704 89/<- %esi 4/r32/esp -5705 # var outputs/edi : (list var1) -5706 68/push 0/imm32/next -5707 51/push-ecx/var-var1 -5708 89/<- %edi 4/r32/esp -5709 # var stmt/esi : statement -5710 68/push 0/imm32/next -5711 57/push-edi/outputs -5712 56/push-esi/inouts -5713 68/push "add"/imm32/operation -5714 68/push 1/imm32 -5715 89/<- %esi 4/r32/esp -5716 # convert -5717 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -5718 (flush _test-output-buffered-file) -5719 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -5725 # check output -5726 (check-next-stream-line-equal _test-output-stream "05/add-to-eax 0x34/imm32" "F - test-add-literal-to-eax") -5727 # . epilogue -5728 89/<- %esp 5/r32/ebp -5729 5d/pop-to-ebp -5730 c3/return -5731 -5732 test-add-literal-to-reg: -5733 # var1/ecx <- add 0x34 -5734 # => -5735 # 81 0/subop/add %ecx 0x34/imm32 -5736 # -5737 # . prologue -5738 55/push-ebp -5739 89/<- %ebp 4/r32/esp -5740 # setup -5741 (clear-stream _test-output-stream) -5742 (clear-stream $_test-output-buffered-file->buffer) -5743 # var type/ecx : (handle tree type-id) = int -5744 68/push 0/imm32/right/null -5745 68/push 1/imm32/left/int -5746 89/<- %ecx 4/r32/esp -5747 # var var-var1/ecx : var in ecx -5748 68/push "ecx"/imm32/register -5749 68/push 0/imm32/no-stack-offset -5750 68/push 1/imm32/block-depth -5751 51/push-ecx -5752 68/push "var1"/imm32 -5753 89/<- %ecx 4/r32/esp -5754 # var type/edx : (handle tree type-id) = literal -5755 68/push 0/imm32/right/null -5756 68/push 0/imm32/left/literal -5757 89/<- %edx 4/r32/esp -5758 # var var-var2/edx : var literal -5759 68/push 0/imm32/no-register -5760 68/push 0/imm32/no-stack-offset -5761 68/push 1/imm32/block-depth -5762 52/push-edx -5763 68/push "0x34"/imm32 -5764 89/<- %edx 4/r32/esp -5765 # var inouts/esi : (list var2) -5766 68/push 0/imm32/next -5767 52/push-edx/var-var2 -5768 89/<- %esi 4/r32/esp -5769 # var outputs/edi : (list var1) -5770 68/push 0/imm32/next -5771 51/push-ecx/var-var1 -5772 89/<- %edi 4/r32/esp -5773 # var stmt/esi : statement -5774 68/push 0/imm32/next -5775 57/push-edi/outputs -5776 56/push-esi/inouts -5777 68/push "add"/imm32/operation -5778 68/push 1/imm32 -5779 89/<- %esi 4/r32/esp -5780 # convert -5781 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -5782 (flush _test-output-buffered-file) -5783 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -5789 # check output -5790 (check-next-stream-line-equal _test-output-stream "81 0/subop/add %ecx 0x34/imm32" "F - test-add-literal-to-reg") -5791 # . epilogue -5792 89/<- %esp 5/r32/ebp -5793 5d/pop-to-ebp -5794 c3/return -5795 -5796 test-add-literal-to-mem: -5797 # add-to var1, 0x34 -5798 # => -5799 # 81 0/subop/add %eax 0x34/imm32 -5800 # -5801 # . prologue -5802 55/push-ebp -5803 89/<- %ebp 4/r32/esp -5804 # setup -5805 (clear-stream _test-output-stream) -5806 (clear-stream $_test-output-buffered-file->buffer) -5807 # var type/ecx : (handle tree type-id) = int -5808 68/push 0/imm32/right/null -5809 68/push 1/imm32/left/int -5810 89/<- %ecx 4/r32/esp -5811 # var var-var1/ecx : var -5812 68/push 0/imm32/no-register -5813 68/push 8/imm32/stack-offset -5814 68/push 1/imm32/block-depth -5815 51/push-ecx -5816 68/push "var1"/imm32 -5817 89/<- %ecx 4/r32/esp -5818 # var type/edx : (handle tree type-id) = literal -5819 68/push 0/imm32/right/null -5820 68/push 0/imm32/left/literal -5821 89/<- %edx 4/r32/esp -5822 # var var-var2/edx : var literal -5823 68/push 0/imm32/no-register -5824 68/push 0/imm32/no-stack-offset -5825 68/push 1/imm32/block-depth -5826 52/push-edx -5827 68/push "0x34"/imm32 -5828 89/<- %edx 4/r32/esp -5829 # var inouts/esi : (list var2) -5830 68/push 0/imm32/next -5831 52/push-edx/var-var2 -5832 89/<- %esi 4/r32/esp -5833 # var inouts = (list var1 inouts) -5834 56/push-esi/next -5835 51/push-ecx/var-var1 -5836 89/<- %esi 4/r32/esp -5837 # var stmt/esi : statement -5838 68/push 0/imm32/next -5839 68/push 0/imm32/outputs -5840 56/push-esi/inouts -5841 68/push "add-to"/imm32/operation -5842 68/push 1/imm32 -5843 89/<- %esi 4/r32/esp -5844 # convert -5845 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -5846 (flush _test-output-buffered-file) -5847 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -5853 # check output -5854 (check-next-stream-line-equal _test-output-stream "81 0/subop/add *(ebp+0x00000008) 0x34/imm32" "F - test-add-literal-to-mem") -5855 # . epilogue -5856 89/<- %esp 5/r32/ebp -5857 5d/pop-to-ebp -5858 c3/return -5859 -5860 test-emit-subx-statement-function-call: -5861 # Call a function on a variable on the stack. -5862 # f foo -5863 # => -5864 # (f2 *(ebp-8)) -5865 # (Changing the function name supports overloading in general, but here it -5866 # just serves to help disambiguate things.) -5867 # -5868 # There's a variable on the var stack as follows: -5869 # name: 'foo' -5870 # type: int -5871 # stack-offset: -8 -5872 # -5873 # There's nothing in primitives. -5874 # -5875 # There's a function with this info: -5876 # name: 'f' -5877 # inout: int/mem -5878 # value: 'f2' -5879 # -5880 # . prologue -5881 55/push-ebp -5882 89/<- %ebp 4/r32/esp -5883 # setup -5884 (clear-stream _test-output-stream) -5885 (clear-stream $_test-output-buffered-file->buffer) -5886 # var type/ecx : (handle tree type-id) = int -5887 68/push 0/imm32/right/null -5888 68/push 1/imm32/left/int -5889 89/<- %ecx 4/r32/esp -5890 # var var-foo/ecx : var -5891 68/push 0/imm32/no-register -5892 68/push -8/imm32/stack-offset -5893 68/push 0/imm32/block-depth -5894 51/push-ecx -5895 68/push "foo"/imm32 -5896 89/<- %ecx 4/r32/esp -5897 # var operands/esi : (list var) -5898 68/push 0/imm32/next -5899 51/push-ecx/var-foo -5900 89/<- %esi 4/r32/esp -5901 # var stmt/esi : statement -5902 68/push 0/imm32/next -5903 68/push 0/imm32/outputs -5904 56/push-esi/inouts -5905 68/push "f"/imm32/operation -5906 68/push 1/imm32 -5907 89/<- %esi 4/r32/esp -5908 # var functions/ebx : function -5909 68/push 0/imm32/next -5910 68/push 0/imm32/body -5911 68/push 0/imm32/outputs -5912 51/push-ecx/inouts # hack; in practice we won't have the same var in function definition and call -5913 68/push "f2"/imm32/subx-name -5914 68/push "f"/imm32/name -5915 89/<- %ebx 4/r32/esp -5916 # convert -5917 (emit-subx-statement _test-output-buffered-file %esi 0 %ebx) -5918 (flush _test-output-buffered-file) -5919 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -5925 # check output -5926 (check-next-stream-line-equal _test-output-stream "(f2 *(ebp+0xfffffff8))" "F - test-emit-subx-statement-function-call") -5927 # . epilogue -5928 89/<- %esp 5/r32/ebp -5929 5d/pop-to-ebp -5930 c3/return -5931 -5932 test-emit-subx-statement-function-call-with-literal-arg: -5933 # Call a function on a literal. -5934 # f 34 -5935 # => -5936 # (f2 34) -5937 # -5938 # . prologue -5939 55/push-ebp -5940 89/<- %ebp 4/r32/esp -5941 # setup -5942 (clear-stream _test-output-stream) -5943 (clear-stream $_test-output-buffered-file->buffer) -5944 # var type/ecx : (handle tree type-id) = literal -5945 68/push 0/imm32/right/null -5946 68/push 0/imm32/left/literal -5947 89/<- %ecx 4/r32/esp -5948 # var var-foo/ecx : var literal -5949 68/push 0/imm32/no-register -5950 68/push 0/imm32/no-stack-offset -5951 68/push 0/imm32/block-depth -5952 51/push-ecx -5953 68/push "34"/imm32 -5954 89/<- %ecx 4/r32/esp -5955 # var operands/esi : (list var) +5553 # There's a variable on the var stack as follows: +5554 # name: 'foo' +5555 # type: int +5556 # register: 'eax' +5557 # +5558 # Primitives are the global definitions. +5559 # +5560 # There are no functions defined. +5561 # +5562 # . prologue +5563 55/push-ebp +5564 89/<- %ebp 4/r32/esp +5565 # setup +5566 (clear-stream _test-output-stream) +5567 (clear-stream $_test-output-buffered-file->buffer) +5568 # var type/ecx : (handle tree type-id) = int +5569 68/push 0/imm32/right/null +5570 68/push 1/imm32/left/int +5571 89/<- %ecx 4/r32/esp +5572 # var var-foo/ecx : var in eax +5573 68/push "eax"/imm32/register +5574 68/push 0/imm32/no-stack-offset +5575 68/push 1/imm32/block-depth +5576 51/push-ecx +5577 68/push "foo"/imm32 +5578 89/<- %ecx 4/r32/esp +5579 # var inouts/edi : (list var) +5580 68/push 0/imm32/next +5581 51/push-ecx/var-foo +5582 89/<- %edi 4/r32/esp +5583 # var stmt/esi : statement +5584 68/push 0/imm32/next +5585 68/push 0/imm32/outputs +5586 57/push-edi/inouts +5587 68/push "increment"/imm32/operation +5588 68/push 1/imm32 +5589 89/<- %esi 4/r32/esp +5590 # convert +5591 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +5592 (flush _test-output-buffered-file) +5593 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5599 # check output +5600 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-increment-var") +5601 # . epilogue +5602 89/<- %esp 5/r32/ebp +5603 5d/pop-to-ebp +5604 c3/return +5605 +5606 test-add-reg-to-reg: +5607 # var1/reg <- add var2/reg +5608 # => +5609 # 01/add %var1 var2 +5610 # +5611 # . prologue +5612 55/push-ebp +5613 89/<- %ebp 4/r32/esp +5614 # setup +5615 (clear-stream _test-output-stream) +5616 (clear-stream $_test-output-buffered-file->buffer) +5617 # var type/ecx : (handle tree type-id) = int +5618 68/push 0/imm32/right/null +5619 68/push 1/imm32/left/int +5620 89/<- %ecx 4/r32/esp +5621 # var var-var1/ecx : var in eax +5622 68/push "eax"/imm32/register +5623 68/push 0/imm32/no-stack-offset +5624 68/push 1/imm32/block-depth +5625 51/push-ecx +5626 68/push "var1"/imm32 +5627 89/<- %ecx 4/r32/esp +5628 # var var-var2/edx : var in ecx +5629 68/push "ecx"/imm32/register +5630 68/push 0/imm32/no-stack-offset +5631 68/push 1/imm32/block-depth +5632 ff 6/subop/push *(ecx+4) # Var-type +5633 68/push "var2"/imm32 +5634 89/<- %edx 4/r32/esp +5635 # var inouts/esi : (list var2) +5636 68/push 0/imm32/next +5637 52/push-edx/var-var2 +5638 89/<- %esi 4/r32/esp +5639 # var outputs/edi : (list var1) +5640 68/push 0/imm32/next +5641 51/push-ecx/var-var1 +5642 89/<- %edi 4/r32/esp +5643 # var stmt/esi : statement +5644 68/push 0/imm32/next +5645 57/push-edi/outputs +5646 56/push-esi/inouts +5647 68/push "add"/imm32/operation +5648 68/push 1/imm32 +5649 89/<- %esi 4/r32/esp +5650 # convert +5651 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +5652 (flush _test-output-buffered-file) +5653 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5659 # check output +5660 (check-next-stream-line-equal _test-output-stream "01/add-to %eax 0x00000001/r32" "F - test-add-reg-to-reg") +5661 # . epilogue +5662 89/<- %esp 5/r32/ebp +5663 5d/pop-to-ebp +5664 c3/return +5665 +5666 test-add-reg-to-mem: +5667 # add-to var1 var2/reg +5668 # => +5669 # 01/add *(ebp+__) var2 +5670 # +5671 # . prologue +5672 55/push-ebp +5673 89/<- %ebp 4/r32/esp +5674 # setup +5675 (clear-stream _test-output-stream) +5676 (clear-stream $_test-output-buffered-file->buffer) +5677 # var type/ecx : (handle tree type-id) = int +5678 68/push 0/imm32/right/null +5679 68/push 1/imm32/left/int +5680 89/<- %ecx 4/r32/esp +5681 # var var-var1/ecx : var +5682 68/push 0/imm32/no-register +5683 68/push 8/imm32/stack-offset +5684 68/push 1/imm32/block-depth +5685 51/push-ecx +5686 68/push "var1"/imm32 +5687 89/<- %ecx 4/r32/esp +5688 # var var-var2/edx : var in ecx +5689 68/push "ecx"/imm32/register +5690 68/push 0/imm32/no-stack-offset +5691 68/push 1/imm32/block-depth +5692 ff 6/subop/push *(ecx+4) # Var-type +5693 68/push "var2"/imm32 +5694 89/<- %edx 4/r32/esp +5695 # var inouts/esi : (list var2) +5696 68/push 0/imm32/next +5697 52/push-edx/var-var2 +5698 89/<- %esi 4/r32/esp +5699 # var inouts = (list var1 var2) +5700 56/push-esi/next +5701 51/push-ecx/var-var1 +5702 89/<- %esi 4/r32/esp +5703 # var stmt/esi : statement +5704 68/push 0/imm32/next +5705 68/push 0/imm32/outputs +5706 56/push-esi/inouts +5707 68/push "add-to"/imm32/operation +5708 68/push 1/imm32 +5709 89/<- %esi 4/r32/esp +5710 # convert +5711 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +5712 (flush _test-output-buffered-file) +5713 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5719 # check output +5720 (check-next-stream-line-equal _test-output-stream "01/add-to *(ebp+0x00000008) 0x00000001/r32" "F - test-add-reg-to-mem") +5721 # . epilogue +5722 89/<- %esp 5/r32/ebp +5723 5d/pop-to-ebp +5724 c3/return +5725 +5726 test-add-mem-to-reg: +5727 # var1/reg <- add var2 +5728 # => +5729 # 03/add *(ebp+__) var1 +5730 # +5731 # . prologue +5732 55/push-ebp +5733 89/<- %ebp 4/r32/esp +5734 # setup +5735 (clear-stream _test-output-stream) +5736 (clear-stream $_test-output-buffered-file->buffer) +5737 # var type/ecx : (handle tree type-id) = int +5738 68/push 0/imm32/right/null +5739 68/push 1/imm32/left/int +5740 89/<- %ecx 4/r32/esp +5741 # var var-var1/ecx : var in eax +5742 68/push "eax"/imm32/register +5743 68/push 0/imm32/no-stack-offset +5744 68/push 1/imm32/block-depth +5745 51/push-ecx +5746 68/push "var1"/imm32 +5747 89/<- %ecx 4/r32/esp +5748 # var var-var2/edx : var +5749 68/push 0/imm32/no-register +5750 68/push 8/imm32/stack-offset +5751 68/push 1/imm32/block-depth +5752 ff 6/subop/push *(ecx+4) # Var-type +5753 68/push "var2"/imm32 +5754 89/<- %edx 4/r32/esp +5755 # var inouts/esi : (list var2) +5756 68/push 0/imm32/next +5757 52/push-edx/var-var2 +5758 89/<- %esi 4/r32/esp +5759 # var outputs/edi : (list var1) +5760 68/push 0/imm32/next +5761 51/push-ecx/var-var1 +5762 89/<- %edi 4/r32/esp +5763 # var stmt/esi : statement +5764 68/push 0/imm32/next +5765 57/push-edi/outputs +5766 56/push-esi/inouts +5767 68/push "add"/imm32/operation +5768 68/push 1/imm32 +5769 89/<- %esi 4/r32/esp +5770 # convert +5771 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +5772 (flush _test-output-buffered-file) +5773 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5779 # check output +5780 (check-next-stream-line-equal _test-output-stream "03/add *(ebp+0x00000008) 0x00000000/r32" "F - test-add-mem-to-reg") +5781 # . epilogue +5782 89/<- %esp 5/r32/ebp +5783 5d/pop-to-ebp +5784 c3/return +5785 +5786 test-add-literal-to-eax: +5787 # var1/eax <- add 0x34 +5788 # => +5789 # 05/add-to-eax 0x34/imm32 +5790 # +5791 # . prologue +5792 55/push-ebp +5793 89/<- %ebp 4/r32/esp +5794 # setup +5795 (clear-stream _test-output-stream) +5796 (clear-stream $_test-output-buffered-file->buffer) +5797 # var type/ecx : (handle tree type-id) = int +5798 68/push 0/imm32/right/null +5799 68/push 1/imm32/left/int +5800 89/<- %ecx 4/r32/esp +5801 # var var-var1/ecx : var in eax +5802 68/push "eax"/imm32/register +5803 68/push 0/imm32/no-stack-offset +5804 68/push 1/imm32/block-depth +5805 51/push-ecx +5806 68/push "var1"/imm32 +5807 89/<- %ecx 4/r32/esp +5808 # var type/edx : (handle tree type-id) = literal +5809 68/push 0/imm32/right/null +5810 68/push 0/imm32/left/literal +5811 89/<- %edx 4/r32/esp +5812 # var var-var2/edx : var literal +5813 68/push 0/imm32/no-register +5814 68/push 0/imm32/no-stack-offset +5815 68/push 1/imm32/block-depth +5816 52/push-edx +5817 68/push "0x34"/imm32 +5818 89/<- %edx 4/r32/esp +5819 # var inouts/esi : (list var2) +5820 68/push 0/imm32/next +5821 52/push-edx/var-var2 +5822 89/<- %esi 4/r32/esp +5823 # var outputs/edi : (list var1) +5824 68/push 0/imm32/next +5825 51/push-ecx/var-var1 +5826 89/<- %edi 4/r32/esp +5827 # var stmt/esi : statement +5828 68/push 0/imm32/next +5829 57/push-edi/outputs +5830 56/push-esi/inouts +5831 68/push "add"/imm32/operation +5832 68/push 1/imm32 +5833 89/<- %esi 4/r32/esp +5834 # convert +5835 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +5836 (flush _test-output-buffered-file) +5837 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5843 # check output +5844 (check-next-stream-line-equal _test-output-stream "05/add-to-eax 0x34/imm32" "F - test-add-literal-to-eax") +5845 # . epilogue +5846 89/<- %esp 5/r32/ebp +5847 5d/pop-to-ebp +5848 c3/return +5849 +5850 test-add-literal-to-reg: +5851 # var1/ecx <- add 0x34 +5852 # => +5853 # 81 0/subop/add %ecx 0x34/imm32 +5854 # +5855 # . prologue +5856 55/push-ebp +5857 89/<- %ebp 4/r32/esp +5858 # setup +5859 (clear-stream _test-output-stream) +5860 (clear-stream $_test-output-buffered-file->buffer) +5861 # var type/ecx : (handle tree type-id) = int +5862 68/push 0/imm32/right/null +5863 68/push 1/imm32/left/int +5864 89/<- %ecx 4/r32/esp +5865 # var var-var1/ecx : var in ecx +5866 68/push "ecx"/imm32/register +5867 68/push 0/imm32/no-stack-offset +5868 68/push 1/imm32/block-depth +5869 51/push-ecx +5870 68/push "var1"/imm32 +5871 89/<- %ecx 4/r32/esp +5872 # var type/edx : (handle tree type-id) = literal +5873 68/push 0/imm32/right/null +5874 68/push 0/imm32/left/literal +5875 89/<- %edx 4/r32/esp +5876 # var var-var2/edx : var literal +5877 68/push 0/imm32/no-register +5878 68/push 0/imm32/no-stack-offset +5879 68/push 1/imm32/block-depth +5880 52/push-edx +5881 68/push "0x34"/imm32 +5882 89/<- %edx 4/r32/esp +5883 # var inouts/esi : (list var2) +5884 68/push 0/imm32/next +5885 52/push-edx/var-var2 +5886 89/<- %esi 4/r32/esp +5887 # var outputs/edi : (list var1) +5888 68/push 0/imm32/next +5889 51/push-ecx/var-var1 +5890 89/<- %edi 4/r32/esp +5891 # var stmt/esi : statement +5892 68/push 0/imm32/next +5893 57/push-edi/outputs +5894 56/push-esi/inouts +5895 68/push "add"/imm32/operation +5896 68/push 1/imm32 +5897 89/<- %esi 4/r32/esp +5898 # convert +5899 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +5900 (flush _test-output-buffered-file) +5901 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5907 # check output +5908 (check-next-stream-line-equal _test-output-stream "81 0/subop/add %ecx 0x34/imm32" "F - test-add-literal-to-reg") +5909 # . epilogue +5910 89/<- %esp 5/r32/ebp +5911 5d/pop-to-ebp +5912 c3/return +5913 +5914 test-add-literal-to-mem: +5915 # add-to var1, 0x34 +5916 # => +5917 # 81 0/subop/add %eax 0x34/imm32 +5918 # +5919 # . prologue +5920 55/push-ebp +5921 89/<- %ebp 4/r32/esp +5922 # setup +5923 (clear-stream _test-output-stream) +5924 (clear-stream $_test-output-buffered-file->buffer) +5925 # var type/ecx : (handle tree type-id) = int +5926 68/push 0/imm32/right/null +5927 68/push 1/imm32/left/int +5928 89/<- %ecx 4/r32/esp +5929 # var var-var1/ecx : var +5930 68/push 0/imm32/no-register +5931 68/push 8/imm32/stack-offset +5932 68/push 1/imm32/block-depth +5933 51/push-ecx +5934 68/push "var1"/imm32 +5935 89/<- %ecx 4/r32/esp +5936 # var type/edx : (handle tree type-id) = literal +5937 68/push 0/imm32/right/null +5938 68/push 0/imm32/left/literal +5939 89/<- %edx 4/r32/esp +5940 # var var-var2/edx : var literal +5941 68/push 0/imm32/no-register +5942 68/push 0/imm32/no-stack-offset +5943 68/push 1/imm32/block-depth +5944 52/push-edx +5945 68/push "0x34"/imm32 +5946 89/<- %edx 4/r32/esp +5947 # var inouts/esi : (list var2) +5948 68/push 0/imm32/next +5949 52/push-edx/var-var2 +5950 89/<- %esi 4/r32/esp +5951 # var inouts = (list var1 inouts) +5952 56/push-esi/next +5953 51/push-ecx/var-var1 +5954 89/<- %esi 4/r32/esp +5955 # var stmt/esi : statement 5956 68/push 0/imm32/next -5957 51/push-ecx/var-foo -5958 89/<- %esi 4/r32/esp -5959 # var stmt/esi : statement -5960 68/push 0/imm32/next -5961 68/push 0/imm32/outputs -5962 56/push-esi/inouts -5963 68/push "f"/imm32/operation -5964 68/push 1/imm32 -5965 89/<- %esi 4/r32/esp -5966 # var functions/ebx : function -5967 68/push 0/imm32/next -5968 68/push 0/imm32/body -5969 68/push 0/imm32/outputs -5970 51/push-ecx/inouts # hack; in practice we won't have the same var in function definition and call -5971 68/push "f2"/imm32/subx-name -5972 68/push "f"/imm32/name -5973 89/<- %ebx 4/r32/esp -5974 # convert -5975 (emit-subx-statement _test-output-buffered-file %esi 0 %ebx) -5976 (flush _test-output-buffered-file) -5977 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -5983 # check output -5984 (check-next-stream-line-equal _test-output-stream "(f2 34)" "F - test-emit-subx-statement-function-call-with-literal-arg") -5985 # . epilogue -5986 89/<- %esp 5/r32/ebp -5987 5d/pop-to-ebp -5988 c3/return -5989 -5990 emit-subx-prologue: # out : (addr buffered-file) -5991 # . prologue -5992 55/push-ebp -5993 89/<- %ebp 4/r32/esp -5994 # -5995 (write-buffered *(ebp+8) "# . prologue\n") -5996 (write-buffered *(ebp+8) "55/push-ebp\n") -5997 (write-buffered *(ebp+8) "89/<- %ebp 4/r32/esp\n") -5998 $emit-subx-prologue:end: -5999 # . epilogue -6000 89/<- %esp 5/r32/ebp -6001 5d/pop-to-ebp -6002 c3/return -6003 -6004 emit-subx-epilogue: # out : (addr buffered-file) -6005 # . prologue -6006 55/push-ebp -6007 89/<- %ebp 4/r32/esp -6008 # -6009 (write-buffered *(ebp+8) "# . epilogue\n") -6010 (write-buffered *(ebp+8) "89/<- %esp 5/r32/ebp\n") -6011 (write-buffered *(ebp+8) "5d/pop-to-ebp\n") -6012 (write-buffered *(ebp+8) "c3/return\n") -6013 $emit-subx-epilogue:end: -6014 # . epilogue -6015 89/<- %esp 5/r32/ebp -6016 5d/pop-to-ebp -6017 c3/return +5957 68/push 0/imm32/outputs +5958 56/push-esi/inouts +5959 68/push "add-to"/imm32/operation +5960 68/push 1/imm32 +5961 89/<- %esi 4/r32/esp +5962 # convert +5963 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +5964 (flush _test-output-buffered-file) +5965 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5971 # check output +5972 (check-next-stream-line-equal _test-output-stream "81 0/subop/add *(ebp+0x00000008) 0x34/imm32" "F - test-add-literal-to-mem") +5973 # . epilogue +5974 89/<- %esp 5/r32/ebp +5975 5d/pop-to-ebp +5976 c3/return +5977 +5978 test-emit-subx-statement-function-call: +5979 # Call a function on a variable on the stack. +5980 # f foo +5981 # => +5982 # (f2 *(ebp-8)) +5983 # (Changing the function name supports overloading in general, but here it +5984 # just serves to help disambiguate things.) +5985 # +5986 # There's a variable on the var stack as follows: +5987 # name: 'foo' +5988 # type: int +5989 # stack-offset: -8 +5990 # +5991 # There's nothing in primitives. +5992 # +5993 # There's a function with this info: +5994 # name: 'f' +5995 # inout: int/mem +5996 # value: 'f2' +5997 # +5998 # . prologue +5999 55/push-ebp +6000 89/<- %ebp 4/r32/esp +6001 # setup +6002 (clear-stream _test-output-stream) +6003 (clear-stream $_test-output-buffered-file->buffer) +6004 # var type/ecx : (handle tree type-id) = int +6005 68/push 0/imm32/right/null +6006 68/push 1/imm32/left/int +6007 89/<- %ecx 4/r32/esp +6008 # var var-foo/ecx : var +6009 68/push 0/imm32/no-register +6010 68/push -8/imm32/stack-offset +6011 68/push 0/imm32/block-depth +6012 51/push-ecx +6013 68/push "foo"/imm32 +6014 89/<- %ecx 4/r32/esp +6015 # var operands/esi : (list var) +6016 68/push 0/imm32/next +6017 51/push-ecx/var-foo +6018 89/<- %esi 4/r32/esp +6019 # var stmt/esi : statement +6020 68/push 0/imm32/next +6021 68/push 0/imm32/outputs +6022 56/push-esi/inouts +6023 68/push "f"/imm32/operation +6024 68/push 1/imm32 +6025 89/<- %esi 4/r32/esp +6026 # var functions/ebx : function +6027 68/push 0/imm32/next +6028 68/push 0/imm32/body +6029 68/push 0/imm32/outputs +6030 51/push-ecx/inouts # hack; in practice we won't have the same var in function definition and call +6031 68/push "f2"/imm32/subx-name +6032 68/push "f"/imm32/name +6033 89/<- %ebx 4/r32/esp +6034 # convert +6035 (emit-subx-statement _test-output-buffered-file %esi 0 %ebx) +6036 (flush _test-output-buffered-file) +6037 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +6043 # check output +6044 (check-next-stream-line-equal _test-output-stream "(f2 *(ebp+0xfffffff8))" "F - test-emit-subx-statement-function-call") +6045 # . epilogue +6046 89/<- %esp 5/r32/ebp +6047 5d/pop-to-ebp +6048 c3/return +6049 +6050 test-emit-subx-statement-function-call-with-literal-arg: +6051 # Call a function on a literal. +6052 # f 34 +6053 # => +6054 # (f2 34) +6055 # +6056 # . prologue +6057 55/push-ebp +6058 89/<- %ebp 4/r32/esp +6059 # setup +6060 (clear-stream _test-output-stream) +6061 (clear-stream $_test-output-buffered-file->buffer) +6062 # var type/ecx : (handle tree type-id) = literal +6063 68/push 0/imm32/right/null +6064 68/push 0/imm32/left/literal +6065 89/<- %ecx 4/r32/esp +6066 # var var-foo/ecx : var literal +6067 68/push 0/imm32/no-register +6068 68/push 0/imm32/no-stack-offset +6069 68/push 0/imm32/block-depth +6070 51/push-ecx +6071 68/push "34"/imm32 +6072 89/<- %ecx 4/r32/esp +6073 # var operands/esi : (list var) +6074 68/push 0/imm32/next +6075 51/push-ecx/var-foo +6076 89/<- %esi 4/r32/esp +6077 # var stmt/esi : statement +6078 68/push 0/imm32/next +6079 68/push 0/imm32/outputs +6080 56/push-esi/inouts +6081 68/push "f"/imm32/operation +6082 68/push 1/imm32 +6083 89/<- %esi 4/r32/esp +6084 # var functions/ebx : function +6085 68/push 0/imm32/next +6086 68/push 0/imm32/body +6087 68/push 0/imm32/outputs +6088 51/push-ecx/inouts # hack; in practice we won't have the same var in function definition and call +6089 68/push "f2"/imm32/subx-name +6090 68/push "f"/imm32/name +6091 89/<- %ebx 4/r32/esp +6092 # convert +6093 (emit-subx-statement _test-output-buffered-file %esi 0 %ebx) +6094 (flush _test-output-buffered-file) +6095 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +6101 # check output +6102 (check-next-stream-line-equal _test-output-stream "(f2 34)" "F - test-emit-subx-statement-function-call-with-literal-arg") +6103 # . epilogue +6104 89/<- %esp 5/r32/ebp +6105 5d/pop-to-ebp +6106 c3/return +6107 +6108 emit-subx-prologue: # out : (addr buffered-file) +6109 # . prologue +6110 55/push-ebp +6111 89/<- %ebp 4/r32/esp +6112 # +6113 (write-buffered *(ebp+8) "# . prologue\n") +6114 (write-buffered *(ebp+8) "55/push-ebp\n") +6115 (write-buffered *(ebp+8) "89/<- %ebp 4/r32/esp\n") +6116 $emit-subx-prologue:end: +6117 # . epilogue +6118 89/<- %esp 5/r32/ebp +6119 5d/pop-to-ebp +6120 c3/return +6121 +6122 emit-subx-epilogue: # out : (addr buffered-file) +6123 # . prologue +6124 55/push-ebp +6125 89/<- %ebp 4/r32/esp +6126 # +6127 (write-buffered *(ebp+8) "# . epilogue\n") +6128 (write-buffered *(ebp+8) "89/<- %esp 5/r32/ebp\n") +6129 (write-buffered *(ebp+8) "5d/pop-to-ebp\n") +6130 (write-buffered *(ebp+8) "c3/return\n") +6131 $emit-subx-epilogue:end: +6132 # . epilogue +6133 89/<- %esp 5/r32/ebp +6134 5d/pop-to-ebp +6135 c3/return -- cgit 1.4.1-2-gfad0