1 | /* Generic hooks for the RTL middle-end. |
2 | Copyright (C) 2004-2023 Free Software Foundation, Inc. |
3 | |
4 | This file is part of GCC. |
5 | |
6 | GCC is free software; you can redistribute it and/or modify it under |
7 | the terms of the GNU General Public License as published by the Free |
8 | Software Foundation; either version 3, or (at your option) any later |
9 | version. |
10 | |
11 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
12 | WARRANTY; without even the implied warranty of MERCHANTABILITY or |
13 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
14 | for more details. |
15 | |
16 | You should have received a copy of the GNU General Public License |
17 | along with GCC; see the file COPYING3. If not see |
18 | <http://www.gnu.org/licenses/>. */ |
19 | |
20 | #include "config.h" |
21 | #include "system.h" |
22 | #include "coretypes.h" |
23 | #include "tm.h" |
24 | #include "function.h" |
25 | #include "rtl.h" |
26 | #include "tree.h" |
27 | #include "insn-config.h" |
28 | #include "memmodel.h" |
29 | #include "emit-rtl.h" |
30 | #include "recog.h" |
31 | #include "rtlhooks-def.h" |
32 | #include "explow.h" |
33 | #include "target.h" |
34 | |
35 | |
36 | /* For speed, we will copy the RTX hooks struct member-by-member |
37 | instead of doing indirect calls. For these reason, we initialize |
38 | *two* struct rtl_hooks globals: rtl_hooks is the one that is used |
39 | to actually call the hooks, while general_rtl_hooks is used |
40 | to restore the hooks by passes that modify them. */ |
41 | |
42 | const struct rtl_hooks general_rtl_hooks = RTL_HOOKS_INITIALIZER; |
43 | struct rtl_hooks rtl_hooks = RTL_HOOKS_INITIALIZER; |
44 | |
45 | rtx |
46 | gen_lowpart_general (machine_mode mode, rtx x) |
47 | { |
48 | rtx result = gen_lowpart_common (mode, x); |
49 | |
50 | if (result) |
51 | return result; |
52 | /* Handle SUBREGs and hard REGs that were rejected by |
53 | simplify_gen_subreg. */ |
54 | else if (REG_P (x) || GET_CODE (x) == SUBREG) |
55 | { |
56 | result = gen_lowpart_common (mode, copy_to_reg (x)); |
57 | gcc_assert (result != 0); |
58 | return result; |
59 | } |
60 | else |
61 | { |
62 | /* The only additional case we can do is MEM. */ |
63 | gcc_assert (MEM_P (x)); |
64 | |
65 | /* The following exposes the use of "x" to CSE. */ |
66 | scalar_int_mode xmode; |
67 | if (is_a <scalar_int_mode> (GET_MODE (x), result: &xmode) |
68 | && GET_MODE_SIZE (mode: xmode) <= UNITS_PER_WORD |
69 | && TRULY_NOOP_TRUNCATION_MODES_P (mode, xmode) |
70 | && !reload_completed) |
71 | return gen_lowpart_general (mode, x: force_reg (xmode, x)); |
72 | |
73 | poly_int64 offset = byte_lowpart_offset (mode, GET_MODE (x)); |
74 | return adjust_address (x, mode, offset); |
75 | } |
76 | } |
77 | |
78 | rtx |
79 | reg_num_sign_bit_copies_general (const_rtx, scalar_int_mode, scalar_int_mode, |
80 | unsigned int *) |
81 | { |
82 | return NULL; |
83 | } |
84 | |
85 | rtx |
86 | reg_nonzero_bits_general (const_rtx, scalar_int_mode, scalar_int_mode, |
87 | unsigned HOST_WIDE_INT *) |
88 | { |
89 | return NULL; |
90 | } |
91 | |
92 | bool |
93 | reg_truncated_to_mode_general (machine_mode mode ATTRIBUTE_UNUSED, |
94 | const_rtx x ATTRIBUTE_UNUSED) |
95 | { |
96 | return false; |
97 | } |
98 | |
99 | /* Assuming that X is an rtx (e.g., MEM, REG or SUBREG) for a fixed-point |
100 | number, return an rtx (MEM, SUBREG, or CONST_INT) that refers to the |
101 | least-significant part of X. |
102 | MODE specifies how big a part of X to return. |
103 | |
104 | If the requested operation cannot be done, 0 is returned. |
105 | |
106 | This is similar to gen_lowpart_general. */ |
107 | |
108 | rtx |
109 | gen_lowpart_if_possible (machine_mode mode, rtx x) |
110 | { |
111 | rtx result = gen_lowpart_common (mode, x); |
112 | |
113 | if (result) |
114 | return result; |
115 | else if (MEM_P (x)) |
116 | { |
117 | /* This is the only other case we handle. */ |
118 | poly_int64 offset = byte_lowpart_offset (mode, GET_MODE (x)); |
119 | rtx new_rtx = adjust_address_nv (x, mode, offset); |
120 | if (! memory_address_addr_space_p (mode, XEXP (new_rtx, 0), |
121 | MEM_ADDR_SPACE (x))) |
122 | return 0; |
123 | |
124 | return new_rtx; |
125 | } |
126 | else if (mode != GET_MODE (x) && GET_MODE (x) != VOIDmode && !SUBREG_P (x) |
127 | && validate_subreg (mode, GET_MODE (x), x, |
128 | subreg_lowpart_offset (outermode: mode, GET_MODE (x)))) |
129 | return gen_lowpart_SUBREG (mode, x); |
130 | else |
131 | return 0; |
132 | } |
133 | |
134 | |