TC-Y Samples
The goal of TC-Y is straightforward: starting from
LIR, generate the ARM instructions, except that you
don’t have actual registers: we still heavily use Temp
s.
Register allocation has been (or will be) done in another stage,
TC-9, Register Allocation.
let
var answer := 42
in
answer := 51
end
$ tc --target-arm --inst-display the-answer-arm.tig
# Tiger final assembler ouput.
# Routine: _main
.global tc_main
.text
tc_main:
# Allocate frame
mov t3, r10
mov t4, r4
mov t5, r5
mov t6, r6
mov t7, r7
mov t8, r8
mov t9, r9
l0:
ldr t1, =42
str t1, [fp, #0]
ldr t2, =51
str t2, [fp, #0]
l1:
mov r10, t3
mov r4, t4
mov r5, t5
mov r6, t6
mov r7, t7
mov r8, t8
mov r9, t9
# Deallocate frame
pop {fp, pc}
.ltorg
$ echo $?
0
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-arm -sI the-answer-arm.tig
# Tiger final assembler ouput.
# Routine: _main
.global tc_main
.text
tc_main:
push {fp, lr}
sub fp, sp, #4
sub sp, sp, #4
l0:
ldr r1, =42
str r1, [fp, #0]
ldr r1, =51
str r1, [fp, #0]
l1:
add sp, sp, #4
pop {fp, pc}
.ltorg
$ echo $?
0
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
$ tc -e --target-arm --inst-display add-arm.tig
# Tiger final assembler ouput.
# Routine: add
.global tc_l0
.text
tc_l0:
# Allocate frame
str r1, [fp, #0]
mov t0, r2
mov t1, r3
mov t8, r10
mov t9, r4
mov t10, r5
mov t11, r6
mov t12, r7
mov t13, r8
mov t14, r9
l2:
add t7, t0, t1
mov r0, t7
l3:
mov r10, t8
mov r4, t9
mov r5, t10
mov r6, t11
mov r7, t12
mov r8, t13
mov r9, t14
# Deallocate frame
pop {fp, pc}
.ltorg
.data
l1:
.word 1
.asciz "\n"
# Routine: _main
.global tc_main
.text
tc_main:
# Allocate frame
mov t19, r10
mov t20, r4
mov t21, r5
mov t22, r6
mov t23, r7
mov t24, r8
mov t25, r9
l4:
mov t5, fp
mov r1, fp
ldr t15, =2
mov r2, t15
ldr t16, =3
mov r3, t16
bl tc_l0
mov t4, r0
mov r1, t5
ldr t17, =1
mov r2, t17
mov r3, t4
bl tc_l0
mov t6, r0
mov r1, t6
bl tc_print_int
ldr t18, =l1
mov r1, t18
bl tc_print
l5:
mov r10, t19
mov r4, t20
mov r5, t21
mov r6, t22
mov r7, t23
mov r8, t24
mov r9, t25
# Deallocate frame
pop {fp, pc}
.ltorg
$ echo $?
0
You must be able to handle functions with any number of arguments:
let
function many(a0 : int, a1 : int, a2 : int, a3 : int, a4 : int,
a5 : int, a6 : int, a7 : int, a8 : int, a9 : int): int =
a0 + a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9
in
print_int(many(0, 1, 2, 3, 4, 5, 6, 7, 8, 9));
print("\n")
end
$ tc -e --target-arm --inst-display many-args-arm.tig
# Tiger final assembler ouput.
# Routine: many
.global tc_l0
.text
tc_l0:
# Allocate frame
str r1, [fp, #0]
mov t0, r2
mov t1, r3
ldr t2, [fp, #12]
ldr t3, [fp, #16]
ldr t4, [fp, #20]
ldr t5, [fp, #24]
ldr t6, [fp, #28]
ldr t7, [fp, #32]
ldr t8, [fp, #36]
ldr t9, [fp, #40]
mov t22, r10
mov t23, r4
mov t24, r5
mov t25, r6
mov t26, r7
mov t27, r8
mov t28, r9
l2:
add t13, t0, t1
add t14, t13, t2
add t15, t14, t3
add t16, t15, t4
add t17, t16, t5
add t18, t17, t6
add t19, t18, t7
add t20, t19, t8
add t21, t20, t9
mov r0, t21
l3:
mov r10, t22
mov r4, t23
mov r5, t24
mov r6, t25
mov r7, t26
mov r8, t27
mov r9, t28
# Deallocate frame
pop {fp, pc}
.ltorg
.data
l1:
.word 1
.asciz "\n"
# Routine: _main
.global tc_main
.text
tc_main:
# Allocate frame
mov t40, r10
mov t41, r4
mov t42, r5
mov t43, r6
mov t44, r7
mov t45, r8
mov t46, r9
l4:
mov r1, fp
ldr t29, =0
mov r2, t29
ldr t30, =1
mov r3, t30
ldr t31, =2
str t31, [sp, #0]
ldr t32, =3
str t32, [sp, #4]
ldr t33, =4
str t33, [sp, #8]
ldr t34, =5
str t34, [sp, #12]
ldr t35, =6
str t35, [sp, #16]
ldr t36, =7
str t36, [sp, #20]
ldr t37, =8
str t37, [sp, #24]
ldr t38, =9
str t38, [sp, #28]
bl tc_l0
mov t12, r0
mov r1, t12
bl tc_print_int
ldr t39, =l1
mov r1, t39
bl tc_print
l5:
mov r10, t40
mov r4, t41
mov r5, t42
mov r6, t43
mov r7, t44
mov r8, t45
mov r9, t46
# Deallocate frame
pop {fp, pc}
.ltorg
$ echo $?
0
The runtime must be functional. No difference must be observable in comparison with a run with HAVM.
substring("", 1, 1)
$ tc -e --target-arm --inst-display substring-0-1-1-arm.tig
# Tiger final assembler ouput.
.data
l0:
.word 0
.asciz ""
# Routine: _main
.global tc_main
.text
tc_main:
# Allocate frame
mov t4, r10
mov t5, r4
mov t6, r5
mov t7, r6
mov t8, r7
mov t9, r8
mov t10, r9
l1:
ldr t1, =l0
mov r1, t1
ldr t2, =1
mov r2, t2
ldr t3, =1
mov r3, t3
bl tc_substring
l2:
mov r10, t4
mov r4, t5
mov r5, t6
mov r6, t7
mov r7, t8
mov r8, t9
mov r9, t10
# Deallocate frame
pop {fp, pc}
.ltorg
$ echo $?
0
$ tc -e --target-arm --asm-compute --inst-display substring-0-1-1-arm.tig
# Tiger final assembler ouput.
.data
l0:
.word 0
.asciz ""
# Routine: _main
.global tc_main
.text
tc_main:
push {fp, lr}
sub fp, sp, #4
sub sp, sp, #0
l1:
ldr r1, =l0
ldr r2, =1
ldr r3, =1
bl tc_substring
l2:
add sp, sp, #0
pop {fp, pc}
.ltorg
$ echo $?
0
$ tc -e --target-arm --asm-display substring-0-1-1-arm.tig > substring-0-1-1-arm.s
$ echo $?
0
$ arm-linux-gnueabihf-gcc -march=armv7-a -osubstring-0-1-1-arm substring-0-1-1-arm.s
/usr/lib/gcc-cross/arm-linux-gnueabihf/11/../../../../arm-linux-gnueabihf/bin/ld: warning: /tmp/ccg4SJTg.o: missing .note.GNU-stack section implies executable stack
/usr/lib/gcc-cross/arm-linux-gnueabihf/11/../../../../arm-linux-gnueabihf/bin/ld: NOTE: This behaviour is deprecated and will be removed in a future version of the linker
$ echo $?
0
$ qemu-arm -L /usr/arm-linux-gnueabihf ./substring-0-1-1-arm
substring: arguments out of bounds
$ echo $?
120
The following example illustrates conditional jumps.
if 42 > 51 then "forty-two" else "fifty-one"
$ tc -e --target-arm --inst-display condjump-arm.tig
# Tiger final assembler ouput.
.data
l0:
.word 9
.asciz "forty-two"
.data
l1:
.word 9
.asciz "fifty-one"
# Routine: _main
.global tc_main
.text
tc_main:
# Allocate frame
mov t4, r10
mov t5, r4
mov t6, r5
mov t7, r6
mov t8, r7
mov t9, r8
mov t10, r9
l5:
ldr t1, =42
cmp t1, #51
bgt l2
l3:
ldr t2, =l1
l4:
b l6
l2:
ldr t3, =l0
b l4
l6:
mov r10, t4
mov r4, t5
mov r5, t6
mov r6, t7
mov r7, t8
mov r8, t9
mov r9, t10
# Deallocate frame
pop {fp, pc}
.ltorg
$ echo $?
0
$ tc -e --target-arm --asm-compute --inst-display condjump-arm.tig
# Tiger final assembler ouput.
.data
l0:
.word 9
.asciz "forty-two"
.data
l1:
.word 9
.asciz "fifty-one"
# Routine: _main
.global tc_main
.text
tc_main:
push {fp, lr}
sub fp, sp, #4
sub sp, sp, #0
l5:
ldr r1, =42
cmp r1, #51
bgt l2
l3:
ldr r1, =l1
l4:
b l6
l2:
ldr r1, =l0
b l4
l6:
add sp, sp, #0
pop {fp, pc}
.ltorg
$ echo $?
0