blob: 9c7f1d466e283ca19563bf9805916270575f7f55 [file] [log] [blame]
/**-------------------------------------------------------------------**
** CLooG **
**-------------------------------------------------------------------**
** pprint.c **
**-------------------------------------------------------------------**
** First version: october 26th 2001 **
**-------------------------------------------------------------------**/
/******************************************************************************
* CLooG : the Chunky Loop Generator (experimental) *
******************************************************************************
* *
* Copyright (C) 2001-2005 Cedric Bastoul *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA *
* *
* CLooG, the Chunky Loop Generator *
* Written by Cedric Bastoul, Cedric.Bastoul@inria.fr *
* *
******************************************************************************/
/* CAUTION: the english used for comments is probably the worst you ever read,
* please feel free to correct and improve it !
*/
/* June 22nd 2005: General adaptation for GMP.
* October 26th 2005: General adaptation from CloogDomain to Matrix data
* structure for all constraint systems.
* October 27th 2005: General adaptation from CloogEqual to Matrix data
* structure for equality spreading.
*/
# include <stdlib.h>
# include <stdio.h>
# include <string.h>
#include <assert.h>
# include "../include/cloog/cloog.h"
#ifdef OSL_SUPPORT
#include <osl/util.h>
#include <osl/body.h>
#include <osl/statement.h>
#include <osl/scop.h>
#endif
static void pprint_name(FILE *dst, struct clast_name *n);
static void pprint_term(struct cloogoptions *i, FILE *dst, struct clast_term *t);
static void pprint_sum(struct cloogoptions *opt,
FILE *dst, struct clast_reduction *r);
static void pprint_binary(struct cloogoptions *i,
FILE *dst, struct clast_binary *b);
static void pprint_minmax_f(struct cloogoptions *info,
FILE *dst, struct clast_reduction *r);
static void pprint_minmax_c(struct cloogoptions *info,
FILE *dst, struct clast_reduction *r);
static void pprint_reduction(struct cloogoptions *i,
FILE *dst, struct clast_reduction *r);
static void pprint_expr(struct cloogoptions *i, FILE *dst, struct clast_expr *e);
static void pprint_equation(struct cloogoptions *i,
FILE *dst, struct clast_equation *eq);
static void pprint_assignment(struct cloogoptions *i, FILE *dst,
struct clast_assignment *a);
static void pprint_user_stmt(struct cloogoptions *options, FILE *dst,
struct clast_user_stmt *u);
static void pprint_guard(struct cloogoptions *options, FILE *dst, int indent,
struct clast_guard *g);
static void pprint_for(struct cloogoptions *options, FILE *dst, int indent,
struct clast_for *f);
static void pprint_stmt_list(struct cloogoptions *options, FILE *dst, int indent,
struct clast_stmt *s);
void pprint_name(FILE *dst, struct clast_name *n)
{
fprintf(dst, "%s", n->name);
}
/**
* This function returns a string containing the printing of a value (possibly
* an iterator or a parameter with its coefficient or a constant).
* - val is the coefficient or constant value,
* - name is a string containing the name of the iterator or of the parameter,
*/
void pprint_term(struct cloogoptions *i, FILE *dst, struct clast_term *t)
{
if (t->var) {
int group = t->var->type == clast_expr_red &&
((struct clast_reduction*) t->var)->n > 1;
if (cloog_int_is_one(t->val))
;
else if (cloog_int_is_neg_one(t->val))
fprintf(dst, "-");
else {
cloog_int_print(dst, t->val);
fprintf(dst, "*");
}
if (group)
fprintf(dst, "(");
pprint_expr(i, dst, t->var);
if (group)
fprintf(dst, ")");
} else
cloog_int_print(dst, t->val);
}
void pprint_sum(struct cloogoptions *opt, FILE *dst, struct clast_reduction *r)
{
int i;
struct clast_term *t;
assert(r->n >= 1);
assert(r->elts[0]->type == clast_expr_term);
t = (struct clast_term *) r->elts[0];
pprint_term(opt, dst, t);
for (i = 1; i < r->n; ++i) {
assert(r->elts[i]->type == clast_expr_term);
t = (struct clast_term *) r->elts[i];
if (cloog_int_is_pos(t->val))
fprintf(dst, "+");
pprint_term(opt, dst, t);
}
}
void pprint_binary(struct cloogoptions *i, FILE *dst, struct clast_binary *b)
{
const char *s1 = NULL, *s2 = NULL, *s3 = NULL;
int group = b->LHS->type == clast_expr_red &&
((struct clast_reduction*) b->LHS)->n > 1;
if (i->language == CLOOG_LANGUAGE_FORTRAN) {
switch (b->type) {
case clast_bin_fdiv:
s1 = "FLOOR(REAL(", s2 = ")/REAL(", s3 = "))";
break;
case clast_bin_cdiv:
s1 = "CEILING(REAL(", s2 = ")/REAL(", s3 = "))";
break;
case clast_bin_div:
if (group)
s1 = "(", s2 = ")/", s3 = "";
else
s1 = "", s2 = "/", s3 = "";
break;
case clast_bin_mod:
s1 = "MOD(", s2 = ", ", s3 = ")";
break;
}
} else {
switch (b->type) {
case clast_bin_fdiv:
s1 = "floord(", s2 = ",", s3 = ")";
break;
case clast_bin_cdiv:
s1 = "ceild(", s2 = ",", s3 = ")";
break;
case clast_bin_div:
if (group)
s1 = "(", s2 = ")/", s3 = "";
else
s1 = "", s2 = "/", s3 = "";
break;
case clast_bin_mod:
if (group)
s1 = "(", s2 = ")%", s3 = "";
else
s1 = "", s2 = "%", s3 = "";
break;
}
}
fprintf(dst, "%s", s1);
pprint_expr(i, dst, b->LHS);
fprintf(dst, "%s", s2);
cloog_int_print(dst, b->RHS);
fprintf(dst, "%s", s3);
}
void pprint_minmax_f(struct cloogoptions *info, FILE *dst, struct clast_reduction *r)
{
int i;
if (r->n == 0)
return;
fprintf(dst, r->type == clast_red_max ? "MAX(" : "MIN(");
pprint_expr(info, dst, r->elts[0]);
for (i = 1; i < r->n; ++i) {
fprintf(dst, ",");
pprint_expr(info, dst, r->elts[i]);
}
fprintf(dst, ")");
}
void pprint_minmax_c(struct cloogoptions *info, FILE *dst, struct clast_reduction *r)
{
int i;
for (i = 1; i < r->n; ++i)
fprintf(dst, r->type == clast_red_max ? "max(" : "min(");
if (r->n > 0)
pprint_expr(info, dst, r->elts[0]);
for (i = 1; i < r->n; ++i) {
fprintf(dst, ",");
pprint_expr(info, dst, r->elts[i]);
fprintf(dst, ")");
}
}
void pprint_reduction(struct cloogoptions *i, FILE *dst, struct clast_reduction *r)
{
switch (r->type) {
case clast_red_sum:
pprint_sum(i, dst, r);
break;
case clast_red_min:
case clast_red_max:
if (r->n == 1) {
pprint_expr(i, dst, r->elts[0]);
break;
}
if (i->language == CLOOG_LANGUAGE_FORTRAN)
pprint_minmax_f(i, dst, r);
else
pprint_minmax_c(i, dst, r);
break;
default:
assert(0);
}
}
void pprint_expr(struct cloogoptions *i, FILE *dst, struct clast_expr *e)
{
if (!e)
return;
switch (e->type) {
case clast_expr_name:
pprint_name(dst, (struct clast_name*) e);
break;
case clast_expr_term:
pprint_term(i, dst, (struct clast_term*) e);
break;
case clast_expr_red:
pprint_reduction(i, dst, (struct clast_reduction*) e);
break;
case clast_expr_bin:
pprint_binary(i, dst, (struct clast_binary*) e);
break;
default:
assert(0);
}
}
void pprint_equation(struct cloogoptions *i, FILE *dst, struct clast_equation *eq)
{
pprint_expr(i, dst, eq->LHS);
if (eq->sign == 0)
fprintf(dst, " == ");
else if (eq->sign > 0)
fprintf(dst, " >= ");
else
fprintf(dst, " <= ");
pprint_expr(i, dst, eq->RHS);
}
void pprint_assignment(struct cloogoptions *i, FILE *dst,
struct clast_assignment *a)
{
if (a->LHS)
fprintf(dst, "%s = ", a->LHS);
pprint_expr(i, dst, a->RHS);
}
/**
* pprint_osl_body function:
* this function pretty-prints the OpenScop body of a given statement.
* It returns 1 if it succeeds to find an OpenScop body to print for
* that statement, 0 otherwise.
* \param[in] options CLooG Options.
* \param[in] dst Output stream.
* \param[in] u Statement to print the OpenScop body.
* \return 1 on success to pretty-print an OpenScop body for u, 0 otherwise.
*/
int pprint_osl_body(struct cloogoptions *options, FILE *dst,
struct clast_user_stmt *u) {
#ifdef OSL_SUPPORT
int i;
char *expr, *tmp;
struct clast_stmt *t;
osl_scop_p scop = options->scop;
osl_statement_p stmt;
osl_body_p body;
if ((scop != NULL) &&
(osl_statement_number(scop->statement) >= u->statement->number)) {
stmt = scop->statement;
/* Go to the convenient statement in the SCoP. */
for (i = 1; i < u->statement->number; i++)
stmt = stmt->next;
/* Ensure it has a printable body. */
if ((osl_generic_has_URI(stmt->body, OSL_URI_BODY)) &&
((body = stmt->body->data) != NULL) &&
(body->expression != NULL) &&
(body->iterators != NULL)) {
expr = osl_util_identifier_substitution(body->expression->string[0],
body->iterators->string);
tmp = expr;
/* Print the body expression, substituting the @...@ markers. */
while (*expr) {
if (*expr == '@') {
int iterator;
expr += sscanf(expr, "@%d", &iterator) + 2; /* 2 for the @s */
t = u->substitutions;
for (i = 0; i < iterator; i++)
t = t->next;
pprint_assignment(options, dst, (struct clast_assignment *)t);
} else {
fprintf(dst, "%c", *expr++);
}
}
fprintf(dst, "\n");
free(tmp);
return 1;
}
}
#endif
return 0;
}
void pprint_user_stmt(struct cloogoptions *options, FILE *dst,
struct clast_user_stmt *u)
{
struct clast_stmt *t;
if (pprint_osl_body(options, dst, u))
return;
if (u->statement->name)
fprintf(dst, "%s", u->statement->name);
else
fprintf(dst, "S%d", u->statement->number);
fprintf(dst, "(");
for (t = u->substitutions; t; t = t->next) {
assert(CLAST_STMT_IS_A(t, stmt_ass));
pprint_assignment(options, dst, (struct clast_assignment *)t);
if (t->next)
fprintf(dst, ",");
}
fprintf(dst, ")");
if (options->language != CLOOG_LANGUAGE_FORTRAN)
fprintf(dst, ";");
fprintf(dst, "\n");
}
void pprint_guard(struct cloogoptions *options, FILE *dst, int indent,
struct clast_guard *g)
{
int k;
if (options->language == CLOOG_LANGUAGE_FORTRAN)
fprintf(dst,"IF ");
else
fprintf(dst,"if ");
if (g->n > 1)
fprintf(dst,"(");
for (k = 0; k < g->n; ++k) {
if (k > 0) {
if (options->language == CLOOG_LANGUAGE_FORTRAN)
fprintf(dst," .AND. ");
else
fprintf(dst," && ");
}
fprintf(dst,"(");
pprint_equation(options, dst, &g->eq[k]);
fprintf(dst,")");
}
if (g->n > 1)
fprintf(dst,")");
if (options->language == CLOOG_LANGUAGE_FORTRAN)
fprintf(dst," THEN\n");
else
fprintf(dst," {\n");
pprint_stmt_list(options, dst, indent + INDENT_STEP, g->then);
fprintf(dst, "%*s", indent, "");
if (options->language == CLOOG_LANGUAGE_FORTRAN)
fprintf(dst,"END IF\n");
else
fprintf(dst,"}\n");
}
void pprint_for(struct cloogoptions *options, FILE *dst, int indent,
struct clast_for *f)
{
if (options->language == CLOOG_LANGUAGE_FORTRAN)
fprintf(dst, "DO ");
else
fprintf(dst, "for (");
if (f->LB) {
fprintf(dst, "%s=", f->iterator);
pprint_expr(options, dst, f->LB);
} else if (options->language == CLOOG_LANGUAGE_FORTRAN)
cloog_die("unbounded loops not allowed in FORTRAN.\n");
if (options->language == CLOOG_LANGUAGE_FORTRAN)
fprintf(dst,", ");
else
fprintf(dst,";");
if (f->UB) {
if (options->language != CLOOG_LANGUAGE_FORTRAN)
fprintf(dst,"%s<=", f->iterator);
pprint_expr(options, dst, f->UB);
} else if (options->language == CLOOG_LANGUAGE_FORTRAN)
cloog_die("unbounded loops not allowed in FORTRAN.\n");
if (options->language == CLOOG_LANGUAGE_FORTRAN) {
if (cloog_int_gt_si(f->stride, 1))
cloog_int_print(dst, f->stride);
fprintf(dst,"\n");
}
else {
if (cloog_int_gt_si(f->stride, 1)) {
fprintf(dst,";%s+=", f->iterator);
cloog_int_print(dst, f->stride);
fprintf(dst, ") {\n");
} else
fprintf(dst, ";%s++) {\n", f->iterator);
}
pprint_stmt_list(options, dst, indent + INDENT_STEP, f->body);
fprintf(dst, "%*s", indent, "");
if (options->language == CLOOG_LANGUAGE_FORTRAN)
fprintf(dst,"END DO\n") ;
else
fprintf(dst,"}\n") ;
}
void pprint_stmt_list(struct cloogoptions *options, FILE *dst, int indent,
struct clast_stmt *s)
{
for ( ; s; s = s->next) {
if (CLAST_STMT_IS_A(s, stmt_root))
continue;
fprintf(dst, "%*s", indent, "");
if (CLAST_STMT_IS_A(s, stmt_ass)) {
pprint_assignment(options, dst, (struct clast_assignment *) s);
if (options->language != CLOOG_LANGUAGE_FORTRAN)
fprintf(dst, ";");
fprintf(dst, "\n");
} else if (CLAST_STMT_IS_A(s, stmt_user)) {
pprint_user_stmt(options, dst, (struct clast_user_stmt *) s);
} else if (CLAST_STMT_IS_A(s, stmt_for)) {
pprint_for(options, dst, indent, (struct clast_for *) s);
} else if (CLAST_STMT_IS_A(s, stmt_guard)) {
pprint_guard(options, dst, indent, (struct clast_guard *) s);
} else if (CLAST_STMT_IS_A(s, stmt_block)) {
fprintf(dst, "{\n");
pprint_stmt_list(options, dst, indent + INDENT_STEP,
((struct clast_block *)s)->body);
fprintf(dst, "%*s", indent, "");
fprintf(dst, "}\n");
} else {
assert(0);
}
}
}
/******************************************************************************
* Pretty Printing (dirty) functions *
******************************************************************************/
void clast_pprint(FILE *foo, struct clast_stmt *root,
int indent, CloogOptions *options)
{
pprint_stmt_list(options, foo, indent, root);
}