1
2   /**-------------------------------------------------------------------**
3    **                              CLooG                                **
4    **-------------------------------------------------------------------**
5    **                             pprint.c                              **
6    **-------------------------------------------------------------------**
7    **                  First version: october 26th 2001                 **
8    **-------------------------------------------------------------------**/
9
10
11/******************************************************************************
12 *               CLooG : the Chunky Loop Generator (experimental)             *
13 ******************************************************************************
14 *                                                                            *
15 * Copyright (C) 2001-2005 Cedric Bastoul                                     *
16 *                                                                            *
17 * This library is free software; you can redistribute it and/or              *
18 * modify it under the terms of the GNU Lesser General Public                 *
19 * License as published by the Free Software Foundation; either               *
20 * version 2.1 of the License, or (at your option) any later version.         *
21 *                                                                            *
22 * This library is distributed in the hope that it will be useful,            *
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of             *
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU          *
25 * Lesser General Public License for more details.                            *
26 *                                                                            *
27 * You should have received a copy of the GNU Lesser General Public           *
28 * License along with this library; if not, write to the Free Software        *
29 * Foundation, Inc., 51 Franklin Street, Fifth Floor,                         *
30 * Boston, MA  02110-1301  USA                                                *
31 *                                                                            *
32 * CLooG, the Chunky Loop Generator                                           *
33 * Written by Cedric Bastoul, Cedric.Bastoul@inria.fr                         *
34 *                                                                            *
35 ******************************************************************************/
36/* CAUTION: the english used for comments is probably the worst you ever read,
37 *          please feel free to correct and improve it !
38 */
39
40/* June    22nd 2005: General adaptation for GMP.
41 * October 26th 2005: General adaptation from CloogDomain to Matrix data
42 *                    structure for all constraint systems.
43 * October 27th 2005: General adaptation from CloogEqual to Matrix data
44 *                    structure for equality spreading.
45 */
46
47# include <stdlib.h>
48# include <stdio.h>
49# include <string.h>
50#include <assert.h>
51# include "../include/cloog/cloog.h"
52
53#ifdef OSL_SUPPORT
54#include <osl/util.h>
55#include <osl/body.h>
56#include <osl/statement.h>
57#include <osl/scop.h>
58#endif
59
60
61static void pprint_name(FILE *dst, struct clast_name *n);
62static void pprint_term(struct cloogoptions *i, FILE *dst, struct clast_term *t);
63static void pprint_sum(struct cloogoptions *opt,
64			FILE *dst, struct clast_reduction *r);
65static void pprint_binary(struct cloogoptions *i,
66			FILE *dst, struct clast_binary *b);
67static void pprint_minmax_f(struct cloogoptions *info,
68			FILE *dst, struct clast_reduction *r);
69static void pprint_minmax_c(struct cloogoptions *info,
70			FILE *dst, struct clast_reduction *r);
71static void pprint_reduction(struct cloogoptions *i,
72			FILE *dst, struct clast_reduction *r);
73static void pprint_expr(struct cloogoptions *i, FILE *dst, struct clast_expr *e);
74static void pprint_equation(struct cloogoptions *i,
75			FILE *dst, struct clast_equation *eq);
76static void pprint_assignment(struct cloogoptions *i, FILE *dst,
77			struct clast_assignment *a);
78static void pprint_user_stmt(struct cloogoptions *options, FILE *dst,
79		       struct clast_user_stmt *u);
80static void pprint_guard(struct cloogoptions *options, FILE *dst, int indent,
81		   struct clast_guard *g);
82static void pprint_for(struct cloogoptions *options, FILE *dst, int indent,
83		 struct clast_for *f);
84static void pprint_stmt_list(struct cloogoptions *options, FILE *dst, int indent,
85		       struct clast_stmt *s);
86
87
88void pprint_name(FILE *dst, struct clast_name *n)
89{
90    fprintf(dst, "%s", n->name);
91}
92
93/**
94 * This function returns a string containing the printing of a value (possibly
95 * an iterator or a parameter with its coefficient or a constant).
96 * - val is the coefficient or constant value,
97 * - name is a string containing the name of the iterator or of the parameter,
98 */
99void pprint_term(struct cloogoptions *i, FILE *dst, struct clast_term *t)
100{
101    if (t->var) {
102	int group = t->var->type == clast_expr_red &&
103		    ((struct clast_reduction*) t->var)->n > 1;
104	if (cloog_int_is_one(t->val))
105	    ;
106	else if (cloog_int_is_neg_one(t->val))
107	    fprintf(dst, "-");
108        else {
109	    cloog_int_print(dst, t->val);
110	    fprintf(dst, "*");
111	}
112	if (group)
113	    fprintf(dst, "(");
114	pprint_expr(i, dst, t->var);
115	if (group)
116	    fprintf(dst, ")");
117    } else
118	cloog_int_print(dst, t->val);
119}
120
121void pprint_sum(struct cloogoptions *opt, FILE *dst, struct clast_reduction *r)
122{
123    int i;
124    struct clast_term *t;
125
126    assert(r->n >= 1);
127    assert(r->elts[0]->type == clast_expr_term);
128    t = (struct clast_term *) r->elts[0];
129    pprint_term(opt, dst, t);
130
131    for (i = 1; i < r->n; ++i) {
132	assert(r->elts[i]->type == clast_expr_term);
133	t = (struct clast_term *) r->elts[i];
134	if (cloog_int_is_pos(t->val))
135	    fprintf(dst, "+");
136	pprint_term(opt, dst, t);
137    }
138}
139
140void pprint_binary(struct cloogoptions *i, FILE *dst, struct clast_binary *b)
141{
142    const char *s1 = NULL, *s2 = NULL, *s3 = NULL;
143    int group = b->LHS->type == clast_expr_red &&
144		((struct clast_reduction*) b->LHS)->n > 1;
145    if (i->language == CLOOG_LANGUAGE_FORTRAN) {
146	switch (b->type) {
147	case clast_bin_fdiv:
148	    s1 = "FLOOR(REAL(", s2 = ")/REAL(", s3 = "))";
149	    break;
150	case clast_bin_cdiv:
151	    s1 = "CEILING(REAL(", s2 = ")/REAL(", s3 = "))";
152	    break;
153	case clast_bin_div:
154	    if (group)
155		s1 = "(", s2 = ")/", s3 = "";
156	    else
157		s1 = "", s2 = "/", s3 = "";
158	    break;
159	case clast_bin_mod:
160	    s1 = "MOD(", s2 = ", ", s3 = ")";
161	    break;
162	}
163    } else {
164	switch (b->type) {
165	case clast_bin_fdiv:
166	    s1 = "floord(", s2 = ",", s3 = ")";
167	    break;
168	case clast_bin_cdiv:
169	    s1 = "ceild(", s2 = ",", s3 = ")";
170	    break;
171	case clast_bin_div:
172	    if (group)
173		s1 = "(", s2 = ")/", s3 = "";
174	    else
175		s1 = "", s2 = "/", s3 = "";
176	    break;
177	case clast_bin_mod:
178	    if (group)
179		s1 = "(", s2 = ")%", s3 = "";
180	    else
181		s1 = "", s2 = "%", s3 = "";
182	    break;
183	}
184    }
185    fprintf(dst, "%s", s1);
186    pprint_expr(i, dst, b->LHS);
187    fprintf(dst, "%s", s2);
188    cloog_int_print(dst, b->RHS);
189    fprintf(dst, "%s", s3);
190}
191
192void pprint_minmax_f(struct cloogoptions *info, FILE *dst, struct clast_reduction *r)
193{
194    int i;
195    if (r->n == 0)
196	return;
197    fprintf(dst, r->type == clast_red_max ? "MAX(" : "MIN(");
198    pprint_expr(info, dst, r->elts[0]);
199    for (i = 1; i < r->n; ++i) {
200	fprintf(dst, ",");
201	pprint_expr(info, dst, r->elts[i]);
202    }
203    fprintf(dst, ")");
204}
205
206void pprint_minmax_c(struct cloogoptions *info, FILE *dst, struct clast_reduction *r)
207{
208    int i;
209    for (i = 1; i < r->n; ++i)
210	fprintf(dst, r->type == clast_red_max ? "max(" : "min(");
211    if (r->n > 0)
212	pprint_expr(info, dst, r->elts[0]);
213    for (i = 1; i < r->n; ++i) {
214	fprintf(dst, ",");
215	pprint_expr(info, dst, r->elts[i]);
216	fprintf(dst, ")");
217    }
218}
219
220void pprint_reduction(struct cloogoptions *i, FILE *dst, struct clast_reduction *r)
221{
222    switch (r->type) {
223    case clast_red_sum:
224	pprint_sum(i, dst, r);
225	break;
226    case clast_red_min:
227    case clast_red_max:
228	if (r->n == 1) {
229	    pprint_expr(i, dst, r->elts[0]);
230	    break;
231	}
232	if (i->language == CLOOG_LANGUAGE_FORTRAN)
233	    pprint_minmax_f(i, dst, r);
234	else
235	    pprint_minmax_c(i, dst, r);
236	break;
237    default:
238	assert(0);
239    }
240}
241
242void pprint_expr(struct cloogoptions *i, FILE *dst, struct clast_expr *e)
243{
244    if (!e)
245	return;
246    switch (e->type) {
247    case clast_expr_name:
248	pprint_name(dst, (struct clast_name*) e);
249	break;
250    case clast_expr_term:
251	pprint_term(i, dst, (struct clast_term*) e);
252	break;
253    case clast_expr_red:
254	pprint_reduction(i, dst, (struct clast_reduction*) e);
255	break;
256    case clast_expr_bin:
257	pprint_binary(i, dst, (struct clast_binary*) e);
258	break;
259    default:
260	assert(0);
261    }
262}
263
264void pprint_equation(struct cloogoptions *i, FILE *dst, struct clast_equation *eq)
265{
266    pprint_expr(i, dst, eq->LHS);
267    if (eq->sign == 0)
268	fprintf(dst, " == ");
269    else if (eq->sign > 0)
270	fprintf(dst, " >= ");
271    else
272	fprintf(dst, " <= ");
273    pprint_expr(i, dst, eq->RHS);
274}
275
276void pprint_assignment(struct cloogoptions *i, FILE *dst,
277			struct clast_assignment *a)
278{
279    if (a->LHS)
280	fprintf(dst, "%s = ", a->LHS);
281    pprint_expr(i, dst, a->RHS);
282}
283
284
285/**
286 * pprint_osl_body function:
287 * this function pretty-prints the OpenScop body of a given statement.
288 * It returns 1 if it succeeds to find an OpenScop body to print for
289 * that statement, 0 otherwise.
290 * \param[in] options CLooG Options.
291 * \param[in] dst     Output stream.
292 * \param[in] u       Statement to print the OpenScop body.
293 * \return 1 on success to pretty-print an OpenScop body for u, 0 otherwise.
294 */
295int pprint_osl_body(struct cloogoptions *options, FILE *dst,
296                    struct clast_user_stmt *u) {
297#ifdef OSL_SUPPORT
298  int i;
299  char *expr, *tmp;
300  struct clast_stmt *t;
301  osl_scop_p scop = options->scop;
302  osl_statement_p stmt;
303  osl_body_p body;
304
305  if ((scop != NULL) &&
306      (osl_statement_number(scop->statement) >= u->statement->number)) {
307    stmt = scop->statement;
308
309    /* Go to the convenient statement in the SCoP. */
310    for (i = 1; i < u->statement->number; i++)
311      stmt = stmt->next;
312
313    /* Ensure it has a printable body. */
314    if ((osl_generic_has_URI(stmt->body, OSL_URI_BODY)) &&
315        ((body = stmt->body->data) != NULL) &&
316        (body->expression != NULL) &&
317        (body->iterators != NULL)) {
318      expr = osl_util_identifier_substitution(body->expression->string[0],
319                                              body->iterators->string);
320      tmp = expr;
321      /* Print the body expression, substituting the @...@ markers. */
322      while (*expr) {
323        if (*expr == '@') {
324          int iterator;
325          expr += sscanf(expr, "@%d", &iterator) + 2; /* 2 for the @s */
326          t = u->substitutions;
327          for (i = 0; i < iterator; i++)
328            t = t->next;
329          pprint_assignment(options, dst, (struct clast_assignment *)t);
330        } else {
331          fprintf(dst, "%c", *expr++);
332        }
333      }
334      fprintf(dst, "\n");
335      free(tmp);
336      return 1;
337    }
338  }
339#endif
340  return 0;
341}
342
343void pprint_user_stmt(struct cloogoptions *options, FILE *dst,
344		       struct clast_user_stmt *u)
345{
346    struct clast_stmt *t;
347
348    if (pprint_osl_body(options, dst, u))
349      return;
350
351    if (u->statement->name)
352	fprintf(dst, "%s", u->statement->name);
353    else
354	fprintf(dst, "S%d", u->statement->number);
355    fprintf(dst, "(");
356    for (t = u->substitutions; t; t = t->next) {
357	assert(CLAST_STMT_IS_A(t, stmt_ass));
358	pprint_assignment(options, dst, (struct clast_assignment *)t);
359	if (t->next)
360	    fprintf(dst, ",");
361    }
362    fprintf(dst, ")");
363    if (options->language != CLOOG_LANGUAGE_FORTRAN)
364	fprintf(dst, ";");
365    fprintf(dst, "\n");
366}
367
368void pprint_guard(struct cloogoptions *options, FILE *dst, int indent,
369		   struct clast_guard *g)
370{
371    int k;
372    if (options->language == CLOOG_LANGUAGE_FORTRAN)
373	fprintf(dst,"IF ");
374    else
375	fprintf(dst,"if ");
376    if (g->n > 1)
377	fprintf(dst,"(");
378    for (k = 0; k < g->n; ++k) {
379	if (k > 0) {
380	    if (options->language == CLOOG_LANGUAGE_FORTRAN)
381		fprintf(dst," .AND. ");
382	    else
383		fprintf(dst," && ");
384	}
385	fprintf(dst,"(");
386        pprint_equation(options, dst, &g->eq[k]);
387	fprintf(dst,")");
388    }
389    if (g->n > 1)
390	fprintf(dst,")");
391    if (options->language == CLOOG_LANGUAGE_FORTRAN)
392	fprintf(dst," THEN\n");
393    else
394	fprintf(dst," {\n");
395
396    pprint_stmt_list(options, dst, indent + INDENT_STEP, g->then);
397
398    fprintf(dst, "%*s", indent, "");
399    if (options->language == CLOOG_LANGUAGE_FORTRAN)
400	fprintf(dst,"END IF\n");
401    else
402	fprintf(dst,"}\n");
403}
404
405void pprint_for(struct cloogoptions *options, FILE *dst, int indent,
406		 struct clast_for *f)
407{
408    if (options->language == CLOOG_LANGUAGE_C) {
409        if ((f->parallel & CLAST_PARALLEL_OMP) && !(f->parallel & CLAST_PARALLEL_MPI)) {
410            if (f->LB) {
411                fprintf(dst, "lbp=");
412                pprint_expr(options, dst, f->LB);
413                fprintf(dst, ";\n");
414            }
415            if (f->UB) {
416                fprintf(dst, "%*s", indent, "");
417                fprintf(dst, "ubp=");
418                pprint_expr(options, dst, f->UB);
419                fprintf(dst, ";\n");
420            }
421            fprintf(dst, "#pragma omp parallel for%s%s%s%s%s%s\n",
422                    (f->private_vars)? " private(":"",
423                    (f->private_vars)? f->private_vars: "",
424                    (f->private_vars)? ")":"",
425                    (f->reduction_vars)? " reduction(": "",
426                    (f->reduction_vars)? f->reduction_vars: "",
427                    (f->reduction_vars)? ")": "");
428            fprintf(dst, "%*s", indent, "");
429        }
430        if ((f->parallel & CLAST_PARALLEL_VEC) && !(f->parallel & CLAST_PARALLEL_OMP)
431               && !(f->parallel & CLAST_PARALLEL_MPI)) {
432            if (f->LB) {
433                fprintf(dst, "lbv=");
434                pprint_expr(options, dst, f->LB);
435                fprintf(dst, ";\n");
436            }
437            if (f->UB) {
438                fprintf(dst, "%*s", indent, "");
439                fprintf(dst, "ubv=");
440                pprint_expr(options, dst, f->UB);
441                fprintf(dst, ";\n");
442            }
443            fprintf(dst, "%*s#pragma ivdep\n", indent, "");
444            fprintf(dst, "%*s#pragma vector always\n", indent, "");
445            fprintf(dst, "%*s", indent, "");
446        }
447        if (f->parallel & CLAST_PARALLEL_MPI) {
448            if (f->LB) {
449                fprintf(dst, "_lb_dist=");
450                pprint_expr(options, dst, f->LB);
451                fprintf(dst, ";\n");
452            }
453            if (f->UB) {
454                fprintf(dst, "%*s", indent, "");
455                fprintf(dst, "_ub_dist=");
456                pprint_expr(options, dst, f->UB);
457                fprintf(dst, ";\n");
458            }
459            fprintf(dst, "%*s", indent, "");
460            fprintf(dst, "polyrt_loop_dist(_lb_dist, _ub_dist, nprocs, my_rank, &lbp, &ubp);\n");
461            if (f->parallel & CLAST_PARALLEL_OMP) {
462                fprintf(dst, "#pragma omp parallel for%s%s%s%s%s%s\n",
463                        (f->private_vars)? " private(":"",
464                        (f->private_vars)? f->private_vars: "",
465                        (f->private_vars)? ")":"",
466                        (f->reduction_vars)? " reduction(": "",
467                        (f->reduction_vars)? f->reduction_vars: "",
468                        (f->reduction_vars)? ")": "");
469            }
470            fprintf(dst, "%*s", indent, "");
471        }
472
473    }
474
475    if (options->language == CLOOG_LANGUAGE_FORTRAN)
476	fprintf(dst, "DO ");
477    else
478	fprintf(dst, "for (");
479
480    if (f->LB) {
481	fprintf(dst, "%s=", f->iterator);
482        if (f->parallel & (CLAST_PARALLEL_OMP | CLAST_PARALLEL_MPI)) {
483            fprintf(dst, "lbp");
484        }else if (f->parallel & CLAST_PARALLEL_VEC){
485            fprintf(dst, "lbv");
486        }else{
487	pprint_expr(options, dst, f->LB);
488        }
489    } else if (options->language == CLOOG_LANGUAGE_FORTRAN)
490	cloog_die("unbounded loops not allowed in FORTRAN.\n");
491
492    if (options->language == CLOOG_LANGUAGE_FORTRAN)
493	fprintf(dst,", ");
494    else
495	fprintf(dst,";");
496
497    if (f->UB) {
498	if (options->language != CLOOG_LANGUAGE_FORTRAN)
499	    fprintf(dst,"%s<=", f->iterator);
500
501        if (f->parallel & (CLAST_PARALLEL_OMP | CLAST_PARALLEL_MPI)) {
502            fprintf(dst, "ubp");
503        }else if (f->parallel & CLAST_PARALLEL_VEC){
504            fprintf(dst, "ubv");
505        }else{
506            pprint_expr(options, dst, f->UB);
507        }
508    }else if (options->language == CLOOG_LANGUAGE_FORTRAN)
509	cloog_die("unbounded loops not allowed in FORTRAN.\n");
510
511    if (options->language == CLOOG_LANGUAGE_FORTRAN) {
512	if (cloog_int_gt_si(f->stride, 1))
513	    cloog_int_print(dst, f->stride);
514	fprintf(dst,"\n");
515    }
516    else {
517	if (cloog_int_gt_si(f->stride, 1)) {
518	    fprintf(dst,";%s+=", f->iterator);
519	    cloog_int_print(dst, f->stride);
520	    fprintf(dst, ") {\n");
521      } else
522	fprintf(dst, ";%s++) {\n", f->iterator);
523    }
524
525    pprint_stmt_list(options, dst, indent + INDENT_STEP, f->body);
526
527    fprintf(dst, "%*s", indent, "");
528    if (options->language == CLOOG_LANGUAGE_FORTRAN)
529	fprintf(dst,"END DO\n") ;
530    else
531	fprintf(dst,"}\n") ;
532}
533
534void pprint_stmt_list(struct cloogoptions *options, FILE *dst, int indent,
535		       struct clast_stmt *s)
536{
537    for ( ; s; s = s->next) {
538	if (CLAST_STMT_IS_A(s, stmt_root))
539	    continue;
540	fprintf(dst, "%*s", indent, "");
541	if (CLAST_STMT_IS_A(s, stmt_ass)) {
542	    pprint_assignment(options, dst, (struct clast_assignment *) s);
543	    if (options->language != CLOOG_LANGUAGE_FORTRAN)
544		fprintf(dst, ";");
545	    fprintf(dst, "\n");
546	} else if (CLAST_STMT_IS_A(s, stmt_user)) {
547	    pprint_user_stmt(options, dst, (struct clast_user_stmt *) s);
548	} else if (CLAST_STMT_IS_A(s, stmt_for)) {
549	    pprint_for(options, dst, indent, (struct clast_for *) s);
550	} else if (CLAST_STMT_IS_A(s, stmt_guard)) {
551	    pprint_guard(options, dst, indent, (struct clast_guard *) s);
552	} else if (CLAST_STMT_IS_A(s, stmt_block)) {
553	    fprintf(dst, "{\n");
554	    pprint_stmt_list(options, dst, indent + INDENT_STEP,
555				((struct clast_block *)s)->body);
556	    fprintf(dst, "%*s", indent, "");
557	    fprintf(dst, "}\n");
558	} else {
559	    assert(0);
560	}
561    }
562}
563
564
565/******************************************************************************
566 *                       Pretty Printing (dirty) functions                    *
567 ******************************************************************************/
568
569void clast_pprint(FILE *foo, struct clast_stmt *root,
570		  int indent, CloogOptions *options)
571{
572    pprint_stmt_list(options, foo, indent, root);
573}
574