rtlhooks.c revision 169689
1169689Skan/* Generic hooks for the RTL middle-end. 2169689Skan Copyright (C) 2004, 2005 Free Software Foundation, Inc. 3169689Skan 4169689SkanThis file is part of GCC. 5169689Skan 6169689SkanGCC is free software; you can redistribute it and/or modify it under 7169689Skanthe terms of the GNU General Public License as published by the Free 8169689SkanSoftware Foundation; either version 2, or (at your option) any later 9169689Skanversion. 10169689Skan 11169689SkanGCC is distributed in the hope that it will be useful, but WITHOUT ANY 12169689SkanWARRANTY; without even the implied warranty of MERCHANTABILITY or 13169689SkanFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14169689Skanfor more details. 15169689Skan 16169689SkanYou should have received a copy of the GNU General Public License 17169689Skanalong with GCC; see the file COPYING. If not, write to the Free 18169689SkanSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 19169689Skan02110-1301, USA. */ 20169689Skan 21169689Skan#include "config.h" 22169689Skan#include "system.h" 23169689Skan#include "coretypes.h" 24169689Skan#include "tm.h" 25169689Skan#include "rtl.h" 26169689Skan#include "rtlhooks-def.h" 27169689Skan#include "expr.h" 28169689Skan#include "recog.h" 29169689Skan 30169689Skan 31169689Skan/* For speed, we will copy the RTX hooks struct member-by-member 32169689Skan instead of doing indirect calls. For these reason, we initialize 33169689Skan *two* struct rtl_hooks globals: rtl_hooks is the one that is used 34169689Skan to actually call the hooks, while general_rtl_hooks is used 35169689Skan to restore the hooks by passes that modify them. */ 36169689Skan 37169689Skanconst struct rtl_hooks general_rtl_hooks = RTL_HOOKS_INITIALIZER; 38169689Skanstruct rtl_hooks rtl_hooks = RTL_HOOKS_INITIALIZER; 39169689Skan 40169689Skanrtx 41169689Skangen_lowpart_general (enum machine_mode mode, rtx x) 42169689Skan{ 43169689Skan rtx result = gen_lowpart_common (mode, x); 44169689Skan 45169689Skan if (result) 46169689Skan return result; 47169689Skan /* If it's a REG, it must be a hard reg that's not valid in MODE. */ 48169689Skan else if (REG_P (x) 49169689Skan /* Or we could have a subreg of a floating point value. */ 50169689Skan || (GET_CODE (x) == SUBREG 51169689Skan && FLOAT_MODE_P (GET_MODE (SUBREG_REG (x))))) 52169689Skan { 53169689Skan result = gen_lowpart_common (mode, copy_to_reg (x)); 54169689Skan gcc_assert (result != 0); 55169689Skan return result; 56169689Skan } 57169689Skan else 58169689Skan { 59169689Skan int offset = 0; 60169689Skan 61169689Skan /* The only additional case we can do is MEM. */ 62169689Skan gcc_assert (MEM_P (x)); 63169689Skan 64169689Skan /* The following exposes the use of "x" to CSE. */ 65169689Skan if (GET_MODE_SIZE (GET_MODE (x)) <= UNITS_PER_WORD 66169689Skan && SCALAR_INT_MODE_P (GET_MODE (x)) 67169689Skan && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode), 68169689Skan GET_MODE_BITSIZE (GET_MODE (x))) 69169689Skan && ! no_new_pseudos) 70169689Skan return gen_lowpart_general (mode, force_reg (GET_MODE (x), x)); 71169689Skan 72169689Skan if (WORDS_BIG_ENDIAN) 73169689Skan offset = (MAX (GET_MODE_SIZE (GET_MODE (x)), UNITS_PER_WORD) 74169689Skan - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD)); 75169689Skan 76169689Skan if (BYTES_BIG_ENDIAN) 77169689Skan /* Adjust the address so that the address-after-the-data 78169689Skan is unchanged. */ 79169689Skan offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode)) 80169689Skan - MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x)))); 81169689Skan 82169689Skan return adjust_address (x, mode, offset); 83169689Skan } 84169689Skan} 85169689Skan 86169689Skan/* Similar to gen_lowpart, but cannot emit any instruction via 87169689Skan copy_to_reg or force_reg. Mainly used in simplify-rtx.c. */ 88169689Skanrtx 89169689Skangen_lowpart_no_emit_general (enum machine_mode mode, rtx x) 90169689Skan{ 91169689Skan rtx result = gen_lowpart_if_possible (mode, x); 92169689Skan if (result) 93169689Skan return result; 94169689Skan else 95169689Skan return x; 96169689Skan} 97169689Skan 98169689Skanrtx 99169689Skanreg_num_sign_bit_copies_general (rtx x ATTRIBUTE_UNUSED, 100169689Skan enum machine_mode mode ATTRIBUTE_UNUSED, 101169689Skan rtx known_x ATTRIBUTE_UNUSED, 102169689Skan enum machine_mode known_mode ATTRIBUTE_UNUSED, 103169689Skan unsigned int known_ret ATTRIBUTE_UNUSED, 104169689Skan unsigned int *result ATTRIBUTE_UNUSED) 105169689Skan{ 106169689Skan return NULL; 107169689Skan} 108169689Skan 109169689Skanrtx 110169689Skanreg_nonzero_bits_general (rtx x ATTRIBUTE_UNUSED, 111169689Skan enum machine_mode mode ATTRIBUTE_UNUSED, 112169689Skan rtx known_x ATTRIBUTE_UNUSED, 113169689Skan enum machine_mode known_mode ATTRIBUTE_UNUSED, 114169689Skan unsigned HOST_WIDE_INT known_ret ATTRIBUTE_UNUSED, 115169689Skan unsigned HOST_WIDE_INT *nonzero ATTRIBUTE_UNUSED) 116169689Skan{ 117169689Skan return NULL; 118169689Skan} 119169689Skan 120169689Skanbool 121169689Skanreg_truncated_to_mode_general (enum machine_mode mode ATTRIBUTE_UNUSED, 122169689Skan rtx x ATTRIBUTE_UNUSED) 123169689Skan{ 124169689Skan return false; 125169689Skan} 126169689Skan 127169689Skan/* Assuming that X is an rtx (e.g., MEM, REG or SUBREG) for a fixed-point 128169689Skan number, return an rtx (MEM, SUBREG, or CONST_INT) that refers to the 129169689Skan least-significant part of X. 130169689Skan MODE specifies how big a part of X to return. 131169689Skan 132169689Skan If the requested operation cannot be done, 0 is returned. 133169689Skan 134169689Skan This is similar to gen_lowpart_general. */ 135169689Skan 136169689Skanrtx 137169689Skangen_lowpart_if_possible (enum machine_mode mode, rtx x) 138169689Skan{ 139169689Skan rtx result = gen_lowpart_common (mode, x); 140169689Skan 141169689Skan if (result) 142169689Skan return result; 143169689Skan else if (MEM_P (x)) 144169689Skan { 145169689Skan /* This is the only other case we handle. */ 146169689Skan int offset = 0; 147169689Skan rtx new; 148169689Skan 149169689Skan if (WORDS_BIG_ENDIAN) 150169689Skan offset = (MAX (GET_MODE_SIZE (GET_MODE (x)), UNITS_PER_WORD) 151169689Skan - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD)); 152169689Skan if (BYTES_BIG_ENDIAN) 153169689Skan /* Adjust the address so that the address-after-the-data is 154169689Skan unchanged. */ 155169689Skan offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode)) 156169689Skan - MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x)))); 157169689Skan 158169689Skan new = adjust_address_nv (x, mode, offset); 159169689Skan if (! memory_address_p (mode, XEXP (new, 0))) 160169689Skan return 0; 161169689Skan 162169689Skan return new; 163169689Skan } 164169689Skan else if (mode != GET_MODE (x) && GET_MODE (x) != VOIDmode) 165169689Skan return gen_lowpart_SUBREG (mode, x); 166169689Skan else 167169689Skan return 0; 168169689Skan} 169169689Skan 170