Next: , Previous: , Up: TC-X   [Contents][Index]


4.19.2 TC-X Samples

The goal of TC-X is straightforward: starting from LIR, generate the IA-32 instructions, except that you don’t have actual registers: we still heavily use Temps. Register allocation has been (or will be) done in a another stage, TC-9.

let
  var answer := 42
in
  answer := 51
end

File 4.88: the-answer-ia32.tig

$ tc --target-ia32 --inst-display the-answer-ia32.tig
/** Tiger final assembler ouput. */

/** Routine: _main */
        .text
        .globl  tc_main
        .type   tc_main,@function
tc_main:
# Allocate frame
        movl    %ebx, %t3
        movl    %edi, %t4
        movl    %esi, %t5
l0:
        movl    $42, %t1
        movl    %t1, (%ebp)
        movl    $51, %t2
        movl    %t2, (%ebp)
l1:
        movl    %t3, %ebx
        movl    %t4, %edi
        movl    %t5, %esi
# Deallocate frame
        ret     $0
l2:
        .size   tc_main,l2-tc_main
        .ident  "LRDE Tiger Compiler"

Example 4.133: tc --target-ia32 --inst-display the-answer-ia32.tig

At this stage the compiler cannot know what registers are used; the frame is not allocated. The final stage, register allocation, addresses this issue. For your information, it results in:

$ tc --target-ia32 -sI the-answer-ia32.tig
/** Tiger final assembler ouput. */

/** Routine: _main */
        .text
        .globl  tc_main
        .type   tc_main,@function
tc_main:
        pushl   %ebp
        subl    $4, %esp
        movl    %esp, %ebp
        subl    $4, %esp
l0:
        movl    $42, %ecx
        movl    %ecx, (%ebp)
        movl    $51, %ecx
        movl    %ecx, (%ebp)
l1:
        addl    $4, %ebp
        leave
        ret     $0
l2:
        .size   tc_main,l2-tc_main
        .ident  "LRDE Tiger Compiler"

Example 4.134: tc --target-ia32 -sI the-answer-ia32.tig


A delicate part of this exercise is handling the function calls:

let function add(x: int, y: int) : int = x + y
in
  print_int(add(1,(add(2, 3)))); print("\n")
end

File 4.89: add-ia32.tig

$ tc -e --target-ia32 --inst-display add-ia32.tig
/** Tiger final assembler ouput. */

/** Routine: add */
        .text
        .globl  tc_l0
        .type   tc_l0,@function
tc_l0:
# Allocate frame
        movl    12(%ebp), %t10
        movl    %t10, (%ebp)
        movl    16(%ebp), %t0
        movl    20(%ebp), %t1
        movl    %ebx, %t7
        movl    %edi, %t8
        movl    %esi, %t9
l2:
        movl    %t0, %t6
        addl    %t1, %t6
        movl    %t6, %eax
l3:
        movl    %t7, %ebx
        movl    %t8, %edi
        movl    %t9, %esi
# Deallocate frame
        ret     $12
l6:
        .size   tc_l0,l6-tc_l0

        .section        .rodata
l1:
        .long 1
        .asciz "\n"

/** Routine: _main */
        .text
        .globl  tc_main
        .type   tc_main,@function
tc_main:
# Allocate frame
        movl    %ebx, %t15
        movl    %edi, %t16
        movl    %esi, %t17
l4:
        movl    $3, %t11
        pushl   %t11
        movl    $2, %t12
        pushl   %t12
        pushl   %ebp
        call    tc_l0
        movl    %eax, %t4
        pushl   %t4
        movl    $1, %t13
        pushl   %t13
        pushl   %ebp
        call    tc_l0
        movl    %eax, %t5
        pushl   %t5
        call    tc_print_int
        lea     l1, %t14
        pushl   %t14
        call    tc_print
l5:
        movl    %t15, %ebx
        movl    %t16, %edi
        movl    %t17, %esi
# Deallocate frame
        ret     $0
l7:
        .size   tc_main,l7-tc_main
        .ident  "LRDE Tiger Compiler"

Example 4.135: tc -e --target-ia32 --inst-display add-ia32.tig


Once your compiler is complete, you can produce an actual IA-32 output, assemble it and link it with gcc to produce a real executable program:

$ tc -e --target-ia32 --asm-compute --inst-display add-ia32.tig
/** Tiger final assembler ouput. */

/** Routine: add */
        .text
        .globl  tc_l0
        .type   tc_l0,@function
tc_l0:
        pushl   %ebp
        subl    $4, %esp
        movl    %esp, %ebp
        subl    $4, %esp
        movl    12(%ebp), %ecx
        movl    %ecx, (%ebp)
        movl    16(%ebp), %eax
        movl    20(%ebp), %ecx
l2:
        addl    %ecx, %eax
l3:
        addl    $4, %ebp
        leave
        ret     $12
l6:
        .size   tc_l0,l6-tc_l0

        .section        .rodata
l1:
        .long 1
        .asciz "\n"

/** Routine: _main */
        .text
        .globl  tc_main
        .type   tc_main,@function
tc_main:
        pushl   %ebp
        subl    $4, %esp
        movl    %esp, %ebp
        subl    $0, %esp
l4:
        movl    $3, %ecx
        pushl   %ecx
        movl    $2, %ecx
        pushl   %ecx
        pushl   %ebp
        call    tc_l0
        pushl   %eax
        movl    $1, %ecx
        pushl   %ecx
        pushl   %ebp
        call    tc_l0
        pushl   %eax
        call    tc_print_int
        lea     l1, %ecx
        pushl   %ecx
        call    tc_print
l5:
        addl    $4, %ebp
        leave
        ret     $0
l7:
        .size   tc_main,l7-tc_main
        .ident  "LRDE Tiger Compiler"

Example 4.136: tc -e --target-ia32 --asm-compute --inst-display add-ia32.tig

$ tc -e --target-ia32 --asm-display add-ia32.tig >add-ia32.s

Example 4.137: tc -e --target-ia32 --asm-display add-ia32.tig >add-ia32.s

$ gcc -m32 -oadd-ia32 add-ia32.s

Example 4.138: gcc -m32 -oadd-ia32 add-ia32.s

$ ./add-ia32
6

Example 4.139: ./add-ia32


The runtime must be functional. No difference must be observable in comparison with a run with HAVM:

substring("", 1, 1)

File 4.90: substring-0-1-1-ia32.tig

$ tc -e --target-ia32 --inst-display substring-0-1-1-ia32.tig
/** Tiger final assembler ouput. */

        .section        .rodata
l0:
        .long 0
        .asciz ""

/** Routine: _main */
        .text
        .globl  tc_main
        .type   tc_main,@function
tc_main:
# Allocate frame
        movl    %ebx, %t4
        movl    %edi, %t5
        movl    %esi, %t6
l1:
        movl    $1, %t1
        pushl   %t1
        movl    $1, %t2
        pushl   %t2
        lea     l0, %t3
        pushl   %t3
        call    tc_substring
l2:
        movl    %t4, %ebx
        movl    %t5, %edi
        movl    %t6, %esi
# Deallocate frame
        ret     $0
l3:
        .size   tc_main,l3-tc_main
        .ident  "LRDE Tiger Compiler"

Example 4.140: tc -e --target-ia32 --inst-display substring-0-1-1-ia32.tig

$ tc -e --target-ia32 --asm-compute --inst-display substring-0-1-1-ia32.tig
/** Tiger final assembler ouput. */

        .section        .rodata
l0:
        .long 0
        .asciz ""

/** Routine: _main */
        .text
        .globl  tc_main
        .type   tc_main,@function
tc_main:
        pushl   %ebp
        subl    $4, %esp
        movl    %esp, %ebp
        subl    $0, %esp
l1:
        movl    $1, %ecx
        pushl   %ecx
        movl    $1, %ecx
        pushl   %ecx
        lea     l0, %ecx
        pushl   %ecx
        call    tc_substring
l2:
        addl    $4, %ebp
        leave
        ret     $0
l3:
        .size   tc_main,l3-tc_main
        .ident  "LRDE Tiger Compiler"

Example 4.141: tc -e --target-ia32 --asm-compute --inst-display substring-0-1-1-ia32.tig

$ tc -e --target-ia32 --asm-display substring-0-1-1-ia32.tig >substring-0-1-1-ia32.s

Example 4.142: tc -e --target-ia32 --asm-display substring-0-1-1-ia32.tig >substring-0-1-1-ia32.s

$ gcc -m32 -osubstring-0-1-1-ia32 substring-0-1-1-ia32.s

Example 4.143: gcc -m32 -osubstring-0-1-1-ia32 substring-0-1-1-ia32.s

$ ./substring-0-1-1-ia32
error→substring: arguments out of bounds
⇒120

Example 4.144: ./substring-0-1-1-ia32


The following example illustrates conditional jumps.

if 42 > 51 then "forty-two" else "fifty-one"

File 4.91: condjump-ia32.tig

$ tc -e --target-ia32 --inst-display condjump-ia32.tig
/** Tiger final assembler ouput. */

        .section        .rodata
l0:
        .long 9
        .asciz "forty-two"

        .section        .rodata
l1:
        .long 9
        .asciz "fifty-one"

/** Routine: _main */
        .text
        .globl  tc_main
        .type   tc_main,@function
tc_main:
# Allocate frame
        movl    %ebx, %t4
        movl    %edi, %t5
        movl    %esi, %t6
l5:
        movl    $42, %t1
        cmp     $51, %t1
        jg      l2
l3:
        lea     l1, %t2
l4:
        jmp     l6
l2:
        lea     l0, %t3
        jmp     l4
l6:
        movl    %t4, %ebx
        movl    %t5, %edi
        movl    %t6, %esi
# Deallocate frame
        ret     $0
l7:
        .size   tc_main,l7-tc_main
        .ident  "LRDE Tiger Compiler"

Example 4.145: tc -e --target-ia32 --inst-display condjump-ia32.tig

$ tc -e --target-ia32 --asm-compute --inst-display condjump-ia32.tig
/** Tiger final assembler ouput. */

        .section        .rodata
l0:
        .long 9
        .asciz "forty-two"

        .section        .rodata
l1:
        .long 9
        .asciz "fifty-one"

/** Routine: _main */
        .text
        .globl  tc_main
        .type   tc_main,@function
tc_main:
        pushl   %ebp
        subl    $4, %esp
        movl    %esp, %ebp
        subl    $0, %esp
l5:
        movl    $42, %ecx
        cmp     $51, %ecx
        jg      l2
l3:
        lea     l1, %ecx
l4:
        jmp     l6
l2:
        lea     l0, %ecx
        jmp     l4
l6:
        addl    $4, %ebp
        leave
        ret     $0
l7:
        .size   tc_main,l7-tc_main
        .ident  "LRDE Tiger Compiler"

Example 4.146: tc -e --target-ia32 --asm-compute --inst-display condjump-ia32.tig


Next: , Previous: , Up: TC-X   [Contents][Index]