/* Optimization of removing unnecessary casts. Copyright (C) 2004 Free Software Foundation, Inc. This file is part of GCC. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "config.h" #include "system.h" #include "coretypes.h" #include "tm.h" #include "errors.h" #include "ggc.h" #include "tree.h" #include "flags.h" #include "rtl.h" #include "tm_p.h" #include "basic-block.h" #include "timevar.h" #include "diagnostic.h" #include "tree-flow.h" #include "tree-pass.h" #include "tree-dump.h" static void tree_ssa_cast (void); static void tree_ssa_cast (void) { basic_block bb; /* Search every basic block for return nodes we may be able to optimize. */ FOR_EACH_BB (bb) { block_stmt_iterator bsi; for(bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) { bool replace_return = false; tree stmt = bsi_stmt (bsi); tree intermed_var; tree type_intermed; tree type_to; tree stmt_intermed; tree from_variable; tree type_from; if (TREE_CODE (stmt) == MODIFY_EXPR && is_gimple_cast (TREE_OPERAND (stmt, 1))) ; else continue; intermed_var = TREE_OPERAND (TREE_OPERAND (stmt, 1), 0); type_intermed = TREE_TYPE (intermed_var); type_to = TREE_TYPE (TREE_OPERAND (stmt, 0)); if (TREE_CODE (intermed_var) != SSA_NAME) continue; stmt_intermed = SSA_NAME_DEF_STMT (intermed_var); if (stmt_intermed != NULL_TREE && TREE_CODE (stmt_intermed) == MODIFY_EXPR && is_gimple_cast (TREE_OPERAND (stmt_intermed, 1))) ; else continue; from_variable = TREE_OPERAND (TREE_OPERAND (stmt_intermed, 1), 0); type_from = TREE_TYPE (from_variable); if (TYPE_MAIN_VARIANT (type_from) == TYPE_MAIN_VARIANT (type_to)) { /* The type that is being converted intermediate is larger or equal to than the current type. */ if (!tree_int_cst_lt (TYPE_SIZE (type_intermed), TYPE_SIZE (type_from))) { /* We can now remove the current casts except for the cast between the from and to. */ TREE_OPERAND (stmt, 1) = from_variable; } else { /* TODO: truncate if we can, using AND_EXPR. */ } } } } cleanup_tree_cfg (); } /* Always do these optimizations if we have SSA trees to work on. */ static bool gate_cast (void) { return 1; } struct tree_opt_pass pass_cast = { "cast", /* name */ gate_cast, /* gate */ tree_ssa_cast, /* execute */ NULL, /* sub */ NULL, /* next */ 0, /* static_pass_number */ TV_TREE_RETURN, /* tv_id */ PROP_cfg | PROP_ssa, /* properties_required */ 0, /* properties_provided */ 0, /* properties_destroyed */ 0, /* todo_flags_start */ TODO_dump_func | TODO_ggc_collect /* todo_flags_finish */ | TODO_verify_ssa | TODO_rename_vars | TODO_verify_flow };