#!perl
# Copyright (C) 2001-2005, The Perl Foundation.
# $Id: bsr.t 16244 2006-12-25 22:14:04Z paultcochrane $

use strict;
use warnings;
use lib qw( . lib ../lib ../../lib );
use Test::More;
use Parrot::Config;
use Parrot::Test tests => 12;

pir_output_is( <<'CODE', <<'OUT', "bsr 1" );
# this tests register allocation/preserving of local bsr calls
.sub test :main
   $I0 = 2
   $I1 = 3
   bsr L
   print $I0
   print $I1
   print "\n"
   end
   noop
L: $I2 = 4
   $I3 = 5
   ret
.end
CODE
23
OUT

##############################
pir_output_is( <<'CODE', <<'OUT', "stack calling conventions" );
.sub test :main
   .local int x
   x = 10
   .const int y = 20

   save y	# save args in reversed order
   save x
   bsr _foo	#(r, s) = _foo(x,y)
   .local int r
   .local int s
   restore r	# restore results in order
   restore s

   print "r = "
   print r
   print "\n"
   print "s = "
   print s
   print "\n"
   end

_foo:		# sub foo(int a, int b)
   saveall
   .local int a, b
   restore  a
   restore  b
   print "a = "
   print a
   print "\n"
   print "b = "
   print b
   print "\n"
   .local int pl
   .local int mi
   pl = a + b
   mi = a - b
   save mi		# from right to left
   save pl		# return (pl, mi)
   restoreall
   ret
.end

CODE
a = 10
b = 20
r = 30
s = -10
OUT

##############################
#
pir_output_is( <<'CODE', <<'OUT', "fact with stack calling conventions" );
.sub test :main
    .local int counter
    counter = 5
    save counter
    bsr _fact
    .local int product
    restore product
    print product
    print "\n"
    end

_fact:
    saveall
    .local int N
    restore  N
    .local int prod
    prod = 1
L1:
    prod = prod * N
    dec N
    if N > 0 goto L1
    save prod
    restoreall
    ret
.end
CODE
120
OUT

##############################
# this is considered a non local bsr
#
pir_output_is( <<'CODE', <<'OUT', "recursive bsr with saveall" );
.sub test :main
   $I0 = 5	# count
   $I1 = 1	# product
   save $I0
   save $I1
   bsr _fact
   restore $I1
   print $I1
   print "\n"
   end
_fact:
   saveall
   restore $I1
   restore $I0
   if $I0 <= 1 goto fin
   $I1 = $I1 * $I0
   dec $I0
   save $I0
   save $I1
   bsr _fact
   restore $I1
fin:
   save $I1
   restoreall
   ret
.end

CODE
120
OUT

##############################
# tail recursion - caller saves
pir_output_is( <<'CODE', <<'OUT', "another recursive bsr" );
.sub test :main
   $I0 = 5	# count
   $I1 = 1	# product
   saveall
   bsr _fact
   save $I1
   restoreall
   restore $I1
   print $I1
   print "\n"
   end
_fact:
   if $I0 <= 1 goto fin
   $I1 = $I1 * $I0
   dec $I0
   saveall
   bsr _fact
   save $I1
   restoreall
   restore $I1
fin:
   ret
.end

CODE
120
OUT

##############################
# tail recursion - caller saves
pir_output_is( <<'CODE', <<'OUT', "tail recursive bsr 2" );
.sub test :main
   $I0 = 5	# count
   $I1 = 1	# product
   saveall
   bsr _fact
   save $I1
   restoreall
   restore $I1
   print $I1
   print "\n"
   end
_fact:
   if $I0 <= 1 goto fin
   $I1 = $I1 * $I0
   dec $I0
   bsr _fact
fin:
   ret
.end

CODE
120
OUT

##############################
# tail recursion - caller saves
pir_output_is( <<'CODE', <<'OUT', "tail recursive bsr - opt" );
.sub test :main
   $I0 = 5	# count
   $I1 = 1	# product
   saveall
   bsr _fact
   save $I1
   restoreall
   restore $I1
   print $I1
   print "\n"
   end
_fact:
   if $I0 <= 1 goto fin
   $I1 = $I1 * $I0
   dec $I0
   branch _fact
fin:
   ret
.end

CODE
120
OUT

##############################
# tail recursion - caller saves - parrot calling convention
pir_output_is( <<'CODE', <<'OUT', "tail recursive bsr, parrot cc" );
.sub test :main
   $I0 = _fact(1, 5)
   print $I0
   print "\n"
   end
.end

# the callers args I5, I6 are used to do the calculation and have
# the same state after, so instead of calling again the sub, just
# a branch to the entry is done
.sub _fact
   .param int f
   .param int n
   if n <= 1 goto fin
   f = f * n
   dec n
   .return _fact(f, n)
fin:
   .return(f)
.end

CODE
120
OUT

##############################
# coroutine
pir_output_is( <<'CODE', <<'OUT', "coroutine" );
.sub test :main
    print "Hello"
    _routine()
    print "perl6"
    _routine()
    print "\n"
    end
.end
.sub _routine
   .local pmc co
    print " "
    .yield()
    print "."
    .yield()

.end
CODE
Hello perl6.
OUT

# This is a workaround to suppress errors from POD::Checker.
my $head1 = '=head1';
my $cut   = '=cut';

pir_output_is( <<"CODE", <<'OUT', "pod before" );
$head1 BLA

 fasel

$cut
.sub test :main
	print "ok 1\\n"
	end
.end
CODE
ok 1
OUT

pir_output_is( <<"CODE", <<'OUT', "pod before, after" );
$head1 FOO

 fasel

$cut
.sub test :main
	print "ok 1\\n"
	end
.end
$head1 BAR

 junk

CODE
ok 1
OUT

pir_output_is( <<'CODE', <<'OUT', "bug #25948" );
.sub main :main
        goto L1
test:
        $I1 = 1
        ret
L1:
        $I2 = 2
        bsr test
        print $I2               # printed 1, not 2
	print "\n"
        end
.end
CODE
2
OUT

# Local Variables:
#   mode: cperl
#   cperl-indent-level: 4
#   fill-column: 100
# End:
# vim: expandtab shiftwidth=4:


syntax highlighted by Code2HTML, v. 0.9.1