示例#1
0
bool
may_propagate_copy (tree dest, tree orig)
{
  tree type_d = TREE_TYPE (dest);
  tree type_o = TREE_TYPE (orig);

  /* If ORIG flows in from an abnormal edge, it cannot be propagated.  */
  if (TREE_CODE (orig) == SSA_NAME
      && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (orig)
      /* If it is the default definition and an automatic variable then
         we can though and it is important that we do to avoid
	 uninitialized regular copies.  */
      && !(SSA_NAME_IS_DEFAULT_DEF (orig)
	   && (SSA_NAME_VAR (orig) == NULL_TREE
	       || TREE_CODE (SSA_NAME_VAR (orig)) == VAR_DECL)))
    return false;

  /* If DEST is an SSA_NAME that flows from an abnormal edge, then it
     cannot be replaced.  */
  if (TREE_CODE (dest) == SSA_NAME
      && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (dest))
    return false;

  /* Do not copy between types for which we *do* need a conversion.  */
  if (!useless_type_conversion_p (type_d, type_o))
    return false;

  /* Generally propagating virtual operands is not ok as that may
     create overlapping life-ranges.  */
  if (TREE_CODE (dest) == SSA_NAME && virtual_operand_p (dest))
    return false;

  /* Anything else is OK.  */
  return true;
}
示例#2
0
bool
gimple_can_coalesce_p (tree name1, tree name2)
{
  /* First check the SSA_NAME's associated DECL.  We only want to
     coalesce if they have the same DECL or both have no associated DECL.  */
  tree var1 = SSA_NAME_VAR (name1);
  tree var2 = SSA_NAME_VAR (name2);
  var1 = (var1 && (!VAR_P (var1) || !DECL_IGNORED_P (var1))) ? var1 : NULL_TREE;
  var2 = (var2 && (!VAR_P (var2) || !DECL_IGNORED_P (var2))) ? var2 : NULL_TREE;
  if (var1 != var2)
    return false;

  /* Now check the types.  If the types are the same, then we should
     try to coalesce V1 and V2.  */
  tree t1 = TREE_TYPE (name1);
  tree t2 = TREE_TYPE (name2);
  if (t1 == t2)
    return true;

  /* If the types are not the same, check for a canonical type match.  This
     (for example) allows coalescing when the types are fundamentally the
     same, but just have different names. 

     Note pointer types with different address spaces may have the same
     canonical type.  Those are rejected for coalescing by the
     types_compatible_p check.  */
  if (TYPE_CANONICAL (t1)
      && TYPE_CANONICAL (t1) == TYPE_CANONICAL (t2)
      && types_compatible_p (t1, t2))
    return true;

  return false;
}
示例#3
0
static void 
process_replaceable (temp_expr_table_p tab, gimple stmt)
{
  tree var, def, basevar;
  int version;
  ssa_op_iter iter;
  bitmap def_vars, use_vars;

#ifdef ENABLE_CHECKING
  gcc_assert (is_replaceable_p (stmt));
#endif

  def = SINGLE_SSA_TREE_OPERAND (stmt, SSA_OP_DEF);
  version = SSA_NAME_VERSION (def);
  basevar = SSA_NAME_VAR (def);
  def_vars = BITMAP_ALLOC (NULL);

  bitmap_set_bit (def_vars, DECL_UID (basevar));

  /* Add this expression to the dependency list for each use partition.  */
  FOR_EACH_SSA_TREE_OPERAND (var, stmt, iter, SSA_OP_USE)
    {
      int var_version = SSA_NAME_VERSION (var);

      use_vars = tab->expr_decl_uids[var_version];
      add_dependence (tab, version, var);
      if (use_vars)
        {
	  bitmap_ior_into (def_vars, use_vars);
	  BITMAP_FREE (tab->expr_decl_uids[var_version]);
	}
      else
	bitmap_set_bit (def_vars, DECL_UID (SSA_NAME_VAR (var)));
    }
示例#4
0
bool
may_propagate_copy_into_asm (tree dest)
{
  /* Hard register operands of asms are special.  Do not bypass.  */
  return !(TREE_CODE (dest) == SSA_NAME
	   && TREE_CODE (SSA_NAME_VAR (dest)) == VAR_DECL
	   && DECL_HARD_REGISTER (SSA_NAME_VAR (dest)));
}
示例#5
0
tree
copy_ssa_name_fn (struct function *fn, tree name, gimple stmt)
{
  tree new_name;

  if (SSA_NAME_VAR (name))
    new_name = make_ssa_name_fn (fn, SSA_NAME_VAR (name), stmt);
  else
    {
      new_name = make_ssa_name_fn (fn, TREE_TYPE (name), stmt);
      SET_SSA_NAME_VAR_OR_IDENTIFIER (new_name, SSA_NAME_IDENTIFIER (name));
    }

  return new_name;
}
static void perturb_latent_entropy(basic_block bb, tree rhs)
{
	gimple_stmt_iterator gsi;
	gimple assign;
	tree addxorrol, temp;

	// 1. create temporary copy of latent_entropy
	temp = create_tmp_var(unsigned_intDI_type_node, "temp_latent_entropy");
	add_referenced_var(temp);

	// 2. read...
	temp = make_ssa_name(temp, NULL);
	assign = gimple_build_assign(temp, latent_entropy_decl);
	SSA_NAME_DEF_STMT(temp) = assign;
	add_referenced_var(latent_entropy_decl);
	gsi = gsi_after_labels(bb);
	gsi_insert_after(&gsi, assign, GSI_NEW_STMT);
	update_stmt(assign);

	// 3. ...modify...
	addxorrol = fold_build2_loc(UNKNOWN_LOCATION, get_op(NULL), unsigned_intDI_type_node, temp, rhs);
	temp = make_ssa_name(SSA_NAME_VAR(temp), NULL);
	assign = gimple_build_assign(temp, addxorrol);
	SSA_NAME_DEF_STMT(temp) = assign;
	gsi_insert_after(&gsi, assign, GSI_NEW_STMT);
	update_stmt(assign);

	// 4. ...write latent_entropy
	assign = gimple_build_assign(latent_entropy_decl, temp);
	gsi_insert_after(&gsi, assign, GSI_NEW_STMT);
	update_stmt(assign);
}
示例#7
0
tree
target_for_debug_bind (tree var)
{
  if (!MAY_HAVE_DEBUG_STMTS)
    return NULL_TREE;

  if (TREE_CODE (var) == SSA_NAME)
    {
      var = SSA_NAME_VAR (var);
      if (var == NULL_TREE)
	return NULL_TREE;
    }

  if ((TREE_CODE (var) != VAR_DECL
       || VAR_DECL_IS_VIRTUAL_OPERAND (var))
      && TREE_CODE (var) != PARM_DECL)
    return NULL_TREE;

  if (DECL_HAS_VALUE_EXPR_P (var))
    return target_for_debug_bind (DECL_VALUE_EXPR (var));

  if (DECL_IGNORED_P (var))
    return NULL_TREE;

  /* var-tracking only tracks registers.  */
  if (!is_gimple_reg_type (TREE_TYPE (var)))
    return NULL_TREE;

  return var;
}
static void
add_stmt_operand (tree *var_p, gimple stmt, int flags)
{
  tree var, sym;

  gcc_assert (SSA_VAR_P (*var_p));

  var = *var_p;
  sym = (TREE_CODE (var) == SSA_NAME ? SSA_NAME_VAR (var) : var);

  /* Mark statements with volatile operands.  */
  if (TREE_THIS_VOLATILE (sym))
    gimple_set_has_volatile_ops (stmt, true);

  if (is_gimple_reg (sym))
    {
      /* The variable is a GIMPLE register.  Add it to real operands.  */
      if (flags & opf_def)
	append_def (var_p);
      else
	append_use (var_p);
    }
  else
    add_virtual_operand (stmt, flags);
}
示例#9
0
static inline void
finalize_ssa_defs (struct function *fn, gimple *stmt)
{
  /* Pre-pend the vdef we may have built.  */
  if (build_vdef != NULL_TREE)
    {
      tree oldvdef = gimple_vdef (stmt);
      if (oldvdef
	  && TREE_CODE (oldvdef) == SSA_NAME)
	oldvdef = SSA_NAME_VAR (oldvdef);
      if (oldvdef != build_vdef)
	gimple_set_vdef (stmt, build_vdef);
    }

  /* Clear and unlink a no longer necessary VDEF.  */
  if (build_vdef == NULL_TREE
      && gimple_vdef (stmt) != NULL_TREE)
    {
      if (TREE_CODE (gimple_vdef (stmt)) == SSA_NAME)
	{
	  unlink_stmt_vdef (stmt);
	  release_ssa_name_fn (fn, gimple_vdef (stmt));
	}
      gimple_set_vdef (stmt, NULL_TREE);
    }

  /* If we have a non-SSA_NAME VDEF, mark it for renaming.  */
  if (gimple_vdef (stmt)
      && TREE_CODE (gimple_vdef (stmt)) != SSA_NAME)
    {
      fn->gimple_df->rename_vops = 1;
      fn->gimple_df->ssa_renaming_needed = 1;
    }
}
示例#10
0
static inline void
finalize_ssa_uses (struct function *fn, gimple *stmt)
{
  unsigned new_i;
  struct use_optype_d new_list;
  use_optype_p old_ops, ptr, last;

  /* Pre-pend the VUSE we may have built.  */
  if (build_vuse != NULL_TREE)
    {
      tree oldvuse = gimple_vuse (stmt);
      if (oldvuse
	  && TREE_CODE (oldvuse) == SSA_NAME)
	oldvuse = SSA_NAME_VAR (oldvuse);
      if (oldvuse != (build_vuse != NULL_TREE
		      ? build_vuse : build_vdef))
	gimple_set_vuse (stmt, NULL_TREE);
      build_uses.safe_insert (0, gimple_vuse_ptr (stmt));
    }

  new_list.next = NULL;
  last = &new_list;

  old_ops = gimple_use_ops (stmt);

  /* Clear a no longer necessary VUSE.  */
  if (build_vuse == NULL_TREE
      && gimple_vuse (stmt) != NULL_TREE)
    gimple_set_vuse (stmt, NULL_TREE);

  /* If there is anything in the old list, free it.  */
  if (old_ops)
    {
      for (ptr = old_ops; ptr->next; ptr = ptr->next)
	delink_imm_use (USE_OP_PTR (ptr));
      delink_imm_use (USE_OP_PTR (ptr));
      ptr->next = gimple_ssa_operands (fn)->free_uses;
      gimple_ssa_operands (fn)->free_uses = old_ops;
    }

  /* If we added a VUSE, make sure to set the operand if it is not already
     present and mark it for renaming.  */
  if (build_vuse != NULL_TREE
      && gimple_vuse (stmt) == NULL_TREE)
    {
      gimple_set_vuse (stmt, gimple_vop (fn));
      fn->gimple_df->rename_vops = 1;
      fn->gimple_df->ssa_renaming_needed = 1;
    }

  /* Now create nodes for all the new nodes.  */
  for (new_i = 0; new_i < build_uses.length (); new_i++)
    {
      tree *op = build_uses[new_i];
      last = add_use_op (fn, stmt, op, last);
    }

  /* Now set the stmt's operands.  */
  gimple_set_use_ops (stmt, new_list.next);
}
示例#11
0
static bool
if_convertible_phi_p (struct loop *loop, basic_block bb, tree phi)
{
  if (dump_file && (dump_flags & TDF_DETAILS))
    {
      fprintf (dump_file, "-------------------------\n");
      print_generic_stmt (dump_file, phi, TDF_SLIM);
    }

  if (bb != loop->header && PHI_NUM_ARGS (phi) != 2)
    {
      if (dump_file && (dump_flags & TDF_DETAILS))
	fprintf (dump_file, "More than two phi node args.\n");
      return false;
    }

  if (!is_gimple_reg (SSA_NAME_VAR (PHI_RESULT (phi))))
    {
      imm_use_iterator imm_iter;
      use_operand_p use_p;
      FOR_EACH_IMM_USE_FAST (use_p, imm_iter, PHI_RESULT (phi))
	{
	  if (TREE_CODE (USE_STMT (use_p)) == PHI_NODE)
	    {
	      if (dump_file && (dump_flags & TDF_DETAILS))
		fprintf (dump_file, "Difficult to handle this virtual phi.\n");
	      return false;
	    }
	}
    }
示例#12
0
/*
 * find all C level function pointer dereferences and forcibly set the highest bit of the pointer
 */
static unsigned int execute_kernexec_fptr(void)
{
	basic_block bb;

	// 1. loop through BBs and GIMPLE statements
	FOR_EACH_BB(bb) {
		gimple_stmt_iterator gsi;

		for (gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi)) {
			// gimple match: h_1 = get_fptr (); D.2709_3 = h_1 (x_2(D));
			tree fn;
			gimple call_stmt;

			// is it a call ...
			call_stmt = gsi_stmt(gsi);
			if (!is_gimple_call(call_stmt))
				continue;
			fn = gimple_call_fn(call_stmt);
			if (TREE_CODE(fn) == ADDR_EXPR)
				continue;
			if (TREE_CODE(fn) != SSA_NAME)
				gcc_unreachable();

			// ... through a function pointer
			if (SSA_NAME_VAR(fn) != NULL_TREE) {
				fn = SSA_NAME_VAR(fn);
				if (TREE_CODE(fn) != VAR_DECL && TREE_CODE(fn) != PARM_DECL) {
					debug_tree(fn);
					gcc_unreachable();
				}
			}
			fn = TREE_TYPE(fn);
			if (TREE_CODE(fn) != POINTER_TYPE)
				continue;
			fn = TREE_TYPE(fn);
			if (TREE_CODE(fn) != FUNCTION_TYPE)
				continue;

			kernexec_instrument_fptr(&gsi);

//debug_tree(gimple_call_fn(call_stmt));
//print_gimple_stmt(stderr, call_stmt, 0, TDF_LINENO);
		}
	}

	return 0;
}
示例#13
0
bool
is_gimple_non_addressable (tree t)
{
  if (TREE_CODE (t) == SSA_NAME)
    t = SSA_NAME_VAR (t);

  return (is_gimple_variable (t) && ! needs_to_live_in_memory (t));
}
static inline unsigned
get_name_decl (const_tree t)
{
  if (TREE_CODE (t) != SSA_NAME)
    return DECL_UID (t);
  else
    return DECL_UID (SSA_NAME_VAR (t));
}
示例#15
0
static t_myproof_variable *read_operand( tree t, t_myproof_function *function )
{
    t_myproof_variable *variable = NULL;
    enum tree_code tc;

    tc = TREE_CODE( t );

    switch ( tc )
	{
	case VAR_DECL:
	case PARM_DECL:
	case CONST_DECL:
	    variable = read_data( t, function );
	    break;

	case ARRAY_REF:
	    printf("variable pass array_ref\n");

	    read_operand( TREE_OPERAND(t,0), function ); /* array base */
	    variable = read_operand( TREE_OPERAND(t,1), function ); /* array index */

	    /* if ( store == true ) */
	    /* 	{ */
	    /* 	    function->nstore++; */
	    /* 	} */
	    /* else */
	    /* 	{ */
	    /* 	    function->nload++; */
	    /* 	} */

	    break;

	case ADDR_EXPR:
	case INDIRECT_REF:
	    /* pointer & dereferencing */
	    break;

	case INTEGER_CST:
	case REAL_CST:
	case STRING_CST:
	    /* integer/real/string constant */
	    break;

	case SSA_NAME:
	    variable = read_data( SSA_NAME_VAR(t), function );
	    break;

	case COND_EXPR:
	case TARGET_MEM_REF:
	    break;

	default:
	    fprintf( stderr, "myproof: read_operand(): unhandled \'%s\'\n", tree_code_name[tc] );
	    gcc_unreachable( );
	}

    return variable;
}
static inline void
finalize_ssa_uses (gimple stmt)
{
  unsigned new_i;
  struct use_optype_d new_list;
  use_optype_p old_ops, ptr, last;

  /* Pre-pend the VUSE we may have built.  */
  if (build_vuse != NULL_TREE)
    {
      tree oldvuse = gimple_vuse (stmt);
      if (oldvuse
	  && TREE_CODE (oldvuse) == SSA_NAME)
	oldvuse = SSA_NAME_VAR (oldvuse);
      if (oldvuse != (build_vuse != NULL_TREE
		      ? build_vuse : build_vdef))
	gimple_set_vuse (stmt, NULL_TREE);
      VEC_safe_insert (tree, heap, build_uses, 0, (tree)gimple_vuse_ptr (stmt));
    }

  new_list.next = NULL;
  last = &new_list;

  old_ops = gimple_use_ops (stmt);

  /* Clear a no longer necessary VUSE.  */
  if (build_vuse == NULL_TREE
      && gimple_vuse (stmt) != NULL_TREE)
    gimple_set_vuse (stmt, NULL_TREE);

  /* If there is anything in the old list, free it.  */
  if (old_ops)
    {
      for (ptr = old_ops; ptr; ptr = ptr->next)
	delink_imm_use (USE_OP_PTR (ptr));
      old_ops->next = gimple_ssa_operands (cfun)->free_uses;
      gimple_ssa_operands (cfun)->free_uses = old_ops;
    }

  /* If we added a VUSE, make sure to set the operand if it is not already
     present and mark it for renaming.  */
  if (build_vuse != NULL_TREE
      && gimple_vuse (stmt) == NULL_TREE)
    {
      gimple_set_vuse (stmt, gimple_vop (cfun));
      mark_sym_for_renaming (gimple_vop (cfun));
    }

  /* Now create nodes for all the new nodes.  */
  for (new_i = 0; new_i < VEC_length (tree, build_uses); new_i++)
    last = add_use_op (stmt,
		       (tree *) VEC_index (tree, build_uses, new_i),
		       last);

  /* Now set the stmt's operands.  */
  gimple_set_use_ops (stmt, new_list.next);
}
示例#17
0
static void
adjust_simduid_builtins (hash_table<simduid_to_vf> *htab)
{
  basic_block bb;

  FOR_EACH_BB_FN (bb, cfun)
    {
      gimple_stmt_iterator i;

      for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i))
	{
	  unsigned int vf = 1;
	  enum internal_fn ifn;
	  gimple stmt = gsi_stmt (i);
	  tree t;
	  if (!is_gimple_call (stmt)
	      || !gimple_call_internal_p (stmt))
	    continue;
	  ifn = gimple_call_internal_fn (stmt);
	  switch (ifn)
	    {
	    case IFN_GOMP_SIMD_LANE:
	    case IFN_GOMP_SIMD_VF:
	    case IFN_GOMP_SIMD_LAST_LANE:
	      break;
	    default:
	      continue;
	    }
	  tree arg = gimple_call_arg (stmt, 0);
	  gcc_assert (arg != NULL_TREE);
	  gcc_assert (TREE_CODE (arg) == SSA_NAME);
	  simduid_to_vf *p = NULL, data;
	  data.simduid = DECL_UID (SSA_NAME_VAR (arg));
	  if (htab)
	    {
	      p = htab->find (&data);
	      if (p)
		vf = p->vf;
	    }
	  switch (ifn)
	    {
	    case IFN_GOMP_SIMD_VF:
	      t = build_int_cst (unsigned_type_node, vf);
	      break;
	    case IFN_GOMP_SIMD_LANE:
	      t = build_int_cst (unsigned_type_node, 0);
	      break;
	    case IFN_GOMP_SIMD_LAST_LANE:
	      t = gimple_call_arg (stmt, 1);
	      break;
	    default:
	      gcc_unreachable ();
	    }
	  update_call_from_tree (&i, t);
	}
    }
示例#18
0
static void
insert_value_copy_on_edge (edge e, int dest, tree src, source_location locus)
{
  rtx seq, x;
  enum machine_mode dest_mode, src_mode;
  int unsignedp;
  tree var;

  if (dump_file && (dump_flags & TDF_DETAILS))
    {
      fprintf (dump_file,
	       "Inserting a value copy on edge BB%d->BB%d : PART.%d = ",
	       e->src->index,
	       e->dest->index, dest);
      print_generic_expr (dump_file, src, TDF_SLIM);
      fprintf (dump_file, "\n");
    }

  gcc_assert (SA.partition_to_pseudo[dest]);

  set_location_for_edge (e);
  /* If a locus is provided, override the default.  */
  if (locus)
    set_curr_insn_source_location (locus);

  start_sequence ();

  var = SSA_NAME_VAR (partition_to_var (SA.map, dest));
  src_mode = TYPE_MODE (TREE_TYPE (src));
  dest_mode = GET_MODE (SA.partition_to_pseudo[dest]);
  gcc_assert (src_mode == TYPE_MODE (TREE_TYPE (var)));
  gcc_assert (!REG_P (SA.partition_to_pseudo[dest])
	      || dest_mode == promote_decl_mode (var, &unsignedp));

  if (src_mode != dest_mode)
    {
      x = expand_expr (src, NULL, src_mode, EXPAND_NORMAL);
      x = convert_modes (dest_mode, src_mode, x, unsignedp);
    }
  else if (src_mode == BLKmode)
    {
      x = SA.partition_to_pseudo[dest];
      store_expr (src, x, 0, false);
    }
  else
    x = expand_expr (src, SA.partition_to_pseudo[dest],
		     dest_mode, EXPAND_NORMAL);

  if (x != SA.partition_to_pseudo[dest])
    emit_move_insn (SA.partition_to_pseudo[dest], x);
  seq = get_insns ();
  end_sequence ();

  insert_insn_on_edge (seq, e);
}
示例#19
0
static void read_operand( tree t )
{
    enum tree_code tc;

    tc = TREE_CODE( t );

    /* tree tree_new = TREE_TYPE( t ); */
    /* enum tree_code tc_new = TREE_CODE ( t ); */

    /* if ( tc_new == REAL_TYPE ) */
    /* 	{ */
    /* 	    printf("this is a real variable\n"); */
    /* 	} */
    /* else if ( tc_new == INTEGER_TYPE ) */
    /* 	{ */
    /* 	    printf("this is an integer variable\n"); */
    /* 	} */

    switch ( tc )
	{
	case VAR_DECL:
	case PARM_DECL:
	case CONST_DECL:
	    read_data( t );
	    break;

	case ARRAY_REF:
	    read_operand( TREE_OPERAND(t,0) ); /* array base */
	    read_operand( TREE_OPERAND(t,1) ); /* array index */
	    break;

	case ADDR_EXPR:
	case INDIRECT_REF:
	    /* pointer & dereferencing */
	    break;

	case INTEGER_CST:
	case REAL_CST:
	case STRING_CST:
	    /* integer/real/string constant */
	    break;

	case SSA_NAME:
	    read_data( SSA_NAME_VAR(t) );
	    break;

	case COND_EXPR:
	case TARGET_MEM_REF:
	    break;

	default:
	    fprintf( stderr, "myproof: read_operand(): unhandled \'%s\'\n", tree_code_name[tc] );
	    gcc_unreachable( );
	}
}
示例#20
0
static bool
verify_ssa_name (tree ssa_name, bool is_virtual)
{
  if (TREE_CODE (ssa_name) != SSA_NAME)
    {
      error ("expected an SSA_NAME object");
      return true;
    }

  if (TREE_TYPE (ssa_name) != TREE_TYPE (SSA_NAME_VAR (ssa_name)))
    {
      error ("type mismatch between an SSA_NAME and its symbol");
      return true;
    }

  if (SSA_NAME_IN_FREE_LIST (ssa_name))
    {
      error ("found an SSA_NAME that had been released into the free pool");
      return true;
    }

  if (is_virtual && is_gimple_reg (ssa_name))
    {
      error ("found a virtual definition for a GIMPLE register");
      return true;
    }

  if (!is_virtual && !is_gimple_reg (ssa_name))
    {
      error ("found a real definition for a non-register");
      return true;
    }

  if (is_virtual && var_ann (SSA_NAME_VAR (ssa_name)) 
      && get_subvars_for_var (SSA_NAME_VAR (ssa_name)) != NULL)
    {
      error ("found real variable when subvariables should have appeared");
      return true;
    }

  return false;
}
示例#21
0
tree
duplicate_ssa_name (tree name, gimple stmt)
{
  tree new_name = make_ssa_name (SSA_NAME_VAR (name), stmt);
  struct ptr_info_def *old_ptr_info = SSA_NAME_PTR_INFO (name);

  if (old_ptr_info)
    duplicate_ssa_name_ptr_info (new_name, old_ptr_info);

  return new_name;
}
tree
make_ssa_name (tree var, tree stmt)
{
    tree t;
    use_operand_p imm;

    gcc_assert (DECL_P (var)
                || TREE_CODE (var) == INDIRECT_REF);

    gcc_assert (!stmt
                || EXPR_P (stmt) || GIMPLE_STMT_P (stmt)
                || TREE_CODE (stmt) == PHI_NODE);

    /* If our free list has an element, then use it.  */
    if (FREE_SSANAMES (cfun))
    {
        t = FREE_SSANAMES (cfun);
        FREE_SSANAMES (cfun) = TREE_CHAIN (FREE_SSANAMES (cfun));
#ifdef GATHER_STATISTICS
        ssa_name_nodes_reused++;
#endif

        /* The node was cleared out when we put it on the free list, so
        there is no need to do so again here.  */
        gcc_assert (ssa_name (SSA_NAME_VERSION (t)) == NULL);
        VEC_replace (tree, SSANAMES (cfun), SSA_NAME_VERSION (t), t);
    }
    else
    {
        t = make_node (SSA_NAME);
        SSA_NAME_VERSION (t) = num_ssa_names;
        VEC_safe_push (tree, gc, SSANAMES (cfun), t);
#ifdef GATHER_STATISTICS
        ssa_name_nodes_created++;
#endif
    }

    TREE_TYPE (t) = TREE_TYPE (var);
    SSA_NAME_VAR (t) = var;
    SSA_NAME_DEF_STMT (t) = stmt;
    SSA_NAME_PTR_INFO (t) = NULL;
    SSA_NAME_IN_FREE_LIST (t) = 0;
    SSA_NAME_IS_DEFAULT_DEF (t) = 0;
    imm = &(SSA_NAME_IMM_USE_NODE (t));
    imm->use = NULL;
    imm->prev = imm;
    imm->next = imm;
    imm->stmt = t;

    return t;
}
示例#23
0
bool
is_gimple_reg (tree t)
{
  var_ann_t ann;

  if (TREE_CODE (t) == SSA_NAME)
    t = SSA_NAME_VAR (t);

  if (!is_gimple_variable (t))
    return false;

  if (!is_gimple_reg_type (TREE_TYPE (t)))
    return false;

  /* A volatile decl is not acceptable because we can't reuse it as
     needed.  We need to copy it into a temp first.  */
  if (TREE_THIS_VOLATILE (t))
    return false;

  /* We define "registers" as things that can be renamed as needed,
     which with our infrastructure does not apply to memory.  */
  if (needs_to_live_in_memory (t))
    return false;

  /* Hard register variables are an interesting case.  For those that
     are call-clobbered, we don't know where all the calls are, since
     we don't (want to) take into account which operations will turn
     into libcalls at the rtl level.  For those that are call-saved,
     we don't currently model the fact that calls may in fact change
     global hard registers, nor do we examine ASM_CLOBBERS at the tree
     level, and so miss variable changes that might imply.  All around,
     it seems safest to not do too much optimization with these at the
     tree level at all.  We'll have to rely on the rtl optimizers to
     clean this up, as there we've got all the appropriate bits exposed.  */
  if (TREE_CODE (t) == VAR_DECL && DECL_HARD_REGISTER (t))
    return false;

  /* Complex values must have been put into ssa form.  That is, no 
     assignments to the individual components.  */
  if (TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE)
    return DECL_COMPLEX_GIMPLE_REG_P (t);

  /* Some compiler temporaries are created to be used exclusively in
     virtual operands (currently memory tags and sub-variables).
     These variables should never be considered GIMPLE registers.  */
  if (DECL_ARTIFICIAL (t) && (ann = var_ann (t)) != NULL)
    return ann->mem_tag_kind == NOT_A_TAG;

  return true;
}
示例#24
0
tree
make_ssa_name_fn (struct function *fn, tree var, gimple stmt)
{
  tree t;
  use_operand_p imm;

  gcc_assert (DECL_P (var));

  /* If our free list has an element, then use it.  */
  if (FREE_SSANAMES (fn))
    {
      t = FREE_SSANAMES (fn);
      FREE_SSANAMES (fn) = TREE_CHAIN (FREE_SSANAMES (fn));
#ifdef GATHER_STATISTICS
      ssa_name_nodes_reused++;
#endif

      /* The node was cleared out when we put it on the free list, so
	 there is no need to do so again here.  */
      gcc_assert (ssa_name (SSA_NAME_VERSION (t)) == NULL);
      VEC_replace (tree, SSANAMES (fn), SSA_NAME_VERSION (t), t);
    }
  else
    {
      t = make_node (SSA_NAME);
      SSA_NAME_VERSION (t) = VEC_length (tree, SSANAMES (fn));
      VEC_safe_push (tree, gc, SSANAMES (fn), t);
#ifdef GATHER_STATISTICS
      ssa_name_nodes_created++;
#endif
    }

  TREE_TYPE (t) = TREE_TYPE (var);
  SSA_NAME_VAR (t) = var;
  SSA_NAME_DEF_STMT (t) = stmt;
  SSA_NAME_PTR_INFO (t) = NULL;
  SSA_NAME_IN_FREE_LIST (t) = 0;
  SSA_NAME_IS_DEFAULT_DEF (t) = 0;
  imm = &(SSA_NAME_IMM_USE_NODE (t));
  imm->use = NULL;
  imm->prev = imm;
  imm->next = imm;
  imm->loc.ssa_name = t;

  return t;
}
示例#25
0
static bool
dest_safe_for_nrv_p (tree dest)
{
  while (handled_component_p (dest))
    dest = TREE_OPERAND (dest, 0);

  if (! SSA_VAR_P (dest))
    return false;

  if (TREE_CODE (dest) == SSA_NAME)
    dest = SSA_NAME_VAR (dest);

  if (is_call_used (dest))
    return false;

  return true;
}
示例#26
0
/*
 * add special KERNEXEC instrumentation: force MSB of fptr to 1, which will produce
 * a non-canonical address from a userland ptr and will just trigger a GPF on dereference
 */
static void kernexec_instrument_fptr_bts(gimple_stmt_iterator *gsi)
{
	gimple assign_intptr, assign_new_fptr, call_stmt;
	tree intptr, orptr, old_fptr, new_fptr, kernexec_mask;

	call_stmt = gsi_stmt(*gsi);
	old_fptr = gimple_call_fn(call_stmt);

	// create temporary unsigned long variable used for bitops and cast fptr to it
	intptr = create_tmp_var(long_unsigned_type_node, "kernexec_bts");
#if BUILDING_GCC_VERSION <= 4007
	add_referenced_var(intptr);
#endif
	intptr = make_ssa_name(intptr, NULL);
	assign_intptr = gimple_build_assign(intptr, fold_convert(long_unsigned_type_node, old_fptr));
	SSA_NAME_DEF_STMT(intptr) = assign_intptr;
	gsi_insert_before(gsi, assign_intptr, GSI_SAME_STMT);
	update_stmt(assign_intptr);

	// apply logical or to temporary unsigned long and bitmask
	kernexec_mask = build_int_cstu(long_long_unsigned_type_node, 0x8000000000000000LL);
//	kernexec_mask = build_int_cstu(long_long_unsigned_type_node, 0xffffffff80000000LL);
	orptr = fold_build2(BIT_IOR_EXPR, long_long_unsigned_type_node, intptr, kernexec_mask);
	intptr = make_ssa_name(SSA_NAME_VAR(intptr), NULL);
	assign_intptr = gimple_build_assign(intptr, orptr);
	SSA_NAME_DEF_STMT(intptr) = assign_intptr;
	gsi_insert_before(gsi, assign_intptr, GSI_SAME_STMT);
	update_stmt(assign_intptr);

	// cast temporary unsigned long back to a temporary fptr variable
	new_fptr = create_tmp_var(TREE_TYPE(old_fptr), "kernexec_fptr");
#if BUILDING_GCC_VERSION <= 4007
	add_referenced_var(new_fptr);
#endif
	new_fptr = make_ssa_name(new_fptr, NULL);
	assign_new_fptr = gimple_build_assign(new_fptr, fold_convert(TREE_TYPE(old_fptr), intptr));
	SSA_NAME_DEF_STMT(new_fptr) = assign_new_fptr;
	gsi_insert_before(gsi, assign_new_fptr, GSI_SAME_STMT);
	update_stmt(assign_new_fptr);

	// replace call stmt fn with the new fptr
	gimple_call_set_fn(call_stmt, new_fptr);
	update_stmt(call_stmt);
}
示例#27
0
static void
execute_return_slot_opt (void)
{
  basic_block bb;

  FOR_EACH_BB (bb)
    {
      block_stmt_iterator i;
      for (i = bsi_start (bb); !bsi_end_p (i); bsi_next (&i))
	{
	  tree stmt = bsi_stmt (i);
	  tree call;

	  if (TREE_CODE (stmt) == MODIFY_EXPR
	      && (call = TREE_OPERAND (stmt, 1),
		  TREE_CODE (call) == CALL_EXPR)
	      && !CALL_EXPR_RETURN_SLOT_OPT (call)
	      && aggregate_value_p (call, call))
	    {
	      def_operand_p def_p;
	      ssa_op_iter op_iter;

	      /* We determine whether or not the LHS address escapes by
		 asking whether it is call clobbered.  When the LHS isn't a
		 simple decl, we need to check the VDEFs, so it's simplest
		 to just loop through all the DEFs.  */
	      FOR_EACH_SSA_DEF_OPERAND (def_p, stmt, op_iter, SSA_OP_ALL_DEFS)
		{
		  tree def = DEF_FROM_PTR (def_p);
		  if (TREE_CODE (def) == SSA_NAME)
		    def = SSA_NAME_VAR (def);
		  if (is_call_clobbered (def))
		    goto unsafe;
		}

	      /* No defs are call clobbered, so the optimization is safe.  */
	      CALL_EXPR_RETURN_SLOT_OPT (call) = 1;
	      /* This is too late to mark the target addressable like we do
		 in gimplify_modify_expr_rhs, but that's OK; anything that
		 wasn't already addressable was handled there.  */

	      unsafe:;
	    }
	}
bool
may_propagate_copy_into_stmt (gimple dest, tree orig)
{
    tree type_d;
    tree type_o;

    /* If the statement is a switch or a single-rhs assignment,
       then the expression to be replaced by the propagation may
       be an SSA_NAME.  Fortunately, there is an explicit tree
       for the expression, so we delegate to may_propagate_copy.  */

    if (gimple_assign_single_p (dest))
        return may_propagate_copy (gimple_assign_rhs1 (dest), orig);
    else if (gimple_code (dest) == GIMPLE_SWITCH)
        return may_propagate_copy (gimple_switch_index (dest), orig);

    /* In other cases, the expression is not materialized, so there
       is no destination to pass to may_propagate_copy.  On the other
       hand, the expression cannot be an SSA_NAME, so the analysis
       is much simpler.  */

    if (TREE_CODE (orig) == SSA_NAME
            && (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (orig)
                ||  TREE_CODE (SSA_NAME_VAR (orig)) == MEMORY_PARTITION_TAG))
        return false;

    if (is_gimple_assign (dest))
        type_d = TREE_TYPE (gimple_assign_lhs (dest));
    else if (gimple_code (dest) == GIMPLE_COND)
        type_d = boolean_type_node;
    else if (is_gimple_call (dest)
             && gimple_call_lhs (dest) != NULL_TREE)
        type_d = TREE_TYPE (gimple_call_lhs (dest));
    else
        gcc_unreachable ();

    type_o = TREE_TYPE (orig);

    if (!useless_type_conversion_p (type_d, type_o))
        return false;

    return true;
}
示例#29
0
static tree
get_real_ref_rhs (tree expr)
{
  switch (TREE_CODE (expr))
    {
      case SSA_NAME:
        {
          /* Given a self-assign statement, say foo.x = foo.x,
             the IR (after SSA) looks like:

             D.1797_14 = foo.x;
             foo.x ={v} D.1797_14;

             So if the rhs EXPR is an SSA_NAME of a temp variable,
             e.g. D.1797_14, we need to grab the rhs of its SSA def
             statement (i.e. foo.x).  */
          tree vdecl = SSA_NAME_VAR (expr);
          if ((!vdecl || DECL_ARTIFICIAL (vdecl))
              && !gimple_nop_p (SSA_NAME_DEF_STMT (expr)))
            {
              gimple def_stmt = SSA_NAME_DEF_STMT (expr);
              /* We are only interested in an assignment with a single
                 rhs operand because if it is not, the original assignment
                 will not possibly be a self-assignment.  */
              if (gimple_assign_single_p (def_stmt))
                return get_real_ref_rhs (gimple_assign_rhs1 (def_stmt));
              else
                return NULL_TREE;
            }
          else
            return vdecl;
        }
      case VAR_DECL:
      case PARM_DECL:
      case FIELD_DECL:
      case COMPONENT_REF:
      case MEM_REF:
      case ARRAY_REF:
        return expr;
      default:
        return NULL_TREE;
    }
}
示例#30
0
static void
warn_self_assign (gimple stmt)
{
  tree rhs, lhs;

  /* Check assigment statement.  */
  if (gimple_assign_single_p (stmt))
    {
      rhs = get_real_ref_rhs (gimple_assign_rhs1 (stmt));
      if (!rhs)
        return;

      lhs = gimple_assign_lhs (stmt);
      if (TREE_CODE (lhs) == SSA_NAME)
        {
          lhs = SSA_NAME_VAR (lhs);
          if (!lhs || DECL_ARTIFICIAL (lhs))
            return;
        }

      compare_and_warn (stmt, lhs, rhs);
    }
  /* Check overloaded operator '=' (if enabled).  */
  else if (check_operator_eq && is_gimple_call (stmt))
    {
      tree fdecl = gimple_call_fndecl (stmt);
      if (fdecl && (DECL_NAME (fdecl) == maybe_get_identifier ("operator=")))
        {
          /* If 'operator=' takes reference operands, the arguments will be 
             ADDR_EXPR trees. In this case, just remove the address-taken
             operator before we compare the lhs and rhs.  */
          lhs = gimple_call_arg (stmt, 0);
          if (TREE_CODE (lhs) == ADDR_EXPR)
            lhs = TREE_OPERAND (lhs, 0);
          rhs = gimple_call_arg (stmt, 1);
          if (TREE_CODE (rhs) == ADDR_EXPR)
            rhs = TREE_OPERAND (rhs, 0);

          compare_and_warn (stmt, lhs, rhs);
        }
    }
}