Parrot runs the ackermann benchmark faster than C.
leo
Heureka - from the -Ofun department

Or - running the ackermann function (and possibly other recursive
functions) really fast.

$ time ./parrot -Oc -C ack.pir 11
Ack(3, 11) = 16381

real    0m0.567s
user    0m0.559s
sys     0m0.008s

$ time ./ack 11
Ack(3,11): 16381

real    0m0.980s
user    0m0.978s
sys     0m0.002s

Parrot is svn head (not optimized BTW), the C version is compiled -O3
with 3.3.5. Below is the C [1] and the PIR source [2]. The ack
function is renamed to __pic_test - currently all the checks that
would enable this optimization are missing, e.g. if only I and N
registers are used and not too many, if there is no introspection and
so on. 

The created JIT code for the ack function is also shown [3]. This is
actually only the recursive part of it, there is a small stub that
moves the arguments into registers and fetches the return result. 

./parrot -Oc -C  turns on tail-recursion optimization (recursive tail
calls are converted to loops). -C is the CGP or direct-threaded
runcore, which is able to recompile statically known stuff into faster
versions by e.g. caching lookups and such.

Have fun,
leo

[1]

/* -*- mode: c -*-
 * $Id: ackermann-gcc-3.code,v 1.8 2005/12/02 08:05:56 bfulgham Exp $
 * http://www.bagley.org/~doug/shootout/
 *
 * modified by Isaac Gouy
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int Ack(int M, int N) { return(M ? (Ack(M-1,N ? Ack(M,(N-1)) : 1)) : N+1); }


int main(int argc, char *argv[]) {
    int n = ((argc == 2) ? atoi(argv[1]) : 1);

    printf("Ack(3,%d): %d\n", n, Ack(3, n));
    return(0);
}

[2]

#!./parrot -C
#
# ackermann - ack(3, 9) is default 
# shootout runs ack(3, 11)
# by Leopold Toetsch

.sub main :main
    .param pmc argv
    .local int argc
    argc = elements argv
    .local int x, y, r
    x = 3
    y = 9
    if argc == 1 goto go
    $S0 = argv[1]
    if argc == 2 goto xdefault
    x = $S0
    $S0 = argv[2]
    y = $S0
    goto go
xdefault:    
    y = $S0
go:
    $P0 = getinterp
    $P0.'recursion_limit'(100000)
    r = __pic_test(x, y)
    .local pmc args
    args = new .ResizableIntegerArray
    push args, x
    push args, y
    push args, r
    $S0 = sprintf "Ack(%d, %d) = %d\n", args
    print $S0
.end

.sub __pic_test
    .param int x
    .param int y
    if x goto a1
        inc y
        .return (y)
a1:
    if y goto a2
        dec x
        .return __pic_test(x, 1)
a2:
    dec y
    y = __pic_test(x, y)
    dec x
    .return __pic_test(x, y)
.end

[3]
0x84a80c7:      test   %edx,%edx
0x84a80c9:      jne    0x84a80d3
0x84a80cf:      inc    %ecx
0x84a80d0:      mov    %ecx,%eax
0x84a80d2:      ret
0x84a80d3:      test   %ecx,%ecx
0x84a80d5:      jne    0x84a80e4
0x84a80db:      dec    %edx
0x84a80dc:      mov    $0x1,%ecx
0x84a80e1:      jmp    0x84a80c7
0x84a80e3:      nop
0x84a80e4:      dec    %ecx
0x84a80e5:      push   %edx
0x84a80e6:      call   0x84a80c7
0x84a80eb:      pop    %edx
0x84a80ec:      mov    %eax,%ecx
0x84a80ee:      mov    %esi,%esi
0x84a80f0:      dec    %edx
0x84a80f1:      jmp    0x84a80c7
0x84a80f3:      ret

Reply via email to