Here is Ackermann converted to ASM.
(define (ack m n)
(cond ((= m 0) (+ n 1))
((= n 0) (ack (- m 1) 1))
(else (ack (- m 1) (ack m (- n 1))))))
(define (main . args)
(run-benchmark
"ack"
ack-iters
(lambda (result) (equal? result 4093))
(lambda (m n) (lambda () (ack m n)))
3
9))
.section .data
_ack_1:
.long 2 + 256<<2
.text
# compute initial value for global variable
# jump past the body of the lambda
jmp _ack_2
.section .rodata
# align pointers so they end in binary 00
.align 4
_ack_3:
.long 0xca11ab1e
.long _ack_4
.long 0
.text
.type _ack_4, @function
_ack_4:
# compute desired %esp on return in %ebx and push it
# the extra offset of 4 skips over the return address
lea 4(%esp,%edx,4), %ebx
push %ebx
push %ebp
lea 12(%esp), %ebp
cmpl $2, %edx
jnz argument_count_wrong
# discarding useless value in %eax
pop %eax
# %ifeq
push %eax
movl 0(%ebp), %eax
push %eax
movl $1 + 0<<2, %eax
cmpl %eax, (%esp)
pop %eax
pop %eax
jnz _ack_5
push %eax
movl $1 + 1<<2, %eax
push %eax
movl 4(%ebp), %eax
# inlined integer add
call ensure_integer
xchg %eax, (%esp)
call ensure_integer
pop %ebx
add %ebx, %eax
dec %eax
jmp _ack_6
_ack_5:
# %ifeq
push %eax
movl 4(%ebp), %eax
push %eax
movl $1 + 0<<2, %eax
cmpl %eax, (%esp)
pop %eax
pop %eax
jnz _ack_7
push %eax
movl $1 + 1<<2, %eax
push %eax
movl $1 + 1<<2, %eax
push %eax
movl 0(%ebp), %eax
# inlined integer subtract
call ensure_integer
xchg %eax, (%esp)
call ensure_integer
sub %eax, (%esp)
pop %eax
inc %eax
# get procedure
push %eax
movl (_ack_1), %eax
# apply procedure
# Tail call; nargs = 2
# Note %esp points at the last thing pushed,
# not the next thing to push. So for 1 arg, we want %ebx=%esp
lea 4(%esp), %ebx
movl -4(%ebp), %edx
movl -8(%ebp), %esp
movl -12(%ebp), %ebp
push 0(%ebx)
push -4(%ebx)
push %edx
call ensure_procedure
movl 4(%eax), %ebx
movl $2, %edx
jmp *%ebx
jmp _ack_8
_ack_7:
push %eax
movl $1 + 1<<2, %eax
push %eax
movl 4(%ebp), %eax
# inlined integer subtract
call ensure_integer
xchg %eax, (%esp)
call ensure_integer
sub %eax, (%esp)
pop %eax
inc %eax
push %eax
movl 0(%ebp), %eax
# get procedure
push %eax
movl (_ack_1), %eax
# apply procedure
call ensure_procedure
movl 4(%eax), %ebx
movl $2, %edx
call *%ebx
push %eax
movl $1 + 1<<2, %eax
push %eax
movl 0(%ebp), %eax
# inlined integer subtract
call ensure_integer
xchg %eax, (%esp)
call ensure_integer
sub %eax, (%esp)
pop %eax
inc %eax
# get procedure
push %eax
movl (_ack_1), %eax
# apply procedure
# Tail call; nargs = 2
# Note %esp points at the last thing pushed,
# not the next thing to push. So for 1 arg, we want %ebx=%esp
lea 4(%esp), %ebx
movl -4(%ebp), %edx
movl -8(%ebp), %esp
movl -12(%ebp), %ebp
push 0(%ebx)
push -4(%ebx)
push %edx
call ensure_procedure
movl 4(%eax), %ebx
movl $2, %edx
jmp *%ebx
_ack_8:
_ack_6:
# procedure epilogue
# get return address
movl -4(%ebp), %edx
movl -8(%ebp), %esp
movl -12(%ebp), %ebp
jmp *%edx
.size _ack_4, .-_ack_4
_ack_2:
push %eax
movl $_ack_3, %eax
# initialize global variable with value
movl %eax, (_ack_1)
pop %eax
.section .data
_main_1:
.long 2 + 256<<2
.text
# compute initial value for global variable
# jump past the body of the lambda
jmp _main_2
.section .rodata
# align pointers so they end in binary 00
.align 4
_main_3:
.long 0xca11ab1e
.long _main_4
.long 0
.text
.type _main_4, @function
_main_4:
# make space for variadic argument list
pop %ebx
push %ebx
push %ebx
# push desired %esp on return
lea 8(%esp,%edx,4), %ebx
push %ebx
push %ebp
lea 12(%esp), %ebp
call package_up_variadic_args
# discarding useless value in %eax
pop %eax
push %eax
movl $1 + 9<<2, %eax
push %eax
movl $1 + 3<<2, %eax
# jump past the body of the lambda
jmp _main_5
.section .rodata
# align pointers so they end in binary 00
.align 4
_main_6:
.long 0xca11ab1e
.long _main_7
.long 0
.text
.type _main_7, @function
_main_7:
# compute desired %esp on return in %ebx and push it
# the extra offset of 4 skips over the return address
lea 4(%esp,%edx,4), %ebx
push %ebx
push %ebp
lea 12(%esp), %ebp
cmpl $2, %edx
jnz argument_count_wrong
# discarding useless value in %eax
pop %eax
# move arg from stack to heap: m
push %eax
movl 0(%ebp), %eax
# moving top of stack to newly allocated heap var
# allocate bytes: 8
push %eax
movl (arena_pointer), %eax
add $8, (arena_pointer)
cmpl $end_arena, (arena_pointer)
ja arena_full
# now %eax points to newly allocated memory
movl $0x1ce11ed, (%eax)
pop 4(%eax)
# move arg from stack to heap: n
push %eax
movl 4(%ebp), %eax
# moving top of stack to newly allocated heap var
# allocate bytes: 8
push %eax
movl (arena_pointer), %eax
add $8, (arena_pointer)
cmpl $end_arena, (arena_pointer)
ja arena_full
# now %eax points to newly allocated memory
movl $0x1ce11ed, (%eax)
pop 4(%eax)
# jump past the body of the lambda
jmp _main_8
.text
.type _main_9, @function
_main_9:
# compute desired %esp on return in %ebx and push it
# the extra offset of 4 skips over the return address
lea 4(%esp,%edx,4), %ebx
push %ebx
push %ebp
lea 12(%esp), %ebp
cmpl $0, %edx
jnz argument_count_wrong
# fetch artifact from closure: 0 m
push 12(%eax)
# fetch artifact from closure: 1 n
push 16(%eax)
# discarding useless value in %eax
pop %eax
# fetching heap var pointer 1
push %eax
movl -20(%ebp), %eax
# fetch current value from the heap
movl 4(%eax), %eax
# fetching heap var pointer 0
push %eax
movl -16(%ebp), %eax
# fetch current value from the heap
movl 4(%eax), %eax
# get procedure
push %eax
movl (_ack_1), %eax
# apply procedure
# Tail call; nargs = 2
# Note %esp points at the last thing pushed,
# not the next thing to push. So for 1 arg, we want %ebx=%esp
lea 4(%esp), %ebx
movl -4(%ebp), %edx
movl -8(%ebp), %esp
movl -12(%ebp), %ebp
push 0(%ebx)
push -4(%ebx)
push %edx
call ensure_procedure
movl 4(%eax), %ebx
movl $2, %edx
jmp *%ebx
# procedure epilogue
# get return address
movl -4(%ebp), %edx
movl -8(%ebp), %esp
movl -12(%ebp), %ebp
jmp *%edx
.size _main_9, .-_main_9
_main_8:
# allocate bytes: 20
push %eax
movl (arena_pointer), %eax
add $20, (arena_pointer)
cmpl $end_arena, (arena_pointer)
ja arena_full
# now %eax points to newly allocated memory
movl %eax, %ebx
movl $0xca11ab1e, (%ebx)
movl $_main_9, 4(%ebx)
movl $2, 8(%ebx)
# fetching heap var pointer 0
push %eax
movl -16(%ebp), %eax
movl %eax, 12(%ebx)
pop %eax
# fetching heap var pointer 1
push %eax
movl -20(%ebp), %eax
movl %eax, 16(%ebx)
pop %eax
# procedure epilogue
# get return address
movl -4(%ebp), %edx
movl -8(%ebp), %esp
movl -12(%ebp), %ebp
jmp *%edx
.size _main_7, .-_main_7
_main_5:
push %eax
movl $_main_6, %eax
# jump past the body of the lambda
jmp _main_10
.section .rodata
# align pointers so they end in binary 00
.align 4
_main_11:
.long 0xca11ab1e
.long _main_12
.long 0
.text
.type _main_12, @function
_main_12:
# compute desired %esp on return in %ebx and push it
# the extra offset of 4 skips over the return address
lea 4(%esp,%edx,4), %ebx
push %ebx
push %ebp
lea 12(%esp), %ebp
cmpl $1, %edx
jnz argument_count_wrong
# discarding useless value in %eax
pop %eax
push %eax
movl $1 + 4093<<2, %eax
push %eax
movl 0(%ebp), %eax
# get procedure
push %eax
movl (_equalP_1), %eax
# apply procedure
# Tail call; nargs = 2
# Note %esp points at the last thing pushed,
# not the next thing to push. So for 1 arg, we want %ebx=%esp
lea 4(%esp), %ebx
movl -4(%ebp), %edx
movl -8(%ebp), %esp
movl -12(%ebp), %ebp
push 0(%ebx)
push -4(%ebx)
push %edx
call ensure_procedure
movl 4(%eax), %ebx
movl $2, %edx
jmp *%ebx
# procedure epilogue
# get return address
movl -4(%ebp), %edx
movl -8(%ebp), %esp
movl -12(%ebp), %ebp
jmp *%edx
.size _main_12, .-_main_12
_main_10:
push %eax
movl $_main_11, %eax
push %eax
movl (_main_13), %eax
.section .rodata
# align pointers so they end in binary 00
.align 4
_main_14:
.long 0xbabb1e
.long 3
.ascii "ack"
.text
push %eax
movl $_main_14, %eax
# get procedure
push %eax
movl (_main_15), %eax
# apply procedure
# Tail call; nargs = 6
# Note %esp points at the last thing pushed,
# not the next thing to push. So for 1 arg, we want %ebx=%esp
lea 20(%esp), %ebx
movl -4(%ebp), %edx
movl -8(%ebp), %esp
movl -12(%ebp), %ebp
push 0(%ebx)
push -4(%ebx)
push -8(%ebx)
push -12(%ebx)
push -16(%ebx)
push -20(%ebx)
push %edx
call ensure_procedure
movl 4(%eax), %ebx
movl $6, %edx
jmp *%ebx
# procedure epilogue
# get return address
movl -4(%ebp), %edx
movl -8(%ebp), %esp
movl -12(%ebp), %ebp
jmp *%edx
.size _main_4, .-_main_4
_main_2:
push %eax
movl $_main_3, %eax
# initialize global variable with value
movl %eax, (_main_1)
pop %eax