1 /*====================================================================*
2 - Copyright (C) 2001 Leptonica. All rights reserved.
3 - This software is distributed in the hope that it will be
4 - useful, but with NO WARRANTY OF ANY KIND.
5 - No author or distributor accepts responsibility to anyone for the
6 - consequences of using this software, or for whether it serves any
7 - particular purpose or works at all, unless he or she says so in
8 - writing. Everyone is granted permission to copy, modify and
9 - redistribute this source code, for commercial or non-commercial
10 - purposes, with the following restrictions: (1) the origin of this
11 - source code must not be misrepresented; (2) modified versions must
12 - be plainly marked as such; and (3) this notice may not be removed
13 - or altered from any source or modified source distribution.
14 *====================================================================*/
15
16
17 /*
18 * fhmtauto.c
19 *
20 * Main function calls:
21 * l_int32 fhmtautogen()
22 * l_int32 fhmtautogen1()
23 * l_int32 fhmtautogen2()
24 *
25 * Static helpers:
26 * static SARRAY *sarrayMakeWplsCode()
27 * static SARRAY *sarrayMakeInnerLoopDWACode()
28 * static char *makeBarrelshiftString()
29 *
30 * This automatically generates dwa code for the hit-miss transform.
31 * Here's a road map for how it all works.
32 *
33 * (1) You generate an array (a SELA) of hit-miss transform SELs.
34 * This can be done in several ways, including
35 * (a) calling the function selaAddHitMiss() for
36 * pre-compiled SELs
37 * (b) generating the SELA in code in line
38 * (c) reading in a SELA from file, using selaRead()
39 * or various other formats.
40 *
41 * (2) You call fhmtautogen1() and fhmtautogen2() on this SELA.
42 * This uses the text files hmttemplate1.txt and
43 * hmttemplate2.txt for building up the source code. See the file
44 * prog/fhmtautogen.c for an example of how this is done.
45 * The output is written to files named fhmtgen.*.c
46 * and fhmtgenlow.*.c, where "*" is an integer that you
47 * input to this function. That integer labels both
48 * the output files, as well as all the functions that
49 * are generated. That way, using different integers,
50 * you can invoke fhmtautogen() any number of times
51 * to get functions that all have different names so that
52 * they can be linked into one program.
53 *
54 * (3) You copy the generated source code back to your src
55 * directory for compilation. Put their names in the
56 * Makefile, regnerate the prototypes, and recompile
57 * the libraries. Look at the Makefile to see how I've
58 * included fhmtgen.1.c and fhmtgenlow.1.c. These files
59 * provide the high-level interfaces for the hmt, and
60 * the low-level interfaces to do the actual work.
61 *
62 * (4) In an application, you now use this interface. Again
63 * for the example files generated, using integer "1":
64 *
65 * PIX *pixHMTDwa_1(PIX *pixd, PIX *pixs, char *selname);
66 *
67 * or
68 *
69 * PIX *pixFHMTGen_1(PIX *pixd, PIX *pixs, char *selname);
70 *
71 * where the selname is one of the set that were defined
72 * as the name field of sels. This set is listed at the
73 * beginning of the file fhmtgen.1.c.
74 * As an example, see the file prog/fmtauto_reg.c, which
75 * verifies the correctness of the implementation by
76 * comparing the dwa result with that of full-image
77 * rasterops.
78 */
79
80 #include <stdio.h>
81 #include <stdlib.h>
82 #include <string.h>
83 #include "allheaders.h"
84
85 #define OUTROOT "fhmtgen"
86 #define TEMPLATE1 "hmttemplate1.txt"
87 #define TEMPLATE2 "hmttemplate2.txt"
88
89 #define BUFFER_SIZE 512
90
91 #define PROTOARGS "(l_uint32 *, l_int32, l_int32, l_int32, l_uint32 *, l_int32);"
92
93 static char * makeBarrelshiftString(l_int32 delx, l_int32 dely, l_int32 type);
94 static SARRAY * sarrayMakeInnerLoopDWACode(SEL *sel, l_int32 nhits, l_int32 nmisses);
95 static SARRAY * sarrayMakeWplsCode(SEL *sel);
96
97 static char wpldecls[][60] = {
98 "l_int32 wpls2;",
99 "l_int32 wpls2, wpls3;",
100 "l_int32 wpls2, wpls3, wpls4;",
101 "l_int32 wpls5;",
102 "l_int32 wpls5, wpls6;",
103 "l_int32 wpls5, wpls6, wpls7;",
104 "l_int32 wpls5, wpls6, wpls7, wpls8;",
105 "l_int32 wpls9;",
106 "l_int32 wpls9, wpls10;",
107 "l_int32 wpls9, wpls10, wpls11;",
108 "l_int32 wpls9, wpls10, wpls11, wpls12;",
109 "l_int32 wpls13;",
110 "l_int32 wpls13, wpls14;",
111 "l_int32 wpls13, wpls14, wpls15;",
112 "l_int32 wpls13, wpls14, wpls15, wpls16;",
113 "l_int32 wpls17;",
114 "l_int32 wpls17, wpls18;",
115 "l_int32 wpls17, wpls18, wpls19;",
116 "l_int32 wpls17, wpls18, wpls19, wpls20;",
117 "l_int32 wpls21;",
118 "l_int32 wpls21, wpls22;",
119 "l_int32 wpls21, wpls22, wpls23;",
120 "l_int32 wpls21, wpls22, wpls23, wpls24;",
121 "l_int32 wpls25;",
122 "l_int32 wpls25, wpls26;",
123 "l_int32 wpls25, wpls26, wpls27;",
124 "l_int32 wpls25, wpls26, wpls27, wpls28;",
125 "l_int32 wpls29;",
126 "l_int32 wpls29, wpls30;",
127 "l_int32 wpls29, wpls30, wpls31;"};
128
129 static char wpldefs[][24] = {
130 " wpls2 = 2 * wpls;",
131 " wpls3 = 3 * wpls;",
132 " wpls4 = 4 * wpls;",
133 " wpls5 = 5 * wpls;",
134 " wpls6 = 6 * wpls;",
135 " wpls7 = 7 * wpls;",
136 " wpls8 = 8 * wpls;",
137 " wpls9 = 9 * wpls;",
138 " wpls10 = 10 * wpls;",
139 " wpls11 = 11 * wpls;",
140 " wpls12 = 12 * wpls;",
141 " wpls13 = 13 * wpls;",
142 " wpls14 = 14 * wpls;",
143 " wpls15 = 15 * wpls;",
144 " wpls16 = 16 * wpls;",
145 " wpls17 = 17 * wpls;",
146 " wpls18 = 18 * wpls;",
147 " wpls19 = 19 * wpls;",
148 " wpls20 = 20 * wpls;",
149 " wpls21 = 21 * wpls;",
150 " wpls22 = 22 * wpls;",
151 " wpls23 = 23 * wpls;",
152 " wpls24 = 24 * wpls;",
153 " wpls25 = 25 * wpls;",
154 " wpls26 = 26 * wpls;",
155 " wpls27 = 27 * wpls;",
156 " wpls28 = 28 * wpls;",
157 " wpls29 = 29 * wpls;",
158 " wpls30 = 30 * wpls;",
159 " wpls31 = 31 * wpls;"};
160
161 static char wplstrp[][10] = {"+ wpls", "+ wpls2", "+ wpls3", "+ wpls4",
162 "+ wpls5", "+ wpls6", "+ wpls7", "+ wpls8",
163 "+ wpls9", "+ wpls10", "+ wpls11", "+ wpls12",
164 "+ wpls13", "+ wpls14", "+ wpls15", "+ wpls16",
165 "+ wpls17", "+ wpls18", "+ wpls19", "+ wpls20",
166 "+ wpls21", "+ wpls22", "+ wpls23", "+ wpls24",
167 "+ wpls25", "+ wpls26", "+ wpls27", "+ wpls28",
168 "+ wpls29", "+ wpls30", "+ wpls31"};
169
170 static char wplstrm[][10] = {"- wpls", "- wpls2", "- wpls3", "- wpls4",
171 "- wpls5", "- wpls6", "- wpls7", "- wpls8",
172 "- wpls9", "- wpls10", "- wpls11", "- wpls12",
173 "- wpls13", "- wpls14", "- wpls15", "- wpls16",
174 "- wpls17", "- wpls18", "- wpls19", "- wpls20",
175 "- wpls21", "- wpls22", "- wpls23", "- wpls24",
176 "- wpls25", "- wpls26", "- wpls27", "- wpls28",
177 "- wpls29", "- wpls30", "- wpls31"};
178
179
180 /*!
181 * fhmtautogen()
182 *
183 * Input: sela
184 * fileindex
185 * filename (<optional>; can be null)
186 * Return: 0 if OK; 1 on error
187 *
188 * Notes:
189 * (1) This function generates all the code for implementing
190 * dwa morphological operations using all the sels in the sela.
191 * (2) See fhmtautogen1() and fhmtautogen2() for details.
192 */
193 l_int32
fhmtautogen(SELA * sela,l_int32 fileindex,const char * filename)194 fhmtautogen(SELA *sela,
195 l_int32 fileindex,
196 const char *filename)
197 {
198 l_int32 ret1, ret2;
199
200 PROCNAME("fhmtautogen");
201
202 if (!sela)
203 return ERROR_INT("sela not defined", procName, 1);
204 ret1 = fhmtautogen1(sela, fileindex, filename);
205 ret2 = fhmtautogen2(sela, fileindex, filename);
206 if (ret1 || ret2)
207 return ERROR_INT("code generation problem", procName, 1);
208 return 0;
209 }
210
211
212 /*!
213 * fhmtautogen1()
214 *
215 * Input: sel array
216 * fileindex
217 * filename (<optional>; can be null)
218 * Return: 0 if OK; 1 on error
219 *
220 * Notes:
221 * (1) This function uses hmttemplate1.txt to create a
222 * top-level file that contains two functions that carry
223 * out the hit-miss transform for any of the sels in
224 * the input sela.
225 * (2) The fileindex parameter is inserted into the output
226 * filename, as described below.
227 * (3) If filename == NULL, the output file is fhmtgen.<n>.c,
228 * where <n> is equal to the 'fileindex' parameter.
229 * (4) If filename != NULL, the output file is <filename>.<n>.c.
230 * (5) Each sel must have at least one hit. A sel with only misses
231 * generates code that will abort the operation if it is called.
232 */
233 l_int32
fhmtautogen1(SELA * sela,l_int32 fileindex,const char * filename)234 fhmtautogen1(SELA *sela,
235 l_int32 fileindex,
236 const char *filename)
237 {
238 char *filestr;
239 char *str_proto1, *str_proto2, *str_proto3;
240 char *str_doc1, *str_doc2, *str_doc3, *str_doc4;
241 char *str_def1, *str_def2, *str_proc1, *str_proc2;
242 char *str_dwa1, *str_low_dt, *str_low_ds;
243 char bigbuf[BUFFER_SIZE];
244 l_int32 i, nsels, nbytes;
245 l_int32 actstart, end, newstart;
246 SARRAY *sa1, *sa2, *sa3;
247
248 PROCNAME("fhmtautogen1");
249
250 if (!sela)
251 return ERROR_INT("sela not defined", procName, 1);
252 if (fileindex < 0)
253 fileindex = 0;
254 if ((nsels = selaGetCount(sela)) == 0)
255 return ERROR_INT("no sels in sela", procName, 1);
256
257 /* Make array of sel names */
258 sa1 = selaGetSelnames(sela);
259
260 /* Make array of textlines from from hmttemplate1.txt */
261 if ((filestr = (char *)arrayRead(TEMPLATE1, &nbytes)) == NULL)
262 return ERROR_INT("filestr not made", procName, 1);
263 if ((sa2 = sarrayCreateLinesFromString(filestr, 1)) == NULL)
264 return ERROR_INT("sa2 not made", procName, 1);
265 FREE(filestr);
266
267 /* Make strings containing function call names */
268 sprintf(bigbuf, "PIX *pixHMTDwa_%d(PIX *pixd, PIX *pixs, "
269 "char *selname);", fileindex);
270 str_proto1 = stringNew(bigbuf);
271 sprintf(bigbuf, "PIX *pixFHMTGen_%d(PIX *pixd, PIX *pixs, "
272 "char *selname);", fileindex);
273 str_proto2 = stringNew(bigbuf);
274 sprintf(bigbuf, "l_int32 fhmtgen_low_%d(l_uint32 *datad, l_int32 w,\n"
275 " l_int32 h, l_int32 wpld,\n"
276 " l_uint32 *datas, l_int32 wpls,\n"
277 " l_int32 index);", fileindex);
278 str_proto3 = stringNew(bigbuf);
279 sprintf(bigbuf, " * PIX *pixHMTDwa_%d()", fileindex);
280 str_doc1 = stringNew(bigbuf);
281 sprintf(bigbuf, " * PIX *pixFHMTGen_%d()", fileindex);
282 str_doc2 = stringNew(bigbuf);
283 sprintf(bigbuf, " * pixHMTDwa_%d()", fileindex);
284 str_doc3 = stringNew(bigbuf);
285 sprintf(bigbuf, " * pixFHMTGen_%d()", fileindex);
286 str_doc4 = stringNew(bigbuf);
287 sprintf(bigbuf, "pixHMTDwa_%d(PIX *pixd,", fileindex);
288 str_def1 = stringNew(bigbuf);
289 sprintf(bigbuf, "pixFHMTGen_%d(PIX *pixd,", fileindex);
290 str_def2 = stringNew(bigbuf);
291 sprintf(bigbuf, " PROCNAME(\"pixHMTDwa_%d\");", fileindex);
292 str_proc1 = stringNew(bigbuf);
293 sprintf(bigbuf, " PROCNAME(\"pixFHMTGen_%d\");", fileindex);
294 str_proc2 = stringNew(bigbuf);
295 sprintf(bigbuf, " pixt2 = pixFHMTGen_%d(NULL, pixt1, selname);",
296 fileindex);
297 str_dwa1 = stringNew(bigbuf);
298 sprintf(bigbuf,
299 " fhmtgen_low_%d(datad, w, h, wpld, datat, wpls, index);",
300 fileindex);
301 str_low_dt = stringNew(bigbuf);
302 sprintf(bigbuf,
303 " fhmtgen_low_%d(datad, w, h, wpld, datas, wpls, index);",
304 fileindex);
305 str_low_ds = stringNew(bigbuf);
306
307 /* Make the output sa */
308 if ((sa3 = sarrayCreate(0)) == NULL)
309 return ERROR_INT("sa3 not made", procName, 1);
310
311 /* Copyright notice and info header */
312 sarrayParseRange(sa2, 0, &actstart, &end, &newstart, "--", 0);
313 sarrayAppendRange(sa3, sa2, actstart, end);
314
315 /* Insert function names as documentation */
316 sarrayAddString(sa3, str_doc1, L_INSERT);
317 sarrayAddString(sa3, str_doc2, L_INSERT);
318
319 /* Add '#include's */
320 sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
321 sarrayAppendRange(sa3, sa2, actstart, end);
322
323 /* Insert function prototypes */
324 sarrayAddString(sa3, str_proto1, L_INSERT);
325 sarrayAddString(sa3, str_proto2, L_INSERT);
326 sarrayAddString(sa3, str_proto3, L_INSERT);
327
328 /* Add static globals */
329 sprintf(bigbuf, "\nstatic l_int32 NUM_SELS_GENERATED = %d;", nsels);
330 sarrayAddString(sa3, bigbuf, L_COPY);
331 sprintf(bigbuf, "static char SEL_NAMES[][80] = {");
332 sarrayAddString(sa3, bigbuf, L_COPY);
333 for (i = 0; i < nsels - 1; i++) {
334 sprintf(bigbuf,
335 " \"%s\",", sarrayGetString(sa1, i, 0));
336 sarrayAddString(sa3, bigbuf, L_COPY);
337 }
338 sprintf(bigbuf,
339 " \"%s\"};", sarrayGetString(sa1, i, 0));
340 sarrayAddString(sa3, bigbuf, L_COPY);
341
342 /* Start pixHMTDwa_*() function description */
343 sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
344 sarrayAppendRange(sa3, sa2, actstart, end);
345 sarrayAddString(sa3, str_doc3, L_INSERT);
346 sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
347 sarrayAppendRange(sa3, sa2, actstart, end);
348
349 /* Finish pixMorphDwa_*() function definition */
350 sarrayAddString(sa3, str_def1, L_INSERT);
351 sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
352 sarrayAppendRange(sa3, sa2, actstart, end);
353 sarrayAddString(sa3, str_proc1, L_INSERT);
354 sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
355 sarrayAppendRange(sa3, sa2, actstart, end);
356 sarrayAddString(sa3, str_dwa1, L_INSERT);
357 sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
358 sarrayAppendRange(sa3, sa2, actstart, end);
359
360 /* Start pixFHMTGen_*() function description */
361 sarrayAddString(sa3, str_doc4, L_INSERT);
362 sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
363 sarrayAppendRange(sa3, sa2, actstart, end);
364
365 /* Finish pixFHMTGen_*() function description */
366 sarrayAddString(sa3, str_def2, L_INSERT);
367 sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
368 sarrayAppendRange(sa3, sa2, actstart, end);
369 sarrayAddString(sa3, str_proc2, L_INSERT);
370 sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
371 sarrayAppendRange(sa3, sa2, actstart, end);
372 sarrayAddString(sa3, str_low_dt, L_INSERT);
373 sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
374 sarrayAppendRange(sa3, sa2, actstart, end);
375 sarrayAddString(sa3, str_low_ds, L_INSERT);
376 sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
377 sarrayAppendRange(sa3, sa2, actstart, end);
378
379 if ((filestr = sarrayToString(sa3, 1)) == NULL)
380 return ERROR_INT("filestr from sa3 not made", procName, 1);
381 nbytes = strlen(filestr);
382 if (filename)
383 sprintf(bigbuf, "%s.%d.c", filename, fileindex);
384 else
385 sprintf(bigbuf, "%s.%d.c", OUTROOT, fileindex);
386 arrayWrite(bigbuf, "w", filestr, nbytes);
387 sarrayDestroy(&sa1);
388 sarrayDestroy(&sa2);
389 sarrayDestroy(&sa3);
390 FREE(filestr);
391 return 0;
392 }
393
394
395 /*!
396 * fhmtautogen2()
397 *
398 * Input: sel array
399 * fileindex
400 * filename (<optional>; can be null)
401 * Return: 0 if OK; 1 on error
402 *
403 * Notes:
404 * (1) This function uses hmttemplate2.txt to create a
405 * low-level file that contains the low-level functions for
406 * implementing the hit-miss transform for every sel
407 * in the input sela.
408 * (2) The fileindex parameter is inserted into the output
409 * filename, as described below.
410 * (3) If filename == NULL, the output file is fhmtgenlow.<n>.c,
411 * where <n> is equal to the 'fileindex' parameter.
412 * (4) If filename != NULL, the output file is <filename>low.<n>.c.
413 */
414 l_int32
fhmtautogen2(SELA * sela,l_int32 fileindex,const char * filename)415 fhmtautogen2(SELA *sela,
416 l_int32 fileindex,
417 const char *filename)
418 {
419 char *filestr, *fname, *linestr;
420 char *str_doc1, *str_doc2, *str_doc3, *str_def1;
421 char bigbuf[BUFFER_SIZE];
422 char breakstring[] = " break;";
423 char staticstring[] = "static void";
424 l_int32 i, k, l, nsels, nbytes, nhits, nmisses;
425 l_int32 actstart, end, newstart;
426 l_int32 argstart, argend, loopstart, loopend, finalstart, finalend;
427 SARRAY *sa1, *sa2, *sa3, *sa4, *sa5, *sa6;
428 SEL *sel;
429
430 PROCNAME("fhmtautogen2");
431
432 if (!sela)
433 return ERROR_INT("sela not defined", procName, 1);
434 if (fileindex < 0)
435 fileindex = 0;
436 if ((nsels = selaGetCount(sela)) == 0)
437 return ERROR_INT("no sels in sela", procName, 1);
438
439 /* Make the array of textlines from hmttemplate2.txt */
440 if ((filestr = (char *)arrayRead(TEMPLATE2, &nbytes)) == NULL)
441 return ERROR_INT("filestr not made", procName, 1);
442 if ((sa1 = sarrayCreateLinesFromString(filestr, 1)) == NULL)
443 return ERROR_INT("sa1 not made", procName, 1);
444 FREE(filestr);
445
446 /* Make the array of static function names */
447 if ((sa2 = sarrayCreate(nsels)) == NULL)
448 return ERROR_INT("sa2 not made", procName, 1);
449 for (i = 0; i < nsels; i++) {
450 sprintf(bigbuf, "fhmt_%d_%d", fileindex, i);
451 sarrayAddString(sa2, bigbuf, 1);
452 }
453
454 /* Make the static prototype strings */
455 if ((sa3 = sarrayCreate(2 * nsels)) == NULL)
456 return ERROR_INT("sa3 not made", procName, 1);
457 for (i = 0; i < nsels; i++) {
458 fname = sarrayGetString(sa2, i, 0);
459 sprintf(bigbuf, "static void %s%s", fname, PROTOARGS);
460 sarrayAddString(sa3, bigbuf, 1);
461 }
462
463 /* Make strings containing function names */
464 sprintf(bigbuf, " * l_int32 fhmtgen_low_%d()",
465 fileindex);
466 str_doc1 = stringNew(bigbuf);
467 sprintf(bigbuf, " * void fhmt_%d_*()", fileindex);
468 str_doc2 = stringNew(bigbuf);
469 sprintf(bigbuf, " * fhmtgen_low_%d()", fileindex);
470 str_doc3 = stringNew(bigbuf);
471 sprintf(bigbuf, "fhmtgen_low_%d(l_uint32 *datad,", fileindex);
472 str_def1 = stringNew(bigbuf);
473
474 /* Output to this sa */
475 if ((sa4 = sarrayCreate(0)) == NULL)
476 return ERROR_INT("sa4 not made", procName, 1);
477
478 /* Copyright notice and info header */
479 sarrayParseRange(sa1, 0, &actstart, &end, &newstart, "--", 0);
480 sarrayAppendRange(sa4, sa1, actstart, end);
481
482 /* Insert function names as documentation */
483 sarrayAddString(sa4, str_doc1, L_INSERT);
484 sarrayParseRange(sa1, newstart, &actstart, &end, &newstart, "--", 0);
485 sarrayAppendRange(sa4, sa1, actstart, end);
486 sarrayAddString(sa4, str_doc2, L_INSERT);
487 sarrayParseRange(sa1, newstart, &actstart, &end, &newstart, "--", 0);
488 sarrayAppendRange(sa4, sa1, actstart, end);
489
490 /* Insert static protos */
491 for (i = 0; i < nsels; i++) {
492 if ((linestr = sarrayGetString(sa3, i, L_COPY)) == NULL)
493 return ERROR_INT("linestr not retrieved", procName, 1);
494 sarrayAddString(sa4, linestr, L_INSERT);
495 }
496
497 /* Insert function header */
498 sarrayParseRange(sa1, newstart, &actstart, &end, &newstart, "--", 0);
499 sarrayAppendRange(sa4, sa1, actstart, end);
500 sarrayAddString(sa4, str_doc3, L_INSERT);
501 sarrayParseRange(sa1, newstart, &actstart, &end, &newstart, "--", 0);
502 sarrayAppendRange(sa4, sa1, actstart, end);
503 sarrayAddString(sa4, str_def1, L_INSERT);
504 sarrayParseRange(sa1, newstart, &actstart, &end, &newstart, "--", 0);
505 sarrayAppendRange(sa4, sa1, actstart, end);
506
507 /* Generate and insert the dispatcher code */
508 for (i = 0; i < nsels; i++) {
509 sprintf(bigbuf, " case %d:", i);
510 sarrayAddString(sa4, bigbuf, L_COPY);
511 sprintf(bigbuf, " %s(datad, w, h, wpld, datas, wpls);",
512 sarrayGetString(sa2, i, L_NOCOPY));
513 sarrayAddString(sa4, bigbuf, L_COPY);
514 sarrayAddString(sa4, breakstring, L_COPY);
515 }
516
517 /* Finish the dispatcher and introduce the low-level code */
518 sarrayParseRange(sa1, newstart, &actstart, &end, &newstart, "--", 0);
519 sarrayAppendRange(sa4, sa1, actstart, end);
520
521 /* Get the range for the args common to all functions */
522 sarrayParseRange(sa1, newstart, &argstart, &argend, &newstart, "--", 0);
523
524 /* Get the range for the loop code common to all functions */
525 sarrayParseRange(sa1, newstart, &loopstart, &loopend, &newstart, "--", 0);
526
527 /* Get the range for the ending code common to all functions */
528 sarrayParseRange(sa1, newstart, &finalstart, &finalend, &newstart, "--", 0);
529
530 /* Do all the static functions */
531 for (i = 0; i < nsels; i++) {
532 /* Generate the function header and add the common args */
533 sarrayAddString(sa4, staticstring, L_COPY);
534 fname = sarrayGetString(sa2, i, L_NOCOPY);
535 sprintf(bigbuf, "%s(l_uint32 *datad,", fname);
536 sarrayAddString(sa4, bigbuf, L_COPY);
537 sarrayAppendRange(sa4, sa1, argstart, argend);
538
539 /* Declare and define wplsN args, as necessary */
540 if ((sel = selaGetSel(sela, i)) == NULL)
541 return ERROR_INT("sel not returned", procName, 1);
542 if ((sa5 = sarrayMakeWplsCode(sel)) == NULL)
543 return ERROR_INT("sa5 not made", procName, 1);
544 sarrayConcatenate(sa4, sa5);
545 sarrayDestroy(&sa5);
546
547 /* Make sure sel has at least one hit */
548 nhits = 0;
549 nmisses = 0;
550 for (k = 0; k < sel->sy; k++) {
551 for (l = 0; l < sel->sx; l++) {
552 if (sel->data[k][l] == 1)
553 nhits++;
554 else if (sel->data[k][l] == 2)
555 nmisses++;
556 }
557 }
558 if (nhits == 0) {
559 linestr = stringNew(" fprintf(stderr, \"Error in HMT: no hits in sel!\\n\");\n}\n\n");
560 sarrayAddString(sa4, linestr, L_INSERT);
561 continue;
562 }
563
564 /* Add the function loop code */
565 sarrayAppendRange(sa4, sa1, loopstart, loopend);
566
567 /* Insert barrel-op code for *dptr */
568 if ((sa6 = sarrayMakeInnerLoopDWACode(sel, nhits, nmisses)) == NULL)
569 return ERROR_INT("sa6 not made", procName, 1);
570 sarrayConcatenate(sa4, sa6);
571 sarrayDestroy(&sa6);
572
573 /* Finish the function code */
574 sarrayAppendRange(sa4, sa1, finalstart, finalend);
575 }
576
577 /* Output to file */
578 if ((filestr = sarrayToString(sa4, 1)) == NULL)
579 return ERROR_INT("filestr from sa4 not made", procName, 1);
580 nbytes = strlen(filestr);
581 if (filename)
582 sprintf(bigbuf, "%slow.%d.c", filename, fileindex);
583 else
584 sprintf(bigbuf, "%slow.%d.c", OUTROOT, fileindex);
585 arrayWrite(bigbuf, "w", filestr, nbytes);
586 sarrayDestroy(&sa1);
587 sarrayDestroy(&sa2);
588 sarrayDestroy(&sa3);
589 sarrayDestroy(&sa4);
590 FREE(filestr);
591
592 return 0;
593 }
594
595
596
597 /*--------------------------------------------------------------------------*
598 * Helper code for sel *
599 *--------------------------------------------------------------------------*/
600 /*!
601 * sarrayMakeWplsCode()
602 */
603 static SARRAY *
sarrayMakeWplsCode(SEL * sel)604 sarrayMakeWplsCode(SEL *sel)
605 {
606 char spacestring[] = " ";
607 l_int32 i, j, ymax, dely;
608 SARRAY *sa;
609
610 PROCNAME("sarrayMakeWplsCode");
611
612 if (!sel)
613 return (SARRAY *)ERROR_PTR("sel not defined", procName, NULL);
614
615 ymax = 0;
616 for (i = 0; i < sel->sy; i++) {
617 for (j = 0; j < sel->sx; j++) {
618 if (sel->data[i][j] == 1) {
619 dely = L_ABS(i - sel->cy);
620 ymax = L_MAX(ymax, dely);
621 }
622 }
623 }
624 if (ymax > 31) {
625 L_WARNING("ymax > 31; truncating to 31", procName);
626 ymax = 31;
627 }
628
629 if ((sa = sarrayCreate(0)) == NULL)
630 return (SARRAY *)ERROR_PTR("sa not made", procName, NULL);
631
632 /* Declarations */
633 if (ymax > 4)
634 sarrayAddString(sa, wpldecls[2], 1);
635 if (ymax > 8)
636 sarrayAddString(sa, wpldecls[6], 1);
637 if (ymax > 12)
638 sarrayAddString(sa, wpldecls[10], 1);
639 if (ymax > 16)
640 sarrayAddString(sa, wpldecls[14], 1);
641 if (ymax > 20)
642 sarrayAddString(sa, wpldecls[18], 1);
643 if (ymax > 24)
644 sarrayAddString(sa, wpldecls[22], 1);
645 if (ymax > 28)
646 sarrayAddString(sa, wpldecls[26], 1);
647 if (ymax > 1)
648 sarrayAddString(sa, wpldecls[ymax - 2], 1);
649
650 sarrayAddString(sa, spacestring, 1);
651
652 /* Definitions */
653 for (i = 2; i <= ymax; i++)
654 sarrayAddString(sa, wpldefs[i - 2], 1);
655
656 return sa;
657 }
658
659
660 /*!
661 * sarrayMakeInnerLoopDWACode()
662 */
663 static SARRAY *
sarrayMakeInnerLoopDWACode(SEL * sel,l_int32 nhits,l_int32 nmisses)664 sarrayMakeInnerLoopDWACode(SEL *sel,
665 l_int32 nhits,
666 l_int32 nmisses)
667 {
668 char *string;
669 char land[] = "&";
670 char bigbuf[BUFFER_SIZE];
671 l_int32 i, j, ntot, nfound, type, delx, dely;
672 SARRAY *sa;
673
674 PROCNAME("sarrayMakeInnerLoopDWACode");
675
676 if (!sel)
677 return (SARRAY *)ERROR_PTR("sel not defined", procName, NULL);
678
679 if ((sa = sarrayCreate(0)) == NULL)
680 return (SARRAY *)ERROR_PTR("sa not made", procName, NULL);
681
682 ntot = nhits + nmisses;
683 nfound = 0;
684 for (i = 0; i < sel->sy; i++) {
685 for (j = 0; j < sel->sx; j++) {
686 type = sel->data[i][j];
687 if (type == SEL_HIT || type == SEL_MISS) {
688 nfound++;
689 dely = i - sel->cy;
690 delx = j - sel->cx;
691 if ((string = makeBarrelshiftString(delx, dely, type))
692 == NULL) {
693 L_WARNING("barrel shift string not made", procName);
694 continue;
695 }
696 if (ntot == 1) /* just one item */
697 sprintf(bigbuf, " *dptr = %s;", string);
698 else if (nfound == 1)
699 sprintf(bigbuf, " *dptr = %s %s", string, land);
700 else if (nfound < ntot)
701 sprintf(bigbuf, " %s %s", string, land);
702 else /* nfound == ntot */
703 sprintf(bigbuf, " %s;", string);
704 sarrayAddString(sa, bigbuf, 1);
705 FREE(string);
706 }
707 }
708 }
709
710 return sa;
711 }
712
713
714 /*!
715 * makeBarrelshiftString()
716 */
717 static char *
makeBarrelshiftString(l_int32 delx,l_int32 dely,l_int32 type)718 makeBarrelshiftString(l_int32 delx, /* j - cx */
719 l_int32 dely, /* i - cy */
720 l_int32 type) /* SEL_HIT or SEL_MISS */
721 {
722 l_int32 absx, absy;
723 char bigbuf[BUFFER_SIZE];
724
725 PROCNAME("makeBarrelshiftString");
726
727 if (delx < -31 || delx > 31)
728 return (char *)ERROR_PTR("delx out of bounds", procName, NULL);
729 if (dely < -31 || dely > 31)
730 return (char *)ERROR_PTR("dely out of bounds", procName, NULL);
731 absx = L_ABS(delx);
732 absy = L_ABS(dely);
733
734 if (type == SEL_HIT) {
735 if ((delx == 0) && (dely == 0))
736 sprintf(bigbuf, "(*sptr)");
737 else if ((delx == 0) && (dely < 0))
738 sprintf(bigbuf, "(*(sptr %s))", wplstrm[absy - 1]);
739 else if ((delx == 0) && (dely > 0))
740 sprintf(bigbuf, "(*(sptr %s))", wplstrp[absy - 1]);
741 else if ((delx < 0) && (dely == 0))
742 sprintf(bigbuf, "((*(sptr) >> %d) | (*(sptr - 1) << %d))",
743 absx, 32 - absx);
744 else if ((delx > 0) && (dely == 0))
745 sprintf(bigbuf, "((*(sptr) << %d) | (*(sptr + 1) >> %d))",
746 absx, 32 - absx);
747 else if ((delx < 0) && (dely < 0))
748 sprintf(bigbuf, "((*(sptr %s) >> %d) | (*(sptr %s - 1) << %d))",
749 wplstrm[absy - 1], absx, wplstrm[absy - 1], 32 - absx);
750 else if ((delx > 0) && (dely < 0))
751 sprintf(bigbuf, "((*(sptr %s) << %d) | (*(sptr %s + 1) >> %d))",
752 wplstrm[absy - 1], absx, wplstrm[absy - 1], 32 - absx);
753 else if ((delx < 0) && (dely > 0))
754 sprintf(bigbuf, "((*(sptr %s) >> %d) | (*(sptr %s - 1) << %d))",
755 wplstrp[absy - 1], absx, wplstrp[absy - 1], 32 - absx);
756 else /* ((delx > 0) && (dely > 0)) */
757 sprintf(bigbuf, "((*(sptr %s) << %d) | (*(sptr %s + 1) >> %d))",
758 wplstrp[absy - 1], absx, wplstrp[absy - 1], 32 - absx);
759 }
760 else { /* type == SEL_MISS */
761 if ((delx == 0) && (dely == 0))
762 sprintf(bigbuf, "(~*sptr)");
763 else if ((delx == 0) && (dely < 0))
764 sprintf(bigbuf, "(~*(sptr %s))", wplstrm[absy - 1]);
765 else if ((delx == 0) && (dely > 0))
766 sprintf(bigbuf, "(~*(sptr %s))", wplstrp[absy - 1]);
767 else if ((delx < 0) && (dely == 0))
768 sprintf(bigbuf, "((~*(sptr) >> %d) | (~*(sptr - 1) << %d))",
769 absx, 32 - absx);
770 else if ((delx > 0) && (dely == 0))
771 sprintf(bigbuf, "((~*(sptr) << %d) | (~*(sptr + 1) >> %d))",
772 absx, 32 - absx);
773 else if ((delx < 0) && (dely < 0))
774 sprintf(bigbuf, "((~*(sptr %s) >> %d) | (~*(sptr %s - 1) << %d))",
775 wplstrm[absy - 1], absx, wplstrm[absy - 1], 32 - absx);
776 else if ((delx > 0) && (dely < 0))
777 sprintf(bigbuf, "((~*(sptr %s) << %d) | (~*(sptr %s + 1) >> %d))",
778 wplstrm[absy - 1], absx, wplstrm[absy - 1], 32 - absx);
779 else if ((delx < 0) && (dely > 0))
780 sprintf(bigbuf, "((~*(sptr %s) >> %d) | (~*(sptr %s - 1) << %d))",
781 wplstrp[absy - 1], absx, wplstrp[absy - 1], 32 - absx);
782 else /* ((delx > 0) && (dely > 0)) */
783 sprintf(bigbuf, "((~*(sptr %s) << %d) | (~*(sptr %s + 1) >> %d))",
784 wplstrp[absy - 1], absx, wplstrp[absy - 1], 32 - absx);
785 }
786
787 return stringNew(bigbuf);
788 }
789
790