#! /usr/bin/perl 


if ($#ARGV < 1) {
    print("Usage: $0 <N> <K> (12 4)\n");
    exit(0);
}

my $N = $ARGV[0];
my $K = $ARGV[1];

open out, ">vec_potrf_mtxmul.h";

print out "#define T(i,j) T_ ## i ## _ ## j\n";
print out "#define R(i,j) R_ ## i ## _ ## j\n";
print out "#define V(i) V_ ## i\n";
print out "#define DECLARE_T(i, j, A) register vector float T(i,j) = *((A) + i*lda + j);\n";
print out "#define DECLARE_R(i, j) register vector float R(i,j) = spu_splats((float)0.0);\n";
print out "#define DECLARE_V(i, A) register vector float V(i) = *((A) + i);\n";

$out = "#define DECLARE_TX(i, A)";
$vout = "#define DECLARE_VX(A)";
for (my $i=0; $i < $K; $i++) {
    $out .= " DECLARE_T(i, $i, A)";
    $vout .= " DECLARE_V($i, A)";
}
print out "$out\n";
print out "$vout\n";

#$rout = "#define DECLARE_RX(i)";
#for (my $i=0; $i < $N/2; $i++) {
#    $rout .= " DECLARE_R(i, $i)";
#}
#print out "$rout\n";

print out "#define DECLARE_T1(A) DECLARE_TX(0, A)\n";
#print out "#define DECLARE_V1(A) DECLARE_VX(A)\n";
print out "#define DECLARE_R1 DECLARE_R(0,0)\n";
print out "#define DECLARE_VR1 DECLARE_R(0,0)\n";

for (my $i=1; $i < $N; $i++) {
    print out "#define DECLARE_T". ($i+1) ."(A) DECLARE_T$i(A) DECLARE_TX($i, A)\n";
#    print out "#define DECLARE_V". ($i+1) ."(A) DECLARE_V$i(A) DECLARE_VX(A)\n";

#    print out "#define DECLARE_R". ($i+1) ." DECLARE_R$i DECLARE_RX($i)\n";

    print out "#define DECLARE_VR". ($i+1) ." DECLARE_VR$i DECLARE_R($i,0)\n";

    print out "#define DECLARE_R". ($i+1) ." DECLARE_R$i";
    for (my $j=0; $j <= $i; $j++) {
	print out " DECLARE_R($j, $i)";
    }
    print out "\n";
}
print out "\n";

print out "#define COMPUTE_T(i, j, l, var) spu_madd(T(i,l), T(j,l), var)\n";

print out "#define COMPUTE_V(A, l, k, var) spu_madd(V(k), A[l*lda + k], var)\n";
#spu_madd(Arow, A[l * lda + k], temp[l]);


#$out = "COMPUTE_T(i, j,  1, spu_mul(T(i,0), T(j,0)))";
$out = "COMPUTE_T(i, j,  1, spu_madd(T(i,0), T(j,0), R(i,j)))";
$vout = "COMPUTE_V(A, l, 1, spu_madd(V(0), A[l*lda], R(l,0)))";
for (my $i = 2; $i < $K; $i++) {
    $out = "COMPUTE_T(i, j, $i, $out)";
    $vout = "COMPUTE_V(A, l, $i, $vout)";
}

#print out "#define COMPUTE_TX(i, j, C) *((C) + i * ldc + j) += sum_across_float4($out);\n";
print out "#define COMPUTE_TX(i, j, C) R(i,j) = $out;\n";
print out "#define COMPUTE_VX(A, l) R(l,0) = $vout;\n";
print out "#define SAVE_TX(i, j, C) *((C) + i * ldc + j) = sum_across_float4(R(i,j));\n";
#print out "#define SAVE_TX(i, j, C) *((C) + i * ldc + j) = spu_extract(R(i,j),0);\n";

print out "#define COMPUTE_T1(C) COMPUTE_TX(0, 0, C)\n";
print out "#define COMPUTE_V1(A) COMPUTE_VX(A, 0)\n";
print out "#define SAVE_T1(C) SAVE_TX(0, 0, C)\n";

for (my $i = 1; $i < $N; $i++) {
    $out = "#define COMPUTE_T".($i+1)."(C) COMPUTE_T$i(C) COMPUTE_TX($i,$i,C)";
    $vout = "#define COMPUTE_V".($i+1)."(A) COMPUTE_V$i(A) COMPUTE_VX(A,$i)";
    $sout = "#define SAVE_T".($i+1)."(C) SAVE_T$i(C) SAVE_TX($i,$i,C)";
    for (my $j = 0; $j < $i; $j++) {
#	$out .= " COMPUTE_TX($j,$i,C) COMPUTE_TX($i,$j,C)";
	$out .= " COMPUTE_TX($j,$i,C)";
	$sout .= " SAVE_TX($j,$i,C)";
    }
    print out "$out\n";
    print out "$vout\n";
    print out "$sout\n";
}
print out "\n";

sub save {
    my $el = shift(@_);
    my $c = shift(@_);
    my @el = @$el;
    my @c = @$c;
    
    my $out = "";
    for ($i = 0; $i <= $#c; $i++) {
	$out.=$c[$i]." = spu_extract(tmp5,$i);";
    }
    return $out;
}

for (my $i = 0; $i < $N; $i++) {
    $out = "#define SUM_T" . ($i+1) . "(C)";
    
    my @el = ();
    my @c = ();
    for (my $l = 0; $l <= $i; $l++) {
        for (my $m = 0; $m <= $l; $m++) {
    	    push @el, "R($m, $l)";
	    push @c, "*((C) + $l * ldc + $m)";
	    if ($#el == 3) {
		$out .= " HSUM($el[0], $el[1], $el[2], $el[3]);";
		$out .= save(\@el, \@c);
		@el = ();
		@c = ();
	    }
	}
    }
    if (@el) {
	while ($#el < 3) { push @el, "zero"; }
	$out .= " HSUM($el[0], $el[1], $el[2], $el[3]);";
	$out .= save(\@el, \@c);
    }   
    
    print out "$out\n"; 


    $out = "#define SUM_V" . ($i+1) . "(C)";
    my @el = ();
    my $cidx = 0;
    for (my $l = 0; $l <= $i; $l++) {
	push @el, "R($l, 0)";
	if ($#el == 3) {
	    $out .= " HSUM($el[0], $el[1], $el[2], $el[3]);";
	    $out .= " C[$cidx] = tmp5;";
	    $cidx++;
	    @el = ();
	}
    }    

    if (@el) {
	while ($#el < 3) { push @el, "zero"; }
	$out .= " HSUM($el[0], $el[1], $el[2], $el[3]);";
	$out .= " C[$cidx] = tmp5;";
    }   

    print out "$out\n"; 
}

close out;
