Logo Search packages:      
Sourcecode: faucc version File versions

simplify.c

/* $Id: simplify.c,v 1.391 2009-01-27 15:40:22 potyra Exp $ 
 *
 * Copyright (C) 2007-2009 FAUcc Team <info@faumachine.org>.
 * This program is free software. You can redistribute it and/or modify it
 * under the terms of the GNU General Public License, either version 2 of
 * the License, or (at your option) any later version. See COPYING.
 */

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "cc1.h"
#include "identifier.h"
#include "declaration.h"
#include "stmt.h"
#include "expr.h"
#include "print.h"
#include "simplify.h"

static int simplify_change;


static void
simplify_rename_all_structunionenums_in_stmt(struct stmt *s)
{
      struct stmt *cs;

      if (s->stmt0) {
            simplify_rename_all_structunionenums_in_stmt(s->stmt0);
      }
      if (s->stmt1) {
            simplify_rename_all_structunionenums_in_stmt(s->stmt1);
      }
      for (cs = s->stmt_first; cs; cs = cs->next) {
            simplify_rename_all_structunionenums_in_stmt(cs);
      }

      if (s->type == STMT_BLOCK) {
            struct declaration *dion;

            for (dion = s->scope->declaration_first; dion; dion = dion->next) {
                  if (dion->type_name
                   && (dion->type_name->type == TYPE_STRUCT
                    || dion->type_name->type == TYPE_UNION
                    || dion->type_name->type == TYPE_ENUM)
                   && dion->type_name->scope) {
                        const char *old;
                        const char *new;

                        old = dion->type_name->identifier;
                        new = identifier_tmp();

                        stmt_rename_structunionenum(s, dion->type_name->type, old, new);
                  }
            }
      }
}

static void
simplify_rename_all_structunionenums_in_func(struct stmt *fs)
{
      simplify_rename_all_structunionenums_in_stmt(fs);
}

static void
simplify_rename_all_typevars_in_func(struct stmt *fs)
{
      struct declaration *dion;

      assert(fs->scope->function);
      assert(fs->scope->function->type_name->parameter);

      for (dion = fs->scope->function->type_name->parameter->declaration_first;
          dion;
          dion = dion->next) {
            if (declaration_name_get(dion)) {
                  declaration_name_set(dion, identifier_tmp());
            }
      }

      for (dion = fs->scope->declaration_first; dion; dion = dion->next) {
            if (declaration_name_get(dion)) {
                  declaration_name_set(dion, identifier_tmp());
            }
      }
}

struct declaration *
simplify_declaration_add(
      struct scope *scope,
      struct type *ts,
      const char *name
)
{
      struct declaration *dion;

      dion = declaration_identifier(name);
      dion->type_name = ts;

      dion->prev = scope->declaration_last;
      dion->next = NULL;
      if (dion->prev) {
            dion->prev->next = dion;
      } else {
            scope->declaration_first = dion;
      }
      scope->declaration_last = dion;

      return dion;
}

/* ----------------------------------------------------------------- */
/* Scope-related Simplifications                                     */
/* ----------------------------------------------------------------- */

static int
simplify_fix_dimensions(struct scope *s)
{
      struct scope *cs;

      for (cs = s->child_first; cs; cs = cs->next) {
            simplify_fix_dimensions(cs);
      }

      if (s->type == SCOPE_GLOBAL
       || s->type == SCOPE_FUNCTION
       || s->type == SCOPE_BLOCK) {
            struct declaration *dion;

            for (dion = s->declaration_first; dion; dion = dion->next) {
                  if (dion->type_name
                   && type_is_array(dion->type_name)
                   && ! type_dimension_get(dion->type_name)
                   && declaration_initializer_get(dion)) {
                        struct expr *e;
                        int count;

                        count = 0;
                        for (e = dion->initializer->first;
                            e;
                            e = e->next) {
                              count++;
                        }
                        dion->type_name->dimension
                                    = expr_integer(count);

                        simplify_change = 1;
                  }
            }
      }

      return 0;
}

static int
simplify_split_vardecl_init(struct stmt *s)
{
      struct stmt *cs;
      int retval;

      retval = 0;

      if (s->stmt0) {
            retval |= simplify_split_vardecl_init(s->stmt0);
      }
      if (s->stmt1) {
            retval |= simplify_split_vardecl_init(s->stmt1);
      }
      for (cs = s->stmt_first; cs; cs = cs->next) {
            retval |= simplify_split_vardecl_init(cs);
      }

      if (s->type == STMT_BLOCK) {
            struct declaration *dion;

            for (dion = s->scope->declaration_last;
                dion;
                dion = dion->prev) {
                  if (dion->storage == STORAGE_NONE
                   || dion->storage == STORAGE_AUTO
                   || dion->storage == STORAGE_REGISTER) {
                        struct expr *initializer;

                        initializer = declaration_initializer_get(dion);

                        if (initializer) {
                              struct stmt *s0;

                              declaration_initializer_set(dion,
                                          NULL);

                              /* FIXME */
                              dion->type_name->mod_const = 0;

                              s0 = stmt_expr(expr_assign(
                                          expr_identifier(dion),
                                          initializer));

                              stmt_prepend(s, s->stmt_first, s0);
                              retval |= 1;
                        }
                  }
            }
      }

      return retval;
}

static int
simplify_merge_declarations_of_blocks_check(struct stmt *s)
{
      struct declaration *dion;

      assert(s->type == STMT_BLOCK);

      for (dion = s->scope->declaration_first; dion; dion = dion->next) {
            assert(dion->type_name);
            if (dion->type_name->scope) {
                  assert(! dion->identifier);
            }
            if (dion->storage != STORAGE_STATIC
             && declaration_initializer_get(dion)) {
                  return 0;
            }
      }

      return 1;
}

static int
simplify_merge_declarations_to_func(struct stmt *fb, struct stmt *s)
{
      struct stmt *cs;
      struct declaration *dion;
      int retval;

      retval = 0;

      if (s->stmt0) {
            retval |= simplify_merge_declarations_to_func(fb, s->stmt0);
      }
      if (s->stmt1) {
            retval |= simplify_merge_declarations_to_func(fb, s->stmt1);
      }
      for (cs = s->stmt_first; cs; cs = cs->next) {
            retval |= simplify_merge_declarations_to_func(fb, cs);
      }

      assert(fb->scope->type == SCOPE_FUNCTION);

      if (s->type == STMT_BLOCK
       && simplify_merge_declarations_of_blocks_check(s)) {
            /*
             * Move all type and variable definitions from
             * inner block to outer block. Rename types/variables.
             */
            for (dion = s->scope->declaration_first; dion; ) {
                  struct declaration *next;
                  const char *new_name;
                  const char *old_name;
                  
                  next = dion->next;

                  /* Remove declaration from inner scope. */
                  if (dion->prev) {
                        dion->prev->next = dion->next;
                  } else {
                        s->scope->declaration_first = dion->next;
                  }
                  if (dion->next) {
                        dion->next->prev = dion->prev;
                  } else {
                        s->scope->declaration_last = dion->prev;
                  }

                  /* Add declaration to outer scope. */
                  dion->prev = fb->scope->declaration_last;
                  dion->next = NULL;
                  if (dion->prev) {
                        dion->prev->next = dion;
                  } else {
                        fb->scope->declaration_first = dion;
                  }
                  fb->scope->declaration_last = dion;

                  /* Rename declarator. */
                  old_name = declaration_name_get(dion);
                  if (old_name) {
                        new_name = identifier_tmp();
                        declaration_name_set(dion, new_name);
                  }

                  dion = next;

                  retval |= 1;
            }
      }

      return retval;
}

static int
simplify_merge_declarations_of_blocks_in_func(struct stmt *fb)
{
      struct stmt *cs;
      int retval;

      retval = 0;

      for (cs = fb->stmt_first; cs; cs = cs->next) {
            retval |= simplify_merge_declarations_to_func(fb, cs);
      }

      return retval;
}

static int
simplify_merge_declarations_of_blocks(struct scope *s)
{
      struct declaration *dion;
      int retval;

      retval = 0;

      for (dion = s->declaration_first; dion; dion = dion->next) {
            if (dion->stmt) {
                  retval |= simplify_merge_declarations_of_blocks_in_func(
                              dion->stmt);
            }
      }

      return retval;
}

static void
cleanup_func_scope_in_expr(
      struct scope *gs,
      struct scope *fs,
      struct type *tt,
      struct expr *e
)
{
      struct expr *ce;
      struct type *ft;

      if (e->type == EXPR_BRACES
       || e->type == EXPR_STRING) {
            ft = NULL;
      } else {
            ft = expr_typeof(fs, e);
      }

      switch (e->type) {
      case EXPR_BRACES:
            if (tt->type == TYPE_STRUCT) {
                  struct declaration *dion;
                  int ret;

                  ret = scope_lookup_structunionenum(fs,
                              tt->type, tt->identifier, &tt);
                  assert(0 <= ret);
                  assert(tt);
                  assert(tt->scope);

                  for (dion = tt->scope->declaration_first, ce = e->first;
                      dion && ce;
                      dion = dion->next, ce = ce->next) {
                        cleanup_func_scope_in_expr(gs, fs,
                                    dion->type_name, ce);
                  }

            } else if (tt->type == TYPE_ARRAY) {
                  for (ce = e->first; ce; ce = ce->next) {
                        cleanup_func_scope_in_expr(gs, fs,
                                    type_array_access(tt), ce);
                  }
            } else {
                  assert(0);
            }
            break;

      case EXPR_STRING:
            if (tt->type == TYPE_ARRAY) {
                  /* Leave as is. */

            } else {
                  struct declaration *dion;

                  dion = declaration_identifier(identifier_tmp());
                  dion->storage = STORAGE_STATIC;
                  dion->type_name = type_const_char_array(e->string_len + 1);
                  dion->initializer = expr_dup(e);

                  scope_declaration_prepend_first(gs, dion);
                  expr_cp(e, expr_identifier(dion));
                  simplify_change = 1;
            }
            break;

      case EXPR_INTEGER:
      case EXPR_REAL:
      case EXPR_IDENTIFIER:
      case EXPR_BUILTIN_VA_ARG:
      case EXPR_STAR:
      case EXPR_AMPHERSAND:
            break;

      case EXPR_TYPE_CONVERSION:
      case EXPR_NEG:
      case EXPR_INV:
            ft = expr_typeof(fs, e->expr0);
            ft = type_pure(ft);
            cleanup_func_scope_in_expr(gs, fs, ft, e->expr0);
            break;

      case EXPR_EQUAL:
      case EXPR_NOT_EQUAL:
      case EXPR_LESS:
      case EXPR_LESS_EQUAL:
      case EXPR_GREATER:
      case EXPR_GREATER_EQUAL:
      case EXPR_LEFT:
      case EXPR_RIGHT:
      case EXPR_ADD:
      case EXPR_SUB:
      case EXPR_MUL:
      case EXPR_DIV:
      case EXPR_MOD:
      case EXPR_AND:
      case EXPR_OR:
      case EXPR_XOR:
      case EXPR_ASSIGN:
            ft = expr_typeof(fs, e->expr0);
            ft = type_pure(ft);
            cleanup_func_scope_in_expr(gs, fs, ft, e->expr0);
            ft = expr_typeof(fs, e->expr1);
            ft = type_pure(ft);
            cleanup_func_scope_in_expr(gs, fs, ft, e->expr1);
            break;

      case EXPR_FUNC:
            for (ce = e->expr1->first; ce; ce = ce->next) {
                  ft = expr_typeof(fs, ce);
                  ft = type_pure(ft);
                  cleanup_func_scope_in_expr(gs, fs, ft, ce);
            }
            break;

      default:
            assert(0);
      }
}

static void
cleanup_func_scope_in_func(struct scope *gs, struct declaration *fd)
{
      struct scope *fs;
      struct declaration *dion;
      struct stmt *cs;

      fs = fd->stmt->scope;

      for (dion = fs->declaration_first; dion; dion = dion->next) {
            if (dion->initializer) {
                  cleanup_func_scope_in_expr(gs, fs,
                              dion->type_name, dion->initializer);
            }
      }

      for (dion = fs->declaration_first; dion;) {
            struct declaration *next;

            next = dion->next;

            if (dion->storage == STORAGE_STATIC
             || dion->storage == STORAGE_TYPEDEF
             || dion->identifier == NULL) {
                  if (dion->identifier) {
                        /* Rename static variable/type definition. */
                        dion->identifier = identifier_tmp();

                  } else if (dion->type_name->scope) {
                        /* Rename struct/union/enum definition. */
                        const char *old;
                        const char *new;

                        assert(dion->type_name->type == TYPE_STRUCT
                            || dion->type_name->type == TYPE_UNION
                            || dion->type_name->type == TYPE_ENUM);

                        old = dion->type_name->identifier;
                        new = identifier_tmp();

                        stmt_rename_structunionenum(fd->stmt,
                                    dion->type_name->type,
                                    old, new);

                        dion->type_name->identifier = new;
                  }

                  /* Remove it from functions scope. */
                  if (dion->prev) {
                        dion->prev->next = dion->next;
                  } else {
                        fs->declaration_first = dion->next;
                  }
                  if (dion->next) {
                        dion->next->prev = dion->prev;
                  } else {
                        fs->declaration_last = dion->prev;
                  }

                  /* Add it to global scope. */
                  dion->prev = fd->prev;
                  dion->next = fd;
                  if (dion->prev) {
                        dion->prev->next = dion;
                  } else {
                        gs->declaration_first = dion;
                  }
                  dion->next->prev = dion;

                  simplify_change = 1;
            }

            dion = next;
      }

      for (cs = fd->stmt->stmt_first; cs; cs = cs->next) {
            struct constraint *c;
            struct type *t;

            if (cs->expr0) {
                  t = expr_typeof(fd->stmt->scope, cs->expr0);
                  t = type_pure(t);
                  cleanup_func_scope_in_expr(gs, fs, t, cs->expr0);
            }
            if (cs->output) {
                  for (c = cs->output->first; c; c = c->next) {
                        t = expr_typeof(fd->stmt->scope, c->expr);
                        t = type_pure(t);
                        cleanup_func_scope_in_expr(gs, fs, t, c->expr);
                  }
            }
            if (cs->input) {
                  for (c = cs->input->first; c; c = c->next) {
                        t = expr_typeof(fd->stmt->scope, c->expr);
                        t = type_pure(t);
                        cleanup_func_scope_in_expr(gs, fs, t, c->expr);
                  }
            }
      }
}

static int
cleanup_func_scope(struct scope *scope, struct declaration *dion)
{
      if (dion->initializer) {
            cleanup_func_scope_in_expr(scope, scope,
                        dion->type_name, dion->initializer);
      } else if (dion->stmt) {
            cleanup_func_scope_in_func(scope, dion);
      }

      return 0;
}

/* ----------------------------------------------------------------- */
/* Expression-related Simplifications                                */
/* ----------------------------------------------------------------- */

static void
simplify_inline_in_expr(struct stmt *block, struct stmt *s, struct expr *e)
{
      struct expr *ce;
      struct declaration *dor0;
      int retval;

      if (e->expr0) {
            simplify_inline_in_expr(block, s, e->expr0);
      }
      if (e->expr1) {
            simplify_inline_in_expr(block, s, e->expr1);
      }
      if (e->expr2) {
            simplify_inline_in_expr(block, s, e->expr2);
      }
      for (ce = e->first; ce; ce = ce->next) {
            simplify_inline_in_expr(block, s, ce);
      }

      if (e->type == EXPR_FUNC
       && e->expr0->type == EXPR_IDENTIFIER) {
            dor0 = e->expr0->declaration;
            assert(dor0);

            if (dor0->mod_inline) {
                  /*
                   * Replace
                   *    inline func(p0, ..., pN) {
                   *          dion0;
                   *          ...
                   *          dionM;
                   *
                   *          s0;
                   *          ...;
                   *          return r;
                   *    }
                   *    ...
                   *    func(a0, ..., aN)
                   * by
                   *          ...
                   *          p0;
                   *          ...
                   *          pN;
                   *          dion0;
                   *          ...
                   *          dionM;
                   *
                   *          p0 = e0;
                   *          ...
                   *          pN = eN;
                   *          s0;
                   *          ...
                   *          r
                   *
                   * Rename all struct/union/enums, types, vars and labels.
                   */
#if 1
                  struct type *ts1;
                  struct scope *param;
                  struct declaration *p;
                  struct expr *a;
                  struct stmt *cs;
                  struct stmt *s0;
                  struct expr *e0;

                  assert(dor0->stmt);
                  simplify_rename_all_structunionenums_in_func(dor0->stmt);
                  simplify_rename_all_typevars_in_func(dor0->stmt);

                  assert(dor0->type_name->type == TYPE_FUNCTION);
                  assert(dor0->type_name->parameter);

                  param = dor0->type_name->parameter;

                  /* Clone parameters. */
                  for (p = param->declaration_first;
                      p;
                      p = p->next) {
                        const char *pn;

                        pn = declaration_name_get(p);

                        if (! pn) {
                              continue;
                        }

                        declaration_type_get(&ts1, p);
                        ts1 = type_pure(ts1);

                        p->clone = simplify_declaration_add(
                                    block->scope, ts1, pn);
                  }

                  /* Clone local variables. */
                  for (p = dor0->stmt->scope->declaration_first;
                      p;
                      p = p->next) {
                        const char *pn;
                        struct expr *pi;

                        pn = declaration_name_get(p);
                        pi = declaration_initializer_get(p);

                        declaration_type_get(&ts1, p);

                        p->clone = simplify_declaration_add(
                                    block->scope, ts1, pn);
                        p->clone->storage = p->storage;
                        p->clone->initializer = pi;
                  }

                  /* Clone local labels. */
                  for (cs = dor0->stmt->stmt_first;
                      cs && cs->type != STMT_RETURN;
                      cs = cs->next) {
                        if (cs->type == STMT_LABEL) {
                              cs->label->clone = label_new(identifier_tmp());
                        }
                  }

                  /* Copy actual values to formal parameters. */
                  a = e->expr1->first;
                  for (p = param->declaration_first; p; p = p->next) {
                        const char *pn;

                        assert(p);
                        pn = declaration_name_get(p);
                        if (! pn) {
                              /* void parameter */
                              continue;
                        }
                        assert(a);

                        e0 = expr_assign(
                              expr_identifier(p->clone),
                              expr_dup(a));
                        s0 = stmt_expr(e0);

                        stmt_prepend(block, s, s0);

                        a = a->next;
                  }

                  /* Copy statements. */
                  for (cs = dor0->stmt->stmt_first;
                      cs && cs->type != STMT_RETURN;
                      cs = cs->next) {
                        s0 = stmt_dup(cs);

                        stmt_prepend(block, s, s0);
                  }
                  assert(! cs
                      || (cs->type == STMT_RETURN && ! cs->next));

                  /* Use return value (if present). */
                  if (cs
                   && cs->expr0) {
                        e0 = expr_dup(cs->expr0);
                  } else {
                        e0 = expr_integer(0);
                  }
                  expr_cp(e, e0);

                  /* Reset clone info. */
                  for (cs = dor0->stmt->stmt_first;
                      cs && cs->type != STMT_RETURN;
                      cs = cs->next) {
                        if (cs->type == STMT_LABEL) {
                              cs->label->clone = NULL;
                        }
                  }

                  for (p = param->declaration_first;
                      p;
                      p = p->next) {
                        p->clone = NULL;
                  }
                  for (p = dor0->stmt->scope->declaration_first;
                      p;
                      p = p->next) {
                        p->clone = NULL;
                  }

                  retval = 1;
#else
                  retval = 0;
#endif

            } else {
                  retval = 0;
            }

            if (retval) {
                  simplify_change = 1;
            }
      }
}

static struct stmt *
simplify_inline_in_stmt(struct stmt *fs, struct stmt *s)
{
      struct stmt *next;
      struct constraint *c;

      switch (s->type) {
      case STMT_NONE:
            assert(0);

      case STMT_WHILE:
      case STMT_DO_WHILE:
      case STMT_FOR:
      case STMT_BREAK:
      case STMT_CONTINUE:
      case STMT_CASE:
      case STMT_DEFAULT:
      case STMT_BLOCK:
            /* Should have been done by replace_control. */
            assert(0);

      case STMT_NULL:
      case STMT_LABEL:
      case STMT_GOTO:
      case STMT_VA_START:
      case STMT_VA_END:
            /* No function calls. */
            next = s->next;
            break;

      case STMT_EXPR:
      case STMT_IF:
      case STMT_SWITCH:
      case STMT_RETURN:
            next = s->next;
            if (s->expr0) {
                  simplify_inline_in_expr(fs, s, s->expr0);
            }
            break;

      case STMT_ASM:
            next = s->next;
            for (c = s->output->first; c; c = c->next) {
                  simplify_inline_in_expr(fs, s, c->expr);
            }
            for (c = s->input->first; c; c = c->next) {
                  simplify_inline_in_expr(fs, s, c->expr);
            }
            break;

      default:
            assert(0);
      }

      return next;
}

static int
simplify_inline(struct stmt *fs)
{
      struct stmt *cs;

      assert(fs->type == STMT_BLOCK);

      if (fs->scope->function->mod_inline) {
            /* Don't do inlining in inline functions. */
            return 0;
      }

      simplify_change = 0;

      for (cs = fs->stmt_first; cs; ) {
            cs = simplify_inline_in_stmt(fs, cs);
      }

      return simplify_change;
}

static void
simplify_pointer_to_int_in_expr_1(
      struct scope *scope,
      struct type *tt,
      struct expr *e
)
{
      struct expr *ce;
      struct expr *e0;
      struct expr *e1;
      struct expr *e2;
      struct type *ft;

      if (e->type != EXPR_BRACES
       && e->type != EXPR_STRING) {
            ft = expr_typeof(scope, e);
      } else {
            ft = NULL;
      }

      switch (e->type) {
      case EXPR_NONE:
            assert(0);
      case EXPR_SIZEOF_TYPE:
      case EXPR_SIZEOF_EXPR:
      case EXPR_BUILTIN_CONSTANT_P:
      case EXPR_BUILTIN_OFFSETOF:

      case EXPR_DOT:
      case EXPR_ARROW:
      case EXPR_ARRAY:

      case EXPR_PRE_INC:
      case EXPR_PRE_DEC:
      case EXPR_POST_INC:
      case EXPR_POST_DEC:
      case EXPR_LEFT_ASSIGN:
      case EXPR_RIGHT_ASSIGN:
      case EXPR_ADD_ASSIGN:
      case EXPR_SUB_ASSIGN:
      case EXPR_MUL_ASSIGN:
      case EXPR_DIV_ASSIGN:
      case EXPR_MOD_ASSIGN:
      case EXPR_AND_ASSIGN:
      case EXPR_OR_ASSIGN:
      case EXPR_XOR_ASSIGN:

      case EXPR_SHORT_AND:
      case EXPR_SHORT_OR:
      case EXPR_CONDITION:
      case EXPR_LIST:
            assert(0);

      case EXPR_BRACES:
            if (tt->type == TYPE_ARRAY) {
                  for (ce = e->first; ce; ce = ce->next) {
                        simplify_pointer_to_int_in_expr_1(scope,
                                    type_array_access(tt), ce);
                  }
            } else if (tt->type == TYPE_STRUCT
                  || tt->type == TYPE_UNION) {
                  struct declaration *dion;
                  int ret;

                  if (! tt->scope) {
                        ret = scope_lookup_structunionenum(scope,
                                    tt->type, tt->identifier, &tt);
                        assert(0 <= ret);
                  }
                  assert(tt);
                  assert(tt->scope);

                  for (dion = tt->scope->declaration_first, ce = e->first;
                      ;
                      dion = dion->next, ce = ce->next) {
                        if (! dion || ! ce) {
                              break;
                        }
                        simplify_pointer_to_int_in_expr_1(scope,
                                    dion->type_name, ce);
                  }
                  break;

            } else {
                  assert(0);
            }
            break;

      case EXPR_INTEGER:
      case EXPR_REAL:
            break;

      case EXPR_STRING:
            if (tt->type == TYPE_POINTER) {
                  /*
                   * Replace
                   *    "..."
                   * by
                   *    (int) "..."
                   */
                  e0 = expr_dup(e);
                  e1 = expr_cast(type_ptrdiff(), e0);

                  expr_cp(e, e1);
                  simplify_change = 1;

            } else if (tt->type == TYPE_ARRAY) {
                  /* Nothing to do... */

            } else {
                  assert(0);
            }
            break;

      case EXPR_IDENTIFIER:
            if (ft->type == TYPE_ARRAY
             || ft->type == TYPE_FUNCTION) {
                  /*
                   * Replace
                   *    array       func
                   * by
                   *    (int) array (int) func
                   */
                  e0 = expr_dup(e);
                  e1 = expr_cast(type_ptrdiff(), e0);

                  expr_cp(e, e1);
                  simplify_change = 1;

            } else if (ft->type == TYPE_POINTER) {
                  /* Will replaced by second step. */
            }
            break;

      case EXPR_AMPHERSAND:
            /*
             * Replace
             *    &x
             * by
             *    (int) &x
             */
            assert(e->expr0->type == EXPR_IDENTIFIER);

            e0 = expr_dup(e);
            e1 = expr_cast(type_ptrdiff(), e0);

            expr_cp(e, e1);
            simplify_change = 1;
            break;

      case EXPR_BUILTIN_VA_ARG:
            if (ft->type == TYPE_POINTER) {
                  /*
                   * Replace
                   *    va_arg(list, type *)
                   * by
                   *    va_arg(list, ptrdiff)
                   */
                  e0 = expr_dup(e);
                  e0->type_name = type_ptrdiff();

                  expr_cp(e, e0);
                  simplify_change = 1;
            }
            break;

      case EXPR_STAR:
            if (expr_typeof(scope, e->expr0)->type == TYPE_ARRAY) {
                  /*
                   * Leave
                   *    *array
                   * as is.
                   */
                  break;

            } else if (ft->type == TYPE_POINTER) {
                  /*
                   * Replace
                   *    *x
                   * by
                   *    *(int *) x
                   */
                  e0 = expr_dup(e->expr0);
                  e1 = expr_cast(type_amphersand(type_ptrdiff()), e0);
                  e2 = expr_star(e1);

            } else {
                  /*
                   * Replace
                   *    *x
                   * by
                   *    *(typeof *x) x
                   */
                  e0 = expr_dup(e->expr0);
                  e1 = expr_cast(type_amphersand(ft), e0);
                  e2 = expr_star(e1);
            }

            expr_cp(e, e2);
            simplify_change = 1;
            break;

      case EXPR_TYPE_CONVERSION:
            if (ft->type == TYPE_POINTER) {
                  /*
                   * Replace
                   *    (typeof *x) x
                   * by
                   *    (int) x
                   */
                  e0 = expr_dup(e->expr0);
                  e1 = expr_cast(type_ptrdiff(), e0);

                  expr_cp(e, e1);
                  simplify_change = 1;
            }
            break;

      case EXPR_NEG:
      case EXPR_INV:
            simplify_pointer_to_int_in_expr_1(scope,
                        expr_typeof(scope, e->expr0), e->expr0);
            break;

      case EXPR_EQUAL:
      case EXPR_NOT_EQUAL:
      case EXPR_LESS:
      case EXPR_LESS_EQUAL:
      case EXPR_GREATER:
      case EXPR_GREATER_EQUAL:
      case EXPR_RIGHT:
      case EXPR_LEFT:
      case EXPR_ADD:
      case EXPR_SUB:
      case EXPR_MUL:
      case EXPR_DIV:
      case EXPR_MOD:
      case EXPR_AND:
      case EXPR_OR:
      case EXPR_XOR:
            simplify_pointer_to_int_in_expr_1(scope,
                        expr_typeof(scope, e->expr0), e->expr0);
            simplify_pointer_to_int_in_expr_1(scope,
                        expr_typeof(scope, e->expr1), e->expr1);
            break;

      case EXPR_FUNC:
            /*
             * Replace function call.
             */
            if (e->expr0->type == EXPR_STAR) {
                  /* FIXME */
            }

            /*
             * Replace function parameters.
             */
            for (ce = e->expr1->first; ce; ce = ce->next) {
                  struct type *pt;

                  pt = expr_typeof(scope, ce);
                  pt = type_pure(pt);
                  simplify_pointer_to_int_in_expr_1(scope, pt, ce);
            }
            break;

      default:
            assert(0);
      }
}

static void
simplify_pointer_to_int_in_init_1(
      struct scope *scope,
      struct type *t,
      struct expr *e
)
{
      simplify_pointer_to_int_in_expr_1(scope, t, e);
}

static void
simplify_pointer_to_int_in_func_1(struct stmt *fs)
{
      struct declaration *dion;
      struct stmt *cs;
      struct constraint *c;
      struct type *t;

      for (dion = fs->scope->declaration_first; dion; dion = dion->next) {
            if (dion->initializer) {
                  simplify_pointer_to_int_in_init_1(fs->scope,
                              dion->type_name,
                              dion->initializer);
            }
      }

      for (cs = fs->stmt_first; cs; cs = cs->next) {
            switch (cs->type) {
            case STMT_LABEL:
                  break;
            case STMT_EXPR:
                  switch (cs->expr0->type) {
                  case EXPR_ASSIGN:
                        t = expr_typeof(fs->scope, cs->expr0->expr0);
                        simplify_pointer_to_int_in_expr_1(fs->scope, t,
                                    cs->expr0->expr0);
                        simplify_pointer_to_int_in_expr_1(fs->scope, t,
                                    cs->expr0->expr1);
                        break;
                  case EXPR_FUNC:
                        t = expr_typeof(fs->scope, cs->expr0);
                        simplify_pointer_to_int_in_expr_1(fs->scope, t,
                                    cs->expr0);
                        break;
                  default:
                        assert(0);
                  }
                  break;
            case STMT_IF:
                  switch (cs->expr0->type) {
                  case EXPR_EQUAL:
                  case EXPR_NOT_EQUAL:
                  case EXPR_LESS:
                  case EXPR_LESS_EQUAL:
                  case EXPR_GREATER:
                  case EXPR_GREATER_EQUAL:
                        t = expr_typeof(fs->scope, cs->expr0);
                        simplify_pointer_to_int_in_expr_1(fs->scope, t,
                                    cs->expr0);
                        break;
                  default:
                        assert(0);
                  }
                  break;
            case STMT_SWITCH:
                  switch (cs->expr0->type) {
                  case EXPR_IDENTIFIER:
                        t = expr_typeof(fs->scope, cs->expr0);
                        simplify_pointer_to_int_in_expr_1(fs->scope, t,
                                    cs->expr0);
                        break;
                  default:
                        assert(0);
                  }
                  break;
            case STMT_GOTO:
                  break;
            case STMT_RETURN:
                  if (cs->expr0) {
                        switch (cs->expr0->type) {
                        case EXPR_INTEGER:
                              break;
                        case EXPR_IDENTIFIER:
                              t = expr_typeof(fs->scope, cs->expr0);
                              simplify_pointer_to_int_in_expr_1(fs->scope, t,
                                          cs->expr0);
                              break;
                        default:
                              assert(0);
                        }
                  }
                  break;
            case STMT_ASM:
                  if (cs->output) {
                        for (c = cs->output->first; c; c = c->next) {
                              simplify_pointer_to_int_in_expr_1(fs->scope,
                                          expr_typeof(fs->scope,
                                                c->expr),
                                          c->expr);
                        }
                  }
                  if (cs->input) {
                        for (c = cs->input->first; c; c = c->next) {
                              simplify_pointer_to_int_in_expr_1(fs->scope,
                                          expr_typeof(fs->scope,
                                                c->expr),
                                          c->expr);
                        }
                  }
                  break;
            case STMT_VA_START:
                  break;
            case STMT_VA_END:
                  break;
            default:
                  assert(0);
            }
      }
}

static void
simplify_pointer_to_int_in_type_2(struct type **tp)
{
      struct type *t0;
      struct type *t1;

      t0 = *tp;
      t1 = type_pointer_to_ptrdiff(t0);
      if (t1 != t0) {
            *tp = t1;
            simplify_change = 1;
      }
}

static void
simplify_pointer_to_int_in_func_2(struct stmt *fs)
{
      struct declaration *dion;

      for (dion = fs->scope->function->type_name->parameter->declaration_first;
          dion;
          dion = dion->next) {
            simplify_pointer_to_int_in_type_2(&dion->type_name);
      }
      for (dion = fs->scope->declaration_first;
          dion;
          dion = dion->next) {
            simplify_pointer_to_int_in_type_2(&dion->type_name);
      }
}

static int
simplify_pointer_to_int(struct scope *scope)
{
      struct declaration *dion;

      /*
       * First step:
       * Replace all expressions
       */
      for (dion = scope->declaration_first; dion; dion = dion->next) {
            if (dion->initializer) {
                  simplify_pointer_to_int_in_init_1(scope,
                              dion->type_name,
                              dion->initializer);
            }
            if (dion->stmt) {
                  simplify_pointer_to_int_in_func_1(dion->stmt);
            }
      }

      /*
       * Second step:
       * Replace types of variables.
       */
      for (dion = scope->declaration_first; dion; dion = dion->next) {
            if (dion->type_name) {
                  simplify_pointer_to_int_in_type_2(&dion->type_name);
            }
            if (dion->stmt) {
                  simplify_pointer_to_int_in_func_2(dion->stmt);
            }
      }

      return 0;
}

static int
simplify_rename_labels_in_stmt(
      struct stmt *top,
      struct stmt *s
)
{
      struct stmt *cs;
      int retval;

      retval = 0;

      if (s->stmt0) {
            retval |= simplify_rename_labels_in_stmt(top, s->stmt0);
      }
      if (s->stmt1) {
            retval |= simplify_rename_labels_in_stmt(top, s->stmt1);
      }
      for (cs = s->stmt_first; cs; cs = cs->next) {
            retval |= simplify_rename_labels_in_stmt(top, cs);
      }

      if (s->type == STMT_LABEL
       && strncmp(s->label->identifier, "__", 2) != 0) {
            s->label->identifier = identifier_tmp();

            retval |= 1;
      }

      return retval;
}

static int
simplify_rename_labels(struct scope *s)
{
      struct declaration *dion;
      int retval;

      retval = 0;

      for (dion = s->declaration_first; dion; dion = dion->next) {
            if (dion->stmt) {
                  retval |= simplify_rename_labels_in_stmt(
                        dion->stmt, dion->stmt);
            }
      }

      return retval;
}

static int
simplify_inline_remove(struct scope *s)
{
      struct declaration *dion;

      for (dion = s->declaration_first; dion; ) {
            struct declaration *next;

            next = dion->next;

            if (dion->mod_inline) {
                  /* Remove inline function from declaration list. */
                  if (dion->prev) {
                        dion->prev->next = dion->next;
                  } else {
                        s->declaration_first = dion->next;
                  }
                  if (dion->next) {
                        dion->next->prev = dion->prev;
                  } else {
                        s->declaration_last = dion->prev;
                  }

                  /* Free inline function. */
                  /* FIXME */
            }

            dion = next;
      }

      return 0;
}

static void
simplify_debug(struct scope *scope, const char *f)
{
      if (opt_d) {
            static int count = 0;
            char path[1024];
            FILE *fp;
            int ret;

            fprintf(stderr, "%s\n", f);

            sprintf(path, "step%04d", count++);
            fp = fopen(path, "w");
            assert(fp);

            ret = setvbuf(fp, NULL, _IONBF, 0);
            assert(ret == 0);

            fprintf(fp, "%s\n", f);
            fprintf(fp, "******************************\n");
            fprintf(fp, "\n");

            print(fp, scope);

            ret = fclose(fp);
            assert(0 <= ret);
      }
}

static int
simplify_once(const char *n, int (*f)(struct scope *), struct scope *s)
{
      int retval;
      int val;

      retval = 0;

      simplify_change = 0;
      val = (*f)(s);
      val |= simplify_change;

      if (val) {
            retval = 1;
            simplify_debug(s, n);
      }

      return retval;
}

static int
simplify_repeat(const char *n, int (*f)(struct scope *), struct scope *s)
{
      int retval;
      int val;

      retval = 0;
restart:;
      simplify_change = 0;
      val = (*f)(s);
      val |= simplify_change;

      if (val) {
            retval = 1;
            simplify_debug(s, n);
            goto restart;
      }

      return retval;
}

static int
simplify_once_dion(
      const char *n,
      int (*f)(struct scope *, struct declaration *),
      struct scope *s
)
{
      struct declaration *dion;
      int retval;
      int val;

      retval = 0;

      for (dion = s->declaration_first; dion; dion = dion->next) {
            simplify_change = 0;
            val = (*f)(s, dion);
            val |= simplify_change;

            if (val) {
                  retval = 1;
                  simplify_debug(s, n);
            }
      }

      return retval;
}

static int
simplify_repeat_dion(
      const char *n,
      int (*f)(struct scope *, struct declaration *),
      struct scope *s
)
{
      struct declaration *dion;
      int retval;
      int val;

      retval = 0;

      for (dion = s->declaration_first; dion; dion = dion->next) {
      restart:;
            simplify_change = 0;
            val = (*f)(s, dion);
            val |= simplify_change;

            if (val) {
                  retval = 1;
                  simplify_debug(s, n);
                  goto restart;
            }
      }

      return retval;
}

static int
simplify_once_func(const char *n, int (*f)(struct stmt *), struct scope *s)
{
      struct declaration *dion;
      int retval;
      int val;

      retval = 0;

      for (dion = s->declaration_first; dion; dion = dion->next) {
            if (dion->stmt) {
                  simplify_change = 0;
                  val = (*f)(dion->stmt);
                  val |= simplify_change;

                  if (val) {
                        retval = 1;
                        simplify_debug(s, n);
                  }
            }
      }

      return retval;
}

static int
simplify_repeat_func(const char *n, int (*f)(struct stmt *), struct scope *s)
{
      struct declaration *dion;
      int retval;
      int val;

      retval = 0;

      for (dion = s->declaration_first; dion; dion = dion->next) {
            if (dion->stmt) {
            restart:;
                  simplify_change = 0;
                  val = (*f)(dion->stmt);
                  val |= simplify_change;

                  if (val) {
                        retval = 1;
                        simplify_debug(s, n);
                        goto restart;
                  }
            }
      }

      return retval;
}

void
simplify(struct scope *scope)
{
      int retval;

      simplify_debug(scope, "parse");

#define ONCE(x, s)            simplify_once(#x, x, s)
#define REPEAT(x, s)          simplify_repeat(#x, x, s)
#define ONCE_DION(x, s)       simplify_once_dion(#x, x, s)
#define REPEAT_DION(x, s)     simplify_repeat_dion(#x, x, s)
#define ONCE_FUNC(x, s)       simplify_once_func(#x, x, s)
#define REPEAT_FUNC(x, s)     simplify_repeat_func(#x, x, s)

      /*
       * First step:
       * Clean up parsed code.
       */
      ONCE(simplify_fix_dimensions, scope);
      ONCE_FUNC(simplify_split_vardecl_init, scope);
      ONCE(simplify_merge_declarations_of_blocks, scope);

      /*
       * Second step:
       * Translate control structures.
       * Split some expressions.
       */
      ONCE_FUNC(stmt_simplify, scope);
      ONCE_FUNC(stmt_simplify_params, scope);
      ONCE_FUNC(stmt_simplify_returns, scope);
      REPEAT_DION(expr_simplify, scope);

      /*
       * Third step:
       * Do inlining.
       */
      REPEAT_FUNC(simplify_inline, scope);
      REPEAT_DION(expr_simplify, scope);

      /*
       * Fourth step:
       * Do optimization.
       */
      do {
            retval = REPEAT_DION(expr_optimize, scope);
            retval |= ONCE_FUNC(stmt_optimize, scope);
      } while (retval);

      /*
       * Fifth step:
       * Replace all pointers by integer vars.
       */
      ONCE(simplify_pointer_to_int, scope);

      /*
       * Sixth step:
       * Do some more optimizations.
       */
      do {
            retval = REPEAT_DION(expr_optimize, scope);
            retval |= ONCE_FUNC(stmt_optimize, scope);
      } while (retval);

      /*
       * Seventh step:
       * Prepare for compiling.
       */
      ONCE(simplify_inline_remove, scope);
      ONCE(simplify_rename_labels, scope);
      ONCE_DION(cleanup_func_scope, scope);
}

Generated by  Doxygen 1.6.0   Back to index