Example #1
0
bool
gimple_stmt_may_fallthru (gimple stmt)
{
  if (!stmt)
    return true;

  switch (gimple_code (stmt))
    {
    case GIMPLE_GOTO:
    case GIMPLE_RETURN:
    case GIMPLE_RESX:
      /* Easy cases.  If the last statement of the seq implies
	 control transfer, then we can't fall through.  */
      return false;

    case GIMPLE_SWITCH:
      /* Switch has already been lowered and represents a branch
	 to a selected label and hence can't fall through.  */
      return false;

    case GIMPLE_COND:
      /* GIMPLE_COND's are already lowered into a two-way branch.  They
	 can't fall through.  */
      return false;

    case GIMPLE_BIND:
      return gimple_seq_may_fallthru (gimple_bind_body (stmt));

    case GIMPLE_TRY:
      if (gimple_try_kind (stmt) == GIMPLE_TRY_CATCH)
        return gimple_try_catch_may_fallthru (stmt);

      /* It must be a GIMPLE_TRY_FINALLY.  */

      /* The finally clause is always executed after the try clause,
	 so if it does not fall through, then the try-finally will not
	 fall through.  Otherwise, if the try clause does not fall
	 through, then when the finally clause falls through it will
	 resume execution wherever the try clause was going.  So the
	 whole try-finally will only fall through if both the try
	 clause and the finally clause fall through.  */
      return (gimple_seq_may_fallthru (gimple_try_eval (stmt))
	      && gimple_seq_may_fallthru (gimple_try_cleanup (stmt)));

    case GIMPLE_EH_ELSE:
      return (gimple_seq_may_fallthru (gimple_eh_else_n_body (stmt))
	      || gimple_seq_may_fallthru (gimple_eh_else_e_body (stmt)));

    case GIMPLE_CALL:
      /* Functions that do not return do not fall through.  */
      return (gimple_call_flags (stmt) & ECF_NORETURN) == 0;

    default:
      return true;
    }
}
Example #2
0
static void
lower_gimple_bind (gimple_stmt_iterator *gsi, struct lower_data *data)
{
  tree old_block = data->block;
  gimple stmt = gsi_stmt (*gsi);
  tree new_block = gimple_bind_block (stmt);

  if (new_block)
    {
      if (new_block == old_block)
	{
	  /* The outermost block of the original function may not be the
	     outermost statement chain of the gimplified function.  So we
	     may see the outermost block just inside the function.  */
	  gcc_assert (new_block == DECL_INITIAL (current_function_decl));
	  new_block = NULL;
	}
      else
	{
	  /* We do not expect to handle duplicate blocks.  */
	  gcc_assert (!TREE_ASM_WRITTEN (new_block));
	  TREE_ASM_WRITTEN (new_block) = 1;

	  /* Block tree may get clobbered by inlining.  Normally this would
	     be fixed in rest_of_decl_compilation using block notes, but
	     since we are not going to emit them, it is up to us.  */
	  BLOCK_CHAIN (new_block) = BLOCK_SUBBLOCKS (old_block);
	  BLOCK_SUBBLOCKS (old_block) = new_block;
	  BLOCK_SUBBLOCKS (new_block) = NULL_TREE;
	  BLOCK_SUPERCONTEXT (new_block) = old_block;

	  data->block = new_block;
	}
    }

  record_vars (gimple_bind_vars (stmt));
  lower_sequence (gimple_bind_body_ptr (stmt), data);

  if (new_block)
    {
      gcc_assert (data->block == new_block);

      BLOCK_SUBBLOCKS (new_block)
	= blocks_nreverse (BLOCK_SUBBLOCKS (new_block));
      data->block = old_block;
    }

  /* The GIMPLE_BIND no longer carries any useful information -- kill it.  */
  gsi_insert_seq_before (gsi, gimple_bind_body (stmt), GSI_SAME_STMT);
  gsi_remove (gsi, false);
}
Example #3
0
static void
test_gimplification ()
{
  tree fndecl = build_trivial_generic_function ();

  /* Convert to gimple: */
  gimplify_function_tree (fndecl);

  /* Verify that we got gimple out of it.  */

  /* The function is now in GIMPLE form but the CFG has not been
     built yet.  */

  /* We should have a struct function for the decl.  */
  function *fun = DECL_STRUCT_FUNCTION (fndecl);
  ASSERT_TRUE (fun != NULL);
  ASSERT_EQ (fndecl, fun->decl);

  /* We expect a GIMPLE_BIND, with two gimple statements within it:
       tmp = 42;
       return tmp;  */

  gimple_seq seq_fn_body = gimple_body (fndecl);
  ASSERT_TRUE (seq_fn_body != NULL);
  gimple *bind_stmt = gimple_seq_first_stmt (seq_fn_body);
  ASSERT_EQ (GIMPLE_BIND, gimple_code (bind_stmt));
  ASSERT_EQ (NULL, bind_stmt->next);

  gimple_seq seq_bind_body = gimple_bind_body (as_a <gbind *> (bind_stmt));

  /* Verify that we have the 2 statements we expect.  */
  ASSERT_TRUE (seq_bind_body != NULL);
  gimple *stmt1 = gimple_seq_first_stmt (seq_bind_body);
  ASSERT_TRUE (stmt1 != NULL);
  ASSERT_EQ (GIMPLE_ASSIGN, gimple_code (stmt1));
  gimple *stmt2 = stmt1->next;
  ASSERT_TRUE (stmt2 != NULL);
  ASSERT_EQ (stmt1, stmt2->prev);
  ASSERT_EQ (GIMPLE_RETURN, gimple_code (stmt2));
}
Example #4
0
static unsigned int
execute_trace ()
{
    gimple_seq body, body_bind_body, inner_cleanup, outer_cleanup;
    gimple inner_try, outer_try;
    tree record_type, func_start_decl, func_end_decl, var_decl,
         function_name_decl, constructor_clobber;
    gimple call_func_start;
    gimple_stmt_iterator gsi;

    // build record type
    record_type = build_type ();
    // build start & end function decl
    func_start_decl = build_function_decl ("__start_ctrace__", record_type);
    func_end_decl = build_function_decl ("__end_ctrace__", record_type);
    // init variables of current body
    body = gimple_body (current_function_decl);

    var_decl = build_decl (UNKNOWN_LOCATION, VAR_DECL,
                           get_identifier ("__ctrace_var__"), record_type);
    DECL_CONTEXT (var_decl) = current_function_decl;
    TREE_ADDRESSABLE (var_decl) = 1;
    declare_vars (var_decl, body, false);
    TREE_USED (var_decl) = 1;
    // mimic __FUNCTION__ builtin.
    function_name_decl = make_fname_decl ();
    declare_vars (function_name_decl, body, false);
    // construct inner try
    // init calls
    call_func_start = gimple_build_call (
                          func_start_decl, 2,
                          build1 (ADDR_EXPR, build_pointer_type (record_type), var_decl),
                          build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (function_name_decl)),
                                  function_name_decl));
    // make inner clean up
    inner_cleanup = gimple_build_call (
                        func_end_decl, 2,
                        build1 (ADDR_EXPR, build_pointer_type (record_type), var_decl),
                        build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (function_name_decl)),
                                function_name_decl));
    // update inner try
    body_bind_body = gimple_bind_body (body);
    inner_try
        = gimple_build_try (body_bind_body, inner_cleanup, GIMPLE_TRY_FINALLY);
    gsi = gsi_start (inner_try);
    gsi_insert_before (&gsi, call_func_start, GSI_NEW_STMT);
    // construct outer try
    constructor_clobber = make_node (CONSTRUCTOR);
    TREE_THIS_VOLATILE (constructor_clobber) = 1;
    TREE_TYPE (constructor_clobber) = TREE_TYPE (var_decl);
    outer_cleanup = gimple_build_assign (var_decl, constructor_clobber);
    // update outer try
    outer_try
        = gimple_build_try (call_func_start, outer_cleanup, GIMPLE_TRY_FINALLY);
    // update body bind body
    gimple_bind_set_body (body, outer_try);
    if (dump_file)
    {
        dump_function_to_file (current_function_decl, dump_file,
                               TDF_TREE | TDF_BLOCKS | TDF_VERBOSE);
    }
    // exit (0);
    return 0;
}
Example #5
0
static void
lower_gimple_bind (gimple_stmt_iterator *gsi, struct lower_data *data)
{
  tree old_block = data->block;
  gbind *stmt = as_a <gbind *> (gsi_stmt (*gsi));
  tree new_block = gimple_bind_block (stmt);

  if (new_block)
    {
      if (new_block == old_block)
	{
	  /* The outermost block of the original function may not be the
	     outermost statement chain of the gimplified function.  So we
	     may see the outermost block just inside the function.  */
	  gcc_assert (new_block == DECL_INITIAL (current_function_decl));
	  new_block = NULL;
	}
      else
	{
	  /* We do not expect to handle duplicate blocks.  */
	  gcc_assert (!TREE_ASM_WRITTEN (new_block));
	  TREE_ASM_WRITTEN (new_block) = 1;

	  /* Block tree may get clobbered by inlining.  Normally this would
	     be fixed in rest_of_decl_compilation using block notes, but
	     since we are not going to emit them, it is up to us.  */
	  BLOCK_CHAIN (new_block) = BLOCK_SUBBLOCKS (old_block);
	  BLOCK_SUBBLOCKS (old_block) = new_block;
	  BLOCK_SUBBLOCKS (new_block) = NULL_TREE;
	  BLOCK_SUPERCONTEXT (new_block) = old_block;

	  data->block = new_block;
	}
    }

  record_vars (gimple_bind_vars (stmt));

  /* Scrap DECL_CHAIN up to BLOCK_VARS to ease GC after we no longer
     need gimple_bind_vars.  */
  tree next;
  /* BLOCK_VARS and gimple_bind_vars share a common sub-chain.  Find
     it by marking all BLOCK_VARS.  */
  if (gimple_bind_block (stmt))
    for (tree t = BLOCK_VARS (gimple_bind_block (stmt)); t; t = DECL_CHAIN (t))
      TREE_VISITED (t) = 1;
  for (tree var = gimple_bind_vars (stmt);
       var && ! TREE_VISITED (var); var = next)
    {
      next = DECL_CHAIN (var);
      DECL_CHAIN (var) = NULL_TREE;
    }
  /* Unmark BLOCK_VARS.  */
  if (gimple_bind_block (stmt))
    for (tree t = BLOCK_VARS (gimple_bind_block (stmt)); t; t = DECL_CHAIN (t))
      TREE_VISITED (t) = 0;

  lower_sequence (gimple_bind_body_ptr (stmt), data);

  if (new_block)
    {
      gcc_assert (data->block == new_block);

      BLOCK_SUBBLOCKS (new_block)
	= blocks_nreverse (BLOCK_SUBBLOCKS (new_block));
      data->block = old_block;
    }

  /* The GIMPLE_BIND no longer carries any useful information -- kill it.  */
  gsi_insert_seq_before (gsi, gimple_bind_body (stmt), GSI_SAME_STMT);
  gsi_remove (gsi, false);
}