コード例 #1
0
ファイル: function-tests.c プロジェクト: duarten/gcc
static void
test_conversion_to_ssa ()
{
  /* As above, construct a trivial function, gimplify it, and build a CFG: */
  tree fndecl = build_trivial_high_gimple_function ();
  function *fun = DECL_STRUCT_FUNCTION (fndecl);
  ASSERT_TRUE (fun != NULL);
  build_cfg (fndecl);

  convert_to_ssa (fndecl);

  verify_three_block_gimple_cfg (fun);

  /* For out trivial test function we should now have something like
     this:
       test_fn ()
       {
	 <bb 2>:
	 _1 = 42;
	 return _1;
       }
  */
  basic_block bb2 = get_real_block (fun);
  gimple *stmt_a = gimple_seq_first_stmt (bb_seq (bb2));
  ASSERT_EQ (GIMPLE_ASSIGN, gimple_code (stmt_a));

  gimple *stmt_b = stmt_a->next;
  ASSERT_EQ (GIMPLE_RETURN, gimple_code (stmt_b));
  ASSERT_EQ (NULL, stmt_b->next);

  greturn *return_stmt = as_a <greturn *> (stmt_b);
  ASSERT_EQ (SSA_NAME, TREE_CODE (gimple_return_retval (return_stmt)));
}
コード例 #2
0
ファイル: function-tests.c プロジェクト: duarten/gcc
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));
}
コード例 #3
0
ファイル: function-tests.c プロジェクト: duarten/gcc
static void
test_building_cfg ()
{
  /* Construct a trivial function, and gimplify it: */
  tree fndecl = build_trivial_high_gimple_function ();
  function *fun = DECL_STRUCT_FUNCTION (fndecl);
  ASSERT_TRUE (fun != NULL);

  /* Build a CFG.  */
  build_cfg (fndecl);

  /* The CFG-building code constructs a 4-block cfg (with
     ENTRY and EXIT):
       test_fn ()
       {
         <bb 2>:
	 D.65 = 42;

	 <bb 3>:
	 return D.65;
       }
     and then ought to merge blocks 2 and 3 in cleanup_tree_cfg.

     Hence we should end up with a simple 3-block cfg, the two "fake" ones,
     and a "real" one:
       [ENTRY] -> [block2] -> [EXIT]
     with code like this:
	 test_fn ()
	 {
	   <bb 2>:
	   D.56 = 42;
	   return D.56;
	 }
  */
  verify_three_block_gimple_cfg (fun);

  /* Verify the statements within the "real" block.  */
  basic_block bb2 = get_real_block (fun);
  gimple *stmt_a = gimple_seq_first_stmt (bb_seq (bb2));
  ASSERT_EQ (GIMPLE_ASSIGN, gimple_code (stmt_a));
  gimple *stmt_b = stmt_a->next;
  ASSERT_EQ (GIMPLE_RETURN, gimple_code (stmt_b));
  ASSERT_EQ (NULL, stmt_b->next);
}
コード例 #4
0
ファイル: gimple-low.c プロジェクト: hnaik/gcc
static unsigned int
lower_function_body (void)
{
  struct lower_data data;
  gimple_seq body = gimple_body (current_function_decl);
  gimple_seq lowered_body;
  gimple_stmt_iterator i;
  gimple bind;
  tree t;
  gimple x;

  /* The gimplifier should've left a body of exactly one statement,
     namely a GIMPLE_BIND.  */
  gcc_assert (gimple_seq_first (body) == gimple_seq_last (body)
	      && gimple_code (gimple_seq_first_stmt (body)) == GIMPLE_BIND);

  memset (&data, 0, sizeof (data));
  data.block = DECL_INITIAL (current_function_decl);
  BLOCK_SUBBLOCKS (data.block) = NULL_TREE;
  BLOCK_CHAIN (data.block) = NULL_TREE;
  TREE_ASM_WRITTEN (data.block) = 1;
  data.return_statements.create (8);

  bind = gimple_seq_first_stmt (body);
  lowered_body = NULL;
  gimple_seq_add_stmt (&lowered_body, bind);
  i = gsi_start (lowered_body);
  lower_gimple_bind (&i, &data);

  i = gsi_last (lowered_body);

  /* If the function falls off the end, we need a null return statement.
     If we've already got one in the return_statements vector, we don't
     need to do anything special.  Otherwise build one by hand.  */
  if (gimple_seq_may_fallthru (lowered_body)
      && (data.return_statements.is_empty ()
	  || gimple_return_retval (data.return_statements.last().stmt) != NULL))
    {
      x = gimple_build_return (NULL);
      gimple_set_location (x, cfun->function_end_locus);
      gimple_set_block (x, DECL_INITIAL (current_function_decl));
      gsi_insert_after (&i, x, GSI_CONTINUE_LINKING);
    }

  /* If we lowered any return statements, emit the representative
     at the end of the function.  */
  while (!data.return_statements.is_empty ())
    {
      return_statements_t t = data.return_statements.pop ();
      x = gimple_build_label (t.label);
      gsi_insert_after (&i, x, GSI_CONTINUE_LINKING);
      gsi_insert_after (&i, t.stmt, GSI_CONTINUE_LINKING);
    }

  /* If the function calls __builtin_setjmp, we need to emit the computed
     goto that will serve as the unique dispatcher for all the receivers.  */
  if (data.calls_builtin_setjmp)
    {
      tree disp_label, disp_var, arg;

      /* Build 'DISP_LABEL:' and insert.  */
      disp_label = create_artificial_label (cfun->function_end_locus);
      /* This mark will create forward edges from every call site.  */
      DECL_NONLOCAL (disp_label) = 1;
      cfun->has_nonlocal_label = 1;
      x = gimple_build_label (disp_label);
      gsi_insert_after (&i, x, GSI_CONTINUE_LINKING);

      /* Build 'DISP_VAR = __builtin_setjmp_dispatcher (DISP_LABEL);'
	 and insert.  */
      disp_var = create_tmp_var (ptr_type_node, "setjmpvar");
      arg = build_addr (disp_label, current_function_decl);
      t = builtin_decl_implicit (BUILT_IN_SETJMP_DISPATCHER);
      x = gimple_build_call (t, 1, arg);
      gimple_call_set_lhs (x, disp_var);

      /* Build 'goto DISP_VAR;' and insert.  */
      gsi_insert_after (&i, x, GSI_CONTINUE_LINKING);
      x = gimple_build_goto (disp_var);
      gsi_insert_after (&i, x, GSI_CONTINUE_LINKING);
    }

  /* Once the old body has been lowered, replace it with the new
     lowered sequence.  */
  gimple_set_body (current_function_decl, lowered_body);

  gcc_assert (data.block == DECL_INITIAL (current_function_decl));
  BLOCK_SUBBLOCKS (data.block)
    = blocks_nreverse (BLOCK_SUBBLOCKS (data.block));

  clear_block_marks (data.block);
  data.return_statements.release ();
  return 0;
}
コード例 #5
0
static unsigned int
lower_function_body (void)
{
  struct lower_data data;
  gimple_seq body = gimple_body (current_function_decl);
  gimple_seq lowered_body;
  gimple_stmt_iterator i;
  gimple bind;
  gimple x;

  /* The gimplifier should've left a body of exactly one statement,
     namely a GIMPLE_BIND.  */
  gcc_assert (gimple_seq_first (body) == gimple_seq_last (body)
	      && gimple_code (gimple_seq_first_stmt (body)) == GIMPLE_BIND);

  memset (&data, 0, sizeof (data));
  data.block = DECL_INITIAL (current_function_decl);
  BLOCK_SUBBLOCKS (data.block) = NULL_TREE;
  BLOCK_CHAIN (data.block) = NULL_TREE;
  TREE_ASM_WRITTEN (data.block) = 1;
  data.return_statements.create (8);

  bind = gimple_seq_first_stmt (body);
  lowered_body = NULL;
  gimple_seq_add_stmt (&lowered_body, bind);
  i = gsi_start (lowered_body);
  lower_gimple_bind (&i, &data);

  i = gsi_last (lowered_body);

  /* If the function falls off the end, we need a null return statement.
     If we've already got one in the return_statements vector, we don't
     need to do anything special.  Otherwise build one by hand.  */
  if (gimple_seq_may_fallthru (lowered_body)
      && (data.return_statements.is_empty ()
	  || (gimple_return_retval (data.return_statements.last().stmt)
	      != NULL)))
    {
      x = gimple_build_return (NULL);
      gimple_set_location (x, cfun->function_end_locus);
      gimple_set_block (x, DECL_INITIAL (current_function_decl));
      gsi_insert_after (&i, x, GSI_CONTINUE_LINKING);
    }

  /* If we lowered any return statements, emit the representative
     at the end of the function.  */
  while (!data.return_statements.is_empty ())
    {
      return_statements_t t = data.return_statements.pop ();
      x = gimple_build_label (t.label);
      gsi_insert_after (&i, x, GSI_CONTINUE_LINKING);
      gsi_insert_after (&i, t.stmt, GSI_CONTINUE_LINKING);
    }

  /* Once the old body has been lowered, replace it with the new
     lowered sequence.  */
  gimple_set_body (current_function_decl, lowered_body);

  gcc_assert (data.block == DECL_INITIAL (current_function_decl));
  BLOCK_SUBBLOCKS (data.block)
    = blocks_nreverse (BLOCK_SUBBLOCKS (data.block));

  clear_block_marks (data.block);
  data.return_statements.release ();
  return 0;
}
コード例 #6
0
ファイル: gimple-low.c プロジェクト: KangDroid/gcc
static unsigned int
lower_function_body (void)
{
  struct lower_data data;
  gimple_seq body = gimple_body (current_function_decl);
  gimple_seq lowered_body;
  gimple_stmt_iterator i;
  gimple *bind;
  gimple *x;

  /* The gimplifier should've left a body of exactly one statement,
     namely a GIMPLE_BIND.  */
  gcc_assert (gimple_seq_first (body) == gimple_seq_last (body)
	      && gimple_code (gimple_seq_first_stmt (body)) == GIMPLE_BIND);

  memset (&data, 0, sizeof (data));
  data.block = DECL_INITIAL (current_function_decl);
  BLOCK_SUBBLOCKS (data.block) = NULL_TREE;
  BLOCK_CHAIN (data.block) = NULL_TREE;
  TREE_ASM_WRITTEN (data.block) = 1;
  data.return_statements.create (8);

  bind = gimple_seq_first_stmt (body);
  lowered_body = NULL;
  gimple_seq_add_stmt (&lowered_body, bind);
  i = gsi_start (lowered_body);
  lower_gimple_bind (&i, &data);

  i = gsi_last (lowered_body);

  /* If we had begin stmt markers from e.g. PCH, but this compilation
     doesn't want them, lower_stmt will have cleaned them up; we can
     now clear the flag that indicates we had them.  */
  if (!MAY_HAVE_DEBUG_MARKER_STMTS && cfun->debug_nonbind_markers)
    {
      /* This counter needs not be exact, but before lowering it will
	 most certainly be.  */
      gcc_assert (cfun->debug_marker_count == 0);
      cfun->debug_nonbind_markers = false;
    }

  /* If the function falls off the end, we need a null return statement.
     If we've already got one in the return_statements vector, we don't
     need to do anything special.  Otherwise build one by hand.  */
  bool may_fallthru = gimple_seq_may_fallthru (lowered_body);
  if (may_fallthru
      && (data.return_statements.is_empty ()
	  || (gimple_return_retval (data.return_statements.last().stmt)
	      != NULL)))
    {
      x = gimple_build_return (NULL);
      gimple_set_location (x, cfun->function_end_locus);
      gimple_set_block (x, DECL_INITIAL (current_function_decl));
      gsi_insert_after (&i, x, GSI_CONTINUE_LINKING);
      may_fallthru = false;
    }

  /* If we lowered any return statements, emit the representative
     at the end of the function.  */
  while (!data.return_statements.is_empty ())
    {
      return_statements_t t = data.return_statements.pop ();
      x = gimple_build_label (t.label);
      gsi_insert_after (&i, x, GSI_CONTINUE_LINKING);
      gsi_insert_after (&i, t.stmt, GSI_CONTINUE_LINKING);
      if (may_fallthru)
	{
	  /* Remove the line number from the representative return statement.
	     It now fills in for the fallthru too.  Failure to remove this
	     will result in incorrect results for coverage analysis.  */
	  gimple_set_location (t.stmt, UNKNOWN_LOCATION);
	  may_fallthru = false;
	}
    }

  /* Once the old body has been lowered, replace it with the new
     lowered sequence.  */
  gimple_set_body (current_function_decl, lowered_body);

  gcc_assert (data.block == DECL_INITIAL (current_function_decl));
  BLOCK_SUBBLOCKS (data.block)
    = blocks_nreverse (BLOCK_SUBBLOCKS (data.block));

  clear_block_marks (data.block);
  data.return_statements.release ();
  return 0;
}