Example #1
0
void
ubsan_expand_bounds_ifn (gimple_stmt_iterator *gsi)
{
  gimple stmt = gsi_stmt (*gsi);
  location_t loc = gimple_location (stmt);
  gcc_assert (gimple_call_num_args (stmt) == 3);

  /* Pick up the arguments of the UBSAN_BOUNDS call.  */
  tree type = TREE_TYPE (TREE_TYPE (gimple_call_arg (stmt, 0)));
  tree index = gimple_call_arg (stmt, 1);
  tree orig_index_type = TREE_TYPE (index);
  tree bound = gimple_call_arg (stmt, 2);

  gimple_stmt_iterator gsi_orig = *gsi;

  /* Create condition "if (index > bound)".  */
  basic_block then_bb, fallthru_bb;
  gimple_stmt_iterator cond_insert_point
    = create_cond_insert_point (gsi, 0/*before_p*/, false, true,
				&then_bb, &fallthru_bb);
  index = fold_convert (TREE_TYPE (bound), index);
  index = force_gimple_operand_gsi (&cond_insert_point, index,
				    true/*simple_p*/, NULL_TREE,
				    false/*before*/, GSI_NEW_STMT);
  gimple g = gimple_build_cond (GT_EXPR, index, bound, NULL_TREE, NULL_TREE);
  gimple_set_location (g, loc);
  gsi_insert_after (&cond_insert_point, g, GSI_NEW_STMT);

  /* Generate __ubsan_handle_out_of_bounds call.  */
  *gsi = gsi_after_labels (then_bb);
  if (flag_sanitize_undefined_trap_on_error)
    g = gimple_build_call (builtin_decl_explicit (BUILT_IN_TRAP), 0);
  else
    {
      tree data
	= ubsan_create_data ("__ubsan_out_of_bounds_data", &loc, NULL,
			     ubsan_type_descriptor (type, UBSAN_PRINT_ARRAY),
			     ubsan_type_descriptor (orig_index_type),
			     NULL_TREE);
      data = build_fold_addr_expr_loc (loc, data);
      enum built_in_function bcode
	= flag_sanitize_recover
	  ? BUILT_IN_UBSAN_HANDLE_OUT_OF_BOUNDS
	  : BUILT_IN_UBSAN_HANDLE_OUT_OF_BOUNDS_ABORT;
      tree fn = builtin_decl_explicit (bcode);
      tree val = force_gimple_operand_gsi (gsi, ubsan_encode_value (index),
					   true, NULL_TREE, true,
					   GSI_SAME_STMT);
      g = gimple_build_call (fn, 2, data, val);
    }
  gimple_set_location (g, loc);
  gsi_insert_before (gsi, g, GSI_SAME_STMT);

  /* Get rid of the UBSAN_BOUNDS call from the IR.  */
  unlink_stmt_vdef (stmt);
  gsi_remove (&gsi_orig, true);

  /* Point GSI to next logical statement.  */
  *gsi = gsi_start_bb (fallthru_bb);
}
Example #2
0
void
gimple_gen_ic_func_profiler (void)
{
  struct cgraph_node * c_node = cgraph_node::get (current_function_decl);
  gimple_stmt_iterator gsi;
  gcall *stmt1;
  gassign *stmt2;
  tree tree_uid, cur_func, void0;

  if (c_node->only_called_directly_p ())
    return;

  gimple_init_edge_profiler ();

  /* Insert code:

    stmt1: __gcov_indirect_call_profiler_v2 (profile_id,
					     &current_function_decl)
   */
  gsi = gsi_after_labels (split_edge (single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun))));

  cur_func = force_gimple_operand_gsi (&gsi,
				       build_addr (current_function_decl,
						   current_function_decl),
				       true, NULL_TREE,
				       true, GSI_SAME_STMT);
  tree_uid = build_int_cst
	      (gcov_type_node, cgraph_node::get (current_function_decl)->profile_id);
  /* Workaround for binutils bug 14342.  Once it is fixed, remove lto path.  */
  if (flag_lto)
    {
      tree counter_ptr, ptr_var;
      counter_ptr = force_gimple_operand_gsi (&gsi, ic_gcov_type_ptr_var,
					      true, NULL_TREE, true,
					      GSI_SAME_STMT);
      ptr_var = force_gimple_operand_gsi (&gsi, ic_void_ptr_var,
					  true, NULL_TREE, true,
					  GSI_SAME_STMT);

      stmt1 = gimple_build_call (tree_indirect_call_profiler_fn, 4,
				 counter_ptr, tree_uid, cur_func, ptr_var);
    }
  else
    {
      stmt1 = gimple_build_call (tree_indirect_call_profiler_fn, 2,
				 tree_uid, cur_func);
    }
  gsi_insert_before (&gsi, stmt1, GSI_SAME_STMT);

  /* Set __gcov_indirect_call_callee to 0,
     so that calls from other modules won't get misattributed
     to the last caller of the current callee. */
  void0 = build_int_cst (build_pointer_type (void_type_node), 0);
  stmt2 = gimple_build_assign (ic_void_ptr_var, void0);
  gsi_insert_before (&gsi, stmt2, GSI_SAME_STMT);
}
Example #3
0
static void
emit_mfence_after_loop (struct loop *loop)
{
  VEC (edge, heap) *exits = get_loop_exit_edges (loop);
  edge exit;
  gimple call;
  gimple_stmt_iterator bsi;
  unsigned i;

  for (i = 0; VEC_iterate (edge, exits, i, exit); i++)
    {
      call = gimple_build_call (FENCE_FOLLOWING_MOVNT, 0);

      if (!single_pred_p (exit->dest)
	  /* If possible, we prefer not to insert the fence on other paths
	     in cfg.  */
	  && !(exit->flags & EDGE_ABNORMAL))
	split_loop_exit_edge (exit);
      bsi = gsi_after_labels (exit->dest);

      gsi_insert_before (&bsi, call, GSI_NEW_STMT);
      mark_virtual_ops_for_renaming (call);
    }

  VEC_free (edge, heap, exits);
  update_ssa (TODO_update_ssa_only_virtuals);
}
Example #4
0
tree
maybe_push_res_to_seq (code_helper rcode, tree type, tree *ops,
		       gimple_seq *seq, tree res)
{
  if (rcode.is_tree_code ())
    {
      if (!res
	  && (TREE_CODE_LENGTH ((tree_code) rcode) == 0
	      || ((tree_code) rcode) == ADDR_EXPR)
	  && is_gimple_val (ops[0]))
	return ops[0];
      if (!seq)
	return NULL_TREE;
      /* Play safe and do not allow abnormals to be mentioned in
         newly created statements.  */
      if ((TREE_CODE (ops[0]) == SSA_NAME
	   && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[0]))
	  || (ops[1]
	      && TREE_CODE (ops[1]) == SSA_NAME
	      && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[1]))
	  || (ops[2]
	      && TREE_CODE (ops[2]) == SSA_NAME
	      && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[2])))
	return NULL_TREE;
      if (!res)
	res = make_ssa_name (type, NULL);
      maybe_build_generic_op (rcode, type, &ops[0], ops[1], ops[2]);
      gimple new_stmt = gimple_build_assign_with_ops (rcode, res,
						      ops[0], ops[1], ops[2]);
      gimple_seq_add_stmt_without_update (seq, new_stmt);
      return res;
    }
  else
    {
      if (!seq)
	return NULL_TREE;
      tree decl = builtin_decl_implicit (rcode);
      if (!decl)
	return NULL_TREE;
      unsigned nargs = type_num_arguments (TREE_TYPE (decl));
      gcc_assert (nargs <= 3);
      /* Play safe and do not allow abnormals to be mentioned in
         newly created statements.  */
      if ((TREE_CODE (ops[0]) == SSA_NAME
	   && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[0]))
	  || (nargs >= 2
	      && TREE_CODE (ops[1]) == SSA_NAME
	      && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[1]))
	  || (nargs == 3
	      && TREE_CODE (ops[2]) == SSA_NAME
	      && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[2])))
	return NULL_TREE;
      if (!res)
	res = make_ssa_name (type, NULL);
      gimple new_stmt = gimple_build_call (decl, nargs, ops[0], ops[1], ops[2]);
      gimple_call_set_lhs (new_stmt, res);
      gimple_seq_add_stmt_without_update (seq, new_stmt);
      return res;
    }
}
Example #5
0
gimple *
omp_build_barrier (tree lhs)
{
  tree fndecl = builtin_decl_explicit (lhs ? BUILT_IN_GOMP_BARRIER_CANCEL
					   : BUILT_IN_GOMP_BARRIER);
  gcall *g = gimple_build_call (fndecl, 0);
  if (lhs)
    gimple_call_set_lhs (g, lhs);
  return g;
}
Example #6
0
void
gimple_gen_time_profiler (unsigned tag, unsigned base,
                          gimple_stmt_iterator &gsi)
{
  tree ref_ptr = tree_coverage_counter_addr (tag, base);
  gcall *call;

  ref_ptr = force_gimple_operand_gsi (&gsi, ref_ptr,
				      true, NULL_TREE, true, GSI_SAME_STMT);
  call = gimple_build_call (tree_time_profiler_fn, 1, ref_ptr);
  gsi_insert_before (&gsi, call, GSI_NEW_STMT);
}
Example #7
0
static bool
remove_exits_and_undefined_stmts (struct loop *loop, unsigned int npeeled)
{
  struct nb_iter_bound *elt;
  bool changed = false;

  for (elt = loop->bounds; elt; elt = elt->next)
    {
      /* If statement is known to be undefined after peeling, turn it
	 into unreachable (or trap when debugging experience is supposed
	 to be good).  */
      if (!elt->is_exit
	  && wi::ltu_p (elt->bound, npeeled))
	{
	  gimple_stmt_iterator gsi = gsi_for_stmt (elt->stmt);
	  gcall *stmt = gimple_build_call
	      (builtin_decl_implicit (BUILT_IN_UNREACHABLE), 0);
	  gimple_set_location (stmt, gimple_location (elt->stmt));
	  gsi_insert_before (&gsi, stmt, GSI_NEW_STMT);
	  split_block (gimple_bb (stmt), stmt);
	  changed = true;
	  if (dump_file && (dump_flags & TDF_DETAILS))
	    {
	      fprintf (dump_file, "Forced statement unreachable: ");
	      print_gimple_stmt (dump_file, elt->stmt, 0, 0);
	    }
	}
      /* If we know the exit will be taken after peeling, update.  */
      else if (elt->is_exit
	       && wi::leu_p (elt->bound, npeeled))
	{
	  basic_block bb = gimple_bb (elt->stmt);
	  edge exit_edge = EDGE_SUCC (bb, 0);

	  if (dump_file && (dump_flags & TDF_DETAILS))
	    {
	      fprintf (dump_file, "Forced exit to be taken: ");
	      print_gimple_stmt (dump_file, elt->stmt, 0, 0);
	    }
	  if (!loop_exit_edge_p (loop, exit_edge))
	    exit_edge = EDGE_SUCC (bb, 1);
	  gcc_checking_assert (loop_exit_edge_p (loop, exit_edge));
	  gcond *cond_stmt = as_a <gcond *> (elt->stmt);
	  if (exit_edge->flags & EDGE_TRUE_VALUE)
	    gimple_cond_make_true (cond_stmt);
	  else
	    gimple_cond_make_false (cond_stmt);
	  update_stmt (cond_stmt);
	  changed = true;
	}
    }
  return changed;
}
static void
insert_trap_and_remove_trailing_statements (gimple_stmt_iterator *si_p, tree op)
{
  /* We want the NULL pointer dereference to actually occur so that
     code that wishes to catch the signal can do so.

     If the dereference is a load, then there's nothing to do as the
     LHS will be a throw-away SSA_NAME and the RHS is the NULL dereference.

     If the dereference is a store and we can easily transform the RHS,
     then simplify the RHS to enable more DCE.   Note that we require the
     statement to be a GIMPLE_ASSIGN which filters out calls on the RHS.  */
  gimple stmt = gsi_stmt (*si_p);
  if (walk_stmt_load_store_ops (stmt, (void *)op, NULL, check_loadstore)
      && is_gimple_assign (stmt)
      && INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_lhs (stmt))))
    {
      /* We just need to turn the RHS into zero converted to the proper
         type.  */
      tree type = TREE_TYPE (gimple_assign_lhs (stmt));
      gimple_assign_set_rhs_code (stmt, INTEGER_CST);
      gimple_assign_set_rhs1 (stmt, fold_convert (type, integer_zero_node));
      update_stmt (stmt);
    }

  gimple new_stmt
    = gimple_build_call (builtin_decl_explicit (BUILT_IN_TRAP), 0);
  gimple_seq seq = NULL;
  gimple_seq_add_stmt (&seq, new_stmt);

  /* If we had a NULL pointer dereference, then we want to insert the
     __builtin_trap after the statement, for the other cases we want
     to insert before the statement.  */
  if (walk_stmt_load_store_ops (stmt, (void *)op,
			        check_loadstore,
				check_loadstore))
    gsi_insert_after (si_p, seq, GSI_NEW_STMT);
  else
    gsi_insert_before (si_p, seq, GSI_NEW_STMT);

  /* We must remove statements from the end of the block so that we
     never reference a released SSA_NAME.  */
  basic_block bb = gimple_bb (gsi_stmt (*si_p));
  for (gimple_stmt_iterator si = gsi_last_bb (bb);
       gsi_stmt (si) != gsi_stmt (*si_p);
       si = gsi_last_bb (bb))
    {
      stmt = gsi_stmt (si);
      unlink_stmt_vdef (stmt);
      gsi_remove (&si, true);
      release_defs (stmt);
    }
}
Example #9
0
static void handle_task_call
(gimple_stmt_iterator gsi, const tracked_func_t* tf)
{
    /* iterator points to the call instruction */

    /* . generate the following statement list:
       generate type T;
       declare T* var;
       var = call __xkaapi_pushdata(sizeof(T));
       foreach args, var->member = local_value;
       call __xkaapi_pushtask();
       call __xkaapi_barrier();
     */

    tree dummy_adapter;
    tree sp;
    tree thread;
    gimple_seq stmts;
    gimple call;

    init_decls();

    /* kaapi_pushdata_aligned */
    gen_alloca_stmts(&stmts, &sp);
    gsi_insert_seq_before(&gsi, stmts, GSI_SAME_STMT);
    /* fixme: gimple_seq_free(alloca_stmts); */

    /* generate the adapter routine */
    /* dummy_adapter = create_dummy_adapter(); */

    /* kaapi_pushtask(self_thread, sp); */
    thread = build_int_cst(ptr_type_node, 0xdeadc0c0);
    call = gimple_build_call(kaapi_pushtask_decl, 2, sp, thread);
    gsi_insert_before(&gsi, call, GSI_SAME_STMT);

    /* kaapi_barrier(); */
    call = gimple_build_call(kaapi_barrier_decl, 0);
    gsi_replace(&gsi, call, true);
}
Example #10
0
static void insert_call(gimple stmt, tree decl)
{
    gimple call;
    gimple_stmt_iterator gsi;

    /* Call the function */
    call = gimple_build_call(decl, 0);
    gsi = gsi_for_stmt(stmt);
    gsi_insert_before(&gsi, call, GSI_NEW_STMT);

    /* So we don't process this bad-boy */
    VEC_safe_push(tree, gc, analyized_fns, decl);
}
Example #11
0
void
gimple_gen_ior_profiler (histogram_value value, unsigned tag, unsigned base)
{
  gimple stmt = value->hvalue.stmt;
  gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
  tree ref_ptr = tree_coverage_counter_addr (tag, base);
  gcall *call;
  tree val;

  ref_ptr = force_gimple_operand_gsi (&gsi, ref_ptr,
				      true, NULL_TREE, true, GSI_SAME_STMT);
  val = prepare_instrumented_value (&gsi, value);
  call = gimple_build_call (tree_ior_profiler_fn, 2, ref_ptr, val);
  gsi_insert_before (&gsi, call, GSI_NEW_STMT);
}
Example #12
0
static void
unloop_loops (bitmap loop_closed_ssa_invalidated,
	      bool *irred_invalidated)
{
  while (loops_to_unloop.length ())
    {
      struct loop *loop = loops_to_unloop.pop ();
      int n_unroll = loops_to_unloop_nunroll.pop ();
      basic_block latch = loop->latch;
      edge latch_edge = loop_latch_edge (loop);
      int flags = latch_edge->flags;
      location_t locus = latch_edge->goto_locus;
      gcall *stmt;
      gimple_stmt_iterator gsi;

      remove_exits_and_undefined_stmts (loop, n_unroll);

      /* Unloop destroys the latch edge.  */
      unloop (loop, irred_invalidated, loop_closed_ssa_invalidated);

      /* Create new basic block for the latch edge destination and wire
	 it in.  */
      stmt = gimple_build_call (builtin_decl_implicit (BUILT_IN_UNREACHABLE), 0);
      latch_edge = make_edge (latch, create_basic_block (NULL, NULL, latch), flags);
      latch_edge->probability = 0;
      latch_edge->count = 0;
      latch_edge->flags |= flags;
      latch_edge->goto_locus = locus;

      latch_edge->dest->loop_father = current_loops->tree_root;
      latch_edge->dest->count = 0;
      latch_edge->dest->frequency = 0;
      set_immediate_dominator (CDI_DOMINATORS, latch_edge->dest, latch_edge->src);

      gsi = gsi_start_bb (latch_edge->dest);
      gsi_insert_after (&gsi, stmt, GSI_NEW_STMT);
    }
  loops_to_unloop.release ();
  loops_to_unloop_nunroll.release ();

  /* Remove edges in peeled copies.  */
  unsigned i;
  edge e;
  FOR_EACH_VEC_ELT (edges_to_remove, i, e)
    {
      bool ok = remove_path (e);
      gcc_assert (ok);
    }
Example #13
0
static void
generate_memset_zero (gimple stmt, tree op0, tree nb_iter,
		      gimple_stmt_iterator bsi)
{
  tree addr_base, nb_bytes;
  bool res = false;
  gimple_seq stmt_list = NULL, stmts;
  gimple fn_call;
  tree mem, fn;
  struct data_reference *dr = XCNEW (struct data_reference);
  location_t loc = gimple_location (stmt);

  DR_STMT (dr) = stmt;
  DR_REF (dr) = op0;
  res = dr_analyze_innermost (dr);
  gcc_assert (res && stride_of_unit_type_p (DR_STEP (dr), TREE_TYPE (op0)));

  nb_bytes = build_size_arg_loc (loc, nb_iter, op0, &stmt_list);
  addr_base = size_binop_loc (loc, PLUS_EXPR, DR_OFFSET (dr), DR_INIT (dr));
  addr_base = fold_convert_loc (loc, sizetype, addr_base);

  /* Test for a negative stride, iterating over every element.  */
  if (integer_zerop (size_binop (PLUS_EXPR,
				 TYPE_SIZE_UNIT (TREE_TYPE (op0)),
				 fold_convert (sizetype, DR_STEP (dr)))))
    {
      addr_base = size_binop_loc (loc, MINUS_EXPR, addr_base,
				  fold_convert_loc (loc, sizetype, nb_bytes));
      addr_base = size_binop_loc (loc, PLUS_EXPR, addr_base,
				  TYPE_SIZE_UNIT (TREE_TYPE (op0)));
    }

  addr_base = fold_build2_loc (loc, POINTER_PLUS_EXPR,
			       TREE_TYPE (DR_BASE_ADDRESS (dr)),
			       DR_BASE_ADDRESS (dr), addr_base);
  mem = force_gimple_operand (addr_base, &stmts, true, NULL);
  gimple_seq_add_seq (&stmt_list, stmts);

  fn = build_fold_addr_expr (implicit_built_in_decls [BUILT_IN_MEMSET]);
  fn_call = gimple_build_call (fn, 3, mem, integer_zero_node, nb_bytes);
  gimple_seq_add_stmt (&stmt_list, fn_call);
  gsi_insert_seq_after (&bsi, stmt_list, GSI_CONTINUE_LINKING);

  if (dump_file && (dump_flags & TDF_DETAILS))
    fprintf (dump_file, "generated memset zero\n");

  free_data_ref (dr);
}
// create the function call to a `record_assignment' function and insert it
// before the given statement
static void insert_instrumentation_fn(gimple curr_stmt, tree var_id,
                                      tree new_value)
{
    // build function declaration
    tree proto = build_function_type_list(
                     void_type_node,      /* return type */
                     integer_type_node,   /* first arg's type */
                     const_ptr_type_node, /* second arg's type */
                     NULL_TREE);
    tree decl = build_fn_decl("record_assignment", proto);

    // build the function call with the new value tree and the variable id tree
    // and insert it before the statement that was passed as the first argument
    gimple call = gimple_build_call(decl, 2, var_id, new_value);
    gimple_stmt_iterator gsi = gsi_for_stmt(curr_stmt);
    gsi_insert_before(&gsi, call, GSI_NEW_STMT);
}
void
gimple_gen_ic_func_profiler (void)
{
  struct cgraph_node * c_node = cgraph_get_node (current_function_decl);
  gimple_stmt_iterator gsi;
  gimple stmt1, stmt2;
  tree tree_uid, cur_func, counter_ptr, ptr_var, void0;

  if (cgraph_only_called_directly_p (c_node))
    return;

  gimple_init_edge_profiler ();

  /* Insert code:

    stmt1: __gcov_indirect_call_profiler (__gcov_indirect_call_counters,
					  current_function_funcdef_no,
					  &current_function_decl,
					  __gcov_indirect_call_callee);
   */
  gsi = gsi_after_labels (single_succ (ENTRY_BLOCK_PTR));

  cur_func = force_gimple_operand_gsi (&gsi,
				       build_addr (current_function_decl,
						   current_function_decl),
				       true, NULL_TREE,
				       true, GSI_SAME_STMT);
  counter_ptr = force_gimple_operand_gsi (&gsi, ic_gcov_type_ptr_var,
					  true, NULL_TREE, true,
					  GSI_SAME_STMT);
  ptr_var = force_gimple_operand_gsi (&gsi, ic_void_ptr_var,
				      true, NULL_TREE, true,
				      GSI_SAME_STMT);
  tree_uid = build_int_cst (gcov_type_node, current_function_funcdef_no);
  stmt1 = gimple_build_call (tree_indirect_call_profiler_fn, 4,
			     counter_ptr, tree_uid, cur_func, ptr_var);
  gsi_insert_before (&gsi, stmt1, GSI_SAME_STMT);

  /* Set __gcov_indirect_call_callee to 0,
     so that calls from other modules won't get misattributed
     to the last caller of the current callee. */
  void0 = build_int_cst (build_pointer_type (void_type_node), 0);
  stmt2 = gimple_build_assign (ic_void_ptr_var, void0);
  gsi_insert_before (&gsi, stmt2, GSI_SAME_STMT);
}
Example #16
0
void
gimple_gen_edge_profiler (int edgeno, edge e)
{
  tree ref, one;
  gimple stmt1, stmt2, stmt3;

  /* We share one temporary variable declaration per function.  This
     gets re-set in tree_profiling.  */
  if (gcov_type_tmp_var == NULL_TREE)
    gcov_type_tmp_var = create_tmp_reg (gcov_type_node, "PROF_edge_counter");

  if (PROFILE_GEN_EDGE_ATOMIC)
    ref = tree_coverage_counter_addr (GCOV_COUNTER_ARCS, edgeno);
  else
    ref = tree_coverage_counter_ref (GCOV_COUNTER_ARCS, edgeno);

  one = build_int_cst (gcov_type_node, 1);
  if (PROFILE_GEN_EDGE_ATOMIC)
    {
      /* __atomic_fetch_add (&counter, 1, MEMMODEL_RELAXED); */
      stmt3 = gimple_build_call (builtin_decl_explicit (
                                   GCOV_TYPE_ATOMIC_FETCH_ADD),
                                 3, ref, one,
                                 build_int_cst (integer_type_node,
                                   MEMMODEL_RELAXED));
      find_referenced_vars_in (stmt3);
    }
  else
    {
      stmt1 = gimple_build_assign (gcov_type_tmp_var, ref);
      gimple_assign_set_lhs (stmt1, make_ssa_name (gcov_type_tmp_var, stmt1));
      find_referenced_vars_in (stmt1);
      stmt2 = gimple_build_assign_with_ops (PLUS_EXPR, gcov_type_tmp_var,
            				gimple_assign_lhs (stmt1), one);
      gimple_assign_set_lhs (stmt2, make_ssa_name (gcov_type_tmp_var, stmt2));
      stmt3 = gimple_build_assign (unshare_expr (ref), gimple_assign_lhs (stmt2));

      gsi_insert_on_edge (e, stmt1);
      gsi_insert_on_edge (e, stmt2);
    }
   gsi_insert_on_edge (e, stmt3);
} 
Example #17
0
static void stackleak_add_instrumentation(gimple_stmt_iterator *gsi)
{
	gimple stmt;
	gcall *track_stack;
	cgraph_node_ptr node;
	int frequency;
	basic_block bb;

	// insert call to void pax_track_stack(void)
	stmt = gimple_build_call(track_function_decl, 0);
	track_stack = as_a_gcall(stmt);
	gsi_insert_after(gsi, track_stack, GSI_CONTINUE_LINKING);

	// update the cgraph
	bb = gimple_bb(track_stack);
	node = cgraph_get_create_node(track_function_decl);
	gcc_assert(node);
	frequency = compute_call_stmt_bb_frequency(current_function_decl, bb);
	cgraph_create_edge(cgraph_get_node(current_function_decl), node, track_stack, bb->count, frequency, bb->loop_depth);
}
static void
lower_builtin_posix_memalign (gimple_stmt_iterator *gsi)
{
  gimple stmt, call = gsi_stmt (*gsi);
  tree pptr = gimple_call_arg (call, 0);
  tree align = gimple_call_arg (call, 1);
  tree res = gimple_call_lhs (call);
  tree ptr = create_tmp_reg (ptr_type_node, NULL);
  if (TREE_CODE (pptr) == ADDR_EXPR)
    {
      tree tem = create_tmp_var (ptr_type_node, NULL);
      TREE_ADDRESSABLE (tem) = 1;
      gimple_call_set_arg (call, 0, build_fold_addr_expr (tem));
      stmt = gimple_build_assign (ptr, tem);
    }
  else
    stmt = gimple_build_assign (ptr,
				fold_build2 (MEM_REF, ptr_type_node, pptr,
					     build_int_cst (ptr_type_node, 0)));
  if (res == NULL_TREE)
    {
      res = create_tmp_reg (integer_type_node, NULL);
      gimple_call_set_lhs (call, res);
    }
  tree align_label = create_artificial_label (UNKNOWN_LOCATION);
  tree noalign_label = create_artificial_label (UNKNOWN_LOCATION);
  gimple cond = gimple_build_cond (EQ_EXPR, res, integer_zero_node,
				   align_label, noalign_label);
  gsi_insert_after (gsi, cond, GSI_NEW_STMT);
  gsi_insert_after (gsi, gimple_build_label (align_label), GSI_NEW_STMT);
  gsi_insert_after (gsi, stmt, GSI_NEW_STMT);
  stmt = gimple_build_call (builtin_decl_implicit (BUILT_IN_ASSUME_ALIGNED),
			    2, ptr, align);
  gimple_call_set_lhs (stmt, ptr);
  gsi_insert_after (gsi, stmt, GSI_NEW_STMT);
  stmt = gimple_build_assign (fold_build2 (MEM_REF, ptr_type_node, pptr,
					   build_int_cst (ptr_type_node, 0)),
			      ptr);
  gsi_insert_after (gsi, stmt, GSI_NEW_STMT);
  gsi_insert_after (gsi, gimple_build_label (noalign_label), GSI_NEW_STMT);
}
Example #19
0
void
gimple_gen_interval_profiler (histogram_value value, unsigned tag, unsigned base)
{
  gimple stmt = value->hvalue.stmt;
  gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
  tree ref = tree_coverage_counter_ref (tag, base), ref_ptr;
  gcall *call;
  tree val;
  tree start = build_int_cst_type (integer_type_node,
				   value->hdata.intvl.int_start);
  tree steps = build_int_cst_type (unsigned_type_node,
				   value->hdata.intvl.steps);

  ref_ptr = force_gimple_operand_gsi (&gsi,
				      build_addr (ref, current_function_decl),
				      true, NULL_TREE, true, GSI_SAME_STMT);
  val = prepare_instrumented_value (&gsi, value);
  call = gimple_build_call (tree_interval_profiler_fn, 4,
			    ref_ptr, val, start, steps);
  gsi_insert_before (&gsi, call, GSI_NEW_STMT);
}
Example #20
0
static void
issue_prefetch_ref (struct mem_ref *ref, unsigned unroll_factor, unsigned ahead)
{
  HOST_WIDE_INT delta;
  tree addr, addr_base, write_p, local;
  gimple prefetch;
  gimple_stmt_iterator bsi;
  unsigned n_prefetches, ap;
  bool nontemporal = ref->reuse_distance >= L2_CACHE_SIZE_BYTES;

  if (dump_file && (dump_flags & TDF_DETAILS))
    fprintf (dump_file, "Issued%s prefetch for %p.\n",
	     nontemporal ? " nontemporal" : "",
	     (void *) ref);

  bsi = gsi_for_stmt (ref->stmt);

  n_prefetches = ((unroll_factor + ref->prefetch_mod - 1)
		  / ref->prefetch_mod);
  addr_base = build_fold_addr_expr_with_type (ref->mem, ptr_type_node);
  addr_base = force_gimple_operand_gsi (&bsi, unshare_expr (addr_base),
					true, NULL, true, GSI_SAME_STMT);
  write_p = ref->write_p ? integer_one_node : integer_zero_node;
  local = build_int_cst (integer_type_node, nontemporal ? 0 : 3);

  for (ap = 0; ap < n_prefetches; ap++)
    {
      /* Determine the address to prefetch.  */
      delta = (ahead + ap * ref->prefetch_mod) * ref->group->step;
      addr = fold_build2 (POINTER_PLUS_EXPR, ptr_type_node,
			  addr_base, size_int (delta));
      addr = force_gimple_operand_gsi (&bsi, unshare_expr (addr), true, NULL,
				       true, GSI_SAME_STMT);

      /* Create the prefetch instruction.  */
      prefetch = gimple_build_call (built_in_decls[BUILT_IN_PREFETCH],
				    3, addr, write_p, local);
      gsi_insert_before (&bsi, prefetch, GSI_SAME_STMT);
    }
}
Example #21
0
static void stackleak_check_alloca(gimple_stmt_iterator *gsi)
{
	gimple stmt;
	gcall *check_alloca;
	tree alloca_size;
	cgraph_node_ptr node;
	int frequency;
	basic_block bb;

	// insert call to void pax_check_alloca(unsigned long size)
	alloca_size = gimple_call_arg(gsi_stmt(*gsi), 0);
	stmt = gimple_build_call(check_function_decl, 1, alloca_size);
	check_alloca = as_a_gcall(stmt);
	gsi_insert_before(gsi, check_alloca, GSI_SAME_STMT);

	// update the cgraph
	bb = gimple_bb(check_alloca);
	node = cgraph_get_create_node(check_function_decl);
	gcc_assert(node);
	frequency = compute_call_stmt_bb_frequency(current_function_decl, bb);
	cgraph_create_edge(cgraph_get_node(current_function_decl), node, check_alloca, bb->count, frequency, bb->loop_depth);
}
Example #22
0
static unsigned int sancov_execute(void)
{
	basic_block bb;

	/* Remove this line when this plugin and kcov will be in the kernel.
	if (!strcmp(DECL_NAME_POINTER(current_function_decl), DECL_NAME_POINTER(sancov_fndecl)))
		return 0;
	*/

	FOR_EACH_BB_FN(bb, cfun) {
		const_gimple stmt;
		gcall *gcall;
		gimple_stmt_iterator gsi = gsi_after_labels(bb);

		if (gsi_end_p(gsi))
			continue;

		stmt = gsi_stmt(gsi);
		gcall = as_a_gcall(gimple_build_call(sancov_fndecl, 0));
		gimple_set_location(gcall, gimple_location(stmt));
		gsi_insert_before(&gsi, gcall, GSI_SAME_STMT);
	}
Example #23
0
/* Insert a call to the runtime function "__slimer_add_fn" which will add the
 * "junk" function created at compile-time to an array at runtime
 */
static void insert_add_fn(gimple stmt, int index)
{
    tree fn;
    gimple call;
    gimple_stmt_iterator gsi;
    static tree decl, proto, idx;

    if (!decl || !proto)
    {
        proto = build_function_type_list(void_type_node, ptr_type_node,
                                         integer_type_node, NULL_TREE);
        decl = build_fn_decl("__slimer_add_fn", proto);
    
        /* Add this fndecl to our list of things we do not process */
        VEC_safe_push(tree, gc, analyized_fns, decl);
    }

    /* Create a constant value and pointer to the function we are to add */
    idx = build_int_cst(integer_type_node, index);
    fn = build_addr(VEC_index(tree, fakes, index), NULL_TREE);
    call = gimple_build_call(decl, 2, fn, idx);
    gsi = gsi_for_stmt(stmt);
    gsi_insert_before(&gsi, call, GSI_NEW_STMT);
}
Example #24
0
static void
mf_build_check_statement_for (tree base, tree limit,
                              gimple_stmt_iterator *instr_gsi,
                              location_t location, tree dirflag)
{
  gimple_stmt_iterator gsi;
  basic_block cond_bb, then_bb, join_bb;
  edge e;
  tree cond, t, u, v;
  tree mf_base;
  tree mf_elem;
  tree mf_limit;
  gimple g;
  gimple_seq seq, stmts;

  /* We first need to split the current basic block, and start altering
     the CFG.  This allows us to insert the statements we're about to
     construct into the right basic blocks.  */

  cond_bb = gimple_bb (gsi_stmt (*instr_gsi));
  gsi = *instr_gsi;
  gsi_prev (&gsi);
  if (! gsi_end_p (gsi))
    e = split_block (cond_bb, gsi_stmt (gsi));
  else
    e = split_block_after_labels (cond_bb);
  cond_bb = e->src;
  join_bb = e->dest;

  /* A recap at this point: join_bb is the basic block at whose head
     is the gimple statement for which this check expression is being
     built.  cond_bb is the (possibly new, synthetic) basic block the
     end of which will contain the cache-lookup code, and a
     conditional that jumps to the cache-miss code or, much more
     likely, over to join_bb.  */

  /* Create the bb that contains the cache-miss fallback block (mf_check).  */
  then_bb = create_empty_bb (cond_bb);
  make_edge (cond_bb, then_bb, EDGE_TRUE_VALUE);
  make_single_succ_edge (then_bb, join_bb, EDGE_FALLTHRU);

  /* Mark the pseudo-fallthrough edge from cond_bb to join_bb.  */
  e = find_edge (cond_bb, join_bb);
  e->flags = EDGE_FALSE_VALUE;
  e->count = cond_bb->count;
  e->probability = REG_BR_PROB_BASE;

  /* Update dominance info.  Note that bb_join's data was
     updated by split_block.  */
  if (dom_info_available_p (CDI_DOMINATORS))
    {
      set_immediate_dominator (CDI_DOMINATORS, then_bb, cond_bb);
      set_immediate_dominator (CDI_DOMINATORS, join_bb, cond_bb);
    }

  /* Update loop info.  */
  if (current_loops)
    add_bb_to_loop (then_bb, cond_bb->loop_father);

  /* Build our local variables.  */
  mf_elem = create_tmp_reg (mf_cache_structptr_type, "__mf_elem");
  mf_base = create_tmp_reg (mf_uintptr_type, "__mf_base");
  mf_limit = create_tmp_reg (mf_uintptr_type, "__mf_limit");

  /* Build: __mf_base = (uintptr_t) <base address expression>.  */
  seq = NULL;
  t = fold_convert_loc (location, mf_uintptr_type,
			unshare_expr (base));
  t = force_gimple_operand (t, &stmts, false, NULL_TREE);
  gimple_seq_add_seq (&seq, stmts);
  g = gimple_build_assign (mf_base, t);
  gimple_set_location (g, location);
  gimple_seq_add_stmt (&seq, g);

  /* Build: __mf_limit = (uintptr_t) <limit address expression>.  */
  t = fold_convert_loc (location, mf_uintptr_type,
			unshare_expr (limit));
  t = force_gimple_operand (t, &stmts, false, NULL_TREE);
  gimple_seq_add_seq (&seq, stmts);
  g = gimple_build_assign (mf_limit, t);
  gimple_set_location (g, location);
  gimple_seq_add_stmt (&seq, g);

  /* Build: __mf_elem = &__mf_lookup_cache [(__mf_base >> __mf_shift)
                                            & __mf_mask].  */
  t = build2 (RSHIFT_EXPR, mf_uintptr_type, mf_base,
              flag_mudflap_threads ? mf_cache_shift_decl
	       : mf_cache_shift_decl_l);
  t = build2 (BIT_AND_EXPR, mf_uintptr_type, t,
              flag_mudflap_threads ? mf_cache_mask_decl
	       : mf_cache_mask_decl_l);
  t = build4 (ARRAY_REF,
              TREE_TYPE (TREE_TYPE (mf_cache_array_decl)),
              mf_cache_array_decl, t, NULL_TREE, NULL_TREE);
  t = build1 (ADDR_EXPR, mf_cache_structptr_type, t);
  t = force_gimple_operand (t, &stmts, false, NULL_TREE);
  gimple_seq_add_seq (&seq, stmts);
  g = gimple_build_assign (mf_elem, t);
  gimple_set_location (g, location);
  gimple_seq_add_stmt (&seq, g);

  /* Quick validity check.

     if (__mf_elem->low > __mf_base
         || (__mf_elem_high < __mf_limit))
        {
          __mf_check ();
          ... and only if single-threaded:
          __mf_lookup_shift_1 = f...;
          __mf_lookup_mask_l = ...;
        }

     It is expected that this body of code is rarely executed so we mark
     the edge to the THEN clause of the conditional jump as unlikely.  */

  /* Construct t <-- '__mf_elem->low  > __mf_base'.  */
  t = build3 (COMPONENT_REF, mf_uintptr_type,
              build1 (INDIRECT_REF, mf_cache_struct_type, mf_elem),
              TYPE_FIELDS (mf_cache_struct_type), NULL_TREE);
  t = build2 (GT_EXPR, boolean_type_node, t, mf_base);

  /* Construct '__mf_elem->high < __mf_limit'.

     First build:
        1) u <--  '__mf_elem->high'
        2) v <--  '__mf_limit'.

     Then build 'u <-- (u < v).  */

  u = build3 (COMPONENT_REF, mf_uintptr_type,
              build1 (INDIRECT_REF, mf_cache_struct_type, mf_elem),
              DECL_CHAIN (TYPE_FIELDS (mf_cache_struct_type)), NULL_TREE);

  v = mf_limit;

  u = build2 (LT_EXPR, boolean_type_node, u, v);

  /* Build the composed conditional: t <-- 't || u'.  Then store the
     result of the evaluation of 't' in a temporary variable which we
     can use as the condition for the conditional jump.  */
  t = build2 (TRUTH_OR_EXPR, boolean_type_node, t, u);
  t = force_gimple_operand (t, &stmts, false, NULL_TREE);
  gimple_seq_add_seq (&seq, stmts);
  cond = create_tmp_reg (boolean_type_node, "__mf_unlikely_cond");
  g = gimple_build_assign  (cond, t);
  gimple_set_location (g, location);
  gimple_seq_add_stmt (&seq, g);

  /* Build the conditional jump.  'cond' is just a temporary so we can
     simply build a void COND_EXPR.  We do need labels in both arms though.  */
  g = gimple_build_cond (NE_EXPR, cond, boolean_false_node, NULL_TREE,
			 NULL_TREE);
  gimple_set_location (g, location);
  gimple_seq_add_stmt (&seq, g);

  /* At this point, after so much hard work, we have only constructed
     the conditional jump,

     if (__mf_elem->low > __mf_base
         || (__mf_elem_high < __mf_limit))

     The lowered GIMPLE tree representing this code is in the statement
     list starting at 'head'.

     We can insert this now in the current basic block, i.e. the one that
     the statement we're instrumenting was originally in.  */
  gsi = gsi_last_bb (cond_bb);
  gsi_insert_seq_after (&gsi, seq, GSI_CONTINUE_LINKING);

  /*  Now build up the body of the cache-miss handling:

     __mf_check();
     refresh *_l vars.

     This is the body of the conditional.  */

  seq = NULL;
  /* u is a string, so it is already a gimple value.  */
  u = mf_file_function_line_tree (location);
  /* NB: we pass the overall [base..limit] range to mf_check.  */
  v = fold_build2_loc (location, PLUS_EXPR, mf_uintptr_type,
		   fold_build2_loc (location,
				MINUS_EXPR, mf_uintptr_type, mf_limit, mf_base),
		   build_int_cst (mf_uintptr_type, 1));
  v = force_gimple_operand (v, &stmts, true, NULL_TREE);
  gimple_seq_add_seq (&seq, stmts);
  g = gimple_build_call (mf_check_fndecl, 4, mf_base, v, dirflag, u);
  gimple_seq_add_stmt (&seq, g);

  if (! flag_mudflap_threads)
    {
      if (stmt_ends_bb_p (g))
	{
	  gsi = gsi_start_bb (then_bb);
	  gsi_insert_seq_after (&gsi, seq, GSI_CONTINUE_LINKING);
	  e = split_block (then_bb, g);
	  then_bb = e->dest;
	  seq = NULL;
	}

      g = gimple_build_assign (mf_cache_shift_decl_l, mf_cache_shift_decl);
      gimple_seq_add_stmt (&seq, g);

      g = gimple_build_assign (mf_cache_mask_decl_l, mf_cache_mask_decl);
      gimple_seq_add_stmt (&seq, g);
    }

  /* Insert the check code in the THEN block.  */
  gsi = gsi_start_bb (then_bb);
  gsi_insert_seq_after (&gsi, seq, GSI_CONTINUE_LINKING);

  *instr_gsi = gsi_start_bb (join_bb);
}
Example #25
0
/* Synthesize a CALL_EXPR and a TRY_FINALLY_EXPR, for this chain of
   _DECLs if appropriate.  Arrange to call the __mf_register function
   now, and the __mf_unregister function later for each.  Return the
   gimple sequence after synthesis.  */
gimple_seq
mx_register_decls (tree decl, gimple_seq seq, location_t location)
{
  gimple_seq finally_stmts = NULL;
  gimple_stmt_iterator initially_stmts = gsi_start (seq);

  while (decl != NULL_TREE)
    {
      if (mf_decl_eligible_p (decl)
          /* Not already processed.  */
          && ! mf_marked_p (decl)
          /* Automatic variable.  */
          && ! DECL_EXTERNAL (decl)
          && ! TREE_STATIC (decl))
        {
          tree size = NULL_TREE, variable_name;
          gimple unregister_fncall, register_fncall;
	  tree unregister_fncall_param, register_fncall_param;

	  /* Variable-sized objects should have sizes already been
	     gimplified when we got here. */
	  size = fold_convert (size_type_node,
			       TYPE_SIZE_UNIT (TREE_TYPE (decl)));
	  gcc_assert (is_gimple_val (size));


          unregister_fncall_param =
	    mf_mark (build1 (ADDR_EXPR,
			     build_pointer_type (TREE_TYPE (decl)),
			     decl));
          /* __mf_unregister (&VARIABLE, sizeof (VARIABLE), __MF_TYPE_STACK) */
          unregister_fncall = gimple_build_call (mf_unregister_fndecl, 3,
						 unregister_fncall_param,
						 size,
						 integer_three_node);


          variable_name = mf_varname_tree (decl);
          register_fncall_param =
	    mf_mark (build1 (ADDR_EXPR,
			     build_pointer_type (TREE_TYPE (decl)),
			     decl));
          /* __mf_register (&VARIABLE, sizeof (VARIABLE), __MF_TYPE_STACK,
	                    "name") */
	  register_fncall = gimple_build_call (mf_register_fndecl, 4,
					       register_fncall_param,
					       size,
					       integer_three_node,
					       variable_name);


          /* Accumulate the two calls.  */
	  gimple_set_location (register_fncall, location);
	  gimple_set_location (unregister_fncall, location);

          /* Add the __mf_register call at the current appending point.  */
          if (gsi_end_p (initially_stmts))
	    {
	      if (!mf_artificial (decl))
		warning (OPT_Wmudflap,
			 "mudflap cannot track %qE in stub function",
			 DECL_NAME (decl));
	    }
	  else
	    {
	      gsi_insert_before (&initially_stmts, register_fncall,
				 GSI_SAME_STMT);

	      /* Accumulate the FINALLY piece.  */
	      gimple_seq_add_stmt (&finally_stmts, unregister_fncall);
	    }
          mf_mark (decl);
        }

      decl = DECL_CHAIN (decl);
    }

  /* Actually, (initially_stmts!=NULL) <=> (finally_stmts!=NULL) */
  if (finally_stmts != NULL)
    {
      gimple stmt = gimple_build_try (seq, finally_stmts, GIMPLE_TRY_FINALLY);
      gimple_seq new_seq = NULL;

      gimple_seq_add_stmt (&new_seq, stmt);
      return new_seq;
    }
   else
    return seq;
}
Example #26
0
unsigned int
execute_fixup_cfg (void)
{
  basic_block bb;
  gimple_stmt_iterator gsi;
  int todo = gimple_in_ssa_p (cfun) ? TODO_verify_ssa : 0;
  gcov_type count_scale;
  edge e;
  edge_iterator ei;

  count_scale
      = GCOV_COMPUTE_SCALE (cgraph_get_node (current_function_decl)->count,
                            ENTRY_BLOCK_PTR->count);

  ENTRY_BLOCK_PTR->count = cgraph_get_node (current_function_decl)->count;
  EXIT_BLOCK_PTR->count = apply_scale (EXIT_BLOCK_PTR->count,
                                       count_scale);

  FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR->succs)
    e->count = apply_scale (e->count, count_scale);

  FOR_EACH_BB (bb)
    {
      bb->count = apply_scale (bb->count, count_scale);
      for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
	{
	  gimple stmt = gsi_stmt (gsi);
	  tree decl = is_gimple_call (stmt)
		      ? gimple_call_fndecl (stmt)
		      : NULL;
	  if (decl)
	    {
	      int flags = gimple_call_flags (stmt);
	      if (flags & (ECF_CONST | ECF_PURE | ECF_LOOPING_CONST_OR_PURE))
		{
		  if (gimple_purge_dead_abnormal_call_edges (bb))
		    todo |= TODO_cleanup_cfg;

		  if (gimple_in_ssa_p (cfun))
		    {
		      todo |= TODO_update_ssa | TODO_cleanup_cfg;
		      update_stmt (stmt);
		    }
		}

	      if (flags & ECF_NORETURN
		  && fixup_noreturn_call (stmt))
		todo |= TODO_cleanup_cfg;
	     }

	  if (maybe_clean_eh_stmt (stmt)
	      && gimple_purge_dead_eh_edges (bb))
	    todo |= TODO_cleanup_cfg;
	}

      FOR_EACH_EDGE (e, ei, bb->succs)
        e->count = apply_scale (e->count, count_scale);

      /* If we have a basic block with no successors that does not
	 end with a control statement or a noreturn call end it with
	 a call to __builtin_unreachable.  This situation can occur
	 when inlining a noreturn call that does in fact return.  */
      if (EDGE_COUNT (bb->succs) == 0)
	{
	  gimple stmt = last_stmt (bb);
	  if (!stmt
	      || (!is_ctrl_stmt (stmt)
		  && (!is_gimple_call (stmt)
		      || (gimple_call_flags (stmt) & ECF_NORETURN) == 0)))
	    {
	      stmt = gimple_build_call
		  (builtin_decl_implicit (BUILT_IN_UNREACHABLE), 0);
	      gimple_stmt_iterator gsi = gsi_last_bb (bb);
	      gsi_insert_after (&gsi, stmt, GSI_NEW_STMT);
	    }
	}
    }
  if (count_scale != REG_BR_PROB_BASE)
    compute_function_frequency ();

  /* We just processed all calls.  */
  if (cfun->gimple_df)
    vec_free (MODIFIED_NORETURN_CALLS (cfun));

  /* Dump a textual representation of the flowgraph.  */
  if (dump_file)
    gimple_dump_cfg (dump_file, dump_flags);

  if (current_loops
      && (todo & TODO_cleanup_cfg))
    loops_state_set (LOOPS_NEED_FIXUP);

  return todo;
}
Example #27
0
static void
my_dump_gimple(gimple gnode, gimple_stmt_iterator *ptrgsi)
{
    int gcode;
    tree tnode;
    tree funcdecl;
    tree desc_node;
    tree ptr_desc_node;
    tree t;
    tree tmp_var;
    tree const_char_restrict_ptr_type_node;
    gimple tmp_gstmt;
    gimple new_gnode;
    const char *hellocstr = "Hello, GCC!\n";
    int i;
    struct c_binding *b;
    expanded_location xloc;

    /*
     * Extract the Gimple Code from a gimple node
     */

    gcode = gimple_code(gnode);

    /*
     * Get the line number of cooresponding 
     * source code from a gimple node
     */
    if(gimple_has_location(gnode))
    {
        xloc = expand_location(gimple_location(gnode));
        printf("line %d:", xloc.line);
    }
    printf("\t\t\t\t%s\n", gimple_code_name[gcode]);
    
    switch(gcode)
    {
        case GIMPLE_ASSIGN:
            /*
             * Add a printf("Hello, GCC!\n"); statement 
             * after the first appearing assignment
             * if yes equals to 1, then we have already
             * added the statement, and no need to add 
             * again
             */
            if(!yes)
            {
                /*
                 * Since printf is a builtin function, we need
                 * to get the function declaration using 
                 * built_in_decls[]. The index number can be
                 * found in gcc source gcc/builtins.def
                 */
                funcdecl = built_in_decls[BUILT_IN_PRINTF];

                if(funcdecl == NULL_TREE)
                {
                    printf("cannot find printf\n");
                }
                else
                {
                    /*
                     * In gimple, every statement is simplified into 
                     * three oprands mode. And our printf() statement 
                     * is change into following two gimple statements:
                     * 
                     * <D.XXX> = (const char * restrict) &"Hello, GCC!\n"[0]
                     * printf(<D.XXX>);
                     *
                     * Note that <D.XXX> is a temporary variable, we can 
                     * actually use any name we like as long as no 
                     * confliction.
                     */

                    /*
                     * Generate a STRING_CST, the value is "Hello, GCC!\n"
                     */
                    desc_node = build_string(strlen(hellocstr), hellocstr);

                    /*
                     * Two points need to notice here:
                     * 1. STRING_CST build by build_string() do
                     *    not have TREE_TYPE set, so we need to 
                     *    set it manually.
                     * 2. build_string() will add a trailing '\0'
                     *    when building the STRING_CST, so we do
                     *    not need to care with it.
                     */
                    TREE_TYPE(desc_node) = build_array_type(
                            char_type_node, 
                            build_index_type(
                                build_int_cst(NULL_TREE, 
                                    strlen(hellocstr))));

                    /*
                     * Define a const char * restrict type node
                     * here for convertion.
                     * I'm not sure why we need to add a restrict
                     * attribute, but GCC really does it when it 
                     * converting a STRING_CST from AST to Gimple.
                     */
                    const_char_restrict_ptr_type_node = 
                        build_qualified_type(
                            build_pointer_type(
                                    build_qualified_type(
                                        char_type_node,
                                        TYPE_QUAL_CONST)),
                            TYPE_QUAL_RESTRICT);

                    /*
                     * When we in AST, if we want to use STRING_CST
                     * the form is like this <ADDR_EXPR<STRING_CST>>,
                     * but when we turn to gimple, it is like this
                     * <ADDR_EXPR<ADDAR_REF<STRING_CST>>>.
                     * So we need to do a convertion there.
                     */

                    /*
                     * First wrap STRING_CST with ARRAY_REF
                     */
                    t = build4(ARRAY_REF, char_type_node, 
                            desc_node, build_int_cst(NULL_TREE, 0), 
                            NULL, NULL);

                    /*
                     * Second wrap ARRAY_REF with ADDR_EXPR
                     */
                    ptr_desc_node = build1(ADDR_EXPR, 
                            const_char_restrict_ptr_type_node,
                            t);

                    /*
                     * I'm not sure why we need to use fold_convert()
                     * here, but if we do not, we cannot make the 
                     * compiling successful.
                     */
                    ptr_desc_node = fold_convert(
                            const_char_restrict_ptr_type_node, 
                            ptr_desc_node);

                    /*
                     * If is_gimple_min_invariant(ptr_desc_node)
                     * is true, we build a corrent argument, otherwise
                     * the argument is not suitable for gimple call
                     */
                    if(!is_gimple_min_invariant(ptr_desc_node))
                    {
                        printf("Something wrong with is_gimple_min_invariant\n");
                        return ;
                    }

                    /*
                     * This applies for a temporary variable
                     */
                    tmp_var = make_rename_temp(
                            const_char_restrict_ptr_type_node,
                            "plugin_var");

                    /*
                     * Build a gimple statement. Still remember that?
                     * <D.XXX> = (const char * restrict) "Hello, GCC!\n"
                     */
                    tmp_gstmt = gimple_build_assign(tmp_var, 
                                                    ptr_desc_node);

                    /*
                     * Check if the gimple statment is corrent
                     */
                    if(!is_gimple_assign(tmp_gstmt))
                    {
                        printf("tmp_gstmt is invalid\n");
                    }

                    printf("Insert gimple statment:");
                    print_gimple_stmt(stdout, tmp_gstmt, 0,
                                TDF_DETAILS | TDF_VERBOSE | TDF_TREE);
                    /*
                     * Insert the gimple statment into the basic block
                     */
                    gsi_insert_after(ptrgsi, tmp_gstmt, 
                            GSI_NEW_STMT);

                    if(is_gimple_operand(tmp_var))
                    {

                        printf("begin to insert printf\n");
                        yes = 1;
                        printf("Insert gimple statment:");
                        /*
                         * Insert the gimple statment printf 
                         * into the basic block
                         */
                        new_gnode = gimple_build_call(
                                funcdecl, 1, tmp_var);
                        print_gimple_stmt(stdout, new_gnode, 0, 0);
                        gsi_insert_after(ptrgsi, new_gnode, 
                                GSI_NEW_STMT); 
                    }
                    else
                    {
                        print_generic_stmt(stdout, ptr_desc_node, 
                                TDF_DETAILS | TDF_VERBOSE | TDF_TREE);
                        printf("Not Gimple Operands\n");
                    }

                    /*
                     * Since we have more than one consecutive statements 
                     * to insert, we can actually use build a gimple 
                     * sequence, insert all statement into the sequence, 
                     * and then insert the sequence into the basic block. 
                     * This seems to be a better method.
                     */
                }
            }
            else
            {
            }
            break;
        default:
            break;
    }
}
Example #28
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;
  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;
}
Example #29
0
static void
lower_builtin_setjmp (gimple_stmt_iterator *gsi)
{
  gimple stmt = gsi_stmt (*gsi);
  location_t loc = gimple_location (stmt);
  tree cont_label = create_artificial_label (loc);
  tree next_label = create_artificial_label (loc);
  tree dest, t, arg;
  gimple g;

  /* NEXT_LABEL is the label __builtin_longjmp will jump to.  Its address is
     passed to both __builtin_setjmp_setup and __builtin_setjmp_receiver.  */
  FORCED_LABEL (next_label) = 1;

  dest = gimple_call_lhs (stmt);

  /* Build '__builtin_setjmp_setup (BUF, NEXT_LABEL)' and insert.  */
  arg = build_addr (next_label, current_function_decl);
  t = builtin_decl_implicit (BUILT_IN_SETJMP_SETUP);
  g = gimple_build_call (t, 2, gimple_call_arg (stmt, 0), arg);
  gimple_set_location (g, loc);
  gimple_set_block (g, gimple_block (stmt));
  gsi_insert_before (gsi, g, GSI_SAME_STMT);

  /* Build 'DEST = 0' and insert.  */
  if (dest)
    {
      g = gimple_build_assign (dest, build_zero_cst (TREE_TYPE (dest)));
      gimple_set_location (g, loc);
      gimple_set_block (g, gimple_block (stmt));
      gsi_insert_before (gsi, g, GSI_SAME_STMT);
    }

  /* Build 'goto CONT_LABEL' and insert.  */
  g = gimple_build_goto (cont_label);
  gsi_insert_before (gsi, g, GSI_SAME_STMT);

  /* Build 'NEXT_LABEL:' and insert.  */
  g = gimple_build_label (next_label);
  gsi_insert_before (gsi, g, GSI_SAME_STMT);

  /* Build '__builtin_setjmp_receiver (NEXT_LABEL)' and insert.  */
  arg = build_addr (next_label, current_function_decl);
  t = builtin_decl_implicit (BUILT_IN_SETJMP_RECEIVER);
  g = gimple_build_call (t, 1, arg);
  gimple_set_location (g, loc);
  gimple_set_block (g, gimple_block (stmt));
  gsi_insert_before (gsi, g, GSI_SAME_STMT);

  /* Build 'DEST = 1' and insert.  */
  if (dest)
    {
      g = gimple_build_assign (dest, fold_convert_loc (loc, TREE_TYPE (dest),
						       integer_one_node));
      gimple_set_location (g, loc);
      gimple_set_block (g, gimple_block (stmt));
      gsi_insert_before (gsi, g, GSI_SAME_STMT);
    }

  /* Build 'CONT_LABEL:' and insert.  */
  g = gimple_build_label (cont_label);
  gsi_insert_before (gsi, g, GSI_SAME_STMT);

  /* Remove the call to __builtin_setjmp.  */
  gsi_remove (gsi, false);
}
Example #30
0
tree
maybe_push_res_to_seq (code_helper rcode, tree type, tree *ops,
		       gimple_seq *seq, tree res)
{
  if (rcode.is_tree_code ())
    {
      if (!res
	  && gimple_simplified_result_is_gimple_val (rcode, ops))
	return ops[0];
      if (mprts_hook)
	{
	  tree tem = mprts_hook (rcode, type, ops);
	  if (tem)
	    return tem;
	}
      if (!seq)
	return NULL_TREE;
      /* Play safe and do not allow abnormals to be mentioned in
         newly created statements.  */
      if ((TREE_CODE (ops[0]) == SSA_NAME
	   && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[0]))
	  || (ops[1]
	      && TREE_CODE (ops[1]) == SSA_NAME
	      && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[1]))
	  || (ops[2]
	      && TREE_CODE (ops[2]) == SSA_NAME
	      && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[2])))
	return NULL_TREE;
      if (!res)
	res = make_ssa_name (type);
      maybe_build_generic_op (rcode, type, &ops[0], ops[1], ops[2]);
      gimple *new_stmt = gimple_build_assign (res, rcode,
					     ops[0], ops[1], ops[2]);
      gimple_seq_add_stmt_without_update (seq, new_stmt);
      return res;
    }
  else
    {
      if (!seq)
	return NULL_TREE;
      tree decl = builtin_decl_implicit (rcode);
      if (!decl)
	return NULL_TREE;
      /* We can't and should not emit calls to non-const functions.  */
      if (!(flags_from_decl_or_type (decl) & ECF_CONST))
	return NULL_TREE;
      /* Play safe and do not allow abnormals to be mentioned in
         newly created statements.  */
      unsigned nargs;
      for (nargs = 0; nargs < 3; ++nargs)
	{
	  if (!ops[nargs])
	    break;
	  if (TREE_CODE (ops[nargs]) == SSA_NAME
	      && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[nargs]))
	    return NULL_TREE;
	}
      gcc_assert (nargs != 0);
      if (!res)
	res = make_ssa_name (type);
      gimple *new_stmt = gimple_build_call (decl, nargs, ops[0], ops[1], ops[2]);
      gimple_call_set_lhs (new_stmt, res);
      gimple_seq_add_stmt_without_update (seq, new_stmt);
      return res;
    }
}