llvm-project/polly/lib/External/isl/isl_printer.c

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

852 lines
20 KiB
C
Raw Normal View History

#include <string.h>
#include <isl_int.h>
#include <isl/id.h>
#include <isl/id_to_id.h>
#include <isl_printer_private.h>
static __isl_give isl_printer *file_start_line(__isl_take isl_printer *p)
{
fprintf(p->file, "%s%*s%s", p->indent_prefix ? p->indent_prefix : "",
p->indent, "", p->prefix ? p->prefix : "");
return p;
}
static __isl_give isl_printer *file_end_line(__isl_take isl_printer *p)
{
fprintf(p->file, "%s\n", p->suffix ? p->suffix : "");
return p;
}
static __isl_give isl_printer *file_flush(__isl_take isl_printer *p)
{
fflush(p->file);
return p;
}
static __isl_give isl_printer *file_print_str(__isl_take isl_printer *p,
const char *s)
{
fprintf(p->file, "%s", s);
return p;
}
static __isl_give isl_printer *file_print_double(__isl_take isl_printer *p,
double d)
{
fprintf(p->file, "%g", d);
return p;
}
static __isl_give isl_printer *file_print_int(__isl_take isl_printer *p, int i)
{
fprintf(p->file, "%d", i);
return p;
}
static __isl_give isl_printer *file_print_isl_int(__isl_take isl_printer *p, isl_int i)
{
isl_int_print(p->file, i, p->width);
return p;
}
static int grow_buf(__isl_keep isl_printer *p, int extra)
{
int new_size;
char *new_buf;
if (p->buf_size == 0)
return -1;
new_size = ((p->buf_n + extra + 1) * 3) / 2;
new_buf = isl_realloc_array(p->ctx, p->buf, char, new_size);
if (!new_buf) {
p->buf_size = 0;
return -1;
}
p->buf = new_buf;
p->buf_size = new_size;
return 0;
}
static __isl_give isl_printer *str_print(__isl_take isl_printer *p,
const char *s, int len)
{
if (p->buf_n + len + 1 >= p->buf_size && grow_buf(p, len))
goto error;
memcpy(p->buf + p->buf_n, s, len);
p->buf_n += len;
p->buf[p->buf_n] = '\0';
return p;
error:
isl_printer_free(p);
return NULL;
}
static __isl_give isl_printer *str_print_indent(__isl_take isl_printer *p,
int indent)
{
int i;
if (p->buf_n + indent + 1 >= p->buf_size && grow_buf(p, indent))
goto error;
for (i = 0; i < indent; ++i)
p->buf[p->buf_n++] = ' ';
[Polly] Update ISL to isl-0.22.1-87-gfee05a13. The primary motivation is to fix an assertion failure in isl_basic_map_alloc_equality: isl_assert(ctx, room_for_con(bmap, 1), return -1); Although the assertion does not occur anymore, I could not identify which of ISL's commits fixed it. Compared to the previous ISL version, Polly requires some changes for this update * Since ISL commit 20d3574 "perform parameter alignment by modifying both arguments to function" isl_*_gist_* and similar functions do not always align the paramter list anymore. This caused the parameter lists in JScop files to become out-of-sync. Since many regression tests use JScop files with a fixed parameter list and order, we explicitly call align_params to ensure a predictable parameter list. * ISL changed some return types to isl_size, a typedef of (signed) int. This caused some issues where the return type was unsigned int before: - No overload for std::max(unsigned,isl_size) - It cause additional 'mixed signed/unsigned comparison' warnings. Since they do not break compilation, and sizes larger than 2^31 were never supported, I am going to fix it separately. * With the change to isl_size, commit 57d547 "isl_*_list_size: return isl_size" also changed the return value in case of an error from 0 to -1. This caused undefined looping over isl_iterator since the 'end iterator' got index -1, never reached from the 'begin iterator' with index 0. * Some internal changes in ISL caused the number of operations to increase when determining access ranges to determine aliasing overlaps. In one test, this caused exceeding the default limit of 800000. The operations-limit was disabled for this test.
2020-02-11 04:51:33 +08:00
p->buf[p->buf_n] = '\0';
return p;
error:
isl_printer_free(p);
return NULL;
}
static __isl_give isl_printer *str_start_line(__isl_take isl_printer *p)
{
if (p->indent_prefix)
p = str_print(p, p->indent_prefix, strlen(p->indent_prefix));
p = str_print_indent(p, p->indent);
if (p->prefix)
p = str_print(p, p->prefix, strlen(p->prefix));
return p;
}
static __isl_give isl_printer *str_end_line(__isl_take isl_printer *p)
{
if (p->suffix)
p = str_print(p, p->suffix, strlen(p->suffix));
p = str_print(p, "\n", strlen("\n"));
return p;
}
static __isl_give isl_printer *str_flush(__isl_take isl_printer *p)
{
p->buf_n = 0;
p->buf[p->buf_n] = '\0';
return p;
}
static __isl_give isl_printer *str_print_str(__isl_take isl_printer *p,
const char *s)
{
return str_print(p, s, strlen(s));
}
static __isl_give isl_printer *str_print_double(__isl_take isl_printer *p,
double d)
{
int left = p->buf_size - p->buf_n;
int need = snprintf(p->buf + p->buf_n, left, "%g", d);
if (need >= left) {
if (grow_buf(p, need))
goto error;
left = p->buf_size - p->buf_n;
need = snprintf(p->buf + p->buf_n, left, "%g", d);
}
p->buf_n += need;
return p;
error:
isl_printer_free(p);
return NULL;
}
static __isl_give isl_printer *str_print_int(__isl_take isl_printer *p, int i)
{
int left = p->buf_size - p->buf_n;
int need = snprintf(p->buf + p->buf_n, left, "%d", i);
if (need >= left) {
if (grow_buf(p, need))
goto error;
left = p->buf_size - p->buf_n;
need = snprintf(p->buf + p->buf_n, left, "%d", i);
}
p->buf_n += need;
return p;
error:
isl_printer_free(p);
return NULL;
}
static __isl_give isl_printer *str_print_isl_int(__isl_take isl_printer *p,
isl_int i)
{
char *s;
int len;
s = isl_int_get_str(i);
len = strlen(s);
if (len < p->width)
p = str_print_indent(p, p->width - len);
p = str_print(p, s, len);
isl_int_free_str(s);
return p;
}
struct isl_printer_ops {
__isl_give isl_printer *(*start_line)(__isl_take isl_printer *p);
__isl_give isl_printer *(*end_line)(__isl_take isl_printer *p);
__isl_give isl_printer *(*print_double)(__isl_take isl_printer *p,
double d);
__isl_give isl_printer *(*print_int)(__isl_take isl_printer *p, int i);
__isl_give isl_printer *(*print_isl_int)(__isl_take isl_printer *p,
isl_int i);
__isl_give isl_printer *(*print_str)(__isl_take isl_printer *p,
const char *s);
__isl_give isl_printer *(*flush)(__isl_take isl_printer *p);
};
static struct isl_printer_ops file_ops = {
file_start_line,
file_end_line,
file_print_double,
file_print_int,
file_print_isl_int,
file_print_str,
file_flush
};
static struct isl_printer_ops str_ops = {
str_start_line,
str_end_line,
str_print_double,
str_print_int,
str_print_isl_int,
str_print_str,
str_flush
};
__isl_give isl_printer *isl_printer_to_file(isl_ctx *ctx, FILE *file)
{
struct isl_printer *p = isl_calloc_type(ctx, struct isl_printer);
if (!p)
return NULL;
p->ctx = ctx;
isl_ctx_ref(p->ctx);
p->ops = &file_ops;
p->file = file;
p->buf = NULL;
p->buf_n = 0;
p->buf_size = 0;
p->indent = 0;
p->output_format = ISL_FORMAT_ISL;
p->indent_prefix = NULL;
p->prefix = NULL;
p->suffix = NULL;
p->width = 0;
p->yaml_style = ISL_YAML_STYLE_FLOW;
return p;
}
__isl_give isl_printer *isl_printer_to_str(isl_ctx *ctx)
{
struct isl_printer *p = isl_calloc_type(ctx, struct isl_printer);
if (!p)
return NULL;
p->ctx = ctx;
isl_ctx_ref(p->ctx);
p->ops = &str_ops;
p->file = NULL;
p->buf = isl_alloc_array(ctx, char, 256);
if (!p->buf)
goto error;
p->buf_n = 0;
p->buf[0] = '\0';
p->buf_size = 256;
p->indent = 0;
p->output_format = ISL_FORMAT_ISL;
p->indent_prefix = NULL;
p->prefix = NULL;
p->suffix = NULL;
p->width = 0;
p->yaml_style = ISL_YAML_STYLE_FLOW;
return p;
error:
isl_printer_free(p);
return NULL;
}
__isl_null isl_printer *isl_printer_free(__isl_take isl_printer *p)
{
if (!p)
return NULL;
free(p->buf);
free(p->indent_prefix);
free(p->prefix);
free(p->suffix);
free(p->yaml_state);
isl_id_to_id_free(p->notes);
isl_ctx_deref(p->ctx);
free(p);
return NULL;
}
isl_ctx *isl_printer_get_ctx(__isl_keep isl_printer *printer)
{
return printer ? printer->ctx : NULL;
}
FILE *isl_printer_get_file(__isl_keep isl_printer *printer)
{
if (!printer)
return NULL;
if (!printer->file)
isl_die(isl_printer_get_ctx(printer), isl_error_invalid,
"not a file printer", return NULL);
return printer->file;
}
__isl_give isl_printer *isl_printer_set_isl_int_width(__isl_take isl_printer *p,
int width)
{
if (!p)
return NULL;
p->width = width;
return p;
}
__isl_give isl_printer *isl_printer_set_indent(__isl_take isl_printer *p,
int indent)
{
if (!p)
return NULL;
p->indent = indent;
return p;
}
__isl_give isl_printer *isl_printer_indent(__isl_take isl_printer *p,
int indent)
{
if (!p)
return NULL;
p->indent += indent;
if (p->indent < 0)
p->indent = 0;
return p;
}
/* Replace the indent prefix of "p" by "prefix".
*/
__isl_give isl_printer *isl_printer_set_indent_prefix(__isl_take isl_printer *p,
const char *prefix)
{
if (!p)
return NULL;
free(p->indent_prefix);
p->indent_prefix = prefix ? strdup(prefix) : NULL;
return p;
}
__isl_give isl_printer *isl_printer_set_prefix(__isl_take isl_printer *p,
const char *prefix)
{
if (!p)
return NULL;
free(p->prefix);
p->prefix = prefix ? strdup(prefix) : NULL;
return p;
}
__isl_give isl_printer *isl_printer_set_suffix(__isl_take isl_printer *p,
const char *suffix)
{
if (!p)
return NULL;
free(p->suffix);
p->suffix = suffix ? strdup(suffix) : NULL;
return p;
}
__isl_give isl_printer *isl_printer_set_output_format(__isl_take isl_printer *p,
int output_format)
{
if (!p)
return NULL;
p->output_format = output_format;
return p;
}
int isl_printer_get_output_format(__isl_keep isl_printer *p)
{
if (!p)
return -1;
return p->output_format;
}
/* Does "p" have a note with identifier "id"?
*/
isl_bool isl_printer_has_note(__isl_keep isl_printer *p,
__isl_keep isl_id *id)
{
if (!p || !id)
return isl_bool_error;
if (!p->notes)
return isl_bool_false;
return isl_id_to_id_has(p->notes, id);
}
/* Retrieve the note identified by "id" from "p".
* The note is assumed to exist.
*/
__isl_give isl_id *isl_printer_get_note(__isl_keep isl_printer *p,
__isl_take isl_id *id)
{
isl_bool has_note;
has_note = isl_printer_has_note(p, id);
if (has_note < 0)
goto error;
if (!has_note)
isl_die(isl_printer_get_ctx(p), isl_error_invalid,
"no such note", goto error);
return isl_id_to_id_get(p->notes, id);
error:
isl_id_free(id);
return NULL;
}
/* Associate "note" to the identifier "id" in "p",
* replacing the previous note associated to the identifier, if any.
*/
__isl_give isl_printer *isl_printer_set_note(__isl_take isl_printer *p,
__isl_take isl_id *id, __isl_take isl_id *note)
{
if (!p || !id || !note)
goto error;
if (!p->notes) {
p->notes = isl_id_to_id_alloc(isl_printer_get_ctx(p), 1);
if (!p->notes)
goto error;
}
p->notes = isl_id_to_id_set(p->notes, id, note);
if (!p->notes)
return isl_printer_free(p);
return p;
error:
isl_printer_free(p);
isl_id_free(id);
isl_id_free(note);
return NULL;
}
2016-01-15 23:54:45 +08:00
/* Keep track of whether the printing to "p" is being performed from
* an isl_*_dump function as specified by "dump".
*/
__isl_give isl_printer *isl_printer_set_dump(__isl_take isl_printer *p,
int dump)
{
if (!p)
return NULL;
p->dump = dump;
return p;
}
/* Set the YAML style of "p" to "yaml_style" and return the updated printer.
*/
__isl_give isl_printer *isl_printer_set_yaml_style(__isl_take isl_printer *p,
int yaml_style)
{
if (!p)
return NULL;
p->yaml_style = yaml_style;
return p;
}
/* Return the YAML style of "p" or -1 on error.
*/
int isl_printer_get_yaml_style(__isl_keep isl_printer *p)
{
if (!p)
return -1;
return p->yaml_style;
}
/* Push "state" onto the stack of currently active YAML elements and
* return the updated printer.
*/
static __isl_give isl_printer *push_state(__isl_take isl_printer *p,
enum isl_yaml_state state)
{
if (!p)
return NULL;
if (p->yaml_size < p->yaml_depth + 1) {
enum isl_yaml_state *state;
state = isl_realloc_array(p->ctx, p->yaml_state,
enum isl_yaml_state, p->yaml_depth + 1);
if (!state)
return isl_printer_free(p);
p->yaml_state = state;
p->yaml_size = p->yaml_depth + 1;
}
p->yaml_state[p->yaml_depth] = state;
p->yaml_depth++;
return p;
}
/* Remove the innermost active YAML element from the stack and
* return the updated printer.
*/
static __isl_give isl_printer *pop_state(__isl_take isl_printer *p)
{
if (!p)
return NULL;
p->yaml_depth--;
return p;
}
/* Set the state of the innermost active YAML element to "state" and
* return the updated printer.
*/
static __isl_give isl_printer *update_state(__isl_take isl_printer *p,
enum isl_yaml_state state)
{
if (!p)
return NULL;
if (p->yaml_depth < 1)
isl_die(isl_printer_get_ctx(p), isl_error_invalid,
"not in YAML construct", return isl_printer_free(p));
p->yaml_state[p->yaml_depth - 1] = state;
return p;
}
/* Return the state of the innermost active YAML element.
* Return isl_yaml_none if we are not inside any YAML element.
*/
static enum isl_yaml_state current_state(__isl_keep isl_printer *p)
{
if (!p)
return isl_yaml_none;
if (p->yaml_depth < 1)
return isl_yaml_none;
return p->yaml_state[p->yaml_depth - 1];
}
/* If we are printing a YAML document and we are at the start of an element,
* print whatever is needed before we can print the actual element and
* keep track of the fact that we are now printing the element.
* If "eol" is set, then whatever we print is going to be the last
* thing that gets printed on this line.
*
* If we are about the print the first key of a mapping, then nothing
* extra needs to be printed. For any other key, however, we need
* to either move to the next line (in block format) or print a comma
* (in flow format).
* Before printing a value in a mapping, we need to print a colon.
*
* For sequences, in flow format, we only need to print a comma
* for each element except the first.
* In block format, before the first element in the sequence,
* we move to a new line, print a dash and increase the indentation.
* Before any other element, we print a dash on a new line,
* temporarily moving the indentation back.
*/
static __isl_give isl_printer *enter_state(__isl_take isl_printer *p,
int eol)
{
enum isl_yaml_state state;
if (!p)
return NULL;
state = current_state(p);
if (state == isl_yaml_mapping_val_start) {
if (eol)
p = p->ops->print_str(p, ":");
else
p = p->ops->print_str(p, ": ");
p = update_state(p, isl_yaml_mapping_val);
} else if (state == isl_yaml_mapping_first_key_start) {
p = update_state(p, isl_yaml_mapping_key);
} else if (state == isl_yaml_mapping_key_start) {
if (p->yaml_style == ISL_YAML_STYLE_FLOW)
p = p->ops->print_str(p, ", ");
else {
p = p->ops->end_line(p);
p = p->ops->start_line(p);
}
p = update_state(p, isl_yaml_mapping_key);
} else if (state == isl_yaml_sequence_first_start) {
if (p->yaml_style != ISL_YAML_STYLE_FLOW) {
p = p->ops->end_line(p);
p = p->ops->start_line(p);
p = p->ops->print_str(p, "- ");
p = isl_printer_indent(p, 2);
}
p = update_state(p, isl_yaml_sequence);
} else if (state == isl_yaml_sequence_start) {
if (p->yaml_style == ISL_YAML_STYLE_FLOW)
p = p->ops->print_str(p, ", ");
else {
p = p->ops->end_line(p);
p = isl_printer_indent(p, -2);
p = p->ops->start_line(p);
p = p->ops->print_str(p, "- ");
p = isl_printer_indent(p, 2);
}
p = update_state(p, isl_yaml_sequence);
}
return p;
}
__isl_give isl_printer *isl_printer_print_str(__isl_take isl_printer *p,
const char *s)
{
if (!p)
return NULL;
if (!s)
return isl_printer_free(p);
p = enter_state(p, 0);
if (!p)
return NULL;
return p->ops->print_str(p, s);
}
__isl_give isl_printer *isl_printer_print_double(__isl_take isl_printer *p,
double d)
{
p = enter_state(p, 0);
if (!p)
return NULL;
return p->ops->print_double(p, d);
}
__isl_give isl_printer *isl_printer_print_int(__isl_take isl_printer *p, int i)
{
p = enter_state(p, 0);
if (!p)
return NULL;
return p->ops->print_int(p, i);
}
__isl_give isl_printer *isl_printer_print_isl_int(__isl_take isl_printer *p,
isl_int i)
{
p = enter_state(p, 0);
if (!p)
return NULL;
return p->ops->print_isl_int(p, i);
}
__isl_give isl_printer *isl_printer_start_line(__isl_take isl_printer *p)
{
if (!p)
return NULL;
return p->ops->start_line(p);
}
__isl_give isl_printer *isl_printer_end_line(__isl_take isl_printer *p)
{
if (!p)
return NULL;
return p->ops->end_line(p);
}
/* Return a copy of the string constructed by the string printer "printer".
*/
__isl_give char *isl_printer_get_str(__isl_keep isl_printer *printer)
{
if (!printer)
return NULL;
if (printer->ops != &str_ops)
isl_die(isl_printer_get_ctx(printer), isl_error_invalid,
"isl_printer_get_str can only be called on a string "
"printer", return NULL);
if (!printer->buf)
return NULL;
return strdup(printer->buf);
}
__isl_give isl_printer *isl_printer_flush(__isl_take isl_printer *p)
{
if (!p)
return NULL;
return p->ops->flush(p);
}
/* Start a YAML mapping and push a new state to reflect that we
* are about to print the first key in a mapping.
*
* In flow style, print the opening brace.
* In block style, move to the next line with an increased indentation,
* except if this is the outer mapping or if we are inside a sequence
* (in which case we have already increased the indentation and we want
* to print the first key on the same line as the dash).
*/
__isl_give isl_printer *isl_printer_yaml_start_mapping(
__isl_take isl_printer *p)
{
enum isl_yaml_state state;
if (!p)
return NULL;
p = enter_state(p, p->yaml_style == ISL_YAML_STYLE_BLOCK);
if (!p)
return NULL;
state = current_state(p);
if (p->yaml_style == ISL_YAML_STYLE_FLOW)
p = p->ops->print_str(p, "{ ");
else if (state != isl_yaml_none && state != isl_yaml_sequence) {
p = p->ops->end_line(p);
p = isl_printer_indent(p, 2);
p = p->ops->start_line(p);
}
p = push_state(p, isl_yaml_mapping_first_key_start);
return p;
}
/* Finish a YAML mapping and pop it from the state stack.
*
* In flow style, print the closing brace.
*
* In block style, first check if we are still in the
* isl_yaml_mapping_first_key_start state. If so, we have not printed
* anything yet, so print "{}" to indicate an empty mapping.
* If we increased the indentation in isl_printer_yaml_start_mapping,
* then decrease it again.
* If this is the outer mapping then print a newline.
*/
__isl_give isl_printer *isl_printer_yaml_end_mapping(
__isl_take isl_printer *p)
{
enum isl_yaml_state state;
state = current_state(p);
p = pop_state(p);
if (!p)
return NULL;
if (p->yaml_style == ISL_YAML_STYLE_FLOW)
return p->ops->print_str(p, " }");
if (state == isl_yaml_mapping_first_key_start)
p = p->ops->print_str(p, "{}");
if (!p)
return NULL;
state = current_state(p);
if (state != isl_yaml_none && state != isl_yaml_sequence)
p = isl_printer_indent(p, -2);
if (state == isl_yaml_none)
p = p->ops->end_line(p);
return p;
}
/* Start a YAML sequence and push a new state to reflect that we
* are about to print the first element in a sequence.
*
* In flow style, print the opening bracket.
*/
__isl_give isl_printer *isl_printer_yaml_start_sequence(
__isl_take isl_printer *p)
{
if (!p)
return NULL;
p = enter_state(p, p->yaml_style == ISL_YAML_STYLE_BLOCK);
p = push_state(p, isl_yaml_sequence_first_start);
if (!p)
return NULL;
if (p->yaml_style == ISL_YAML_STYLE_FLOW)
p = p->ops->print_str(p, "[ ");
return p;
}
/* Finish a YAML sequence and pop it from the state stack.
*
* In flow style, print the closing bracket.
*
* In block style, check if we are still in the
* isl_yaml_sequence_first_start state. If so, we have not printed
* anything yet, so print "[]" or " []" to indicate an empty sequence.
* We print the extra space when we instructed enter_state not
* to print a space at the end of the line.
* Otherwise, undo the increase in indentation performed by
* enter_state when moving away from the isl_yaml_sequence_first_start
* state.
* If this is the outer sequence then print a newline.
*/
__isl_give isl_printer *isl_printer_yaml_end_sequence(
__isl_take isl_printer *p)
{
enum isl_yaml_state state, up;
state = current_state(p);
p = pop_state(p);
if (!p)
return NULL;
if (p->yaml_style == ISL_YAML_STYLE_FLOW)
return p->ops->print_str(p, " ]");
up = current_state(p);
if (state == isl_yaml_sequence_first_start) {
if (up == isl_yaml_mapping_val)
p = p->ops->print_str(p, " []");
else
p = p->ops->print_str(p, "[]");
} else {
p = isl_printer_indent(p, -2);
}
if (!p)
return NULL;
state = current_state(p);
if (state == isl_yaml_none)
p = p->ops->end_line(p);
return p;
}
/* Mark the fact that the current element is finished and that
* the next output belongs to the next element.
* In particular, if we are printing a key, then prepare for
* printing the subsequent value. If we are printing a value,
* prepare for printing the next key. If we are printing an
* element in a sequence, prepare for printing the next element.
*/
__isl_give isl_printer *isl_printer_yaml_next(__isl_take isl_printer *p)
{
enum isl_yaml_state state;
if (!p)
return NULL;
if (p->yaml_depth < 1)
isl_die(isl_printer_get_ctx(p), isl_error_invalid,
"not in YAML construct", return isl_printer_free(p));
state = current_state(p);
if (state == isl_yaml_mapping_key)
state = isl_yaml_mapping_val_start;
else if (state == isl_yaml_mapping_val)
state = isl_yaml_mapping_key_start;
else if (state == isl_yaml_sequence)
state = isl_yaml_sequence_start;
p = update_state(p, state);
return p;
}