示例#1
0
/*
 * leaveblock - exit a block
 */
void leaveblock()
{
   struct id_entry **i, *p, *tmp;

   if (level > 0) {
      for (i = id_table; i < &id_table[ITABSIZE]; i++) {
         for (p = *i; p; p = tmp)
            if (p->i_blevel < level)
               break;
            else {
               tmp = p->i_link;
               free(p);
            }
         *i = p;
      }
      level--;
   }
   exit_block();
}
void new_block_table (astree *block_node) {
   for (auto &i : block_node->children) {
      switch(i->symbol) {
      case (TOK_VARDECL):
         new_var_table(i);
         break;
      case (TOK_BLOCK): {
         symbol_table *iblock = enter_block();
         idents.push_back(iblock);
         new_block_table(i);
         exit_block();
         break;
      }
      default:
         break;
      }
   }
   block_node->checked = true;
}
// Table for newly found function
void new_fn_table (astree *fn_node) {
   if (fn_node == NULL || fn_node->children.empty()) return;
   astree *type_node = fn_node->children[0];
   if (type_node == NULL || type_node->children.empty()) return;
   astree *name_node = type_node->children[0];
   if (name_node == NULL) return;
   astree *params_node = fn_node->children[1];
   if (params_node == NULL) return;
   astree *fnblock_node = fn_node->children[2];
   if (fnblock_node == NULL) return;

   symbol *fn_symbol = new_symbol(fn_node);
   if (fn_symbol == NULL) return;
   fn_symbol->attributes.set(ATTR_function);
   fn_symbol->parameters = new vector<symbol*>();

   symbol_dump(fn_symbol, (string *)name_node->clexinfo);

   // new block
   symbol_table *fn_table = enter_block();
   idents.push_back(fn_table);

   fprintf(oil_file, "%s __%s (\n", type_node->clexinfo->c_str(),
                                    name_node->clexinfo->c_str());
   // parameters
   for (auto &param_type : params_node->children) {
      new_fn_parameter(param_type, fn_table, fn_symbol);
      if (param_type == params_node->children.back()) {
         fprintf(oil_file, ")\n");
      } else {
         fprintf(oil_file, ",\n");
      }
   }
   fprintf(oil_file, "{\n");
   // block
   new_block_table(fnblock_node);
   exit_block();
   sym_insertion(idents[blockstack.back()],
                 fn_symbol, (string*)name_node->clexinfo);
   fn_node->checked = true;
   fprintf(oil_file, "{\n");
}
示例#4
0
/*
 * leaveblock - exit a block
 */
void leaveblock()
{  
    dump(level, stdout);
    int i = 0;
    for(i = 0; i < ITABSIZE; i++){
        if(id_table[i] != NULL){
            {
                struct id_entry* entry = id_table[i];
                for(entry; entry != NULL; entry = entry->i_link){
                    {
                        if(entry->i_blevel == level){
                            id_table[i] = entry->i_link;
                            free(entry);
                        }
                    }
                }
            }
        }
    }
    level--;
    exit_block();
}
// Perform a DFS traversal of passed in astree.
void fn_names_traversal (astree *root) {
   if (root == NULL) return;
   if (root->children.empty()) {
      return;
   } else {
      for (auto &child : root->children) {
         if (child->checked) continue;
         switch(child->symbol) {
            case TOK_STRUCT: new_type_table(child); break;
            case TOK_FUNCTION: new_fn_table(child); break;
            case TOK_VARDECL: new_var_table(child); break;
            case TOK_BLOCK: {
               symbol_table *iblock = enter_block();
               idents.push_back(iblock);
               new_block_table(child);
               exit_block();
               break;
            }
         }
         fn_names_traversal(child);
      }
   }
}
示例#6
0
gboolean
cov_function_t::solve()
{
    int passes, changes;
    cov_arc_t *a;
    cov_block_t *b;

    /* For every block in the file,
       - if every exit/entrance arc has a known count, then set the block count
       - if the block count is known, and every exit/entrance arc but one has
	 a known execution count, then set the count of the remaining arc

       As arc counts are set, decrement the succ/pred count, but don't delete
       the arc, that way we can easily tell when all arcs are known, or only
       one arc is unknown.  */

    /* The order that the basic blocks are iterated through is important.
       Since the code that finds spanning trees starts with block 0, low numbered
       arcs are put on the spanning tree in preference to high numbered arcs.
       Hence, most instrumented arcs are at the end.  Graph solving works much
       faster if we propagate numbers from the end to the start.

       This takes an average of slightly more than 3 passes.  */

    solve_log.debug(" ---> %s\n", name_.data());

    /*
     * In the new gcc 3.3 file format we cannot expect to get arcs into
     * the entry block and out of the exit block.  So if we don't get any,
     * tweak the {in,out}_ninvalid_ count up to effective infinity to
     * ensure the solve algorithm doesn't accidentally use the lack of
     * counts.
     */
    assert(num_blocks() >= 2);
    if ((b = blocks_->nth(entry_block()))->in_arcs_.head() == 0)
    {
	assert(file_->format_version_ > 0);
	b->in_ninvalid_ = ~0U;
	solve_log.debug("entry block tweaked\n");
    }
    if ((b = blocks_->nth(exit_block()))->out_arcs_.head() == 0)
    {
	assert(file_->format_version_ > 0);
	b->out_ninvalid_ = ~0U;
	solve_log.debug("exit block tweaked\n");
    }

    changes = 1;
    passes = 0;
    while (changes)
    {
	passes++;
	changes = 0;

	solve_log.debug("pass %d\n", passes);

	for (ptrarray_iterator_t<cov_block_t> bitr = blocks_->last() ; *bitr ; --bitr)
	{
	    b = *bitr;
	    solve_log.debug("[%d]\n", b->bindex());

	    if (!b->count_valid_)
	    {
		solve_log.debug("[%d] out_ninvalid_=%u in_ninvalid_=%u\n",
			    b->bindex(), b->out_ninvalid_, b->in_ninvalid_);

		/*
		 * For blocks with calls we have to ignore the outbound total
		 * when calculating the block count, because of the possibility
		 * of calls to fork(), exit() or other functions which can
		 * return more or less frequently than they're called.  Given
		 * the existance of longjmp() all calls are potentially like
		 * that.
		 */
		if (b->out_ncalls_ == 0 && b->out_ninvalid_ == 0)
		{
		    b->set_count(cov_arc_t::total(b->out_arcs_));
		    changes++;
		    solve_log.debug("[%d] count=%llu\n", b->bindex(), (unsigned long long)b->count());
		}
		else if (b->in_ninvalid_ == 0)
		{
		    b->set_count(cov_arc_t::total(b->in_arcs_));
		    changes++;
		    solve_log.debug("[%d] count=%llu\n", b->bindex(), (unsigned long long)b->count());
		}
	    }

	    if (b->count_valid_)
	    {
		if (b->out_ninvalid_ == 1)
		{
		    /* Search for the invalid arc, and set its count.  */
		    if ((a = cov_arc_t::find_invalid(b->out_arcs_, FALSE)) == 0)
			return FALSE;   /* ERROR */
		    /* Calculate count for remaining arc by conservation.  */
		    /* One of the counts will be invalid, but it is zero,
		       so adding it in also doesn't hurt.  */
		    count_t out_total = cov_arc_t::total(b->out_arcs_);
		    if (b->count_ < out_total)
		    {
			solve_log.warning("Function %s cannot be solved because "
					  "the arc counts are inconsistent, suppressing\n",
					  name_.data());
			suppress(cov_suppressions.find(0, cov_suppression_t::UNSOLVABLE));
			return TRUE;
		    }
		    assert(b->count_ >= out_total);
		    a->set_count(b->count_ - out_total);
		    changes++;
		    solve_log.debug("[%d->%d] count=%llu\n",
			    a->from()->bindex(), a->to()->bindex(),
			    (unsigned long long)a->count());
		}
		if (b->in_ninvalid_ == 1)
		{
		    /* Search for the invalid arc, and set its count.  */
		    if ((a = cov_arc_t::find_invalid(b->in_arcs_, FALSE)) == 0)
			return FALSE;   /* ERROR */
		    /* Calculate count for remaining arc by conservation.  */
		    /* One of the counts will be invalid, but it is zero,
		       so adding it in also doesn't hurt.  */
		    count_t in_total = cov_arc_t::total(b->in_arcs_);
		    if (b->count_ < in_total)
		    {
			solve_log.warning("Function %s cannot be solved because "
					  "the arc counts are inconsistent, suppressing\n",
					  name_.data());
			suppress(cov_suppressions.find(0, cov_suppression_t::UNSOLVABLE));
			return TRUE;
		    }
		    assert(b->count_ >= in_total);
		    a->set_count(b->count_ - in_total);
		    changes++;
		    solve_log.debug("[%d->%d] count=%llu\n",
			    a->from()->bindex(), a->to()->bindex(),
			    (unsigned long long)a->count());
		}
	    }
	}
    }

    /*
     * If the graph has been correctly solved, every block will
     * have a valid count and all its inbound and outbounds arcs
     * will also have valid counts.
     */
    for (ptrarray_iterator_t<cov_block_t> bitr = blocks_->first() ; *bitr ; ++bitr)
    {
	b = *bitr;
	if (!b->count_valid_)
	    return FALSE;
	if (b->out_ninvalid_ > 0 && b->out_ninvalid_ < ~0U)
	    return FALSE;
	if (b->in_ninvalid_ > 0 && b->in_ninvalid_ < ~0U)
	    return FALSE;
	if (cov_arc_t::find_invalid(b->in_arcs_, TRUE) != 0)
	    return FALSE;
	if (cov_arc_t::find_invalid(b->out_arcs_, TRUE) != 0)
	    return FALSE;
    }

    solve_log.debug("Solved flow graph for %s in %d passes\n", name(), passes);

    return TRUE;
}
示例#7
0
文件: compile.c 项目: MUME/mudlle
static void generate_component(component comp, fncode fn)
{
  clist args;

  set_lineno(comp->lineno, fn);

  switch (comp->vclass)
    {
    case c_assign:
      {
	ulong offset;
        bool is_static;
	variable_class vclass = env_lookup(comp->u.assign.symbol, &offset,
                                           false, true, &is_static);
	component val = comp->u.assign.value;

	if (val->vclass == c_closure)
	  {
	    /* Defining a function, give it a name */
	    if (vclass == global_var)
	      val->u.closure->varname = comp->u.assign.symbol;
	    else
	      {
		char *varname = allocate(fnmemory(fn), strlen(comp->u.assign.symbol) + 7);

		sprintf(varname, "local-%s", comp->u.assign.symbol);
		val->u.closure->varname = varname;
	      }
	  }

        if (is_static)
          {
            ins1(op_recall + vclass, offset, fn);
            generate_component(comp->u.assign.value, fn);
            mexecute(g_symbol_set, NULL, 2, fn);
            break;
          }

	generate_component(comp->u.assign.value, fn);

	set_lineno(comp->lineno, fn);

        if (vclass == global_var)
	  massign(offset, comp->u.assign.symbol, fn);
	else
	  ins1(op_assign + vclass, offset, fn);
	/* Note: varname becomes a dangling pointer when fnmemory(fn) is
	   deallocated, but it is never used again so this does not cause
	   a problem. */
	break;
      }
    case c_vref:
    case c_recall:
      {
        bool is_vref = comp->vclass == c_vref;
	ulong offset;
        bool is_static;
	variable_class vclass = env_lookup(comp->u.recall, &offset,
                                           true, is_vref, &is_static);

        if (is_static)
          {
            assert(vclass != global_var);
            ins1(op_recall + vclass, offset, fn);
            ulong gidx = is_vref ? g_make_symbol_ref : g_symbol_get;
            mexecute(gidx, NULL, 1, fn);
            break;
          }
	if (vclass != global_var)
          ins1((is_vref ? op_vref : op_recall) + vclass, offset, fn);
        else if (is_vref)
          {
            if (!mwritable(offset, comp->u.recall))
              return;
            ins_constant(makeint(offset), fn);
          }
        else
          mrecall(offset, comp->u.recall, fn);
        if (is_vref)
          mexecute(g_make_variable_ref, "make_variable_ref", 1, fn);
	break;
      }
    case c_constant:
      ins_constant(make_constant(comp->u.cst), fn);
      break;
    case c_closure:
      {
	uword idx;

	idx = add_constant(generate_function(comp->u.closure, false, fn), fn);
	if (idx < ARG1_MAX) ins1(op_closure_code1, idx, fn);
	else ins2(op_closure_code2, idx, fn);
	break;
      }
    case c_block:
      generate_block(comp->u.blk, fn);
      break;
    case c_labeled:
      start_block(comp->u.labeled.name, fn);
      generate_component(comp->u.labeled.expression, fn);
      end_block(fn);
      break;
    case c_exit:
      generate_component(comp->u.labeled.expression, fn);
      if (!exit_block(comp->u.labeled.name, fn)) {
	if (!comp->u.labeled.name)
	  log_error("no loop to exit from");
	else
	  log_error("no block labeled %s", comp->u.labeled.name);
      }
      break;
    case c_execute:
      {
	uword count;

	generate_args(comp->u.execute->next, fn, &count);
	set_lineno(comp->lineno, fn);
	generate_execute(comp->u.execute->c, count, fn);
	break;
      }
    case c_builtin:
      args = comp->u.builtin.args;

      switch (comp->u.builtin.fn)
	{
	case b_if: {
          block cb = new_codeblock(fnmemory(fn), NULL,
                                   new_clist(fnmemory(fn), args->next->c,
                                             new_clist(fnmemory(fn),
                                                       component_undefined,
                                                       NULL)),
                                   NULL, NULL, -1);
	  generate_if(args->c, new_component(fnmemory(fn),
                                             args->next->c->lineno,
                                             c_block, cb),
		      component_undefined, fn);
	  break;
        }
	case b_ifelse:
	  generate_if(args->c, args->next->c, args->next->next->c, fn);
	  break;
	case b_sc_and: case b_sc_or:
	  generate_if(comp, component_true, component_false, fn);
	  break;

	case b_while:
	  generate_while(args->c, args->next->c, fn);
	  break;

	case b_loop:
	  {
	    label loop = new_label(fn);

            env_start_loop();
	    set_label(loop, fn);
	    start_block(NULL, fn);
	    generate_component(args->c, fn);
	    branch(op_loop1, loop, fn);
	    end_block(fn);
            env_end_loop();
	    adjust_depth(1, fn);
	    break;
	  }

	case b_add: case b_subtract:
	case b_ref: case b_set:
	case b_bitor: case b_bitand:
	case b_not:
	case b_eq: case b_ne:
	case b_lt: case b_le: case b_ge: case b_gt:
	  {
	    uword count;

	    assert(comp->u.builtin.fn < last_builtin);
	    generate_args(args, fn, &count);
	    set_lineno(comp->lineno, fn);
	    ins0(builtin_ops[comp->u.builtin.fn], fn);
	    break;
	  }
	default:
	  {
	    uword count;

	    assert(comp->u.builtin.fn < last_builtin);
	    generate_args(args, fn, &count);
	    set_lineno(comp->lineno, fn);
	    mexecute(builtin_functions[comp->u.builtin.fn], NULL, count, fn);
	    break;
	  }
	}
      break;
    default: abort();
    }
}
示例#8
0
void generate_component(component comp, const char *mlabel, bool discard, fncode fn)
{
  clist args;

  switch (comp->vclass)
    {
    case c_assign:
      {
	u16 offset;
	mtype t;
	variable_class vclass = env_lookup(comp->l, comp->u.assign.symbol, &offset, &t, FALSE);
	component val = comp->u.assign.value;

	if (val->vclass == c_closure)
	  {
	    /* Defining a function, give it a name */
	    if (vclass == global_var)
	      val->u.closure->varname = comp->u.assign.symbol;
	    else
	      {
		char *varname = allocate(fnmemory(fn), strlen(comp->u.assign.symbol) + 7);

		sprintf(varname, "local-%s", comp->u.assign.symbol);
		val->u.closure->varname = varname;
	      }
	  }
	generate_component(comp->u.assign.value, NULL, FALSE, fn);
	if (t != stype_any)
	  ins0(OPmscheck4 + t, fn);
	if (vclass == global_var)
	  massign(comp->l, offset, comp->u.assign.symbol, fn);
	else if (vclass == closure_var)
	  ins1(OPmwritec, offset, fn);
	else
	  ins1(OPmwritel, offset, fn);
	/* Note: varname becomes a dangling pointer when fnmemory(fn) is
	   deallocated, but it is never used again so this does not cause
	   a problem. */
	break;
      }
    case c_recall:
      scompile_recall(comp->l, comp->u.recall, fn);
      break;
    case c_constant:
      ins_constant(make_constant(comp->u.cst, FALSE, fn), fn);
      break;
    case c_scheme:
      scheme_compile_mgc(comp->l, make_constant(comp->u.cst, TRUE, fn), discard, fn);
      discard = FALSE;
      break;
    case c_closure:
      generate_function(comp->u.closure, fn);
      break;
    case c_block:
      generate_block(comp->u.blk, discard, fn);
      discard = FALSE;
      break;
    case c_decl: 
      {
	vlist decl, next;

	/* declare variables one at a time (any x = y, y = 2; is an error) */
	for (decl = comp->u.decls; decl; decl = next)
	  {
	    next = decl->next;
	    decl->next = NULL;

	    env_declare(decl);
	    generate_decls(decl, fn);
	  }
	generate_component(component_undefined, NULL, FALSE, fn);
	break;
      }
    case c_labeled: {
      start_block(comp->u.labeled.name, FALSE, discard, fn);
      generate_component(comp->u.labeled.expression, comp->u.labeled.name, discard, fn);
      end_block(fn);
      discard = FALSE;
      break;
    }
    case c_exit:
      {
	bool discard_exit;
	label exitlab = exit_block(comp->u.labeled.name, FALSE, &discard_exit, fn);

	if (comp->u.labeled.expression != component_undefined && discard_exit)
	  warning(comp->l, "break result is ignored");
	generate_component(comp->u.labeled.expression, NULL, discard_exit, fn);
	if (exitlab)
	  branch(OPmba3, exitlab, fn);
	else 
	  {
	    if (!comp->u.labeled.name)
	      log_error(comp->l, "No loop to exit from");
	    else
	      log_error(comp->l, "No block labeled %s", comp->u.labeled.name);
	  }
	/* Callers expect generate_component to increase stack depth by 1  */
	if (discard_exit)
	  adjust_depth(1, fn);
	break;
      }
    case c_continue:
      {
	bool discard_exit; /* Meaningless for continue blocks */
	label exitlab = exit_block(comp->u.labeled.name, TRUE, &discard_exit, fn);

	if (exitlab)
	  branch(OPmba3, exitlab, fn);
	else 
	  {
	    if (comp->u.labeled.name[0] == '<')
	      log_error(comp->l, "No loop to continue");
	    else
	      log_error(comp->l, "No loop labeled %s", comp->u.labeled.name);
	  }
	/* Callers expect generate_component to increase stack depth by 1 (*/
	adjust_depth(1, fn);
	break;
      }
    case c_execute:
      {
	u16 count;

	generate_args(comp->u.execute->next, fn, &count);
	generate_execute(comp->u.execute->c, count, fn);
	break;
      }
    case c_builtin:
      args = comp->u.builtin.args;

      switch (comp->u.builtin.fn)
	{
	case b_if:
	  generate_if(args->c, args->next->c, NULL, TRUE, fn);
	  generate_component(component_undefined, NULL, FALSE, fn);
	  break;
	case b_ifelse:
	  generate_if(args->c, args->next->c, args->next->next->c, discard, fn);
	  discard = FALSE;
	  break;
	case b_sc_and: case b_sc_or:
	  generate_if(comp, component_true, component_false, discard, fn);
	  discard = FALSE;
	  break;

	case b_while:
	  enter_loop(fn);
	  generate_while(args->c, args->next->c, mlabel, discard, fn);
	  exit_loop(fn);
	  discard = FALSE;
	  break;

	case b_dowhile:
	  enter_loop(fn);
	  generate_dowhile(args->c, args->next->c, mlabel, discard, fn);
	  exit_loop(fn);
	  discard = FALSE;
	  break;

	case b_for:
	  enter_loop(fn);
	  generate_for(args->c, args->next->c, args->next->next->c,
		       args->next->next->next->c, mlabel, discard, fn);
	  exit_loop(fn);
	  discard = FALSE;
	  break;

	default:
	  {
	    u16 count;

	    assert(comp->u.builtin.fn < last_builtin);
	    generate_args(args, fn, &count);
	    ins0(builtin_ops[comp->u.builtin.fn], fn);
	    break;
	  }
	case b_cons:
	  {
	    u16 count;
	    u16 goffset;
	    mtype t;

	    assert(comp->u.builtin.fn < last_builtin);
	    generate_args(args, fn, &count);
	    goffset = global_lookup(fnglobals(fn),
				    builtin_functions[comp->u.builtin.fn], &t);
	    mexecute(comp->l, goffset, NULL, count, fn);
	    break;
	  }
	}
      break;
    default: assert(0);
    }
  if (discard)
    ins0(OPmpop, fn);
}