f6b117708c55f41c93fae5d83cfe4cf56e63011a
[blender-staging.git] / extern / ode / dist / ode / fbuild / BuildMultidot
1 #!/usr/bin/perl
2 #
3 #########################################################################
4 #                                                                       #
5 # Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith.       #
6 # All rights reserved.  Email: russ@q12.org   Web: www.q12.org          #
7 #                                                                       #
8 # This library is free software; you can redistribute it and/or         #
9 # modify it under the terms of EITHER:                                  #
10 #   (1) The GNU Lesser General Public License as published by the Free  #
11 #       Software Foundation; either version 2.1 of the License, or (at  #
12 #       your option) any later version. The text of the GNU Lesser      #
13 #       General Public License is included with this library in the     #
14 #       file LICENSE.TXT.                                               #
15 #   (2) The BSD-style license that is included with this library in     #
16 #       the file LICENSE-BSD.TXT.                                       #
17 #                                                                       #
18 # This library is distributed in the hope that it will be useful,       #
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of        #
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files    #
21 # LICENSE.TXT and LICENSE-BSD.TXT for more details.                     #
22 #                                                                       #
23 #########################################################################
24
25 # multi-dot-product code generator. this code generator is based on the
26 # dot-product code generator.
27 #
28 # code generation parameters, set in a parameters file:
29 #    FNAME    : name of source file to generate - a .c file will be made
30 #    N1       : block size (number of `a' vectors to dot)
31 #    UNROLL1  : inner loop unrolling factor (1..)
32 #    FETCH    : max num of a[i]'s and b[i]'s to load ahead of muls
33 #    LAT1     : load -> mul latency (>=1)
34 #    LAT2     : mul -> add latency (>=1). if this is 1, use fused mul-add
35 #
36 #############################################################################
37
38 require ("BuildUtil");
39
40 # get and check code generation parameters
41 error ("Usage: BuildMultidot <parameters-file>") if $#ARGV != 0;
42 do $ARGV[0];
43
44 if (!defined($FNAME) || !defined($N1) || !defined($UNROLL1) ||
45     !defined($FETCH) || !defined($LAT1) || !defined($LAT2)) {
46   error ("code generation parameters not defined");
47 }
48
49 # check parameters
50 error ("bad N1") if $N1 < 2;
51 error ("bad UNROLL1") if $UNROLL1 < 1;
52 error ("bad FETCH") if $FETCH < 1;
53 error ("bad LAT1") if $LAT1 < 1;
54 error ("bad LAT2") if $LAT2 < 1;
55
56 #############################################################################
57
58 open (FOUT,">$FNAME.c") or die "can't open $FNAME.c for writing";
59
60 # file and function header
61 output (<<END);
62 /* generated code, do not edit. */
63
64 #include "ode/matrix.h"
65
66
67 END
68 output ("void dMultidot$N1 (");
69 for ($i=0; $i<$N1; $i++) {
70   output ("const dReal *a$i, ");
71 }
72 output ("const dReal *b, dReal *outsum, int n)\n{\n");
73
74 output ("dReal ");
75 for ($i=0; $i<$UNROLL1; $i++) {
76   for ($j=0; $j<$N1; $j++) {
77     output ("p$i$j,");
78     output ("m$i$j,") if $LAT2 > 1;
79   }
80   output ("q$i,");
81 }
82 for ($i=0; $i<$N1; $i++) {
83   output ("sum$i");
84   output (",") if $i < ($N1-1);
85 }
86 output (";\n");
87 for ($i=0; $i<$N1; $i++) {
88   output ("sum$i = 0;\n");
89 }
90 output (<<END);
91 n -= $UNROLL1;
92 while (n >= 0) {
93 END
94
95 @load = ();             # slot where a[i]'s and b[i]'s loaded
96 @mul = ();              # slot where multiply i happened
97 @add = ();              # slow where add i happened
98
99 for ($i=0; $i<$N1; $i++) {
100   output ("p0$i = a$i [0];\n");
101 }
102 output ("q0 = b[0];\n");
103 push (@load,0);
104
105 $slot=0;                # one slot for every load/mul/add/nop issued
106 for (;;) {
107   $startslot = $slot;
108
109   # do next load
110   if (($#load - $#mul) < $FETCH && ($#load+1) < $UNROLL1) {
111     push (@load,$slot);
112     for ($j=0; $j<$N1; $j++) {
113       output ("p$#load$j = a$j [$#load];\n");
114     }
115     output ("q$#load = b[$#load];\n");
116     $slot++;
117   }
118
119   # do next multiply
120   if ($#load > $#mul && $slot >= ($load[$#mul+1] + $LAT1) &&
121       ($#mul+1) < $UNROLL1) {
122     push (@mul,$slot);
123     if ($LAT2 > 1) {
124       for ($j=0; $j<$N1; $j++) {
125         output ("m$#mul$j = p$#mul$j * q$#mul;\n");
126       }
127     }
128     else {
129       for ($j=0; $j<$N1; $j++) {
130         output ("sum$j += p$#mul$j * q$#mul;\n");
131       }
132       last if ($#mul+1) >= $UNROLL1;
133     }
134     $slot++;
135   }
136   # do next add
137   if ($LAT2 > 1) {
138     if ($#mul > $#add && $slot >= ($mul[$#add+1] + $LAT2)) {
139       push (@add,$slot);
140       for ($j=0; $j<$N1; $j++) {
141         output ("sum$j += m$#add$j;\n");
142       }
143       $slot++;
144       last if ($#add+1) >= $UNROLL1;
145     }
146   }
147
148   if ($slot == $startslot) {
149     # comment ("nop");
150     $slot++;
151   }
152 }
153
154 for ($j=0; $j<$N1; $j++) {
155   output ("a$j += $UNROLL1;\n");
156 }
157 output ("b += $UNROLL1;\n");
158 output ("n -= $UNROLL1;\n");
159 output ("}\n");
160
161 output ("n += $UNROLL1;\n");
162 output ("while (n > 0) {\n");
163 output ("q0 = *b;\n");
164 for ($j=0; $j<$N1; $j++) {
165   output ("sum$j += (*a$j) * q0;\n");
166   output ("a$j++;\n");
167 }
168 output ("b++;\n");
169 output ("n--;\n");
170 output ("}\n");
171 for ($j=0; $j<$N1; $j++) {
172   output ("outsum[$j] = sum$j;\n");
173 }
174 output ("}\n");