1e4b17023SJohn Marino /* Medium-level subroutines: convert bit-field store and extract
2e4b17023SJohn Marino and shifts, multiplies and divides to rtl instructions.
3e4b17023SJohn Marino Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
4e4b17023SJohn Marino 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
5e4b17023SJohn Marino 2011
6e4b17023SJohn Marino Free Software Foundation, Inc.
7e4b17023SJohn Marino
8e4b17023SJohn Marino This file is part of GCC.
9e4b17023SJohn Marino
10e4b17023SJohn Marino GCC is free software; you can redistribute it and/or modify it under
11e4b17023SJohn Marino the terms of the GNU General Public License as published by the Free
12e4b17023SJohn Marino Software Foundation; either version 3, or (at your option) any later
13e4b17023SJohn Marino version.
14e4b17023SJohn Marino
15e4b17023SJohn Marino GCC is distributed in the hope that it will be useful, but WITHOUT ANY
16e4b17023SJohn Marino WARRANTY; without even the implied warranty of MERCHANTABILITY or
17e4b17023SJohn Marino FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18e4b17023SJohn Marino for more details.
19e4b17023SJohn Marino
20e4b17023SJohn Marino You should have received a copy of the GNU General Public License
21e4b17023SJohn Marino along with GCC; see the file COPYING3. If not see
22e4b17023SJohn Marino <http://www.gnu.org/licenses/>. */
23e4b17023SJohn Marino
24e4b17023SJohn Marino
25e4b17023SJohn Marino #include "config.h"
26e4b17023SJohn Marino #include "system.h"
27e4b17023SJohn Marino #include "coretypes.h"
28e4b17023SJohn Marino #include "tm.h"
29e4b17023SJohn Marino #include "diagnostic-core.h"
30e4b17023SJohn Marino #include "rtl.h"
31e4b17023SJohn Marino #include "tree.h"
32e4b17023SJohn Marino #include "tm_p.h"
33e4b17023SJohn Marino #include "flags.h"
34e4b17023SJohn Marino #include "insn-config.h"
35e4b17023SJohn Marino #include "expr.h"
36e4b17023SJohn Marino #include "optabs.h"
37e4b17023SJohn Marino #include "recog.h"
38e4b17023SJohn Marino #include "langhooks.h"
39e4b17023SJohn Marino #include "df.h"
40e4b17023SJohn Marino #include "target.h"
41e4b17023SJohn Marino #include "expmed.h"
42e4b17023SJohn Marino
43e4b17023SJohn Marino struct target_expmed default_target_expmed;
44e4b17023SJohn Marino #if SWITCHABLE_TARGET
45e4b17023SJohn Marino struct target_expmed *this_target_expmed = &default_target_expmed;
46e4b17023SJohn Marino #endif
47e4b17023SJohn Marino
48e4b17023SJohn Marino static void store_fixed_bit_field (rtx, unsigned HOST_WIDE_INT,
49e4b17023SJohn Marino unsigned HOST_WIDE_INT,
50e4b17023SJohn Marino unsigned HOST_WIDE_INT,
51e4b17023SJohn Marino unsigned HOST_WIDE_INT,
52e4b17023SJohn Marino unsigned HOST_WIDE_INT,
53e4b17023SJohn Marino rtx);
54e4b17023SJohn Marino static void store_split_bit_field (rtx, unsigned HOST_WIDE_INT,
55e4b17023SJohn Marino unsigned HOST_WIDE_INT,
56e4b17023SJohn Marino unsigned HOST_WIDE_INT,
57e4b17023SJohn Marino unsigned HOST_WIDE_INT,
58e4b17023SJohn Marino rtx);
59e4b17023SJohn Marino static rtx extract_fixed_bit_field (enum machine_mode, rtx,
60e4b17023SJohn Marino unsigned HOST_WIDE_INT,
61e4b17023SJohn Marino unsigned HOST_WIDE_INT,
62e4b17023SJohn Marino unsigned HOST_WIDE_INT, rtx, int, bool);
63e4b17023SJohn Marino static rtx mask_rtx (enum machine_mode, int, int, int);
64e4b17023SJohn Marino static rtx lshift_value (enum machine_mode, rtx, int, int);
65e4b17023SJohn Marino static rtx extract_split_bit_field (rtx, unsigned HOST_WIDE_INT,
66e4b17023SJohn Marino unsigned HOST_WIDE_INT, int);
67e4b17023SJohn Marino static void do_cmp_and_jump (rtx, rtx, enum rtx_code, enum machine_mode, rtx);
68e4b17023SJohn Marino static rtx expand_smod_pow2 (enum machine_mode, rtx, HOST_WIDE_INT);
69e4b17023SJohn Marino static rtx expand_sdiv_pow2 (enum machine_mode, rtx, HOST_WIDE_INT);
70e4b17023SJohn Marino
71e4b17023SJohn Marino /* Test whether a value is zero of a power of two. */
72e4b17023SJohn Marino #define EXACT_POWER_OF_2_OR_ZERO_P(x) (((x) & ((x) - 1)) == 0)
73e4b17023SJohn Marino
74e4b17023SJohn Marino #ifndef SLOW_UNALIGNED_ACCESS
75e4b17023SJohn Marino #define SLOW_UNALIGNED_ACCESS(MODE, ALIGN) STRICT_ALIGNMENT
76e4b17023SJohn Marino #endif
77e4b17023SJohn Marino
78e4b17023SJohn Marino
79e4b17023SJohn Marino /* Reduce conditional compilation elsewhere. */
80e4b17023SJohn Marino #ifndef HAVE_insv
81e4b17023SJohn Marino #define HAVE_insv 0
82e4b17023SJohn Marino #define CODE_FOR_insv CODE_FOR_nothing
83e4b17023SJohn Marino #define gen_insv(a,b,c,d) NULL_RTX
84e4b17023SJohn Marino #endif
85e4b17023SJohn Marino #ifndef HAVE_extv
86e4b17023SJohn Marino #define HAVE_extv 0
87e4b17023SJohn Marino #define CODE_FOR_extv CODE_FOR_nothing
88e4b17023SJohn Marino #define gen_extv(a,b,c,d) NULL_RTX
89e4b17023SJohn Marino #endif
90e4b17023SJohn Marino #ifndef HAVE_extzv
91e4b17023SJohn Marino #define HAVE_extzv 0
92e4b17023SJohn Marino #define CODE_FOR_extzv CODE_FOR_nothing
93e4b17023SJohn Marino #define gen_extzv(a,b,c,d) NULL_RTX
94e4b17023SJohn Marino #endif
95e4b17023SJohn Marino
96e4b17023SJohn Marino void
init_expmed(void)97e4b17023SJohn Marino init_expmed (void)
98e4b17023SJohn Marino {
99e4b17023SJohn Marino struct
100e4b17023SJohn Marino {
101e4b17023SJohn Marino struct rtx_def reg; rtunion reg_fld[2];
102e4b17023SJohn Marino struct rtx_def plus; rtunion plus_fld1;
103e4b17023SJohn Marino struct rtx_def neg;
104e4b17023SJohn Marino struct rtx_def mult; rtunion mult_fld1;
105e4b17023SJohn Marino struct rtx_def sdiv; rtunion sdiv_fld1;
106e4b17023SJohn Marino struct rtx_def udiv; rtunion udiv_fld1;
107e4b17023SJohn Marino struct rtx_def zext;
108e4b17023SJohn Marino struct rtx_def sdiv_32; rtunion sdiv_32_fld1;
109e4b17023SJohn Marino struct rtx_def smod_32; rtunion smod_32_fld1;
110e4b17023SJohn Marino struct rtx_def wide_mult; rtunion wide_mult_fld1;
111e4b17023SJohn Marino struct rtx_def wide_lshr; rtunion wide_lshr_fld1;
112e4b17023SJohn Marino struct rtx_def wide_trunc;
113e4b17023SJohn Marino struct rtx_def shift; rtunion shift_fld1;
114e4b17023SJohn Marino struct rtx_def shift_mult; rtunion shift_mult_fld1;
115e4b17023SJohn Marino struct rtx_def shift_add; rtunion shift_add_fld1;
116e4b17023SJohn Marino struct rtx_def shift_sub0; rtunion shift_sub0_fld1;
117e4b17023SJohn Marino struct rtx_def shift_sub1; rtunion shift_sub1_fld1;
118e4b17023SJohn Marino } all;
119e4b17023SJohn Marino
120e4b17023SJohn Marino rtx pow2[MAX_BITS_PER_WORD];
121e4b17023SJohn Marino rtx cint[MAX_BITS_PER_WORD];
122e4b17023SJohn Marino int m, n;
123e4b17023SJohn Marino enum machine_mode mode, wider_mode;
124e4b17023SJohn Marino int speed;
125e4b17023SJohn Marino
126e4b17023SJohn Marino
127e4b17023SJohn Marino for (m = 1; m < MAX_BITS_PER_WORD; m++)
128e4b17023SJohn Marino {
129e4b17023SJohn Marino pow2[m] = GEN_INT ((HOST_WIDE_INT) 1 << m);
130e4b17023SJohn Marino cint[m] = GEN_INT (m);
131e4b17023SJohn Marino }
132e4b17023SJohn Marino memset (&all, 0, sizeof all);
133e4b17023SJohn Marino
134e4b17023SJohn Marino PUT_CODE (&all.reg, REG);
135e4b17023SJohn Marino /* Avoid using hard regs in ways which may be unsupported. */
136e4b17023SJohn Marino SET_REGNO (&all.reg, LAST_VIRTUAL_REGISTER + 1);
137e4b17023SJohn Marino
138e4b17023SJohn Marino PUT_CODE (&all.plus, PLUS);
139e4b17023SJohn Marino XEXP (&all.plus, 0) = &all.reg;
140e4b17023SJohn Marino XEXP (&all.plus, 1) = &all.reg;
141e4b17023SJohn Marino
142e4b17023SJohn Marino PUT_CODE (&all.neg, NEG);
143e4b17023SJohn Marino XEXP (&all.neg, 0) = &all.reg;
144e4b17023SJohn Marino
145e4b17023SJohn Marino PUT_CODE (&all.mult, MULT);
146e4b17023SJohn Marino XEXP (&all.mult, 0) = &all.reg;
147e4b17023SJohn Marino XEXP (&all.mult, 1) = &all.reg;
148e4b17023SJohn Marino
149e4b17023SJohn Marino PUT_CODE (&all.sdiv, DIV);
150e4b17023SJohn Marino XEXP (&all.sdiv, 0) = &all.reg;
151e4b17023SJohn Marino XEXP (&all.sdiv, 1) = &all.reg;
152e4b17023SJohn Marino
153e4b17023SJohn Marino PUT_CODE (&all.udiv, UDIV);
154e4b17023SJohn Marino XEXP (&all.udiv, 0) = &all.reg;
155e4b17023SJohn Marino XEXP (&all.udiv, 1) = &all.reg;
156e4b17023SJohn Marino
157e4b17023SJohn Marino PUT_CODE (&all.sdiv_32, DIV);
158e4b17023SJohn Marino XEXP (&all.sdiv_32, 0) = &all.reg;
159e4b17023SJohn Marino XEXP (&all.sdiv_32, 1) = 32 < MAX_BITS_PER_WORD ? cint[32] : GEN_INT (32);
160e4b17023SJohn Marino
161e4b17023SJohn Marino PUT_CODE (&all.smod_32, MOD);
162e4b17023SJohn Marino XEXP (&all.smod_32, 0) = &all.reg;
163e4b17023SJohn Marino XEXP (&all.smod_32, 1) = XEXP (&all.sdiv_32, 1);
164e4b17023SJohn Marino
165e4b17023SJohn Marino PUT_CODE (&all.zext, ZERO_EXTEND);
166e4b17023SJohn Marino XEXP (&all.zext, 0) = &all.reg;
167e4b17023SJohn Marino
168e4b17023SJohn Marino PUT_CODE (&all.wide_mult, MULT);
169e4b17023SJohn Marino XEXP (&all.wide_mult, 0) = &all.zext;
170e4b17023SJohn Marino XEXP (&all.wide_mult, 1) = &all.zext;
171e4b17023SJohn Marino
172e4b17023SJohn Marino PUT_CODE (&all.wide_lshr, LSHIFTRT);
173e4b17023SJohn Marino XEXP (&all.wide_lshr, 0) = &all.wide_mult;
174e4b17023SJohn Marino
175e4b17023SJohn Marino PUT_CODE (&all.wide_trunc, TRUNCATE);
176e4b17023SJohn Marino XEXP (&all.wide_trunc, 0) = &all.wide_lshr;
177e4b17023SJohn Marino
178e4b17023SJohn Marino PUT_CODE (&all.shift, ASHIFT);
179e4b17023SJohn Marino XEXP (&all.shift, 0) = &all.reg;
180e4b17023SJohn Marino
181e4b17023SJohn Marino PUT_CODE (&all.shift_mult, MULT);
182e4b17023SJohn Marino XEXP (&all.shift_mult, 0) = &all.reg;
183e4b17023SJohn Marino
184e4b17023SJohn Marino PUT_CODE (&all.shift_add, PLUS);
185e4b17023SJohn Marino XEXP (&all.shift_add, 0) = &all.shift_mult;
186e4b17023SJohn Marino XEXP (&all.shift_add, 1) = &all.reg;
187e4b17023SJohn Marino
188e4b17023SJohn Marino PUT_CODE (&all.shift_sub0, MINUS);
189e4b17023SJohn Marino XEXP (&all.shift_sub0, 0) = &all.shift_mult;
190e4b17023SJohn Marino XEXP (&all.shift_sub0, 1) = &all.reg;
191e4b17023SJohn Marino
192e4b17023SJohn Marino PUT_CODE (&all.shift_sub1, MINUS);
193e4b17023SJohn Marino XEXP (&all.shift_sub1, 0) = &all.reg;
194e4b17023SJohn Marino XEXP (&all.shift_sub1, 1) = &all.shift_mult;
195e4b17023SJohn Marino
196e4b17023SJohn Marino for (speed = 0; speed < 2; speed++)
197e4b17023SJohn Marino {
198e4b17023SJohn Marino crtl->maybe_hot_insn_p = speed;
199e4b17023SJohn Marino zero_cost[speed] = set_src_cost (const0_rtx, speed);
200e4b17023SJohn Marino
201e4b17023SJohn Marino for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
202e4b17023SJohn Marino mode != VOIDmode;
203e4b17023SJohn Marino mode = GET_MODE_WIDER_MODE (mode))
204e4b17023SJohn Marino {
205e4b17023SJohn Marino PUT_MODE (&all.reg, mode);
206e4b17023SJohn Marino PUT_MODE (&all.plus, mode);
207e4b17023SJohn Marino PUT_MODE (&all.neg, mode);
208e4b17023SJohn Marino PUT_MODE (&all.mult, mode);
209e4b17023SJohn Marino PUT_MODE (&all.sdiv, mode);
210e4b17023SJohn Marino PUT_MODE (&all.udiv, mode);
211e4b17023SJohn Marino PUT_MODE (&all.sdiv_32, mode);
212e4b17023SJohn Marino PUT_MODE (&all.smod_32, mode);
213e4b17023SJohn Marino PUT_MODE (&all.wide_trunc, mode);
214e4b17023SJohn Marino PUT_MODE (&all.shift, mode);
215e4b17023SJohn Marino PUT_MODE (&all.shift_mult, mode);
216e4b17023SJohn Marino PUT_MODE (&all.shift_add, mode);
217e4b17023SJohn Marino PUT_MODE (&all.shift_sub0, mode);
218e4b17023SJohn Marino PUT_MODE (&all.shift_sub1, mode);
219e4b17023SJohn Marino
220e4b17023SJohn Marino add_cost[speed][mode] = set_src_cost (&all.plus, speed);
221e4b17023SJohn Marino neg_cost[speed][mode] = set_src_cost (&all.neg, speed);
222e4b17023SJohn Marino mul_cost[speed][mode] = set_src_cost (&all.mult, speed);
223e4b17023SJohn Marino sdiv_cost[speed][mode] = set_src_cost (&all.sdiv, speed);
224e4b17023SJohn Marino udiv_cost[speed][mode] = set_src_cost (&all.udiv, speed);
225e4b17023SJohn Marino
226e4b17023SJohn Marino sdiv_pow2_cheap[speed][mode] = (set_src_cost (&all.sdiv_32, speed)
227e4b17023SJohn Marino <= 2 * add_cost[speed][mode]);
228e4b17023SJohn Marino smod_pow2_cheap[speed][mode] = (set_src_cost (&all.smod_32, speed)
229e4b17023SJohn Marino <= 4 * add_cost[speed][mode]);
230e4b17023SJohn Marino
231e4b17023SJohn Marino wider_mode = GET_MODE_WIDER_MODE (mode);
232e4b17023SJohn Marino if (wider_mode != VOIDmode)
233e4b17023SJohn Marino {
234e4b17023SJohn Marino PUT_MODE (&all.zext, wider_mode);
235e4b17023SJohn Marino PUT_MODE (&all.wide_mult, wider_mode);
236e4b17023SJohn Marino PUT_MODE (&all.wide_lshr, wider_mode);
237e4b17023SJohn Marino XEXP (&all.wide_lshr, 1) = GEN_INT (GET_MODE_BITSIZE (mode));
238e4b17023SJohn Marino
239e4b17023SJohn Marino mul_widen_cost[speed][wider_mode]
240e4b17023SJohn Marino = set_src_cost (&all.wide_mult, speed);
241e4b17023SJohn Marino mul_highpart_cost[speed][mode]
242e4b17023SJohn Marino = set_src_cost (&all.wide_trunc, speed);
243e4b17023SJohn Marino }
244e4b17023SJohn Marino
245e4b17023SJohn Marino shift_cost[speed][mode][0] = 0;
246e4b17023SJohn Marino shiftadd_cost[speed][mode][0] = shiftsub0_cost[speed][mode][0]
247e4b17023SJohn Marino = shiftsub1_cost[speed][mode][0] = add_cost[speed][mode];
248e4b17023SJohn Marino
249e4b17023SJohn Marino n = MIN (MAX_BITS_PER_WORD, GET_MODE_BITSIZE (mode));
250e4b17023SJohn Marino for (m = 1; m < n; m++)
251e4b17023SJohn Marino {
252e4b17023SJohn Marino XEXP (&all.shift, 1) = cint[m];
253e4b17023SJohn Marino XEXP (&all.shift_mult, 1) = pow2[m];
254e4b17023SJohn Marino
255e4b17023SJohn Marino shift_cost[speed][mode][m] = set_src_cost (&all.shift, speed);
256e4b17023SJohn Marino shiftadd_cost[speed][mode][m] = set_src_cost (&all.shift_add,
257e4b17023SJohn Marino speed);
258e4b17023SJohn Marino shiftsub0_cost[speed][mode][m] = set_src_cost (&all.shift_sub0,
259e4b17023SJohn Marino speed);
260e4b17023SJohn Marino shiftsub1_cost[speed][mode][m] = set_src_cost (&all.shift_sub1,
261e4b17023SJohn Marino speed);
262e4b17023SJohn Marino }
263e4b17023SJohn Marino }
264e4b17023SJohn Marino }
265e4b17023SJohn Marino if (alg_hash_used_p)
266e4b17023SJohn Marino memset (alg_hash, 0, sizeof (alg_hash));
267e4b17023SJohn Marino else
268e4b17023SJohn Marino alg_hash_used_p = true;
269e4b17023SJohn Marino default_rtl_profile ();
270e4b17023SJohn Marino }
271e4b17023SJohn Marino
272e4b17023SJohn Marino /* Return an rtx representing minus the value of X.
273e4b17023SJohn Marino MODE is the intended mode of the result,
274e4b17023SJohn Marino useful if X is a CONST_INT. */
275e4b17023SJohn Marino
276e4b17023SJohn Marino rtx
negate_rtx(enum machine_mode mode,rtx x)277e4b17023SJohn Marino negate_rtx (enum machine_mode mode, rtx x)
278e4b17023SJohn Marino {
279e4b17023SJohn Marino rtx result = simplify_unary_operation (NEG, mode, x, mode);
280e4b17023SJohn Marino
281e4b17023SJohn Marino if (result == 0)
282e4b17023SJohn Marino result = expand_unop (mode, neg_optab, x, NULL_RTX, 0);
283e4b17023SJohn Marino
284e4b17023SJohn Marino return result;
285e4b17023SJohn Marino }
286e4b17023SJohn Marino
287e4b17023SJohn Marino /* Report on the availability of insv/extv/extzv and the desired mode
288e4b17023SJohn Marino of each of their operands. Returns MAX_MACHINE_MODE if HAVE_foo
289e4b17023SJohn Marino is false; else the mode of the specified operand. If OPNO is -1,
290e4b17023SJohn Marino all the caller cares about is whether the insn is available. */
291e4b17023SJohn Marino enum machine_mode
mode_for_extraction(enum extraction_pattern pattern,int opno)292e4b17023SJohn Marino mode_for_extraction (enum extraction_pattern pattern, int opno)
293e4b17023SJohn Marino {
294e4b17023SJohn Marino const struct insn_data_d *data;
295e4b17023SJohn Marino
296e4b17023SJohn Marino switch (pattern)
297e4b17023SJohn Marino {
298e4b17023SJohn Marino case EP_insv:
299e4b17023SJohn Marino if (HAVE_insv)
300e4b17023SJohn Marino {
301e4b17023SJohn Marino data = &insn_data[CODE_FOR_insv];
302e4b17023SJohn Marino break;
303e4b17023SJohn Marino }
304e4b17023SJohn Marino return MAX_MACHINE_MODE;
305e4b17023SJohn Marino
306e4b17023SJohn Marino case EP_extv:
307e4b17023SJohn Marino if (HAVE_extv)
308e4b17023SJohn Marino {
309e4b17023SJohn Marino data = &insn_data[CODE_FOR_extv];
310e4b17023SJohn Marino break;
311e4b17023SJohn Marino }
312e4b17023SJohn Marino return MAX_MACHINE_MODE;
313e4b17023SJohn Marino
314e4b17023SJohn Marino case EP_extzv:
315e4b17023SJohn Marino if (HAVE_extzv)
316e4b17023SJohn Marino {
317e4b17023SJohn Marino data = &insn_data[CODE_FOR_extzv];
318e4b17023SJohn Marino break;
319e4b17023SJohn Marino }
320e4b17023SJohn Marino return MAX_MACHINE_MODE;
321e4b17023SJohn Marino
322e4b17023SJohn Marino default:
323e4b17023SJohn Marino gcc_unreachable ();
324e4b17023SJohn Marino }
325e4b17023SJohn Marino
326e4b17023SJohn Marino if (opno == -1)
327e4b17023SJohn Marino return VOIDmode;
328e4b17023SJohn Marino
329e4b17023SJohn Marino /* Everyone who uses this function used to follow it with
330e4b17023SJohn Marino if (result == VOIDmode) result = word_mode; */
331e4b17023SJohn Marino if (data->operand[opno].mode == VOIDmode)
332e4b17023SJohn Marino return word_mode;
333e4b17023SJohn Marino return data->operand[opno].mode;
334e4b17023SJohn Marino }
335e4b17023SJohn Marino
336e4b17023SJohn Marino /* A subroutine of store_bit_field, with the same arguments. Return true
337e4b17023SJohn Marino if the operation could be implemented.
338e4b17023SJohn Marino
339e4b17023SJohn Marino If FALLBACK_P is true, fall back to store_fixed_bit_field if we have
340e4b17023SJohn Marino no other way of implementing the operation. If FALLBACK_P is false,
341e4b17023SJohn Marino return false instead. */
342e4b17023SJohn Marino
343e4b17023SJohn Marino static bool
store_bit_field_1(rtx str_rtx,unsigned HOST_WIDE_INT bitsize,unsigned HOST_WIDE_INT bitnum,unsigned HOST_WIDE_INT bitregion_start,unsigned HOST_WIDE_INT bitregion_end,enum machine_mode fieldmode,rtx value,bool fallback_p)344e4b17023SJohn Marino store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
345e4b17023SJohn Marino unsigned HOST_WIDE_INT bitnum,
346e4b17023SJohn Marino unsigned HOST_WIDE_INT bitregion_start,
347e4b17023SJohn Marino unsigned HOST_WIDE_INT bitregion_end,
348e4b17023SJohn Marino enum machine_mode fieldmode,
349e4b17023SJohn Marino rtx value, bool fallback_p)
350e4b17023SJohn Marino {
351e4b17023SJohn Marino unsigned int unit
352e4b17023SJohn Marino = (MEM_P (str_rtx)) ? BITS_PER_UNIT : BITS_PER_WORD;
353e4b17023SJohn Marino unsigned HOST_WIDE_INT offset, bitpos;
354e4b17023SJohn Marino rtx op0 = str_rtx;
355e4b17023SJohn Marino int byte_offset;
356e4b17023SJohn Marino rtx orig_value;
357e4b17023SJohn Marino
358e4b17023SJohn Marino enum machine_mode op_mode = mode_for_extraction (EP_insv, 3);
359e4b17023SJohn Marino
360e4b17023SJohn Marino while (GET_CODE (op0) == SUBREG)
361e4b17023SJohn Marino {
362e4b17023SJohn Marino /* The following line once was done only if WORDS_BIG_ENDIAN,
363e4b17023SJohn Marino but I think that is a mistake. WORDS_BIG_ENDIAN is
364e4b17023SJohn Marino meaningful at a much higher level; when structures are copied
365e4b17023SJohn Marino between memory and regs, the higher-numbered regs
366e4b17023SJohn Marino always get higher addresses. */
367e4b17023SJohn Marino int inner_mode_size = GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0)));
368e4b17023SJohn Marino int outer_mode_size = GET_MODE_SIZE (GET_MODE (op0));
369e4b17023SJohn Marino
370e4b17023SJohn Marino byte_offset = 0;
371e4b17023SJohn Marino
372e4b17023SJohn Marino /* Paradoxical subregs need special handling on big endian machines. */
373e4b17023SJohn Marino if (SUBREG_BYTE (op0) == 0 && inner_mode_size < outer_mode_size)
374e4b17023SJohn Marino {
375e4b17023SJohn Marino int difference = inner_mode_size - outer_mode_size;
376e4b17023SJohn Marino
377e4b17023SJohn Marino if (WORDS_BIG_ENDIAN)
378e4b17023SJohn Marino byte_offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
379e4b17023SJohn Marino if (BYTES_BIG_ENDIAN)
380e4b17023SJohn Marino byte_offset += difference % UNITS_PER_WORD;
381e4b17023SJohn Marino }
382e4b17023SJohn Marino else
383e4b17023SJohn Marino byte_offset = SUBREG_BYTE (op0);
384e4b17023SJohn Marino
385e4b17023SJohn Marino bitnum += byte_offset * BITS_PER_UNIT;
386e4b17023SJohn Marino op0 = SUBREG_REG (op0);
387e4b17023SJohn Marino }
388e4b17023SJohn Marino
389e4b17023SJohn Marino /* No action is needed if the target is a register and if the field
390e4b17023SJohn Marino lies completely outside that register. This can occur if the source
391e4b17023SJohn Marino code contains an out-of-bounds access to a small array. */
392e4b17023SJohn Marino if (REG_P (op0) && bitnum >= GET_MODE_BITSIZE (GET_MODE (op0)))
393e4b17023SJohn Marino return true;
394e4b17023SJohn Marino
395e4b17023SJohn Marino /* Use vec_set patterns for inserting parts of vectors whenever
396e4b17023SJohn Marino available. */
397e4b17023SJohn Marino if (VECTOR_MODE_P (GET_MODE (op0))
398e4b17023SJohn Marino && !MEM_P (op0)
399e4b17023SJohn Marino && optab_handler (vec_set_optab, GET_MODE (op0)) != CODE_FOR_nothing
400e4b17023SJohn Marino && fieldmode == GET_MODE_INNER (GET_MODE (op0))
401e4b17023SJohn Marino && bitsize == GET_MODE_BITSIZE (GET_MODE_INNER (GET_MODE (op0)))
402e4b17023SJohn Marino && !(bitnum % GET_MODE_BITSIZE (GET_MODE_INNER (GET_MODE (op0)))))
403e4b17023SJohn Marino {
404e4b17023SJohn Marino struct expand_operand ops[3];
405e4b17023SJohn Marino enum machine_mode outermode = GET_MODE (op0);
406e4b17023SJohn Marino enum machine_mode innermode = GET_MODE_INNER (outermode);
407e4b17023SJohn Marino enum insn_code icode = optab_handler (vec_set_optab, outermode);
408e4b17023SJohn Marino int pos = bitnum / GET_MODE_BITSIZE (innermode);
409e4b17023SJohn Marino
410e4b17023SJohn Marino create_fixed_operand (&ops[0], op0);
411e4b17023SJohn Marino create_input_operand (&ops[1], value, innermode);
412e4b17023SJohn Marino create_integer_operand (&ops[2], pos);
413e4b17023SJohn Marino if (maybe_expand_insn (icode, 3, ops))
414e4b17023SJohn Marino return true;
415e4b17023SJohn Marino }
416e4b17023SJohn Marino
417e4b17023SJohn Marino /* If the target is a register, overwriting the entire object, or storing
418e4b17023SJohn Marino a full-word or multi-word field can be done with just a SUBREG.
419e4b17023SJohn Marino
420e4b17023SJohn Marino If the target is memory, storing any naturally aligned field can be
421e4b17023SJohn Marino done with a simple store. For targets that support fast unaligned
422e4b17023SJohn Marino memory, any naturally sized, unit aligned field can be done directly. */
423e4b17023SJohn Marino
424e4b17023SJohn Marino offset = bitnum / unit;
425e4b17023SJohn Marino bitpos = bitnum % unit;
426e4b17023SJohn Marino byte_offset = (bitnum % BITS_PER_WORD) / BITS_PER_UNIT
427e4b17023SJohn Marino + (offset * UNITS_PER_WORD);
428e4b17023SJohn Marino
429e4b17023SJohn Marino if (bitpos == 0
430e4b17023SJohn Marino && bitsize == GET_MODE_BITSIZE (fieldmode)
431e4b17023SJohn Marino && (!MEM_P (op0)
432e4b17023SJohn Marino ? ((GET_MODE_SIZE (fieldmode) >= UNITS_PER_WORD
433e4b17023SJohn Marino || GET_MODE_SIZE (GET_MODE (op0)) == GET_MODE_SIZE (fieldmode))
434e4b17023SJohn Marino && ((GET_MODE (op0) == fieldmode && byte_offset == 0)
435e4b17023SJohn Marino || validate_subreg (fieldmode, GET_MODE (op0), op0,
436e4b17023SJohn Marino byte_offset)))
437e4b17023SJohn Marino : (! SLOW_UNALIGNED_ACCESS (fieldmode, MEM_ALIGN (op0))
438e4b17023SJohn Marino || (offset * BITS_PER_UNIT % bitsize == 0
439e4b17023SJohn Marino && MEM_ALIGN (op0) % GET_MODE_BITSIZE (fieldmode) == 0))))
440e4b17023SJohn Marino {
441e4b17023SJohn Marino if (MEM_P (op0))
442e4b17023SJohn Marino op0 = adjust_address (op0, fieldmode, offset);
443e4b17023SJohn Marino else if (GET_MODE (op0) != fieldmode)
444e4b17023SJohn Marino op0 = simplify_gen_subreg (fieldmode, op0, GET_MODE (op0),
445e4b17023SJohn Marino byte_offset);
446e4b17023SJohn Marino emit_move_insn (op0, value);
447e4b17023SJohn Marino return true;
448e4b17023SJohn Marino }
449e4b17023SJohn Marino
450e4b17023SJohn Marino /* Make sure we are playing with integral modes. Pun with subregs
451e4b17023SJohn Marino if we aren't. This must come after the entire register case above,
452e4b17023SJohn Marino since that case is valid for any mode. The following cases are only
453e4b17023SJohn Marino valid for integral modes. */
454e4b17023SJohn Marino {
455e4b17023SJohn Marino enum machine_mode imode = int_mode_for_mode (GET_MODE (op0));
456e4b17023SJohn Marino if (imode != GET_MODE (op0))
457e4b17023SJohn Marino {
458e4b17023SJohn Marino if (MEM_P (op0))
459e4b17023SJohn Marino op0 = adjust_address (op0, imode, 0);
460e4b17023SJohn Marino else
461e4b17023SJohn Marino {
462e4b17023SJohn Marino gcc_assert (imode != BLKmode);
463e4b17023SJohn Marino op0 = gen_lowpart (imode, op0);
464e4b17023SJohn Marino }
465e4b17023SJohn Marino }
466e4b17023SJohn Marino }
467e4b17023SJohn Marino
468e4b17023SJohn Marino /* We may be accessing data outside the field, which means
469e4b17023SJohn Marino we can alias adjacent data. */
470e4b17023SJohn Marino /* ?? not always for C++0x memory model ?? */
471e4b17023SJohn Marino if (MEM_P (op0))
472e4b17023SJohn Marino {
473e4b17023SJohn Marino op0 = shallow_copy_rtx (op0);
474e4b17023SJohn Marino set_mem_alias_set (op0, 0);
475e4b17023SJohn Marino set_mem_expr (op0, 0);
476e4b17023SJohn Marino }
477e4b17023SJohn Marino
478e4b17023SJohn Marino /* If OP0 is a register, BITPOS must count within a word.
479e4b17023SJohn Marino But as we have it, it counts within whatever size OP0 now has.
480e4b17023SJohn Marino On a bigendian machine, these are not the same, so convert. */
481e4b17023SJohn Marino if (BYTES_BIG_ENDIAN
482e4b17023SJohn Marino && !MEM_P (op0)
483e4b17023SJohn Marino && unit > GET_MODE_BITSIZE (GET_MODE (op0)))
484e4b17023SJohn Marino bitpos += unit - GET_MODE_BITSIZE (GET_MODE (op0));
485e4b17023SJohn Marino
486e4b17023SJohn Marino /* Storing an lsb-aligned field in a register
487e4b17023SJohn Marino can be done with a movestrict instruction. */
488e4b17023SJohn Marino
489e4b17023SJohn Marino if (!MEM_P (op0)
490e4b17023SJohn Marino && (BYTES_BIG_ENDIAN ? bitpos + bitsize == unit : bitpos == 0)
491e4b17023SJohn Marino && bitsize == GET_MODE_BITSIZE (fieldmode)
492e4b17023SJohn Marino && optab_handler (movstrict_optab, fieldmode) != CODE_FOR_nothing)
493e4b17023SJohn Marino {
494e4b17023SJohn Marino struct expand_operand ops[2];
495e4b17023SJohn Marino enum insn_code icode = optab_handler (movstrict_optab, fieldmode);
496e4b17023SJohn Marino rtx arg0 = op0;
497e4b17023SJohn Marino unsigned HOST_WIDE_INT subreg_off;
498e4b17023SJohn Marino
499e4b17023SJohn Marino if (GET_CODE (arg0) == SUBREG)
500e4b17023SJohn Marino {
501e4b17023SJohn Marino /* Else we've got some float mode source being extracted into
502e4b17023SJohn Marino a different float mode destination -- this combination of
503e4b17023SJohn Marino subregs results in Severe Tire Damage. */
504e4b17023SJohn Marino gcc_assert (GET_MODE (SUBREG_REG (arg0)) == fieldmode
505e4b17023SJohn Marino || GET_MODE_CLASS (fieldmode) == MODE_INT
506e4b17023SJohn Marino || GET_MODE_CLASS (fieldmode) == MODE_PARTIAL_INT);
507e4b17023SJohn Marino arg0 = SUBREG_REG (arg0);
508e4b17023SJohn Marino }
509e4b17023SJohn Marino
510e4b17023SJohn Marino subreg_off = (bitnum % BITS_PER_WORD) / BITS_PER_UNIT
511e4b17023SJohn Marino + (offset * UNITS_PER_WORD);
512e4b17023SJohn Marino if (validate_subreg (fieldmode, GET_MODE (arg0), arg0, subreg_off))
513e4b17023SJohn Marino {
514e4b17023SJohn Marino arg0 = gen_rtx_SUBREG (fieldmode, arg0, subreg_off);
515e4b17023SJohn Marino
516e4b17023SJohn Marino create_fixed_operand (&ops[0], arg0);
517e4b17023SJohn Marino /* Shrink the source operand to FIELDMODE. */
518e4b17023SJohn Marino create_convert_operand_to (&ops[1], value, fieldmode, false);
519e4b17023SJohn Marino if (maybe_expand_insn (icode, 2, ops))
520e4b17023SJohn Marino return true;
521e4b17023SJohn Marino }
522e4b17023SJohn Marino }
523e4b17023SJohn Marino
524e4b17023SJohn Marino /* Handle fields bigger than a word. */
525e4b17023SJohn Marino
526e4b17023SJohn Marino if (bitsize > BITS_PER_WORD)
527e4b17023SJohn Marino {
528e4b17023SJohn Marino /* Here we transfer the words of the field
529e4b17023SJohn Marino in the order least significant first.
530e4b17023SJohn Marino This is because the most significant word is the one which may
531e4b17023SJohn Marino be less than full.
532e4b17023SJohn Marino However, only do that if the value is not BLKmode. */
533e4b17023SJohn Marino
534e4b17023SJohn Marino unsigned int backwards = WORDS_BIG_ENDIAN && fieldmode != BLKmode;
535e4b17023SJohn Marino unsigned int nwords = (bitsize + (BITS_PER_WORD - 1)) / BITS_PER_WORD;
536e4b17023SJohn Marino unsigned int i;
537e4b17023SJohn Marino rtx last;
538e4b17023SJohn Marino
539e4b17023SJohn Marino /* This is the mode we must force value to, so that there will be enough
540e4b17023SJohn Marino subwords to extract. Note that fieldmode will often (always?) be
541e4b17023SJohn Marino VOIDmode, because that is what store_field uses to indicate that this
542e4b17023SJohn Marino is a bit field, but passing VOIDmode to operand_subword_force
543e4b17023SJohn Marino is not allowed. */
544e4b17023SJohn Marino fieldmode = GET_MODE (value);
545e4b17023SJohn Marino if (fieldmode == VOIDmode)
546e4b17023SJohn Marino fieldmode = smallest_mode_for_size (nwords * BITS_PER_WORD, MODE_INT);
547e4b17023SJohn Marino
548e4b17023SJohn Marino last = get_last_insn ();
549e4b17023SJohn Marino for (i = 0; i < nwords; i++)
550e4b17023SJohn Marino {
551e4b17023SJohn Marino /* If I is 0, use the low-order word in both field and target;
552e4b17023SJohn Marino if I is 1, use the next to lowest word; and so on. */
553e4b17023SJohn Marino unsigned int wordnum = (backwards
554e4b17023SJohn Marino ? GET_MODE_SIZE (fieldmode) / UNITS_PER_WORD
555e4b17023SJohn Marino - i - 1
556e4b17023SJohn Marino : i);
557e4b17023SJohn Marino unsigned int bit_offset = (backwards
558e4b17023SJohn Marino ? MAX ((int) bitsize - ((int) i + 1)
559e4b17023SJohn Marino * BITS_PER_WORD,
560e4b17023SJohn Marino 0)
561e4b17023SJohn Marino : (int) i * BITS_PER_WORD);
562e4b17023SJohn Marino rtx value_word = operand_subword_force (value, wordnum, fieldmode);
563e4b17023SJohn Marino unsigned HOST_WIDE_INT new_bitsize =
564e4b17023SJohn Marino MIN (BITS_PER_WORD, bitsize - i * BITS_PER_WORD);
565e4b17023SJohn Marino
566e4b17023SJohn Marino /* If the remaining chunk doesn't have full wordsize we have
567e4b17023SJohn Marino to make sure that for big endian machines the higher order
568e4b17023SJohn Marino bits are used. */
569e4b17023SJohn Marino if (new_bitsize < BITS_PER_WORD && BYTES_BIG_ENDIAN && !backwards)
570e4b17023SJohn Marino value_word = simplify_expand_binop (word_mode, lshr_optab,
571e4b17023SJohn Marino value_word,
572e4b17023SJohn Marino GEN_INT (BITS_PER_WORD
573e4b17023SJohn Marino - new_bitsize),
574e4b17023SJohn Marino NULL_RTX, true,
575e4b17023SJohn Marino OPTAB_LIB_WIDEN);
576e4b17023SJohn Marino
577e4b17023SJohn Marino if (!store_bit_field_1 (op0, new_bitsize,
578e4b17023SJohn Marino bitnum + bit_offset,
579e4b17023SJohn Marino bitregion_start, bitregion_end,
580e4b17023SJohn Marino word_mode,
581e4b17023SJohn Marino value_word, fallback_p))
582e4b17023SJohn Marino {
583e4b17023SJohn Marino delete_insns_since (last);
584e4b17023SJohn Marino return false;
585e4b17023SJohn Marino }
586e4b17023SJohn Marino }
587e4b17023SJohn Marino return true;
588e4b17023SJohn Marino }
589e4b17023SJohn Marino
590e4b17023SJohn Marino /* From here on we can assume that the field to be stored in is
591e4b17023SJohn Marino a full-word (whatever type that is), since it is shorter than a word. */
592e4b17023SJohn Marino
593e4b17023SJohn Marino /* OFFSET is the number of words or bytes (UNIT says which)
594e4b17023SJohn Marino from STR_RTX to the first word or byte containing part of the field. */
595e4b17023SJohn Marino
596e4b17023SJohn Marino if (!MEM_P (op0))
597e4b17023SJohn Marino {
598e4b17023SJohn Marino if (offset != 0
599e4b17023SJohn Marino || GET_MODE_SIZE (GET_MODE (op0)) > UNITS_PER_WORD)
600e4b17023SJohn Marino {
601e4b17023SJohn Marino if (!REG_P (op0))
602e4b17023SJohn Marino {
603e4b17023SJohn Marino /* Since this is a destination (lvalue), we can't copy
604e4b17023SJohn Marino it to a pseudo. We can remove a SUBREG that does not
605e4b17023SJohn Marino change the size of the operand. Such a SUBREG may
606e4b17023SJohn Marino have been added above. */
607e4b17023SJohn Marino gcc_assert (GET_CODE (op0) == SUBREG
608e4b17023SJohn Marino && (GET_MODE_SIZE (GET_MODE (op0))
609e4b17023SJohn Marino == GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0)))));
610e4b17023SJohn Marino op0 = SUBREG_REG (op0);
611e4b17023SJohn Marino }
612e4b17023SJohn Marino op0 = gen_rtx_SUBREG (mode_for_size (BITS_PER_WORD, MODE_INT, 0),
613e4b17023SJohn Marino op0, (offset * UNITS_PER_WORD));
614e4b17023SJohn Marino }
615e4b17023SJohn Marino offset = 0;
616e4b17023SJohn Marino }
617e4b17023SJohn Marino
618e4b17023SJohn Marino /* If VALUE has a floating-point or complex mode, access it as an
619e4b17023SJohn Marino integer of the corresponding size. This can occur on a machine
620e4b17023SJohn Marino with 64 bit registers that uses SFmode for float. It can also
621e4b17023SJohn Marino occur for unaligned float or complex fields. */
622e4b17023SJohn Marino orig_value = value;
623e4b17023SJohn Marino if (GET_MODE (value) != VOIDmode
624e4b17023SJohn Marino && GET_MODE_CLASS (GET_MODE (value)) != MODE_INT
625e4b17023SJohn Marino && GET_MODE_CLASS (GET_MODE (value)) != MODE_PARTIAL_INT)
626e4b17023SJohn Marino {
627e4b17023SJohn Marino value = gen_reg_rtx (int_mode_for_mode (GET_MODE (value)));
628e4b17023SJohn Marino emit_move_insn (gen_lowpart (GET_MODE (orig_value), value), orig_value);
629e4b17023SJohn Marino }
630e4b17023SJohn Marino
631e4b17023SJohn Marino /* Now OFFSET is nonzero only if OP0 is memory
632e4b17023SJohn Marino and is therefore always measured in bytes. */
633e4b17023SJohn Marino
634e4b17023SJohn Marino if (HAVE_insv
635e4b17023SJohn Marino && GET_MODE (value) != BLKmode
636e4b17023SJohn Marino && bitsize > 0
637e4b17023SJohn Marino && GET_MODE_BITSIZE (op_mode) >= bitsize
638e4b17023SJohn Marino /* Do not use insv for volatile bitfields when
639e4b17023SJohn Marino -fstrict-volatile-bitfields is in effect. */
640e4b17023SJohn Marino && !(MEM_P (op0) && MEM_VOLATILE_P (op0)
641e4b17023SJohn Marino && flag_strict_volatile_bitfields > 0)
642e4b17023SJohn Marino && ! ((REG_P (op0) || GET_CODE (op0) == SUBREG)
643e4b17023SJohn Marino && (bitsize + bitpos > GET_MODE_BITSIZE (op_mode)))
644e4b17023SJohn Marino /* Do not use insv if the bit region is restricted and
645e4b17023SJohn Marino op_mode integer at offset doesn't fit into the
646e4b17023SJohn Marino restricted region. */
647e4b17023SJohn Marino && !(MEM_P (op0) && bitregion_end
648e4b17023SJohn Marino && bitnum - bitpos + GET_MODE_BITSIZE (op_mode)
649e4b17023SJohn Marino > bitregion_end + 1))
650e4b17023SJohn Marino {
651e4b17023SJohn Marino struct expand_operand ops[4];
652e4b17023SJohn Marino int xbitpos = bitpos;
653e4b17023SJohn Marino rtx value1;
654e4b17023SJohn Marino rtx xop0 = op0;
655e4b17023SJohn Marino rtx last = get_last_insn ();
656e4b17023SJohn Marino bool copy_back = false;
657e4b17023SJohn Marino
658e4b17023SJohn Marino /* Add OFFSET into OP0's address. */
659e4b17023SJohn Marino if (MEM_P (xop0))
660e4b17023SJohn Marino xop0 = adjust_address (xop0, byte_mode, offset);
661e4b17023SJohn Marino
662e4b17023SJohn Marino /* If xop0 is a register, we need it in OP_MODE
663e4b17023SJohn Marino to make it acceptable to the format of insv. */
664e4b17023SJohn Marino if (GET_CODE (xop0) == SUBREG)
665e4b17023SJohn Marino /* We can't just change the mode, because this might clobber op0,
666e4b17023SJohn Marino and we will need the original value of op0 if insv fails. */
667e4b17023SJohn Marino xop0 = gen_rtx_SUBREG (op_mode, SUBREG_REG (xop0), SUBREG_BYTE (xop0));
668e4b17023SJohn Marino if (REG_P (xop0) && GET_MODE (xop0) != op_mode)
669e4b17023SJohn Marino xop0 = gen_lowpart_SUBREG (op_mode, xop0);
670e4b17023SJohn Marino
671e4b17023SJohn Marino /* If the destination is a paradoxical subreg such that we need a
672e4b17023SJohn Marino truncate to the inner mode, perform the insertion on a temporary and
673e4b17023SJohn Marino truncate the result to the original destination. Note that we can't
674e4b17023SJohn Marino just truncate the paradoxical subreg as (truncate:N (subreg:W (reg:N
675e4b17023SJohn Marino X) 0)) is (reg:N X). */
676e4b17023SJohn Marino if (GET_CODE (xop0) == SUBREG
677e4b17023SJohn Marino && REG_P (SUBREG_REG (xop0))
678e4b17023SJohn Marino && (!TRULY_NOOP_TRUNCATION_MODES_P (GET_MODE (SUBREG_REG (xop0)),
679e4b17023SJohn Marino op_mode)))
680e4b17023SJohn Marino {
681e4b17023SJohn Marino rtx tem = gen_reg_rtx (op_mode);
682e4b17023SJohn Marino emit_move_insn (tem, xop0);
683e4b17023SJohn Marino xop0 = tem;
684e4b17023SJohn Marino copy_back = true;
685e4b17023SJohn Marino }
686e4b17023SJohn Marino
687e4b17023SJohn Marino /* We have been counting XBITPOS within UNIT.
688e4b17023SJohn Marino Count instead within the size of the register. */
689e4b17023SJohn Marino if (BYTES_BIG_ENDIAN && !MEM_P (xop0))
690e4b17023SJohn Marino xbitpos += GET_MODE_BITSIZE (op_mode) - unit;
691e4b17023SJohn Marino
692e4b17023SJohn Marino unit = GET_MODE_BITSIZE (op_mode);
693e4b17023SJohn Marino
694e4b17023SJohn Marino /* If BITS_BIG_ENDIAN is zero on a BYTES_BIG_ENDIAN machine, we count
695e4b17023SJohn Marino "backwards" from the size of the unit we are inserting into.
696e4b17023SJohn Marino Otherwise, we count bits from the most significant on a
697e4b17023SJohn Marino BYTES/BITS_BIG_ENDIAN machine. */
698e4b17023SJohn Marino
699e4b17023SJohn Marino if (BITS_BIG_ENDIAN != BYTES_BIG_ENDIAN)
700e4b17023SJohn Marino xbitpos = unit - bitsize - xbitpos;
701e4b17023SJohn Marino
702e4b17023SJohn Marino /* Convert VALUE to op_mode (which insv insn wants) in VALUE1. */
703e4b17023SJohn Marino value1 = value;
704e4b17023SJohn Marino if (GET_MODE (value) != op_mode)
705e4b17023SJohn Marino {
706e4b17023SJohn Marino if (GET_MODE_BITSIZE (GET_MODE (value)) >= bitsize)
707e4b17023SJohn Marino {
708e4b17023SJohn Marino /* Optimization: Don't bother really extending VALUE
709e4b17023SJohn Marino if it has all the bits we will actually use. However,
710e4b17023SJohn Marino if we must narrow it, be sure we do it correctly. */
711e4b17023SJohn Marino
712e4b17023SJohn Marino if (GET_MODE_SIZE (GET_MODE (value)) < GET_MODE_SIZE (op_mode))
713e4b17023SJohn Marino {
714e4b17023SJohn Marino rtx tmp;
715e4b17023SJohn Marino
716e4b17023SJohn Marino tmp = simplify_subreg (op_mode, value1, GET_MODE (value), 0);
717e4b17023SJohn Marino if (! tmp)
718e4b17023SJohn Marino tmp = simplify_gen_subreg (op_mode,
719e4b17023SJohn Marino force_reg (GET_MODE (value),
720e4b17023SJohn Marino value1),
721e4b17023SJohn Marino GET_MODE (value), 0);
722e4b17023SJohn Marino value1 = tmp;
723e4b17023SJohn Marino }
724e4b17023SJohn Marino else
725e4b17023SJohn Marino value1 = gen_lowpart (op_mode, value1);
726e4b17023SJohn Marino }
727e4b17023SJohn Marino else if (CONST_INT_P (value))
728e4b17023SJohn Marino value1 = gen_int_mode (INTVAL (value), op_mode);
729e4b17023SJohn Marino else
730e4b17023SJohn Marino /* Parse phase is supposed to make VALUE's data type
731e4b17023SJohn Marino match that of the component reference, which is a type
732e4b17023SJohn Marino at least as wide as the field; so VALUE should have
733e4b17023SJohn Marino a mode that corresponds to that type. */
734e4b17023SJohn Marino gcc_assert (CONSTANT_P (value));
735e4b17023SJohn Marino }
736e4b17023SJohn Marino
737e4b17023SJohn Marino create_fixed_operand (&ops[0], xop0);
738e4b17023SJohn Marino create_integer_operand (&ops[1], bitsize);
739e4b17023SJohn Marino create_integer_operand (&ops[2], xbitpos);
740e4b17023SJohn Marino create_input_operand (&ops[3], value1, op_mode);
741e4b17023SJohn Marino if (maybe_expand_insn (CODE_FOR_insv, 4, ops))
742e4b17023SJohn Marino {
743e4b17023SJohn Marino if (copy_back)
744e4b17023SJohn Marino convert_move (op0, xop0, true);
745e4b17023SJohn Marino return true;
746e4b17023SJohn Marino }
747e4b17023SJohn Marino delete_insns_since (last);
748e4b17023SJohn Marino }
749e4b17023SJohn Marino
750e4b17023SJohn Marino /* If OP0 is a memory, try copying it to a register and seeing if a
751e4b17023SJohn Marino cheap register alternative is available. */
752e4b17023SJohn Marino if (HAVE_insv && MEM_P (op0))
753e4b17023SJohn Marino {
754e4b17023SJohn Marino enum machine_mode bestmode;
755e4b17023SJohn Marino unsigned HOST_WIDE_INT maxbits = MAX_FIXED_MODE_SIZE;
756e4b17023SJohn Marino
757e4b17023SJohn Marino if (bitregion_end)
758e4b17023SJohn Marino maxbits = bitregion_end - bitregion_start + 1;
759e4b17023SJohn Marino
760e4b17023SJohn Marino /* Get the mode to use for inserting into this field. If OP0 is
761e4b17023SJohn Marino BLKmode, get the smallest mode consistent with the alignment. If
762e4b17023SJohn Marino OP0 is a non-BLKmode object that is no wider than OP_MODE, use its
763e4b17023SJohn Marino mode. Otherwise, use the smallest mode containing the field. */
764e4b17023SJohn Marino
765e4b17023SJohn Marino if (GET_MODE (op0) == BLKmode
766e4b17023SJohn Marino || GET_MODE_BITSIZE (GET_MODE (op0)) > maxbits
767e4b17023SJohn Marino || (op_mode != MAX_MACHINE_MODE
768e4b17023SJohn Marino && GET_MODE_SIZE (GET_MODE (op0)) > GET_MODE_SIZE (op_mode)))
769e4b17023SJohn Marino bestmode = get_best_mode (bitsize, bitnum,
770e4b17023SJohn Marino bitregion_start, bitregion_end,
771e4b17023SJohn Marino MEM_ALIGN (op0),
772e4b17023SJohn Marino (op_mode == MAX_MACHINE_MODE
773e4b17023SJohn Marino ? VOIDmode : op_mode),
774e4b17023SJohn Marino MEM_VOLATILE_P (op0));
775e4b17023SJohn Marino else
776e4b17023SJohn Marino bestmode = GET_MODE (op0);
777e4b17023SJohn Marino
778e4b17023SJohn Marino if (bestmode != VOIDmode
779e4b17023SJohn Marino && GET_MODE_SIZE (bestmode) >= GET_MODE_SIZE (fieldmode)
780e4b17023SJohn Marino && !(SLOW_UNALIGNED_ACCESS (bestmode, MEM_ALIGN (op0))
781e4b17023SJohn Marino && GET_MODE_BITSIZE (bestmode) > MEM_ALIGN (op0)))
782e4b17023SJohn Marino {
783e4b17023SJohn Marino rtx last, tempreg, xop0;
784e4b17023SJohn Marino unsigned HOST_WIDE_INT xoffset, xbitpos;
785e4b17023SJohn Marino
786e4b17023SJohn Marino last = get_last_insn ();
787e4b17023SJohn Marino
788e4b17023SJohn Marino /* Adjust address to point to the containing unit of
789e4b17023SJohn Marino that mode. Compute the offset as a multiple of this unit,
790e4b17023SJohn Marino counting in bytes. */
791e4b17023SJohn Marino unit = GET_MODE_BITSIZE (bestmode);
792e4b17023SJohn Marino xoffset = (bitnum / unit) * GET_MODE_SIZE (bestmode);
793e4b17023SJohn Marino xbitpos = bitnum % unit;
794e4b17023SJohn Marino xop0 = adjust_address (op0, bestmode, xoffset);
795e4b17023SJohn Marino
796e4b17023SJohn Marino /* Fetch that unit, store the bitfield in it, then store
797e4b17023SJohn Marino the unit. */
798e4b17023SJohn Marino tempreg = copy_to_reg (xop0);
799e4b17023SJohn Marino if (store_bit_field_1 (tempreg, bitsize, xbitpos,
800e4b17023SJohn Marino bitregion_start, bitregion_end,
801e4b17023SJohn Marino fieldmode, orig_value, false))
802e4b17023SJohn Marino {
803e4b17023SJohn Marino emit_move_insn (xop0, tempreg);
804e4b17023SJohn Marino return true;
805e4b17023SJohn Marino }
806e4b17023SJohn Marino delete_insns_since (last);
807e4b17023SJohn Marino }
808e4b17023SJohn Marino }
809e4b17023SJohn Marino
810e4b17023SJohn Marino if (!fallback_p)
811e4b17023SJohn Marino return false;
812e4b17023SJohn Marino
813e4b17023SJohn Marino store_fixed_bit_field (op0, offset, bitsize, bitpos,
814e4b17023SJohn Marino bitregion_start, bitregion_end, value);
815e4b17023SJohn Marino return true;
816e4b17023SJohn Marino }
817e4b17023SJohn Marino
818e4b17023SJohn Marino /* Generate code to store value from rtx VALUE
819e4b17023SJohn Marino into a bit-field within structure STR_RTX
820e4b17023SJohn Marino containing BITSIZE bits starting at bit BITNUM.
821e4b17023SJohn Marino
822e4b17023SJohn Marino BITREGION_START is bitpos of the first bitfield in this region.
823e4b17023SJohn Marino BITREGION_END is the bitpos of the ending bitfield in this region.
824e4b17023SJohn Marino These two fields are 0, if the C++ memory model does not apply,
825e4b17023SJohn Marino or we are not interested in keeping track of bitfield regions.
826e4b17023SJohn Marino
827e4b17023SJohn Marino FIELDMODE is the machine-mode of the FIELD_DECL node for this field. */
828e4b17023SJohn Marino
829e4b17023SJohn Marino void
store_bit_field(rtx str_rtx,unsigned HOST_WIDE_INT bitsize,unsigned HOST_WIDE_INT bitnum,unsigned HOST_WIDE_INT bitregion_start,unsigned HOST_WIDE_INT bitregion_end,enum machine_mode fieldmode,rtx value)830e4b17023SJohn Marino store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
831e4b17023SJohn Marino unsigned HOST_WIDE_INT bitnum,
832e4b17023SJohn Marino unsigned HOST_WIDE_INT bitregion_start,
833e4b17023SJohn Marino unsigned HOST_WIDE_INT bitregion_end,
834e4b17023SJohn Marino enum machine_mode fieldmode,
835e4b17023SJohn Marino rtx value)
836e4b17023SJohn Marino {
837e4b17023SJohn Marino /* Under the C++0x memory model, we must not touch bits outside the
838e4b17023SJohn Marino bit region. Adjust the address to start at the beginning of the
839e4b17023SJohn Marino bit region. */
840e4b17023SJohn Marino if (MEM_P (str_rtx) && bitregion_start > 0)
841e4b17023SJohn Marino {
842e4b17023SJohn Marino enum machine_mode bestmode;
843e4b17023SJohn Marino enum machine_mode op_mode;
844e4b17023SJohn Marino unsigned HOST_WIDE_INT offset;
845e4b17023SJohn Marino
846e4b17023SJohn Marino op_mode = mode_for_extraction (EP_insv, 3);
847e4b17023SJohn Marino if (op_mode == MAX_MACHINE_MODE)
848e4b17023SJohn Marino op_mode = VOIDmode;
849e4b17023SJohn Marino
850e4b17023SJohn Marino gcc_assert ((bitregion_start % BITS_PER_UNIT) == 0);
851e4b17023SJohn Marino
852e4b17023SJohn Marino offset = bitregion_start / BITS_PER_UNIT;
853e4b17023SJohn Marino bitnum -= bitregion_start;
854e4b17023SJohn Marino bitregion_end -= bitregion_start;
855e4b17023SJohn Marino bitregion_start = 0;
856e4b17023SJohn Marino bestmode = get_best_mode (bitsize, bitnum,
857e4b17023SJohn Marino bitregion_start, bitregion_end,
858e4b17023SJohn Marino MEM_ALIGN (str_rtx),
859e4b17023SJohn Marino op_mode,
860e4b17023SJohn Marino MEM_VOLATILE_P (str_rtx));
861e4b17023SJohn Marino str_rtx = adjust_address (str_rtx, bestmode, offset);
862e4b17023SJohn Marino }
863e4b17023SJohn Marino
864e4b17023SJohn Marino if (!store_bit_field_1 (str_rtx, bitsize, bitnum,
865e4b17023SJohn Marino bitregion_start, bitregion_end,
866e4b17023SJohn Marino fieldmode, value, true))
867e4b17023SJohn Marino gcc_unreachable ();
868e4b17023SJohn Marino }
869e4b17023SJohn Marino
870e4b17023SJohn Marino /* Use shifts and boolean operations to store VALUE
871e4b17023SJohn Marino into a bit field of width BITSIZE
872e4b17023SJohn Marino in a memory location specified by OP0 except offset by OFFSET bytes.
873e4b17023SJohn Marino (OFFSET must be 0 if OP0 is a register.)
874e4b17023SJohn Marino The field starts at position BITPOS within the byte.
875e4b17023SJohn Marino (If OP0 is a register, it may be a full word or a narrower mode,
876e4b17023SJohn Marino but BITPOS still counts within a full word,
877e4b17023SJohn Marino which is significant on bigendian machines.) */
878e4b17023SJohn Marino
879e4b17023SJohn Marino static void
store_fixed_bit_field(rtx op0,unsigned HOST_WIDE_INT offset,unsigned HOST_WIDE_INT bitsize,unsigned HOST_WIDE_INT bitpos,unsigned HOST_WIDE_INT bitregion_start,unsigned HOST_WIDE_INT bitregion_end,rtx value)880e4b17023SJohn Marino store_fixed_bit_field (rtx op0, unsigned HOST_WIDE_INT offset,
881e4b17023SJohn Marino unsigned HOST_WIDE_INT bitsize,
882e4b17023SJohn Marino unsigned HOST_WIDE_INT bitpos,
883e4b17023SJohn Marino unsigned HOST_WIDE_INT bitregion_start,
884e4b17023SJohn Marino unsigned HOST_WIDE_INT bitregion_end,
885e4b17023SJohn Marino rtx value)
886e4b17023SJohn Marino {
887e4b17023SJohn Marino enum machine_mode mode;
888e4b17023SJohn Marino unsigned int total_bits = BITS_PER_WORD;
889e4b17023SJohn Marino rtx temp;
890e4b17023SJohn Marino int all_zero = 0;
891e4b17023SJohn Marino int all_one = 0;
892e4b17023SJohn Marino
893e4b17023SJohn Marino /* There is a case not handled here:
894e4b17023SJohn Marino a structure with a known alignment of just a halfword
895e4b17023SJohn Marino and a field split across two aligned halfwords within the structure.
896e4b17023SJohn Marino Or likewise a structure with a known alignment of just a byte
897e4b17023SJohn Marino and a field split across two bytes.
898e4b17023SJohn Marino Such cases are not supposed to be able to occur. */
899e4b17023SJohn Marino
900e4b17023SJohn Marino if (REG_P (op0) || GET_CODE (op0) == SUBREG)
901e4b17023SJohn Marino {
902e4b17023SJohn Marino gcc_assert (!offset);
903e4b17023SJohn Marino /* Special treatment for a bit field split across two registers. */
904e4b17023SJohn Marino if (bitsize + bitpos > BITS_PER_WORD)
905e4b17023SJohn Marino {
906e4b17023SJohn Marino store_split_bit_field (op0, bitsize, bitpos,
907e4b17023SJohn Marino bitregion_start, bitregion_end,
908e4b17023SJohn Marino value);
909e4b17023SJohn Marino return;
910e4b17023SJohn Marino }
911e4b17023SJohn Marino }
912e4b17023SJohn Marino else
913e4b17023SJohn Marino {
914e4b17023SJohn Marino unsigned HOST_WIDE_INT maxbits = MAX_FIXED_MODE_SIZE;
915e4b17023SJohn Marino
916e4b17023SJohn Marino if (bitregion_end)
917e4b17023SJohn Marino maxbits = bitregion_end - bitregion_start + 1;
918e4b17023SJohn Marino
919e4b17023SJohn Marino /* Get the proper mode to use for this field. We want a mode that
920e4b17023SJohn Marino includes the entire field. If such a mode would be larger than
921e4b17023SJohn Marino a word, we won't be doing the extraction the normal way.
922e4b17023SJohn Marino We don't want a mode bigger than the destination. */
923e4b17023SJohn Marino
924e4b17023SJohn Marino mode = GET_MODE (op0);
925e4b17023SJohn Marino if (GET_MODE_BITSIZE (mode) == 0
926e4b17023SJohn Marino || GET_MODE_BITSIZE (mode) > GET_MODE_BITSIZE (word_mode))
927e4b17023SJohn Marino mode = word_mode;
928e4b17023SJohn Marino
929e4b17023SJohn Marino if (MEM_VOLATILE_P (op0)
930e4b17023SJohn Marino && GET_MODE_BITSIZE (GET_MODE (op0)) > 0
931e4b17023SJohn Marino && GET_MODE_BITSIZE (GET_MODE (op0)) <= maxbits
932e4b17023SJohn Marino && flag_strict_volatile_bitfields > 0)
933e4b17023SJohn Marino mode = GET_MODE (op0);
934e4b17023SJohn Marino else
935e4b17023SJohn Marino mode = get_best_mode (bitsize, bitpos + offset * BITS_PER_UNIT,
936e4b17023SJohn Marino bitregion_start, bitregion_end,
937e4b17023SJohn Marino MEM_ALIGN (op0), mode, MEM_VOLATILE_P (op0));
938e4b17023SJohn Marino
939e4b17023SJohn Marino if (mode == VOIDmode)
940e4b17023SJohn Marino {
941e4b17023SJohn Marino /* The only way this should occur is if the field spans word
942e4b17023SJohn Marino boundaries. */
943e4b17023SJohn Marino store_split_bit_field (op0, bitsize, bitpos + offset * BITS_PER_UNIT,
944e4b17023SJohn Marino bitregion_start, bitregion_end, value);
945e4b17023SJohn Marino return;
946e4b17023SJohn Marino }
947e4b17023SJohn Marino
948e4b17023SJohn Marino total_bits = GET_MODE_BITSIZE (mode);
949e4b17023SJohn Marino
950e4b17023SJohn Marino /* Make sure bitpos is valid for the chosen mode. Adjust BITPOS to
951e4b17023SJohn Marino be in the range 0 to total_bits-1, and put any excess bytes in
952e4b17023SJohn Marino OFFSET. */
953e4b17023SJohn Marino if (bitpos >= total_bits)
954e4b17023SJohn Marino {
955e4b17023SJohn Marino offset += (bitpos / total_bits) * (total_bits / BITS_PER_UNIT);
956e4b17023SJohn Marino bitpos -= ((bitpos / total_bits) * (total_bits / BITS_PER_UNIT)
957e4b17023SJohn Marino * BITS_PER_UNIT);
958e4b17023SJohn Marino }
959e4b17023SJohn Marino
960e4b17023SJohn Marino /* Get ref to an aligned byte, halfword, or word containing the field.
961e4b17023SJohn Marino Adjust BITPOS to be position within a word,
962e4b17023SJohn Marino and OFFSET to be the offset of that word.
963e4b17023SJohn Marino Then alter OP0 to refer to that word. */
964e4b17023SJohn Marino bitpos += (offset % (total_bits / BITS_PER_UNIT)) * BITS_PER_UNIT;
965e4b17023SJohn Marino offset -= (offset % (total_bits / BITS_PER_UNIT));
966e4b17023SJohn Marino op0 = adjust_address (op0, mode, offset);
967e4b17023SJohn Marino }
968e4b17023SJohn Marino
969e4b17023SJohn Marino mode = GET_MODE (op0);
970e4b17023SJohn Marino
971e4b17023SJohn Marino /* Now MODE is either some integral mode for a MEM as OP0,
972e4b17023SJohn Marino or is a full-word for a REG as OP0. TOTAL_BITS corresponds.
973e4b17023SJohn Marino The bit field is contained entirely within OP0.
974e4b17023SJohn Marino BITPOS is the starting bit number within OP0.
975e4b17023SJohn Marino (OP0's mode may actually be narrower than MODE.) */
976e4b17023SJohn Marino
977e4b17023SJohn Marino if (BYTES_BIG_ENDIAN)
978e4b17023SJohn Marino /* BITPOS is the distance between our msb
979e4b17023SJohn Marino and that of the containing datum.
980e4b17023SJohn Marino Convert it to the distance from the lsb. */
981e4b17023SJohn Marino bitpos = total_bits - bitsize - bitpos;
982e4b17023SJohn Marino
983e4b17023SJohn Marino /* Now BITPOS is always the distance between our lsb
984e4b17023SJohn Marino and that of OP0. */
985e4b17023SJohn Marino
986e4b17023SJohn Marino /* Shift VALUE left by BITPOS bits. If VALUE is not constant,
987e4b17023SJohn Marino we must first convert its mode to MODE. */
988e4b17023SJohn Marino
989e4b17023SJohn Marino if (CONST_INT_P (value))
990e4b17023SJohn Marino {
991e4b17023SJohn Marino HOST_WIDE_INT v = INTVAL (value);
992e4b17023SJohn Marino
993e4b17023SJohn Marino if (bitsize < HOST_BITS_PER_WIDE_INT)
994e4b17023SJohn Marino v &= ((HOST_WIDE_INT) 1 << bitsize) - 1;
995e4b17023SJohn Marino
996e4b17023SJohn Marino if (v == 0)
997e4b17023SJohn Marino all_zero = 1;
998e4b17023SJohn Marino else if ((bitsize < HOST_BITS_PER_WIDE_INT
999e4b17023SJohn Marino && v == ((HOST_WIDE_INT) 1 << bitsize) - 1)
1000e4b17023SJohn Marino || (bitsize == HOST_BITS_PER_WIDE_INT && v == -1))
1001e4b17023SJohn Marino all_one = 1;
1002e4b17023SJohn Marino
1003e4b17023SJohn Marino value = lshift_value (mode, value, bitpos, bitsize);
1004e4b17023SJohn Marino }
1005e4b17023SJohn Marino else
1006e4b17023SJohn Marino {
1007e4b17023SJohn Marino int must_and = (GET_MODE_BITSIZE (GET_MODE (value)) != bitsize
1008e4b17023SJohn Marino && bitpos + bitsize != GET_MODE_BITSIZE (mode));
1009e4b17023SJohn Marino
1010e4b17023SJohn Marino if (GET_MODE (value) != mode)
1011e4b17023SJohn Marino value = convert_to_mode (mode, value, 1);
1012e4b17023SJohn Marino
1013e4b17023SJohn Marino if (must_and)
1014e4b17023SJohn Marino value = expand_binop (mode, and_optab, value,
1015e4b17023SJohn Marino mask_rtx (mode, 0, bitsize, 0),
1016e4b17023SJohn Marino NULL_RTX, 1, OPTAB_LIB_WIDEN);
1017e4b17023SJohn Marino if (bitpos > 0)
1018e4b17023SJohn Marino value = expand_shift (LSHIFT_EXPR, mode, value,
1019e4b17023SJohn Marino bitpos, NULL_RTX, 1);
1020e4b17023SJohn Marino }
1021e4b17023SJohn Marino
1022e4b17023SJohn Marino /* Now clear the chosen bits in OP0,
1023e4b17023SJohn Marino except that if VALUE is -1 we need not bother. */
1024e4b17023SJohn Marino /* We keep the intermediates in registers to allow CSE to combine
1025e4b17023SJohn Marino consecutive bitfield assignments. */
1026e4b17023SJohn Marino
1027e4b17023SJohn Marino temp = force_reg (mode, op0);
1028e4b17023SJohn Marino
1029e4b17023SJohn Marino if (! all_one)
1030e4b17023SJohn Marino {
1031e4b17023SJohn Marino temp = expand_binop (mode, and_optab, temp,
1032e4b17023SJohn Marino mask_rtx (mode, bitpos, bitsize, 1),
1033e4b17023SJohn Marino NULL_RTX, 1, OPTAB_LIB_WIDEN);
1034e4b17023SJohn Marino temp = force_reg (mode, temp);
1035e4b17023SJohn Marino }
1036e4b17023SJohn Marino
1037e4b17023SJohn Marino /* Now logical-or VALUE into OP0, unless it is zero. */
1038e4b17023SJohn Marino
1039e4b17023SJohn Marino if (! all_zero)
1040e4b17023SJohn Marino {
1041e4b17023SJohn Marino temp = expand_binop (mode, ior_optab, temp, value,
1042e4b17023SJohn Marino NULL_RTX, 1, OPTAB_LIB_WIDEN);
1043e4b17023SJohn Marino temp = force_reg (mode, temp);
1044e4b17023SJohn Marino }
1045e4b17023SJohn Marino
1046e4b17023SJohn Marino if (op0 != temp)
1047e4b17023SJohn Marino {
1048e4b17023SJohn Marino op0 = copy_rtx (op0);
1049e4b17023SJohn Marino emit_move_insn (op0, temp);
1050e4b17023SJohn Marino }
1051e4b17023SJohn Marino }
1052e4b17023SJohn Marino
1053e4b17023SJohn Marino /* Store a bit field that is split across multiple accessible memory objects.
1054e4b17023SJohn Marino
1055e4b17023SJohn Marino OP0 is the REG, SUBREG or MEM rtx for the first of the objects.
1056e4b17023SJohn Marino BITSIZE is the field width; BITPOS the position of its first bit
1057e4b17023SJohn Marino (within the word).
1058e4b17023SJohn Marino VALUE is the value to store.
1059e4b17023SJohn Marino
1060e4b17023SJohn Marino This does not yet handle fields wider than BITS_PER_WORD. */
1061e4b17023SJohn Marino
1062e4b17023SJohn Marino static void
store_split_bit_field(rtx op0,unsigned HOST_WIDE_INT bitsize,unsigned HOST_WIDE_INT bitpos,unsigned HOST_WIDE_INT bitregion_start,unsigned HOST_WIDE_INT bitregion_end,rtx value)1063e4b17023SJohn Marino store_split_bit_field (rtx op0, unsigned HOST_WIDE_INT bitsize,
1064e4b17023SJohn Marino unsigned HOST_WIDE_INT bitpos,
1065e4b17023SJohn Marino unsigned HOST_WIDE_INT bitregion_start,
1066e4b17023SJohn Marino unsigned HOST_WIDE_INT bitregion_end,
1067e4b17023SJohn Marino rtx value)
1068e4b17023SJohn Marino {
1069e4b17023SJohn Marino unsigned int unit;
1070e4b17023SJohn Marino unsigned int bitsdone = 0;
1071e4b17023SJohn Marino
1072e4b17023SJohn Marino /* Make sure UNIT isn't larger than BITS_PER_WORD, we can only handle that
1073e4b17023SJohn Marino much at a time. */
1074e4b17023SJohn Marino if (REG_P (op0) || GET_CODE (op0) == SUBREG)
1075e4b17023SJohn Marino unit = BITS_PER_WORD;
1076e4b17023SJohn Marino else
1077e4b17023SJohn Marino unit = MIN (MEM_ALIGN (op0), BITS_PER_WORD);
1078e4b17023SJohn Marino
1079e4b17023SJohn Marino /* If VALUE is a constant other than a CONST_INT, get it into a register in
1080e4b17023SJohn Marino WORD_MODE. If we can do this using gen_lowpart_common, do so. Note
1081e4b17023SJohn Marino that VALUE might be a floating-point constant. */
1082e4b17023SJohn Marino if (CONSTANT_P (value) && !CONST_INT_P (value))
1083e4b17023SJohn Marino {
1084e4b17023SJohn Marino rtx word = gen_lowpart_common (word_mode, value);
1085e4b17023SJohn Marino
1086e4b17023SJohn Marino if (word && (value != word))
1087e4b17023SJohn Marino value = word;
1088e4b17023SJohn Marino else
1089e4b17023SJohn Marino value = gen_lowpart_common (word_mode,
1090e4b17023SJohn Marino force_reg (GET_MODE (value) != VOIDmode
1091e4b17023SJohn Marino ? GET_MODE (value)
1092e4b17023SJohn Marino : word_mode, value));
1093e4b17023SJohn Marino }
1094e4b17023SJohn Marino
1095e4b17023SJohn Marino while (bitsdone < bitsize)
1096e4b17023SJohn Marino {
1097e4b17023SJohn Marino unsigned HOST_WIDE_INT thissize;
1098e4b17023SJohn Marino rtx part, word;
1099e4b17023SJohn Marino unsigned HOST_WIDE_INT thispos;
1100e4b17023SJohn Marino unsigned HOST_WIDE_INT offset;
1101e4b17023SJohn Marino
1102e4b17023SJohn Marino offset = (bitpos + bitsdone) / unit;
1103e4b17023SJohn Marino thispos = (bitpos + bitsdone) % unit;
1104e4b17023SJohn Marino
1105e4b17023SJohn Marino /* When region of bytes we can touch is restricted, decrease
1106e4b17023SJohn Marino UNIT close to the end of the region as needed. */
1107e4b17023SJohn Marino if (bitregion_end
1108e4b17023SJohn Marino && unit > BITS_PER_UNIT
1109e4b17023SJohn Marino && bitpos + bitsdone - thispos + unit > bitregion_end + 1)
1110e4b17023SJohn Marino {
1111e4b17023SJohn Marino unit = unit / 2;
1112e4b17023SJohn Marino continue;
1113e4b17023SJohn Marino }
1114e4b17023SJohn Marino
1115e4b17023SJohn Marino /* THISSIZE must not overrun a word boundary. Otherwise,
1116e4b17023SJohn Marino store_fixed_bit_field will call us again, and we will mutually
1117e4b17023SJohn Marino recurse forever. */
1118e4b17023SJohn Marino thissize = MIN (bitsize - bitsdone, BITS_PER_WORD);
1119e4b17023SJohn Marino thissize = MIN (thissize, unit - thispos);
1120e4b17023SJohn Marino
1121e4b17023SJohn Marino if (BYTES_BIG_ENDIAN)
1122e4b17023SJohn Marino {
1123e4b17023SJohn Marino int total_bits;
1124e4b17023SJohn Marino
1125e4b17023SJohn Marino /* We must do an endian conversion exactly the same way as it is
1126e4b17023SJohn Marino done in extract_bit_field, so that the two calls to
1127e4b17023SJohn Marino extract_fixed_bit_field will have comparable arguments. */
1128e4b17023SJohn Marino if (!MEM_P (value) || GET_MODE (value) == BLKmode)
1129e4b17023SJohn Marino total_bits = BITS_PER_WORD;
1130e4b17023SJohn Marino else
1131e4b17023SJohn Marino total_bits = GET_MODE_BITSIZE (GET_MODE (value));
1132e4b17023SJohn Marino
1133e4b17023SJohn Marino /* Fetch successively less significant portions. */
1134e4b17023SJohn Marino if (CONST_INT_P (value))
1135e4b17023SJohn Marino part = GEN_INT (((unsigned HOST_WIDE_INT) (INTVAL (value))
1136e4b17023SJohn Marino >> (bitsize - bitsdone - thissize))
1137e4b17023SJohn Marino & (((HOST_WIDE_INT) 1 << thissize) - 1));
1138e4b17023SJohn Marino else
1139e4b17023SJohn Marino /* The args are chosen so that the last part includes the
1140e4b17023SJohn Marino lsb. Give extract_bit_field the value it needs (with
1141e4b17023SJohn Marino endianness compensation) to fetch the piece we want. */
1142e4b17023SJohn Marino part = extract_fixed_bit_field (word_mode, value, 0, thissize,
1143e4b17023SJohn Marino total_bits - bitsize + bitsdone,
1144e4b17023SJohn Marino NULL_RTX, 1, false);
1145e4b17023SJohn Marino }
1146e4b17023SJohn Marino else
1147e4b17023SJohn Marino {
1148e4b17023SJohn Marino /* Fetch successively more significant portions. */
1149e4b17023SJohn Marino if (CONST_INT_P (value))
1150e4b17023SJohn Marino part = GEN_INT (((unsigned HOST_WIDE_INT) (INTVAL (value))
1151e4b17023SJohn Marino >> bitsdone)
1152e4b17023SJohn Marino & (((HOST_WIDE_INT) 1 << thissize) - 1));
1153e4b17023SJohn Marino else
1154e4b17023SJohn Marino part = extract_fixed_bit_field (word_mode, value, 0, thissize,
1155e4b17023SJohn Marino bitsdone, NULL_RTX, 1, false);
1156e4b17023SJohn Marino }
1157e4b17023SJohn Marino
1158e4b17023SJohn Marino /* If OP0 is a register, then handle OFFSET here.
1159e4b17023SJohn Marino
1160e4b17023SJohn Marino When handling multiword bitfields, extract_bit_field may pass
1161e4b17023SJohn Marino down a word_mode SUBREG of a larger REG for a bitfield that actually
1162e4b17023SJohn Marino crosses a word boundary. Thus, for a SUBREG, we must find
1163e4b17023SJohn Marino the current word starting from the base register. */
1164e4b17023SJohn Marino if (GET_CODE (op0) == SUBREG)
1165e4b17023SJohn Marino {
1166e4b17023SJohn Marino int word_offset = (SUBREG_BYTE (op0) / UNITS_PER_WORD) + offset;
1167e4b17023SJohn Marino enum machine_mode sub_mode = GET_MODE (SUBREG_REG (op0));
1168e4b17023SJohn Marino if (sub_mode != BLKmode && GET_MODE_SIZE (sub_mode) < UNITS_PER_WORD)
1169e4b17023SJohn Marino word = word_offset ? const0_rtx : op0;
1170e4b17023SJohn Marino else
1171e4b17023SJohn Marino word = operand_subword_force (SUBREG_REG (op0), word_offset,
1172e4b17023SJohn Marino GET_MODE (SUBREG_REG (op0)));
1173e4b17023SJohn Marino offset = 0;
1174e4b17023SJohn Marino }
1175e4b17023SJohn Marino else if (REG_P (op0))
1176e4b17023SJohn Marino {
1177e4b17023SJohn Marino enum machine_mode op0_mode = GET_MODE (op0);
1178e4b17023SJohn Marino if (op0_mode != BLKmode && GET_MODE_SIZE (op0_mode) < UNITS_PER_WORD)
1179e4b17023SJohn Marino word = offset ? const0_rtx : op0;
1180e4b17023SJohn Marino else
1181e4b17023SJohn Marino word = operand_subword_force (op0, offset, GET_MODE (op0));
1182e4b17023SJohn Marino offset = 0;
1183e4b17023SJohn Marino }
1184e4b17023SJohn Marino else
1185e4b17023SJohn Marino word = op0;
1186e4b17023SJohn Marino
1187e4b17023SJohn Marino /* OFFSET is in UNITs, and UNIT is in bits.
1188e4b17023SJohn Marino store_fixed_bit_field wants offset in bytes. If WORD is const0_rtx,
1189e4b17023SJohn Marino it is just an out-of-bounds access. Ignore it. */
1190e4b17023SJohn Marino if (word != const0_rtx)
1191e4b17023SJohn Marino store_fixed_bit_field (word, offset * unit / BITS_PER_UNIT, thissize,
1192e4b17023SJohn Marino thispos, bitregion_start, bitregion_end, part);
1193e4b17023SJohn Marino bitsdone += thissize;
1194e4b17023SJohn Marino }
1195e4b17023SJohn Marino }
1196e4b17023SJohn Marino
1197e4b17023SJohn Marino /* A subroutine of extract_bit_field_1 that converts return value X
1198e4b17023SJohn Marino to either MODE or TMODE. MODE, TMODE and UNSIGNEDP are arguments
1199e4b17023SJohn Marino to extract_bit_field. */
1200e4b17023SJohn Marino
1201e4b17023SJohn Marino static rtx
convert_extracted_bit_field(rtx x,enum machine_mode mode,enum machine_mode tmode,bool unsignedp)1202e4b17023SJohn Marino convert_extracted_bit_field (rtx x, enum machine_mode mode,
1203e4b17023SJohn Marino enum machine_mode tmode, bool unsignedp)
1204e4b17023SJohn Marino {
1205e4b17023SJohn Marino if (GET_MODE (x) == tmode || GET_MODE (x) == mode)
1206e4b17023SJohn Marino return x;
1207e4b17023SJohn Marino
1208e4b17023SJohn Marino /* If the x mode is not a scalar integral, first convert to the
1209e4b17023SJohn Marino integer mode of that size and then access it as a floating-point
1210e4b17023SJohn Marino value via a SUBREG. */
1211e4b17023SJohn Marino if (!SCALAR_INT_MODE_P (tmode))
1212e4b17023SJohn Marino {
1213e4b17023SJohn Marino enum machine_mode smode;
1214e4b17023SJohn Marino
1215e4b17023SJohn Marino smode = mode_for_size (GET_MODE_BITSIZE (tmode), MODE_INT, 0);
1216e4b17023SJohn Marino x = convert_to_mode (smode, x, unsignedp);
1217e4b17023SJohn Marino x = force_reg (smode, x);
1218e4b17023SJohn Marino return gen_lowpart (tmode, x);
1219e4b17023SJohn Marino }
1220e4b17023SJohn Marino
1221e4b17023SJohn Marino return convert_to_mode (tmode, x, unsignedp);
1222e4b17023SJohn Marino }
1223e4b17023SJohn Marino
1224e4b17023SJohn Marino /* A subroutine of extract_bit_field, with the same arguments.
1225e4b17023SJohn Marino If FALLBACK_P is true, fall back to extract_fixed_bit_field
1226e4b17023SJohn Marino if we can find no other means of implementing the operation.
1227e4b17023SJohn Marino if FALLBACK_P is false, return NULL instead. */
1228e4b17023SJohn Marino
1229e4b17023SJohn Marino static rtx
extract_bit_field_1(rtx str_rtx,unsigned HOST_WIDE_INT bitsize,unsigned HOST_WIDE_INT bitnum,int unsignedp,bool packedp,rtx target,enum machine_mode mode,enum machine_mode tmode,bool fallback_p)1230e4b17023SJohn Marino extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
1231e4b17023SJohn Marino unsigned HOST_WIDE_INT bitnum,
1232e4b17023SJohn Marino int unsignedp, bool packedp, rtx target,
1233e4b17023SJohn Marino enum machine_mode mode, enum machine_mode tmode,
1234e4b17023SJohn Marino bool fallback_p)
1235e4b17023SJohn Marino {
1236e4b17023SJohn Marino unsigned int unit
1237e4b17023SJohn Marino = (MEM_P (str_rtx)) ? BITS_PER_UNIT : BITS_PER_WORD;
1238e4b17023SJohn Marino unsigned HOST_WIDE_INT offset, bitpos;
1239e4b17023SJohn Marino rtx op0 = str_rtx;
1240e4b17023SJohn Marino enum machine_mode int_mode;
1241e4b17023SJohn Marino enum machine_mode ext_mode;
1242e4b17023SJohn Marino enum machine_mode mode1;
1243e4b17023SJohn Marino int byte_offset;
1244e4b17023SJohn Marino
1245e4b17023SJohn Marino if (tmode == VOIDmode)
1246e4b17023SJohn Marino tmode = mode;
1247e4b17023SJohn Marino
1248e4b17023SJohn Marino while (GET_CODE (op0) == SUBREG)
1249e4b17023SJohn Marino {
1250e4b17023SJohn Marino bitnum += SUBREG_BYTE (op0) * BITS_PER_UNIT;
1251e4b17023SJohn Marino op0 = SUBREG_REG (op0);
1252e4b17023SJohn Marino }
1253e4b17023SJohn Marino
1254e4b17023SJohn Marino /* If we have an out-of-bounds access to a register, just return an
1255e4b17023SJohn Marino uninitialized register of the required mode. This can occur if the
1256e4b17023SJohn Marino source code contains an out-of-bounds access to a small array. */
1257e4b17023SJohn Marino if (REG_P (op0) && bitnum >= GET_MODE_BITSIZE (GET_MODE (op0)))
1258e4b17023SJohn Marino return gen_reg_rtx (tmode);
1259e4b17023SJohn Marino
1260e4b17023SJohn Marino if (REG_P (op0)
1261e4b17023SJohn Marino && mode == GET_MODE (op0)
1262e4b17023SJohn Marino && bitnum == 0
1263e4b17023SJohn Marino && bitsize == GET_MODE_BITSIZE (GET_MODE (op0)))
1264e4b17023SJohn Marino {
1265e4b17023SJohn Marino /* We're trying to extract a full register from itself. */
1266e4b17023SJohn Marino return op0;
1267e4b17023SJohn Marino }
1268e4b17023SJohn Marino
1269e4b17023SJohn Marino /* See if we can get a better vector mode before extracting. */
1270e4b17023SJohn Marino if (VECTOR_MODE_P (GET_MODE (op0))
1271e4b17023SJohn Marino && !MEM_P (op0)
1272e4b17023SJohn Marino && GET_MODE_INNER (GET_MODE (op0)) != tmode)
1273e4b17023SJohn Marino {
1274e4b17023SJohn Marino enum machine_mode new_mode;
1275e4b17023SJohn Marino
1276e4b17023SJohn Marino if (GET_MODE_CLASS (tmode) == MODE_FLOAT)
1277e4b17023SJohn Marino new_mode = MIN_MODE_VECTOR_FLOAT;
1278e4b17023SJohn Marino else if (GET_MODE_CLASS (tmode) == MODE_FRACT)
1279e4b17023SJohn Marino new_mode = MIN_MODE_VECTOR_FRACT;
1280e4b17023SJohn Marino else if (GET_MODE_CLASS (tmode) == MODE_UFRACT)
1281e4b17023SJohn Marino new_mode = MIN_MODE_VECTOR_UFRACT;
1282e4b17023SJohn Marino else if (GET_MODE_CLASS (tmode) == MODE_ACCUM)
1283e4b17023SJohn Marino new_mode = MIN_MODE_VECTOR_ACCUM;
1284e4b17023SJohn Marino else if (GET_MODE_CLASS (tmode) == MODE_UACCUM)
1285e4b17023SJohn Marino new_mode = MIN_MODE_VECTOR_UACCUM;
1286e4b17023SJohn Marino else
1287e4b17023SJohn Marino new_mode = MIN_MODE_VECTOR_INT;
1288e4b17023SJohn Marino
1289e4b17023SJohn Marino for (; new_mode != VOIDmode ; new_mode = GET_MODE_WIDER_MODE (new_mode))
1290e4b17023SJohn Marino if (GET_MODE_SIZE (new_mode) == GET_MODE_SIZE (GET_MODE (op0))
1291e4b17023SJohn Marino && targetm.vector_mode_supported_p (new_mode))
1292e4b17023SJohn Marino break;
1293e4b17023SJohn Marino if (new_mode != VOIDmode)
1294e4b17023SJohn Marino op0 = gen_lowpart (new_mode, op0);
1295e4b17023SJohn Marino }
1296e4b17023SJohn Marino
1297e4b17023SJohn Marino /* Use vec_extract patterns for extracting parts of vectors whenever
1298e4b17023SJohn Marino available. */
1299e4b17023SJohn Marino if (VECTOR_MODE_P (GET_MODE (op0))
1300e4b17023SJohn Marino && !MEM_P (op0)
1301e4b17023SJohn Marino && optab_handler (vec_extract_optab, GET_MODE (op0)) != CODE_FOR_nothing
1302e4b17023SJohn Marino && ((bitnum + bitsize - 1) / GET_MODE_BITSIZE (GET_MODE_INNER (GET_MODE (op0)))
1303e4b17023SJohn Marino == bitnum / GET_MODE_BITSIZE (GET_MODE_INNER (GET_MODE (op0)))))
1304e4b17023SJohn Marino {
1305e4b17023SJohn Marino struct expand_operand ops[3];
1306e4b17023SJohn Marino enum machine_mode outermode = GET_MODE (op0);
1307e4b17023SJohn Marino enum machine_mode innermode = GET_MODE_INNER (outermode);
1308e4b17023SJohn Marino enum insn_code icode = optab_handler (vec_extract_optab, outermode);
1309e4b17023SJohn Marino unsigned HOST_WIDE_INT pos = bitnum / GET_MODE_BITSIZE (innermode);
1310e4b17023SJohn Marino
1311e4b17023SJohn Marino create_output_operand (&ops[0], target, innermode);
1312e4b17023SJohn Marino create_input_operand (&ops[1], op0, outermode);
1313e4b17023SJohn Marino create_integer_operand (&ops[2], pos);
1314e4b17023SJohn Marino if (maybe_expand_insn (icode, 3, ops))
1315e4b17023SJohn Marino {
1316e4b17023SJohn Marino target = ops[0].value;
1317e4b17023SJohn Marino if (GET_MODE (target) != mode)
1318e4b17023SJohn Marino return gen_lowpart (tmode, target);
1319e4b17023SJohn Marino return target;
1320e4b17023SJohn Marino }
1321e4b17023SJohn Marino }
1322e4b17023SJohn Marino
1323e4b17023SJohn Marino /* Make sure we are playing with integral modes. Pun with subregs
1324e4b17023SJohn Marino if we aren't. */
1325e4b17023SJohn Marino {
1326e4b17023SJohn Marino enum machine_mode imode = int_mode_for_mode (GET_MODE (op0));
1327e4b17023SJohn Marino if (imode != GET_MODE (op0))
1328e4b17023SJohn Marino {
1329e4b17023SJohn Marino if (MEM_P (op0))
1330e4b17023SJohn Marino op0 = adjust_address (op0, imode, 0);
1331e4b17023SJohn Marino else if (imode != BLKmode)
1332e4b17023SJohn Marino {
1333e4b17023SJohn Marino op0 = gen_lowpart (imode, op0);
1334e4b17023SJohn Marino
1335e4b17023SJohn Marino /* If we got a SUBREG, force it into a register since we
1336e4b17023SJohn Marino aren't going to be able to do another SUBREG on it. */
1337e4b17023SJohn Marino if (GET_CODE (op0) == SUBREG)
1338e4b17023SJohn Marino op0 = force_reg (imode, op0);
1339e4b17023SJohn Marino }
1340e4b17023SJohn Marino else if (REG_P (op0))
1341e4b17023SJohn Marino {
1342e4b17023SJohn Marino rtx reg, subreg;
1343e4b17023SJohn Marino imode = smallest_mode_for_size (GET_MODE_BITSIZE (GET_MODE (op0)),
1344e4b17023SJohn Marino MODE_INT);
1345e4b17023SJohn Marino reg = gen_reg_rtx (imode);
1346e4b17023SJohn Marino subreg = gen_lowpart_SUBREG (GET_MODE (op0), reg);
1347e4b17023SJohn Marino emit_move_insn (subreg, op0);
1348e4b17023SJohn Marino op0 = reg;
1349e4b17023SJohn Marino bitnum += SUBREG_BYTE (subreg) * BITS_PER_UNIT;
1350e4b17023SJohn Marino }
1351e4b17023SJohn Marino else
1352e4b17023SJohn Marino {
1353e4b17023SJohn Marino rtx mem = assign_stack_temp (GET_MODE (op0),
1354e4b17023SJohn Marino GET_MODE_SIZE (GET_MODE (op0)), 0);
1355e4b17023SJohn Marino emit_move_insn (mem, op0);
1356e4b17023SJohn Marino op0 = adjust_address (mem, BLKmode, 0);
1357e4b17023SJohn Marino }
1358e4b17023SJohn Marino }
1359e4b17023SJohn Marino }
1360e4b17023SJohn Marino
1361e4b17023SJohn Marino /* We may be accessing data outside the field, which means
1362e4b17023SJohn Marino we can alias adjacent data. */
1363e4b17023SJohn Marino if (MEM_P (op0))
1364e4b17023SJohn Marino {
1365e4b17023SJohn Marino op0 = shallow_copy_rtx (op0);
1366e4b17023SJohn Marino set_mem_alias_set (op0, 0);
1367e4b17023SJohn Marino set_mem_expr (op0, 0);
1368e4b17023SJohn Marino }
1369e4b17023SJohn Marino
1370e4b17023SJohn Marino /* Extraction of a full-word or multi-word value from a structure
1371e4b17023SJohn Marino in a register or aligned memory can be done with just a SUBREG.
1372e4b17023SJohn Marino A subword value in the least significant part of a register
1373e4b17023SJohn Marino can also be extracted with a SUBREG. For this, we need the
1374e4b17023SJohn Marino byte offset of the value in op0. */
1375e4b17023SJohn Marino
1376e4b17023SJohn Marino bitpos = bitnum % unit;
1377e4b17023SJohn Marino offset = bitnum / unit;
1378e4b17023SJohn Marino byte_offset = bitpos / BITS_PER_UNIT + offset * UNITS_PER_WORD;
1379e4b17023SJohn Marino
1380e4b17023SJohn Marino /* If OP0 is a register, BITPOS must count within a word.
1381e4b17023SJohn Marino But as we have it, it counts within whatever size OP0 now has.
1382e4b17023SJohn Marino On a bigendian machine, these are not the same, so convert. */
1383e4b17023SJohn Marino if (BYTES_BIG_ENDIAN
1384e4b17023SJohn Marino && !MEM_P (op0)
1385e4b17023SJohn Marino && unit > GET_MODE_BITSIZE (GET_MODE (op0)))
1386e4b17023SJohn Marino bitpos += unit - GET_MODE_BITSIZE (GET_MODE (op0));
1387e4b17023SJohn Marino
1388e4b17023SJohn Marino /* ??? We currently assume TARGET is at least as big as BITSIZE.
1389e4b17023SJohn Marino If that's wrong, the solution is to test for it and set TARGET to 0
1390e4b17023SJohn Marino if needed. */
1391e4b17023SJohn Marino
1392e4b17023SJohn Marino /* Only scalar integer modes can be converted via subregs. There is an
1393e4b17023SJohn Marino additional problem for FP modes here in that they can have a precision
1394e4b17023SJohn Marino which is different from the size. mode_for_size uses precision, but
1395e4b17023SJohn Marino we want a mode based on the size, so we must avoid calling it for FP
1396e4b17023SJohn Marino modes. */
1397e4b17023SJohn Marino mode1 = (SCALAR_INT_MODE_P (tmode)
1398e4b17023SJohn Marino ? mode_for_size (bitsize, GET_MODE_CLASS (tmode), 0)
1399e4b17023SJohn Marino : mode);
1400e4b17023SJohn Marino
1401e4b17023SJohn Marino /* If the bitfield is volatile, we need to make sure the access
1402e4b17023SJohn Marino remains on a type-aligned boundary. */
1403e4b17023SJohn Marino if (GET_CODE (op0) == MEM
1404e4b17023SJohn Marino && MEM_VOLATILE_P (op0)
1405e4b17023SJohn Marino && GET_MODE_BITSIZE (GET_MODE (op0)) > 0
1406e4b17023SJohn Marino && flag_strict_volatile_bitfields > 0)
1407e4b17023SJohn Marino goto no_subreg_mode_swap;
1408e4b17023SJohn Marino
1409e4b17023SJohn Marino if (((bitsize >= BITS_PER_WORD && bitsize == GET_MODE_BITSIZE (mode)
1410e4b17023SJohn Marino && bitpos % BITS_PER_WORD == 0)
1411e4b17023SJohn Marino || (mode1 != BLKmode
1412e4b17023SJohn Marino /* ??? The big endian test here is wrong. This is correct
1413e4b17023SJohn Marino if the value is in a register, and if mode_for_size is not
1414e4b17023SJohn Marino the same mode as op0. This causes us to get unnecessarily
1415e4b17023SJohn Marino inefficient code from the Thumb port when -mbig-endian. */
1416e4b17023SJohn Marino && (BYTES_BIG_ENDIAN
1417e4b17023SJohn Marino ? bitpos + bitsize == BITS_PER_WORD
1418e4b17023SJohn Marino : bitpos == 0)))
1419e4b17023SJohn Marino && ((!MEM_P (op0)
1420e4b17023SJohn Marino && TRULY_NOOP_TRUNCATION_MODES_P (mode1, GET_MODE (op0))
1421e4b17023SJohn Marino && GET_MODE_SIZE (mode1) != 0
1422e4b17023SJohn Marino && byte_offset % GET_MODE_SIZE (mode1) == 0)
1423e4b17023SJohn Marino || (MEM_P (op0)
1424e4b17023SJohn Marino && (! SLOW_UNALIGNED_ACCESS (mode, MEM_ALIGN (op0))
1425e4b17023SJohn Marino || (offset * BITS_PER_UNIT % bitsize == 0
1426e4b17023SJohn Marino && MEM_ALIGN (op0) % bitsize == 0)))))
1427e4b17023SJohn Marino {
1428e4b17023SJohn Marino if (MEM_P (op0))
1429e4b17023SJohn Marino op0 = adjust_address (op0, mode1, offset);
1430e4b17023SJohn Marino else if (mode1 != GET_MODE (op0))
1431e4b17023SJohn Marino {
1432e4b17023SJohn Marino rtx sub = simplify_gen_subreg (mode1, op0, GET_MODE (op0),
1433e4b17023SJohn Marino byte_offset);
1434e4b17023SJohn Marino if (sub == NULL)
1435e4b17023SJohn Marino goto no_subreg_mode_swap;
1436e4b17023SJohn Marino op0 = sub;
1437e4b17023SJohn Marino }
1438e4b17023SJohn Marino if (mode1 != mode)
1439e4b17023SJohn Marino return convert_to_mode (tmode, op0, unsignedp);
1440e4b17023SJohn Marino return op0;
1441e4b17023SJohn Marino }
1442e4b17023SJohn Marino no_subreg_mode_swap:
1443e4b17023SJohn Marino
1444e4b17023SJohn Marino /* Handle fields bigger than a word. */
1445e4b17023SJohn Marino
1446e4b17023SJohn Marino if (bitsize > BITS_PER_WORD)
1447e4b17023SJohn Marino {
1448e4b17023SJohn Marino /* Here we transfer the words of the field
1449e4b17023SJohn Marino in the order least significant first.
1450e4b17023SJohn Marino This is because the most significant word is the one which may
1451e4b17023SJohn Marino be less than full. */
1452e4b17023SJohn Marino
1453e4b17023SJohn Marino unsigned int nwords = (bitsize + (BITS_PER_WORD - 1)) / BITS_PER_WORD;
1454e4b17023SJohn Marino unsigned int i;
1455e4b17023SJohn Marino
1456e4b17023SJohn Marino if (target == 0 || !REG_P (target) || !valid_multiword_target_p (target))
1457e4b17023SJohn Marino target = gen_reg_rtx (mode);
1458e4b17023SJohn Marino
1459e4b17023SJohn Marino /* Indicate for flow that the entire target reg is being set. */
1460e4b17023SJohn Marino emit_clobber (target);
1461e4b17023SJohn Marino
1462e4b17023SJohn Marino for (i = 0; i < nwords; i++)
1463e4b17023SJohn Marino {
1464e4b17023SJohn Marino /* If I is 0, use the low-order word in both field and target;
1465e4b17023SJohn Marino if I is 1, use the next to lowest word; and so on. */
1466e4b17023SJohn Marino /* Word number in TARGET to use. */
1467e4b17023SJohn Marino unsigned int wordnum
1468e4b17023SJohn Marino = (WORDS_BIG_ENDIAN
1469e4b17023SJohn Marino ? GET_MODE_SIZE (GET_MODE (target)) / UNITS_PER_WORD - i - 1
1470e4b17023SJohn Marino : i);
1471e4b17023SJohn Marino /* Offset from start of field in OP0. */
1472e4b17023SJohn Marino unsigned int bit_offset = (WORDS_BIG_ENDIAN
1473e4b17023SJohn Marino ? MAX (0, ((int) bitsize - ((int) i + 1)
1474e4b17023SJohn Marino * (int) BITS_PER_WORD))
1475e4b17023SJohn Marino : (int) i * BITS_PER_WORD);
1476e4b17023SJohn Marino rtx target_part = operand_subword (target, wordnum, 1, VOIDmode);
1477e4b17023SJohn Marino rtx result_part
1478e4b17023SJohn Marino = extract_bit_field (op0, MIN (BITS_PER_WORD,
1479e4b17023SJohn Marino bitsize - i * BITS_PER_WORD),
1480e4b17023SJohn Marino bitnum + bit_offset, 1, false, target_part, mode,
1481e4b17023SJohn Marino word_mode);
1482e4b17023SJohn Marino
1483e4b17023SJohn Marino gcc_assert (target_part);
1484e4b17023SJohn Marino
1485e4b17023SJohn Marino if (result_part != target_part)
1486e4b17023SJohn Marino emit_move_insn (target_part, result_part);
1487e4b17023SJohn Marino }
1488e4b17023SJohn Marino
1489e4b17023SJohn Marino if (unsignedp)
1490e4b17023SJohn Marino {
1491e4b17023SJohn Marino /* Unless we've filled TARGET, the upper regs in a multi-reg value
1492e4b17023SJohn Marino need to be zero'd out. */
1493e4b17023SJohn Marino if (GET_MODE_SIZE (GET_MODE (target)) > nwords * UNITS_PER_WORD)
1494e4b17023SJohn Marino {
1495e4b17023SJohn Marino unsigned int i, total_words;
1496e4b17023SJohn Marino
1497e4b17023SJohn Marino total_words = GET_MODE_SIZE (GET_MODE (target)) / UNITS_PER_WORD;
1498e4b17023SJohn Marino for (i = nwords; i < total_words; i++)
1499e4b17023SJohn Marino emit_move_insn
1500e4b17023SJohn Marino (operand_subword (target,
1501e4b17023SJohn Marino WORDS_BIG_ENDIAN ? total_words - i - 1 : i,
1502e4b17023SJohn Marino 1, VOIDmode),
1503e4b17023SJohn Marino const0_rtx);
1504e4b17023SJohn Marino }
1505e4b17023SJohn Marino return target;
1506e4b17023SJohn Marino }
1507e4b17023SJohn Marino
1508e4b17023SJohn Marino /* Signed bit field: sign-extend with two arithmetic shifts. */
1509e4b17023SJohn Marino target = expand_shift (LSHIFT_EXPR, mode, target,
1510e4b17023SJohn Marino GET_MODE_BITSIZE (mode) - bitsize, NULL_RTX, 0);
1511e4b17023SJohn Marino return expand_shift (RSHIFT_EXPR, mode, target,
1512e4b17023SJohn Marino GET_MODE_BITSIZE (mode) - bitsize, NULL_RTX, 0);
1513e4b17023SJohn Marino }
1514e4b17023SJohn Marino
1515e4b17023SJohn Marino /* From here on we know the desired field is smaller than a word. */
1516e4b17023SJohn Marino
1517e4b17023SJohn Marino /* Check if there is a correspondingly-sized integer field, so we can
1518e4b17023SJohn Marino safely extract it as one size of integer, if necessary; then
1519e4b17023SJohn Marino truncate or extend to the size that is wanted; then use SUBREGs or
1520e4b17023SJohn Marino convert_to_mode to get one of the modes we really wanted. */
1521e4b17023SJohn Marino
1522e4b17023SJohn Marino int_mode = int_mode_for_mode (tmode);
1523e4b17023SJohn Marino if (int_mode == BLKmode)
1524e4b17023SJohn Marino int_mode = int_mode_for_mode (mode);
1525e4b17023SJohn Marino /* Should probably push op0 out to memory and then do a load. */
1526e4b17023SJohn Marino gcc_assert (int_mode != BLKmode);
1527e4b17023SJohn Marino
1528e4b17023SJohn Marino /* OFFSET is the number of words or bytes (UNIT says which)
1529e4b17023SJohn Marino from STR_RTX to the first word or byte containing part of the field. */
1530e4b17023SJohn Marino if (!MEM_P (op0))
1531e4b17023SJohn Marino {
1532e4b17023SJohn Marino if (offset != 0
1533e4b17023SJohn Marino || GET_MODE_SIZE (GET_MODE (op0)) > UNITS_PER_WORD)
1534e4b17023SJohn Marino {
1535e4b17023SJohn Marino if (!REG_P (op0))
1536e4b17023SJohn Marino op0 = copy_to_reg (op0);
1537e4b17023SJohn Marino op0 = gen_rtx_SUBREG (mode_for_size (BITS_PER_WORD, MODE_INT, 0),
1538e4b17023SJohn Marino op0, (offset * UNITS_PER_WORD));
1539e4b17023SJohn Marino }
1540e4b17023SJohn Marino offset = 0;
1541e4b17023SJohn Marino }
1542e4b17023SJohn Marino
1543e4b17023SJohn Marino /* Now OFFSET is nonzero only for memory operands. */
1544e4b17023SJohn Marino ext_mode = mode_for_extraction (unsignedp ? EP_extzv : EP_extv, 0);
1545e4b17023SJohn Marino if (ext_mode != MAX_MACHINE_MODE
1546e4b17023SJohn Marino && bitsize > 0
1547e4b17023SJohn Marino && GET_MODE_BITSIZE (ext_mode) >= bitsize
1548e4b17023SJohn Marino /* Do not use extv/extzv for volatile bitfields when
1549e4b17023SJohn Marino -fstrict-volatile-bitfields is in effect. */
1550e4b17023SJohn Marino && !(MEM_P (op0) && MEM_VOLATILE_P (op0)
1551e4b17023SJohn Marino && flag_strict_volatile_bitfields > 0)
1552e4b17023SJohn Marino /* If op0 is a register, we need it in EXT_MODE to make it
1553e4b17023SJohn Marino acceptable to the format of ext(z)v. */
1554e4b17023SJohn Marino && !(GET_CODE (op0) == SUBREG && GET_MODE (op0) != ext_mode)
1555e4b17023SJohn Marino && !((REG_P (op0) || GET_CODE (op0) == SUBREG)
1556e4b17023SJohn Marino && (bitsize + bitpos > GET_MODE_BITSIZE (ext_mode))))
1557e4b17023SJohn Marino {
1558e4b17023SJohn Marino struct expand_operand ops[4];
1559e4b17023SJohn Marino unsigned HOST_WIDE_INT xbitpos = bitpos, xoffset = offset;
1560e4b17023SJohn Marino rtx xop0 = op0;
1561e4b17023SJohn Marino rtx xtarget = target;
1562e4b17023SJohn Marino rtx xspec_target = target;
1563e4b17023SJohn Marino rtx xspec_target_subreg = 0;
1564e4b17023SJohn Marino
1565e4b17023SJohn Marino /* If op0 is a register, we need it in EXT_MODE to make it
1566e4b17023SJohn Marino acceptable to the format of ext(z)v. */
1567e4b17023SJohn Marino if (REG_P (xop0) && GET_MODE (xop0) != ext_mode)
1568e4b17023SJohn Marino xop0 = gen_lowpart_SUBREG (ext_mode, xop0);
1569e4b17023SJohn Marino if (MEM_P (xop0))
1570e4b17023SJohn Marino /* Get ref to first byte containing part of the field. */
1571e4b17023SJohn Marino xop0 = adjust_address (xop0, byte_mode, xoffset);
1572e4b17023SJohn Marino
1573e4b17023SJohn Marino /* Now convert from counting within UNIT to counting in EXT_MODE. */
1574e4b17023SJohn Marino if (BYTES_BIG_ENDIAN && !MEM_P (xop0))
1575e4b17023SJohn Marino xbitpos += GET_MODE_BITSIZE (ext_mode) - unit;
1576e4b17023SJohn Marino
1577e4b17023SJohn Marino unit = GET_MODE_BITSIZE (ext_mode);
1578e4b17023SJohn Marino
1579e4b17023SJohn Marino /* If BITS_BIG_ENDIAN is zero on a BYTES_BIG_ENDIAN machine, we count
1580e4b17023SJohn Marino "backwards" from the size of the unit we are extracting from.
1581e4b17023SJohn Marino Otherwise, we count bits from the most significant on a
1582e4b17023SJohn Marino BYTES/BITS_BIG_ENDIAN machine. */
1583e4b17023SJohn Marino
1584e4b17023SJohn Marino if (BITS_BIG_ENDIAN != BYTES_BIG_ENDIAN)
1585e4b17023SJohn Marino xbitpos = unit - bitsize - xbitpos;
1586e4b17023SJohn Marino
1587e4b17023SJohn Marino if (xtarget == 0)
1588e4b17023SJohn Marino xtarget = xspec_target = gen_reg_rtx (tmode);
1589e4b17023SJohn Marino
1590e4b17023SJohn Marino if (GET_MODE (xtarget) != ext_mode)
1591e4b17023SJohn Marino {
1592e4b17023SJohn Marino /* Don't use LHS paradoxical subreg if explicit truncation is needed
1593e4b17023SJohn Marino between the mode of the extraction (word_mode) and the target
1594e4b17023SJohn Marino mode. Instead, create a temporary and use convert_move to set
1595e4b17023SJohn Marino the target. */
1596e4b17023SJohn Marino if (REG_P (xtarget)
1597e4b17023SJohn Marino && TRULY_NOOP_TRUNCATION_MODES_P (GET_MODE (xtarget), ext_mode))
1598e4b17023SJohn Marino {
1599e4b17023SJohn Marino xtarget = gen_lowpart (ext_mode, xtarget);
1600e4b17023SJohn Marino if (GET_MODE_PRECISION (ext_mode)
1601e4b17023SJohn Marino > GET_MODE_PRECISION (GET_MODE (xspec_target)))
1602e4b17023SJohn Marino xspec_target_subreg = xtarget;
1603e4b17023SJohn Marino }
1604e4b17023SJohn Marino else
1605e4b17023SJohn Marino xtarget = gen_reg_rtx (ext_mode);
1606e4b17023SJohn Marino }
1607e4b17023SJohn Marino
1608e4b17023SJohn Marino create_output_operand (&ops[0], xtarget, ext_mode);
1609e4b17023SJohn Marino create_fixed_operand (&ops[1], xop0);
1610e4b17023SJohn Marino create_integer_operand (&ops[2], bitsize);
1611e4b17023SJohn Marino create_integer_operand (&ops[3], xbitpos);
1612e4b17023SJohn Marino if (maybe_expand_insn (unsignedp ? CODE_FOR_extzv : CODE_FOR_extv,
1613e4b17023SJohn Marino 4, ops))
1614e4b17023SJohn Marino {
1615e4b17023SJohn Marino xtarget = ops[0].value;
1616e4b17023SJohn Marino if (xtarget == xspec_target)
1617e4b17023SJohn Marino return xtarget;
1618e4b17023SJohn Marino if (xtarget == xspec_target_subreg)
1619e4b17023SJohn Marino return xspec_target;
1620e4b17023SJohn Marino return convert_extracted_bit_field (xtarget, mode, tmode, unsignedp);
1621e4b17023SJohn Marino }
1622e4b17023SJohn Marino }
1623e4b17023SJohn Marino
1624e4b17023SJohn Marino /* If OP0 is a memory, try copying it to a register and seeing if a
1625e4b17023SJohn Marino cheap register alternative is available. */
1626e4b17023SJohn Marino if (ext_mode != MAX_MACHINE_MODE && MEM_P (op0))
1627e4b17023SJohn Marino {
1628e4b17023SJohn Marino enum machine_mode bestmode;
1629e4b17023SJohn Marino
1630e4b17023SJohn Marino /* Get the mode to use for inserting into this field. If
1631e4b17023SJohn Marino OP0 is BLKmode, get the smallest mode consistent with the
1632e4b17023SJohn Marino alignment. If OP0 is a non-BLKmode object that is no
1633e4b17023SJohn Marino wider than EXT_MODE, use its mode. Otherwise, use the
1634e4b17023SJohn Marino smallest mode containing the field. */
1635e4b17023SJohn Marino
1636e4b17023SJohn Marino if (GET_MODE (op0) == BLKmode
1637e4b17023SJohn Marino || (ext_mode != MAX_MACHINE_MODE
1638e4b17023SJohn Marino && GET_MODE_SIZE (GET_MODE (op0)) > GET_MODE_SIZE (ext_mode)))
1639e4b17023SJohn Marino bestmode = get_best_mode (bitsize, bitnum, 0, 0, MEM_ALIGN (op0),
1640e4b17023SJohn Marino (ext_mode == MAX_MACHINE_MODE
1641e4b17023SJohn Marino ? VOIDmode : ext_mode),
1642e4b17023SJohn Marino MEM_VOLATILE_P (op0));
1643e4b17023SJohn Marino else
1644e4b17023SJohn Marino bestmode = GET_MODE (op0);
1645e4b17023SJohn Marino
1646e4b17023SJohn Marino if (bestmode != VOIDmode
1647e4b17023SJohn Marino && !(SLOW_UNALIGNED_ACCESS (bestmode, MEM_ALIGN (op0))
1648e4b17023SJohn Marino && GET_MODE_BITSIZE (bestmode) > MEM_ALIGN (op0)))
1649e4b17023SJohn Marino {
1650e4b17023SJohn Marino unsigned HOST_WIDE_INT xoffset, xbitpos;
1651e4b17023SJohn Marino
1652e4b17023SJohn Marino /* Compute the offset as a multiple of this unit,
1653e4b17023SJohn Marino counting in bytes. */
1654e4b17023SJohn Marino unit = GET_MODE_BITSIZE (bestmode);
1655e4b17023SJohn Marino xoffset = (bitnum / unit) * GET_MODE_SIZE (bestmode);
1656e4b17023SJohn Marino xbitpos = bitnum % unit;
1657e4b17023SJohn Marino
1658e4b17023SJohn Marino /* Make sure the register is big enough for the whole field. */
1659e4b17023SJohn Marino if (xoffset * BITS_PER_UNIT + unit
1660e4b17023SJohn Marino >= offset * BITS_PER_UNIT + bitsize)
1661e4b17023SJohn Marino {
1662e4b17023SJohn Marino rtx last, result, xop0;
1663e4b17023SJohn Marino
1664e4b17023SJohn Marino last = get_last_insn ();
1665e4b17023SJohn Marino
1666e4b17023SJohn Marino /* Fetch it to a register in that size. */
1667e4b17023SJohn Marino xop0 = adjust_address (op0, bestmode, xoffset);
1668e4b17023SJohn Marino xop0 = force_reg (bestmode, xop0);
1669e4b17023SJohn Marino result = extract_bit_field_1 (xop0, bitsize, xbitpos,
1670e4b17023SJohn Marino unsignedp, packedp, target,
1671e4b17023SJohn Marino mode, tmode, false);
1672e4b17023SJohn Marino if (result)
1673e4b17023SJohn Marino return result;
1674e4b17023SJohn Marino
1675e4b17023SJohn Marino delete_insns_since (last);
1676e4b17023SJohn Marino }
1677e4b17023SJohn Marino }
1678e4b17023SJohn Marino }
1679e4b17023SJohn Marino
1680e4b17023SJohn Marino if (!fallback_p)
1681e4b17023SJohn Marino return NULL;
1682e4b17023SJohn Marino
1683e4b17023SJohn Marino target = extract_fixed_bit_field (int_mode, op0, offset, bitsize,
1684e4b17023SJohn Marino bitpos, target, unsignedp, packedp);
1685e4b17023SJohn Marino return convert_extracted_bit_field (target, mode, tmode, unsignedp);
1686e4b17023SJohn Marino }
1687e4b17023SJohn Marino
1688e4b17023SJohn Marino /* Generate code to extract a byte-field from STR_RTX
1689e4b17023SJohn Marino containing BITSIZE bits, starting at BITNUM,
1690e4b17023SJohn Marino and put it in TARGET if possible (if TARGET is nonzero).
1691e4b17023SJohn Marino Regardless of TARGET, we return the rtx for where the value is placed.
1692e4b17023SJohn Marino
1693e4b17023SJohn Marino STR_RTX is the structure containing the byte (a REG or MEM).
1694e4b17023SJohn Marino UNSIGNEDP is nonzero if this is an unsigned bit field.
1695e4b17023SJohn Marino PACKEDP is nonzero if the field has the packed attribute.
1696e4b17023SJohn Marino MODE is the natural mode of the field value once extracted.
1697e4b17023SJohn Marino TMODE is the mode the caller would like the value to have;
1698e4b17023SJohn Marino but the value may be returned with type MODE instead.
1699e4b17023SJohn Marino
1700e4b17023SJohn Marino If a TARGET is specified and we can store in it at no extra cost,
1701e4b17023SJohn Marino we do so, and return TARGET.
1702e4b17023SJohn Marino Otherwise, we return a REG of mode TMODE or MODE, with TMODE preferred
1703e4b17023SJohn Marino if they are equally easy. */
1704e4b17023SJohn Marino
1705e4b17023SJohn Marino rtx
extract_bit_field(rtx str_rtx,unsigned HOST_WIDE_INT bitsize,unsigned HOST_WIDE_INT bitnum,int unsignedp,bool packedp,rtx target,enum machine_mode mode,enum machine_mode tmode)1706e4b17023SJohn Marino extract_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
1707e4b17023SJohn Marino unsigned HOST_WIDE_INT bitnum, int unsignedp, bool packedp,
1708e4b17023SJohn Marino rtx target, enum machine_mode mode, enum machine_mode tmode)
1709e4b17023SJohn Marino {
1710e4b17023SJohn Marino return extract_bit_field_1 (str_rtx, bitsize, bitnum, unsignedp, packedp,
1711e4b17023SJohn Marino target, mode, tmode, true);
1712e4b17023SJohn Marino }
1713e4b17023SJohn Marino
1714e4b17023SJohn Marino /* Extract a bit field using shifts and boolean operations
1715e4b17023SJohn Marino Returns an rtx to represent the value.
1716e4b17023SJohn Marino OP0 addresses a register (word) or memory (byte).
1717e4b17023SJohn Marino BITPOS says which bit within the word or byte the bit field starts in.
1718e4b17023SJohn Marino OFFSET says how many bytes farther the bit field starts;
1719e4b17023SJohn Marino it is 0 if OP0 is a register.
1720e4b17023SJohn Marino BITSIZE says how many bits long the bit field is.
1721e4b17023SJohn Marino (If OP0 is a register, it may be narrower than a full word,
1722e4b17023SJohn Marino but BITPOS still counts within a full word,
1723e4b17023SJohn Marino which is significant on bigendian machines.)
1724e4b17023SJohn Marino
1725e4b17023SJohn Marino UNSIGNEDP is nonzero for an unsigned bit field (don't sign-extend value).
1726e4b17023SJohn Marino PACKEDP is true if the field has the packed attribute.
1727e4b17023SJohn Marino
1728e4b17023SJohn Marino If TARGET is nonzero, attempts to store the value there
1729e4b17023SJohn Marino and return TARGET, but this is not guaranteed.
1730e4b17023SJohn Marino If TARGET is not used, create a pseudo-reg of mode TMODE for the value. */
1731e4b17023SJohn Marino
1732e4b17023SJohn Marino static rtx
extract_fixed_bit_field(enum machine_mode tmode,rtx op0,unsigned HOST_WIDE_INT offset,unsigned HOST_WIDE_INT bitsize,unsigned HOST_WIDE_INT bitpos,rtx target,int unsignedp,bool packedp)1733e4b17023SJohn Marino extract_fixed_bit_field (enum machine_mode tmode, rtx op0,
1734e4b17023SJohn Marino unsigned HOST_WIDE_INT offset,
1735e4b17023SJohn Marino unsigned HOST_WIDE_INT bitsize,
1736e4b17023SJohn Marino unsigned HOST_WIDE_INT bitpos, rtx target,
1737e4b17023SJohn Marino int unsignedp, bool packedp)
1738e4b17023SJohn Marino {
1739e4b17023SJohn Marino unsigned int total_bits = BITS_PER_WORD;
1740e4b17023SJohn Marino enum machine_mode mode;
1741e4b17023SJohn Marino
1742e4b17023SJohn Marino if (GET_CODE (op0) == SUBREG || REG_P (op0))
1743e4b17023SJohn Marino {
1744e4b17023SJohn Marino /* Special treatment for a bit field split across two registers. */
1745e4b17023SJohn Marino if (bitsize + bitpos > BITS_PER_WORD)
1746e4b17023SJohn Marino return extract_split_bit_field (op0, bitsize, bitpos, unsignedp);
1747e4b17023SJohn Marino }
1748e4b17023SJohn Marino else
1749e4b17023SJohn Marino {
1750e4b17023SJohn Marino /* Get the proper mode to use for this field. We want a mode that
1751e4b17023SJohn Marino includes the entire field. If such a mode would be larger than
1752e4b17023SJohn Marino a word, we won't be doing the extraction the normal way. */
1753e4b17023SJohn Marino
1754e4b17023SJohn Marino if (MEM_VOLATILE_P (op0)
1755e4b17023SJohn Marino && flag_strict_volatile_bitfields > 0)
1756e4b17023SJohn Marino {
1757e4b17023SJohn Marino if (GET_MODE_BITSIZE (GET_MODE (op0)) > 0)
1758e4b17023SJohn Marino mode = GET_MODE (op0);
1759e4b17023SJohn Marino else if (target && GET_MODE_BITSIZE (GET_MODE (target)) > 0)
1760e4b17023SJohn Marino mode = GET_MODE (target);
1761e4b17023SJohn Marino else
1762e4b17023SJohn Marino mode = tmode;
1763e4b17023SJohn Marino }
1764e4b17023SJohn Marino else
1765e4b17023SJohn Marino mode = get_best_mode (bitsize, bitpos + offset * BITS_PER_UNIT, 0, 0,
1766e4b17023SJohn Marino MEM_ALIGN (op0), word_mode, MEM_VOLATILE_P (op0));
1767e4b17023SJohn Marino
1768e4b17023SJohn Marino if (mode == VOIDmode)
1769e4b17023SJohn Marino /* The only way this should occur is if the field spans word
1770e4b17023SJohn Marino boundaries. */
1771e4b17023SJohn Marino return extract_split_bit_field (op0, bitsize,
1772e4b17023SJohn Marino bitpos + offset * BITS_PER_UNIT,
1773e4b17023SJohn Marino unsignedp);
1774e4b17023SJohn Marino
1775e4b17023SJohn Marino total_bits = GET_MODE_BITSIZE (mode);
1776e4b17023SJohn Marino
1777e4b17023SJohn Marino /* Make sure bitpos is valid for the chosen mode. Adjust BITPOS to
1778e4b17023SJohn Marino be in the range 0 to total_bits-1, and put any excess bytes in
1779e4b17023SJohn Marino OFFSET. */
1780e4b17023SJohn Marino if (bitpos >= total_bits)
1781e4b17023SJohn Marino {
1782e4b17023SJohn Marino offset += (bitpos / total_bits) * (total_bits / BITS_PER_UNIT);
1783e4b17023SJohn Marino bitpos -= ((bitpos / total_bits) * (total_bits / BITS_PER_UNIT)
1784e4b17023SJohn Marino * BITS_PER_UNIT);
1785e4b17023SJohn Marino }
1786e4b17023SJohn Marino
1787e4b17023SJohn Marino /* If we're accessing a volatile MEM, we can't do the next
1788e4b17023SJohn Marino alignment step if it results in a multi-word access where we
1789e4b17023SJohn Marino otherwise wouldn't have one. So, check for that case
1790e4b17023SJohn Marino here. */
1791e4b17023SJohn Marino if (MEM_P (op0)
1792e4b17023SJohn Marino && MEM_VOLATILE_P (op0)
1793e4b17023SJohn Marino && flag_strict_volatile_bitfields > 0
1794e4b17023SJohn Marino && bitpos + bitsize <= total_bits
1795e4b17023SJohn Marino && bitpos + bitsize + (offset % (total_bits / BITS_PER_UNIT)) * BITS_PER_UNIT > total_bits)
1796e4b17023SJohn Marino {
1797e4b17023SJohn Marino if (STRICT_ALIGNMENT)
1798e4b17023SJohn Marino {
1799e4b17023SJohn Marino static bool informed_about_misalignment = false;
1800e4b17023SJohn Marino bool warned;
1801e4b17023SJohn Marino
1802e4b17023SJohn Marino if (packedp)
1803e4b17023SJohn Marino {
1804e4b17023SJohn Marino if (bitsize == total_bits)
1805e4b17023SJohn Marino warned = warning_at (input_location, OPT_fstrict_volatile_bitfields,
1806e4b17023SJohn Marino "multiple accesses to volatile structure member"
1807e4b17023SJohn Marino " because of packed attribute");
1808e4b17023SJohn Marino else
1809e4b17023SJohn Marino warned = warning_at (input_location, OPT_fstrict_volatile_bitfields,
1810e4b17023SJohn Marino "multiple accesses to volatile structure bitfield"
1811e4b17023SJohn Marino " because of packed attribute");
1812e4b17023SJohn Marino
1813e4b17023SJohn Marino return extract_split_bit_field (op0, bitsize,
1814e4b17023SJohn Marino bitpos + offset * BITS_PER_UNIT,
1815e4b17023SJohn Marino unsignedp);
1816e4b17023SJohn Marino }
1817e4b17023SJohn Marino
1818e4b17023SJohn Marino if (bitsize == total_bits)
1819e4b17023SJohn Marino warned = warning_at (input_location, OPT_fstrict_volatile_bitfields,
1820e4b17023SJohn Marino "mis-aligned access used for structure member");
1821e4b17023SJohn Marino else
1822e4b17023SJohn Marino warned = warning_at (input_location, OPT_fstrict_volatile_bitfields,
1823e4b17023SJohn Marino "mis-aligned access used for structure bitfield");
1824e4b17023SJohn Marino
1825e4b17023SJohn Marino if (! informed_about_misalignment && warned)
1826e4b17023SJohn Marino {
1827e4b17023SJohn Marino informed_about_misalignment = true;
1828e4b17023SJohn Marino inform (input_location,
1829e4b17023SJohn Marino "when a volatile object spans multiple type-sized locations,"
1830e4b17023SJohn Marino " the compiler must choose between using a single mis-aligned access to"
1831e4b17023SJohn Marino " preserve the volatility, or using multiple aligned accesses to avoid"
1832e4b17023SJohn Marino " runtime faults; this code may fail at runtime if the hardware does"
1833e4b17023SJohn Marino " not allow this access");
1834e4b17023SJohn Marino }
1835e4b17023SJohn Marino }
1836e4b17023SJohn Marino }
1837e4b17023SJohn Marino else
1838e4b17023SJohn Marino {
1839e4b17023SJohn Marino
1840e4b17023SJohn Marino /* Get ref to an aligned byte, halfword, or word containing the field.
1841e4b17023SJohn Marino Adjust BITPOS to be position within a word,
1842e4b17023SJohn Marino and OFFSET to be the offset of that word.
1843e4b17023SJohn Marino Then alter OP0 to refer to that word. */
1844e4b17023SJohn Marino bitpos += (offset % (total_bits / BITS_PER_UNIT)) * BITS_PER_UNIT;
1845e4b17023SJohn Marino offset -= (offset % (total_bits / BITS_PER_UNIT));
1846e4b17023SJohn Marino }
1847e4b17023SJohn Marino
1848e4b17023SJohn Marino op0 = adjust_address (op0, mode, offset);
1849e4b17023SJohn Marino }
1850e4b17023SJohn Marino
1851e4b17023SJohn Marino mode = GET_MODE (op0);
1852e4b17023SJohn Marino
1853e4b17023SJohn Marino if (BYTES_BIG_ENDIAN)
1854e4b17023SJohn Marino /* BITPOS is the distance between our msb and that of OP0.
1855e4b17023SJohn Marino Convert it to the distance from the lsb. */
1856e4b17023SJohn Marino bitpos = total_bits - bitsize - bitpos;
1857e4b17023SJohn Marino
1858e4b17023SJohn Marino /* Now BITPOS is always the distance between the field's lsb and that of OP0.
1859e4b17023SJohn Marino We have reduced the big-endian case to the little-endian case. */
1860e4b17023SJohn Marino
1861e4b17023SJohn Marino if (unsignedp)
1862e4b17023SJohn Marino {
1863e4b17023SJohn Marino if (bitpos)
1864e4b17023SJohn Marino {
1865e4b17023SJohn Marino /* If the field does not already start at the lsb,
1866e4b17023SJohn Marino shift it so it does. */
1867e4b17023SJohn Marino /* Maybe propagate the target for the shift. */
1868e4b17023SJohn Marino /* But not if we will return it--could confuse integrate.c. */
1869e4b17023SJohn Marino rtx subtarget = (target != 0 && REG_P (target) ? target : 0);
1870e4b17023SJohn Marino if (tmode != mode) subtarget = 0;
1871e4b17023SJohn Marino op0 = expand_shift (RSHIFT_EXPR, mode, op0, bitpos, subtarget, 1);
1872e4b17023SJohn Marino }
1873e4b17023SJohn Marino /* Convert the value to the desired mode. */
1874e4b17023SJohn Marino if (mode != tmode)
1875e4b17023SJohn Marino op0 = convert_to_mode (tmode, op0, 1);
1876e4b17023SJohn Marino
1877e4b17023SJohn Marino /* Unless the msb of the field used to be the msb when we shifted,
1878e4b17023SJohn Marino mask out the upper bits. */
1879e4b17023SJohn Marino
1880e4b17023SJohn Marino if (GET_MODE_BITSIZE (mode) != bitpos + bitsize)
1881e4b17023SJohn Marino return expand_binop (GET_MODE (op0), and_optab, op0,
1882e4b17023SJohn Marino mask_rtx (GET_MODE (op0), 0, bitsize, 0),
1883e4b17023SJohn Marino target, 1, OPTAB_LIB_WIDEN);
1884e4b17023SJohn Marino return op0;
1885e4b17023SJohn Marino }
1886e4b17023SJohn Marino
1887e4b17023SJohn Marino /* To extract a signed bit-field, first shift its msb to the msb of the word,
1888e4b17023SJohn Marino then arithmetic-shift its lsb to the lsb of the word. */
1889e4b17023SJohn Marino op0 = force_reg (mode, op0);
1890e4b17023SJohn Marino
1891e4b17023SJohn Marino /* Find the narrowest integer mode that contains the field. */
1892e4b17023SJohn Marino
1893e4b17023SJohn Marino for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode;
1894e4b17023SJohn Marino mode = GET_MODE_WIDER_MODE (mode))
1895e4b17023SJohn Marino if (GET_MODE_BITSIZE (mode) >= bitsize + bitpos)
1896e4b17023SJohn Marino {
1897e4b17023SJohn Marino op0 = convert_to_mode (mode, op0, 0);
1898e4b17023SJohn Marino break;
1899e4b17023SJohn Marino }
1900e4b17023SJohn Marino
1901e4b17023SJohn Marino if (mode != tmode)
1902e4b17023SJohn Marino target = 0;
1903e4b17023SJohn Marino
1904e4b17023SJohn Marino if (GET_MODE_BITSIZE (mode) != (bitsize + bitpos))
1905e4b17023SJohn Marino {
1906e4b17023SJohn Marino int amount = GET_MODE_BITSIZE (mode) - (bitsize + bitpos);
1907e4b17023SJohn Marino /* Maybe propagate the target for the shift. */
1908e4b17023SJohn Marino rtx subtarget = (target != 0 && REG_P (target) ? target : 0);
1909e4b17023SJohn Marino op0 = expand_shift (LSHIFT_EXPR, mode, op0, amount, subtarget, 1);
1910e4b17023SJohn Marino }
1911e4b17023SJohn Marino
1912e4b17023SJohn Marino return expand_shift (RSHIFT_EXPR, mode, op0,
1913e4b17023SJohn Marino GET_MODE_BITSIZE (mode) - bitsize, target, 0);
1914e4b17023SJohn Marino }
1915e4b17023SJohn Marino
1916e4b17023SJohn Marino /* Return a constant integer (CONST_INT or CONST_DOUBLE) mask value
1917e4b17023SJohn Marino of mode MODE with BITSIZE ones followed by BITPOS zeros, or the
1918e4b17023SJohn Marino complement of that if COMPLEMENT. The mask is truncated if
1919e4b17023SJohn Marino necessary to the width of mode MODE. The mask is zero-extended if
1920e4b17023SJohn Marino BITSIZE+BITPOS is too small for MODE. */
1921e4b17023SJohn Marino
1922e4b17023SJohn Marino static rtx
mask_rtx(enum machine_mode mode,int bitpos,int bitsize,int complement)1923e4b17023SJohn Marino mask_rtx (enum machine_mode mode, int bitpos, int bitsize, int complement)
1924e4b17023SJohn Marino {
1925e4b17023SJohn Marino double_int mask;
1926e4b17023SJohn Marino
1927e4b17023SJohn Marino mask = double_int_mask (bitsize);
1928e4b17023SJohn Marino mask = double_int_lshift (mask, bitpos, HOST_BITS_PER_DOUBLE_INT, false);
1929e4b17023SJohn Marino
1930e4b17023SJohn Marino if (complement)
1931e4b17023SJohn Marino mask = double_int_not (mask);
1932e4b17023SJohn Marino
1933e4b17023SJohn Marino return immed_double_int_const (mask, mode);
1934e4b17023SJohn Marino }
1935e4b17023SJohn Marino
1936e4b17023SJohn Marino /* Return a constant integer (CONST_INT or CONST_DOUBLE) rtx with the value
1937e4b17023SJohn Marino VALUE truncated to BITSIZE bits and then shifted left BITPOS bits. */
1938e4b17023SJohn Marino
1939e4b17023SJohn Marino static rtx
lshift_value(enum machine_mode mode,rtx value,int bitpos,int bitsize)1940e4b17023SJohn Marino lshift_value (enum machine_mode mode, rtx value, int bitpos, int bitsize)
1941e4b17023SJohn Marino {
1942e4b17023SJohn Marino double_int val;
1943e4b17023SJohn Marino
1944e4b17023SJohn Marino val = double_int_zext (uhwi_to_double_int (INTVAL (value)), bitsize);
1945e4b17023SJohn Marino val = double_int_lshift (val, bitpos, HOST_BITS_PER_DOUBLE_INT, false);
1946e4b17023SJohn Marino
1947e4b17023SJohn Marino return immed_double_int_const (val, mode);
1948e4b17023SJohn Marino }
1949e4b17023SJohn Marino
1950e4b17023SJohn Marino /* Extract a bit field that is split across two words
1951e4b17023SJohn Marino and return an RTX for the result.
1952e4b17023SJohn Marino
1953e4b17023SJohn Marino OP0 is the REG, SUBREG or MEM rtx for the first of the two words.
1954e4b17023SJohn Marino BITSIZE is the field width; BITPOS, position of its first bit, in the word.
1955e4b17023SJohn Marino UNSIGNEDP is 1 if should zero-extend the contents; else sign-extend. */
1956e4b17023SJohn Marino
1957e4b17023SJohn Marino static rtx
extract_split_bit_field(rtx op0,unsigned HOST_WIDE_INT bitsize,unsigned HOST_WIDE_INT bitpos,int unsignedp)1958e4b17023SJohn Marino extract_split_bit_field (rtx op0, unsigned HOST_WIDE_INT bitsize,
1959e4b17023SJohn Marino unsigned HOST_WIDE_INT bitpos, int unsignedp)
1960e4b17023SJohn Marino {
1961e4b17023SJohn Marino unsigned int unit;
1962e4b17023SJohn Marino unsigned int bitsdone = 0;
1963e4b17023SJohn Marino rtx result = NULL_RTX;
1964e4b17023SJohn Marino int first = 1;
1965e4b17023SJohn Marino
1966e4b17023SJohn Marino /* Make sure UNIT isn't larger than BITS_PER_WORD, we can only handle that
1967e4b17023SJohn Marino much at a time. */
1968e4b17023SJohn Marino if (REG_P (op0) || GET_CODE (op0) == SUBREG)
1969e4b17023SJohn Marino unit = BITS_PER_WORD;
1970e4b17023SJohn Marino else
1971e4b17023SJohn Marino unit = MIN (MEM_ALIGN (op0), BITS_PER_WORD);
1972e4b17023SJohn Marino
1973e4b17023SJohn Marino while (bitsdone < bitsize)
1974e4b17023SJohn Marino {
1975e4b17023SJohn Marino unsigned HOST_WIDE_INT thissize;
1976e4b17023SJohn Marino rtx part, word;
1977e4b17023SJohn Marino unsigned HOST_WIDE_INT thispos;
1978e4b17023SJohn Marino unsigned HOST_WIDE_INT offset;
1979e4b17023SJohn Marino
1980e4b17023SJohn Marino offset = (bitpos + bitsdone) / unit;
1981e4b17023SJohn Marino thispos = (bitpos + bitsdone) % unit;
1982e4b17023SJohn Marino
1983e4b17023SJohn Marino /* THISSIZE must not overrun a word boundary. Otherwise,
1984e4b17023SJohn Marino extract_fixed_bit_field will call us again, and we will mutually
1985e4b17023SJohn Marino recurse forever. */
1986e4b17023SJohn Marino thissize = MIN (bitsize - bitsdone, BITS_PER_WORD);
1987e4b17023SJohn Marino thissize = MIN (thissize, unit - thispos);
1988e4b17023SJohn Marino
1989e4b17023SJohn Marino /* If OP0 is a register, then handle OFFSET here.
1990e4b17023SJohn Marino
1991e4b17023SJohn Marino When handling multiword bitfields, extract_bit_field may pass
1992e4b17023SJohn Marino down a word_mode SUBREG of a larger REG for a bitfield that actually
1993e4b17023SJohn Marino crosses a word boundary. Thus, for a SUBREG, we must find
1994e4b17023SJohn Marino the current word starting from the base register. */
1995e4b17023SJohn Marino if (GET_CODE (op0) == SUBREG)
1996e4b17023SJohn Marino {
1997e4b17023SJohn Marino int word_offset = (SUBREG_BYTE (op0) / UNITS_PER_WORD) + offset;
1998e4b17023SJohn Marino word = operand_subword_force (SUBREG_REG (op0), word_offset,
1999e4b17023SJohn Marino GET_MODE (SUBREG_REG (op0)));
2000e4b17023SJohn Marino offset = 0;
2001e4b17023SJohn Marino }
2002e4b17023SJohn Marino else if (REG_P (op0))
2003e4b17023SJohn Marino {
2004e4b17023SJohn Marino word = operand_subword_force (op0, offset, GET_MODE (op0));
2005e4b17023SJohn Marino offset = 0;
2006e4b17023SJohn Marino }
2007e4b17023SJohn Marino else
2008e4b17023SJohn Marino word = op0;
2009e4b17023SJohn Marino
2010e4b17023SJohn Marino /* Extract the parts in bit-counting order,
2011e4b17023SJohn Marino whose meaning is determined by BYTES_PER_UNIT.
2012e4b17023SJohn Marino OFFSET is in UNITs, and UNIT is in bits.
2013e4b17023SJohn Marino extract_fixed_bit_field wants offset in bytes. */
2014e4b17023SJohn Marino part = extract_fixed_bit_field (word_mode, word,
2015e4b17023SJohn Marino offset * unit / BITS_PER_UNIT,
2016e4b17023SJohn Marino thissize, thispos, 0, 1, false);
2017e4b17023SJohn Marino bitsdone += thissize;
2018e4b17023SJohn Marino
2019e4b17023SJohn Marino /* Shift this part into place for the result. */
2020e4b17023SJohn Marino if (BYTES_BIG_ENDIAN)
2021e4b17023SJohn Marino {
2022e4b17023SJohn Marino if (bitsize != bitsdone)
2023e4b17023SJohn Marino part = expand_shift (LSHIFT_EXPR, word_mode, part,
2024e4b17023SJohn Marino bitsize - bitsdone, 0, 1);
2025e4b17023SJohn Marino }
2026e4b17023SJohn Marino else
2027e4b17023SJohn Marino {
2028e4b17023SJohn Marino if (bitsdone != thissize)
2029e4b17023SJohn Marino part = expand_shift (LSHIFT_EXPR, word_mode, part,
2030e4b17023SJohn Marino bitsdone - thissize, 0, 1);
2031e4b17023SJohn Marino }
2032e4b17023SJohn Marino
2033e4b17023SJohn Marino if (first)
2034e4b17023SJohn Marino result = part;
2035e4b17023SJohn Marino else
2036e4b17023SJohn Marino /* Combine the parts with bitwise or. This works
2037e4b17023SJohn Marino because we extracted each part as an unsigned bit field. */
2038e4b17023SJohn Marino result = expand_binop (word_mode, ior_optab, part, result, NULL_RTX, 1,
2039e4b17023SJohn Marino OPTAB_LIB_WIDEN);
2040e4b17023SJohn Marino
2041e4b17023SJohn Marino first = 0;
2042e4b17023SJohn Marino }
2043e4b17023SJohn Marino
2044e4b17023SJohn Marino /* Unsigned bit field: we are done. */
2045e4b17023SJohn Marino if (unsignedp)
2046e4b17023SJohn Marino return result;
2047e4b17023SJohn Marino /* Signed bit field: sign-extend with two arithmetic shifts. */
2048e4b17023SJohn Marino result = expand_shift (LSHIFT_EXPR, word_mode, result,
2049e4b17023SJohn Marino BITS_PER_WORD - bitsize, NULL_RTX, 0);
2050e4b17023SJohn Marino return expand_shift (RSHIFT_EXPR, word_mode, result,
2051e4b17023SJohn Marino BITS_PER_WORD - bitsize, NULL_RTX, 0);
2052e4b17023SJohn Marino }
2053e4b17023SJohn Marino
2054e4b17023SJohn Marino /* Try to read the low bits of SRC as an rvalue of mode MODE, preserving
2055e4b17023SJohn Marino the bit pattern. SRC_MODE is the mode of SRC; if this is smaller than
2056e4b17023SJohn Marino MODE, fill the upper bits with zeros. Fail if the layout of either
2057e4b17023SJohn Marino mode is unknown (as for CC modes) or if the extraction would involve
2058e4b17023SJohn Marino unprofitable mode punning. Return the value on success, otherwise
2059e4b17023SJohn Marino return null.
2060e4b17023SJohn Marino
2061e4b17023SJohn Marino This is different from gen_lowpart* in these respects:
2062e4b17023SJohn Marino
2063e4b17023SJohn Marino - the returned value must always be considered an rvalue
2064e4b17023SJohn Marino
2065e4b17023SJohn Marino - when MODE is wider than SRC_MODE, the extraction involves
2066e4b17023SJohn Marino a zero extension
2067e4b17023SJohn Marino
2068e4b17023SJohn Marino - when MODE is smaller than SRC_MODE, the extraction involves
2069e4b17023SJohn Marino a truncation (and is thus subject to TRULY_NOOP_TRUNCATION).
2070e4b17023SJohn Marino
2071e4b17023SJohn Marino In other words, this routine performs a computation, whereas the
2072e4b17023SJohn Marino gen_lowpart* routines are conceptually lvalue or rvalue subreg
2073e4b17023SJohn Marino operations. */
2074e4b17023SJohn Marino
2075e4b17023SJohn Marino rtx
extract_low_bits(enum machine_mode mode,enum machine_mode src_mode,rtx src)2076e4b17023SJohn Marino extract_low_bits (enum machine_mode mode, enum machine_mode src_mode, rtx src)
2077e4b17023SJohn Marino {
2078e4b17023SJohn Marino enum machine_mode int_mode, src_int_mode;
2079e4b17023SJohn Marino
2080e4b17023SJohn Marino if (mode == src_mode)
2081e4b17023SJohn Marino return src;
2082e4b17023SJohn Marino
2083e4b17023SJohn Marino if (CONSTANT_P (src))
2084e4b17023SJohn Marino {
2085e4b17023SJohn Marino /* simplify_gen_subreg can't be used here, as if simplify_subreg
2086e4b17023SJohn Marino fails, it will happily create (subreg (symbol_ref)) or similar
2087e4b17023SJohn Marino invalid SUBREGs. */
2088e4b17023SJohn Marino unsigned int byte = subreg_lowpart_offset (mode, src_mode);
2089e4b17023SJohn Marino rtx ret = simplify_subreg (mode, src, src_mode, byte);
2090e4b17023SJohn Marino if (ret)
2091e4b17023SJohn Marino return ret;
2092e4b17023SJohn Marino
2093e4b17023SJohn Marino if (GET_MODE (src) == VOIDmode
2094e4b17023SJohn Marino || !validate_subreg (mode, src_mode, src, byte))
2095e4b17023SJohn Marino return NULL_RTX;
2096e4b17023SJohn Marino
2097e4b17023SJohn Marino src = force_reg (GET_MODE (src), src);
2098e4b17023SJohn Marino return gen_rtx_SUBREG (mode, src, byte);
2099e4b17023SJohn Marino }
2100e4b17023SJohn Marino
2101e4b17023SJohn Marino if (GET_MODE_CLASS (mode) == MODE_CC || GET_MODE_CLASS (src_mode) == MODE_CC)
2102e4b17023SJohn Marino return NULL_RTX;
2103e4b17023SJohn Marino
2104e4b17023SJohn Marino if (GET_MODE_BITSIZE (mode) == GET_MODE_BITSIZE (src_mode)
2105e4b17023SJohn Marino && MODES_TIEABLE_P (mode, src_mode))
2106e4b17023SJohn Marino {
2107e4b17023SJohn Marino rtx x = gen_lowpart_common (mode, src);
2108e4b17023SJohn Marino if (x)
2109e4b17023SJohn Marino return x;
2110e4b17023SJohn Marino }
2111e4b17023SJohn Marino
2112e4b17023SJohn Marino src_int_mode = int_mode_for_mode (src_mode);
2113e4b17023SJohn Marino int_mode = int_mode_for_mode (mode);
2114e4b17023SJohn Marino if (src_int_mode == BLKmode || int_mode == BLKmode)
2115e4b17023SJohn Marino return NULL_RTX;
2116e4b17023SJohn Marino
2117e4b17023SJohn Marino if (!MODES_TIEABLE_P (src_int_mode, src_mode))
2118e4b17023SJohn Marino return NULL_RTX;
2119e4b17023SJohn Marino if (!MODES_TIEABLE_P (int_mode, mode))
2120e4b17023SJohn Marino return NULL_RTX;
2121e4b17023SJohn Marino
2122e4b17023SJohn Marino src = gen_lowpart (src_int_mode, src);
2123e4b17023SJohn Marino src = convert_modes (int_mode, src_int_mode, src, true);
2124e4b17023SJohn Marino src = gen_lowpart (mode, src);
2125e4b17023SJohn Marino return src;
2126e4b17023SJohn Marino }
2127e4b17023SJohn Marino
2128e4b17023SJohn Marino /* Add INC into TARGET. */
2129e4b17023SJohn Marino
2130e4b17023SJohn Marino void
expand_inc(rtx target,rtx inc)2131e4b17023SJohn Marino expand_inc (rtx target, rtx inc)
2132e4b17023SJohn Marino {
2133e4b17023SJohn Marino rtx value = expand_binop (GET_MODE (target), add_optab,
2134e4b17023SJohn Marino target, inc,
2135e4b17023SJohn Marino target, 0, OPTAB_LIB_WIDEN);
2136e4b17023SJohn Marino if (value != target)
2137e4b17023SJohn Marino emit_move_insn (target, value);
2138e4b17023SJohn Marino }
2139e4b17023SJohn Marino
2140e4b17023SJohn Marino /* Subtract DEC from TARGET. */
2141e4b17023SJohn Marino
2142e4b17023SJohn Marino void
expand_dec(rtx target,rtx dec)2143e4b17023SJohn Marino expand_dec (rtx target, rtx dec)
2144e4b17023SJohn Marino {
2145e4b17023SJohn Marino rtx value = expand_binop (GET_MODE (target), sub_optab,
2146e4b17023SJohn Marino target, dec,
2147e4b17023SJohn Marino target, 0, OPTAB_LIB_WIDEN);
2148e4b17023SJohn Marino if (value != target)
2149e4b17023SJohn Marino emit_move_insn (target, value);
2150e4b17023SJohn Marino }
2151e4b17023SJohn Marino
2152e4b17023SJohn Marino /* Output a shift instruction for expression code CODE,
2153e4b17023SJohn Marino with SHIFTED being the rtx for the value to shift,
2154e4b17023SJohn Marino and AMOUNT the rtx for the amount to shift by.
2155e4b17023SJohn Marino Store the result in the rtx TARGET, if that is convenient.
2156e4b17023SJohn Marino If UNSIGNEDP is nonzero, do a logical shift; otherwise, arithmetic.
2157e4b17023SJohn Marino Return the rtx for where the value is. */
2158e4b17023SJohn Marino
2159e4b17023SJohn Marino static rtx
expand_shift_1(enum tree_code code,enum machine_mode mode,rtx shifted,rtx amount,rtx target,int unsignedp)2160e4b17023SJohn Marino expand_shift_1 (enum tree_code code, enum machine_mode mode, rtx shifted,
2161e4b17023SJohn Marino rtx amount, rtx target, int unsignedp)
2162e4b17023SJohn Marino {
2163e4b17023SJohn Marino rtx op1, temp = 0;
2164e4b17023SJohn Marino int left = (code == LSHIFT_EXPR || code == LROTATE_EXPR);
2165e4b17023SJohn Marino int rotate = (code == LROTATE_EXPR || code == RROTATE_EXPR);
2166e4b17023SJohn Marino optab lshift_optab = ashl_optab;
2167e4b17023SJohn Marino optab rshift_arith_optab = ashr_optab;
2168e4b17023SJohn Marino optab rshift_uns_optab = lshr_optab;
2169e4b17023SJohn Marino optab lrotate_optab = rotl_optab;
2170e4b17023SJohn Marino optab rrotate_optab = rotr_optab;
2171e4b17023SJohn Marino enum machine_mode op1_mode;
2172e4b17023SJohn Marino int attempt;
2173e4b17023SJohn Marino bool speed = optimize_insn_for_speed_p ();
2174e4b17023SJohn Marino
2175e4b17023SJohn Marino op1 = amount;
2176e4b17023SJohn Marino op1_mode = GET_MODE (op1);
2177e4b17023SJohn Marino
2178e4b17023SJohn Marino /* Determine whether the shift/rotate amount is a vector, or scalar. If the
2179e4b17023SJohn Marino shift amount is a vector, use the vector/vector shift patterns. */
2180e4b17023SJohn Marino if (VECTOR_MODE_P (mode) && VECTOR_MODE_P (op1_mode))
2181e4b17023SJohn Marino {
2182e4b17023SJohn Marino lshift_optab = vashl_optab;
2183e4b17023SJohn Marino rshift_arith_optab = vashr_optab;
2184e4b17023SJohn Marino rshift_uns_optab = vlshr_optab;
2185e4b17023SJohn Marino lrotate_optab = vrotl_optab;
2186e4b17023SJohn Marino rrotate_optab = vrotr_optab;
2187e4b17023SJohn Marino }
2188e4b17023SJohn Marino
2189e4b17023SJohn Marino /* Previously detected shift-counts computed by NEGATE_EXPR
2190e4b17023SJohn Marino and shifted in the other direction; but that does not work
2191e4b17023SJohn Marino on all machines. */
2192e4b17023SJohn Marino
2193e4b17023SJohn Marino if (SHIFT_COUNT_TRUNCATED)
2194e4b17023SJohn Marino {
2195e4b17023SJohn Marino if (CONST_INT_P (op1)
2196e4b17023SJohn Marino && ((unsigned HOST_WIDE_INT) INTVAL (op1) >=
2197e4b17023SJohn Marino (unsigned HOST_WIDE_INT) GET_MODE_BITSIZE (mode)))
2198e4b17023SJohn Marino op1 = GEN_INT ((unsigned HOST_WIDE_INT) INTVAL (op1)
2199e4b17023SJohn Marino % GET_MODE_BITSIZE (mode));
2200e4b17023SJohn Marino else if (GET_CODE (op1) == SUBREG
2201e4b17023SJohn Marino && subreg_lowpart_p (op1)
2202*5ce9237cSJohn Marino && SCALAR_INT_MODE_P (GET_MODE (SUBREG_REG (op1)))
2203*5ce9237cSJohn Marino && SCALAR_INT_MODE_P (GET_MODE (op1)))
2204e4b17023SJohn Marino op1 = SUBREG_REG (op1);
2205e4b17023SJohn Marino }
2206e4b17023SJohn Marino
2207e4b17023SJohn Marino if (op1 == const0_rtx)
2208e4b17023SJohn Marino return shifted;
2209e4b17023SJohn Marino
2210e4b17023SJohn Marino /* Check whether its cheaper to implement a left shift by a constant
2211e4b17023SJohn Marino bit count by a sequence of additions. */
2212e4b17023SJohn Marino if (code == LSHIFT_EXPR
2213e4b17023SJohn Marino && CONST_INT_P (op1)
2214e4b17023SJohn Marino && INTVAL (op1) > 0
2215e4b17023SJohn Marino && INTVAL (op1) < GET_MODE_PRECISION (mode)
2216e4b17023SJohn Marino && INTVAL (op1) < MAX_BITS_PER_WORD
2217e4b17023SJohn Marino && shift_cost[speed][mode][INTVAL (op1)] > INTVAL (op1) * add_cost[speed][mode]
2218e4b17023SJohn Marino && shift_cost[speed][mode][INTVAL (op1)] != MAX_COST)
2219e4b17023SJohn Marino {
2220e4b17023SJohn Marino int i;
2221e4b17023SJohn Marino for (i = 0; i < INTVAL (op1); i++)
2222e4b17023SJohn Marino {
2223e4b17023SJohn Marino temp = force_reg (mode, shifted);
2224e4b17023SJohn Marino shifted = expand_binop (mode, add_optab, temp, temp, NULL_RTX,
2225e4b17023SJohn Marino unsignedp, OPTAB_LIB_WIDEN);
2226e4b17023SJohn Marino }
2227e4b17023SJohn Marino return shifted;
2228e4b17023SJohn Marino }
2229e4b17023SJohn Marino
2230e4b17023SJohn Marino for (attempt = 0; temp == 0 && attempt < 3; attempt++)
2231e4b17023SJohn Marino {
2232e4b17023SJohn Marino enum optab_methods methods;
2233e4b17023SJohn Marino
2234e4b17023SJohn Marino if (attempt == 0)
2235e4b17023SJohn Marino methods = OPTAB_DIRECT;
2236e4b17023SJohn Marino else if (attempt == 1)
2237e4b17023SJohn Marino methods = OPTAB_WIDEN;
2238e4b17023SJohn Marino else
2239e4b17023SJohn Marino methods = OPTAB_LIB_WIDEN;
2240e4b17023SJohn Marino
2241e4b17023SJohn Marino if (rotate)
2242e4b17023SJohn Marino {
2243e4b17023SJohn Marino /* Widening does not work for rotation. */
2244e4b17023SJohn Marino if (methods == OPTAB_WIDEN)
2245e4b17023SJohn Marino continue;
2246e4b17023SJohn Marino else if (methods == OPTAB_LIB_WIDEN)
2247e4b17023SJohn Marino {
2248e4b17023SJohn Marino /* If we have been unable to open-code this by a rotation,
2249e4b17023SJohn Marino do it as the IOR of two shifts. I.e., to rotate A
2250e4b17023SJohn Marino by N bits, compute (A << N) | ((unsigned) A >> (C - N))
2251e4b17023SJohn Marino where C is the bitsize of A.
2252e4b17023SJohn Marino
2253e4b17023SJohn Marino It is theoretically possible that the target machine might
2254e4b17023SJohn Marino not be able to perform either shift and hence we would
2255e4b17023SJohn Marino be making two libcalls rather than just the one for the
2256e4b17023SJohn Marino shift (similarly if IOR could not be done). We will allow
2257e4b17023SJohn Marino this extremely unlikely lossage to avoid complicating the
2258e4b17023SJohn Marino code below. */
2259e4b17023SJohn Marino
2260e4b17023SJohn Marino rtx subtarget = target == shifted ? 0 : target;
2261e4b17023SJohn Marino rtx new_amount, other_amount;
2262e4b17023SJohn Marino rtx temp1;
2263e4b17023SJohn Marino
2264e4b17023SJohn Marino new_amount = op1;
2265e4b17023SJohn Marino if (CONST_INT_P (op1))
2266e4b17023SJohn Marino other_amount = GEN_INT (GET_MODE_BITSIZE (mode)
2267e4b17023SJohn Marino - INTVAL (op1));
2268e4b17023SJohn Marino else
2269e4b17023SJohn Marino other_amount
2270e4b17023SJohn Marino = simplify_gen_binary (MINUS, GET_MODE (op1),
2271e4b17023SJohn Marino GEN_INT (GET_MODE_PRECISION (mode)),
2272e4b17023SJohn Marino op1);
2273e4b17023SJohn Marino
2274e4b17023SJohn Marino shifted = force_reg (mode, shifted);
2275e4b17023SJohn Marino
2276e4b17023SJohn Marino temp = expand_shift_1 (left ? LSHIFT_EXPR : RSHIFT_EXPR,
2277e4b17023SJohn Marino mode, shifted, new_amount, 0, 1);
2278e4b17023SJohn Marino temp1 = expand_shift_1 (left ? RSHIFT_EXPR : LSHIFT_EXPR,
2279e4b17023SJohn Marino mode, shifted, other_amount,
2280e4b17023SJohn Marino subtarget, 1);
2281e4b17023SJohn Marino return expand_binop (mode, ior_optab, temp, temp1, target,
2282e4b17023SJohn Marino unsignedp, methods);
2283e4b17023SJohn Marino }
2284e4b17023SJohn Marino
2285e4b17023SJohn Marino temp = expand_binop (mode,
2286e4b17023SJohn Marino left ? lrotate_optab : rrotate_optab,
2287e4b17023SJohn Marino shifted, op1, target, unsignedp, methods);
2288e4b17023SJohn Marino }
2289e4b17023SJohn Marino else if (unsignedp)
2290e4b17023SJohn Marino temp = expand_binop (mode,
2291e4b17023SJohn Marino left ? lshift_optab : rshift_uns_optab,
2292e4b17023SJohn Marino shifted, op1, target, unsignedp, methods);
2293e4b17023SJohn Marino
2294e4b17023SJohn Marino /* Do arithmetic shifts.
2295e4b17023SJohn Marino Also, if we are going to widen the operand, we can just as well
2296e4b17023SJohn Marino use an arithmetic right-shift instead of a logical one. */
2297e4b17023SJohn Marino if (temp == 0 && ! rotate
2298e4b17023SJohn Marino && (! unsignedp || (! left && methods == OPTAB_WIDEN)))
2299e4b17023SJohn Marino {
2300e4b17023SJohn Marino enum optab_methods methods1 = methods;
2301e4b17023SJohn Marino
2302e4b17023SJohn Marino /* If trying to widen a log shift to an arithmetic shift,
2303e4b17023SJohn Marino don't accept an arithmetic shift of the same size. */
2304e4b17023SJohn Marino if (unsignedp)
2305e4b17023SJohn Marino methods1 = OPTAB_MUST_WIDEN;
2306e4b17023SJohn Marino
2307e4b17023SJohn Marino /* Arithmetic shift */
2308e4b17023SJohn Marino
2309e4b17023SJohn Marino temp = expand_binop (mode,
2310e4b17023SJohn Marino left ? lshift_optab : rshift_arith_optab,
2311e4b17023SJohn Marino shifted, op1, target, unsignedp, methods1);
2312e4b17023SJohn Marino }
2313e4b17023SJohn Marino
2314e4b17023SJohn Marino /* We used to try extzv here for logical right shifts, but that was
2315e4b17023SJohn Marino only useful for one machine, the VAX, and caused poor code
2316e4b17023SJohn Marino generation there for lshrdi3, so the code was deleted and a
2317e4b17023SJohn Marino define_expand for lshrsi3 was added to vax.md. */
2318e4b17023SJohn Marino }
2319e4b17023SJohn Marino
2320e4b17023SJohn Marino gcc_assert (temp);
2321e4b17023SJohn Marino return temp;
2322e4b17023SJohn Marino }
2323e4b17023SJohn Marino
2324e4b17023SJohn Marino /* Output a shift instruction for expression code CODE,
2325e4b17023SJohn Marino with SHIFTED being the rtx for the value to shift,
2326e4b17023SJohn Marino and AMOUNT the amount to shift by.
2327e4b17023SJohn Marino Store the result in the rtx TARGET, if that is convenient.
2328e4b17023SJohn Marino If UNSIGNEDP is nonzero, do a logical shift; otherwise, arithmetic.
2329e4b17023SJohn Marino Return the rtx for where the value is. */
2330e4b17023SJohn Marino
2331e4b17023SJohn Marino rtx
expand_shift(enum tree_code code,enum machine_mode mode,rtx shifted,int amount,rtx target,int unsignedp)2332e4b17023SJohn Marino expand_shift (enum tree_code code, enum machine_mode mode, rtx shifted,
2333e4b17023SJohn Marino int amount, rtx target, int unsignedp)
2334e4b17023SJohn Marino {
2335e4b17023SJohn Marino return expand_shift_1 (code, mode,
2336e4b17023SJohn Marino shifted, GEN_INT (amount), target, unsignedp);
2337e4b17023SJohn Marino }
2338e4b17023SJohn Marino
2339e4b17023SJohn Marino /* Output a shift instruction for expression code CODE,
2340e4b17023SJohn Marino with SHIFTED being the rtx for the value to shift,
2341e4b17023SJohn Marino and AMOUNT the tree for the amount to shift by.
2342e4b17023SJohn Marino Store the result in the rtx TARGET, if that is convenient.
2343e4b17023SJohn Marino If UNSIGNEDP is nonzero, do a logical shift; otherwise, arithmetic.
2344e4b17023SJohn Marino Return the rtx for where the value is. */
2345e4b17023SJohn Marino
2346e4b17023SJohn Marino rtx
expand_variable_shift(enum tree_code code,enum machine_mode mode,rtx shifted,tree amount,rtx target,int unsignedp)2347e4b17023SJohn Marino expand_variable_shift (enum tree_code code, enum machine_mode mode, rtx shifted,
2348e4b17023SJohn Marino tree amount, rtx target, int unsignedp)
2349e4b17023SJohn Marino {
2350e4b17023SJohn Marino return expand_shift_1 (code, mode,
2351e4b17023SJohn Marino shifted, expand_normal (amount), target, unsignedp);
2352e4b17023SJohn Marino }
2353e4b17023SJohn Marino
2354e4b17023SJohn Marino
2355e4b17023SJohn Marino /* Indicates the type of fixup needed after a constant multiplication.
2356e4b17023SJohn Marino BASIC_VARIANT means no fixup is needed, NEGATE_VARIANT means that
2357e4b17023SJohn Marino the result should be negated, and ADD_VARIANT means that the
2358e4b17023SJohn Marino multiplicand should be added to the result. */
2359e4b17023SJohn Marino enum mult_variant {basic_variant, negate_variant, add_variant};
2360e4b17023SJohn Marino
2361e4b17023SJohn Marino static void synth_mult (struct algorithm *, unsigned HOST_WIDE_INT,
2362e4b17023SJohn Marino const struct mult_cost *, enum machine_mode mode);
2363e4b17023SJohn Marino static bool choose_mult_variant (enum machine_mode, HOST_WIDE_INT,
2364e4b17023SJohn Marino struct algorithm *, enum mult_variant *, int);
2365e4b17023SJohn Marino static rtx expand_mult_const (enum machine_mode, rtx, HOST_WIDE_INT, rtx,
2366e4b17023SJohn Marino const struct algorithm *, enum mult_variant);
2367e4b17023SJohn Marino static unsigned HOST_WIDE_INT choose_multiplier (unsigned HOST_WIDE_INT, int,
2368e4b17023SJohn Marino int, rtx *, int *, int *);
2369e4b17023SJohn Marino static unsigned HOST_WIDE_INT invert_mod2n (unsigned HOST_WIDE_INT, int);
2370e4b17023SJohn Marino static rtx extract_high_half (enum machine_mode, rtx);
2371e4b17023SJohn Marino static rtx expand_mult_highpart (enum machine_mode, rtx, rtx, rtx, int, int);
2372e4b17023SJohn Marino static rtx expand_mult_highpart_optab (enum machine_mode, rtx, rtx, rtx,
2373e4b17023SJohn Marino int, int);
2374e4b17023SJohn Marino /* Compute and return the best algorithm for multiplying by T.
2375e4b17023SJohn Marino The algorithm must cost less than cost_limit
2376e4b17023SJohn Marino If retval.cost >= COST_LIMIT, no algorithm was found and all
2377e4b17023SJohn Marino other field of the returned struct are undefined.
2378e4b17023SJohn Marino MODE is the machine mode of the multiplication. */
2379e4b17023SJohn Marino
2380e4b17023SJohn Marino static void
synth_mult(struct algorithm * alg_out,unsigned HOST_WIDE_INT t,const struct mult_cost * cost_limit,enum machine_mode mode)2381e4b17023SJohn Marino synth_mult (struct algorithm *alg_out, unsigned HOST_WIDE_INT t,
2382e4b17023SJohn Marino const struct mult_cost *cost_limit, enum machine_mode mode)
2383e4b17023SJohn Marino {
2384e4b17023SJohn Marino int m;
2385e4b17023SJohn Marino struct algorithm *alg_in, *best_alg;
2386e4b17023SJohn Marino struct mult_cost best_cost;
2387e4b17023SJohn Marino struct mult_cost new_limit;
2388e4b17023SJohn Marino int op_cost, op_latency;
2389e4b17023SJohn Marino unsigned HOST_WIDE_INT orig_t = t;
2390e4b17023SJohn Marino unsigned HOST_WIDE_INT q;
2391e4b17023SJohn Marino int maxm = MIN (BITS_PER_WORD, GET_MODE_BITSIZE (mode));
2392e4b17023SJohn Marino int hash_index;
2393e4b17023SJohn Marino bool cache_hit = false;
2394e4b17023SJohn Marino enum alg_code cache_alg = alg_zero;
2395e4b17023SJohn Marino bool speed = optimize_insn_for_speed_p ();
2396e4b17023SJohn Marino
2397e4b17023SJohn Marino /* Indicate that no algorithm is yet found. If no algorithm
2398e4b17023SJohn Marino is found, this value will be returned and indicate failure. */
2399e4b17023SJohn Marino alg_out->cost.cost = cost_limit->cost + 1;
2400e4b17023SJohn Marino alg_out->cost.latency = cost_limit->latency + 1;
2401e4b17023SJohn Marino
2402e4b17023SJohn Marino if (cost_limit->cost < 0
2403e4b17023SJohn Marino || (cost_limit->cost == 0 && cost_limit->latency <= 0))
2404e4b17023SJohn Marino return;
2405e4b17023SJohn Marino
2406e4b17023SJohn Marino /* Restrict the bits of "t" to the multiplication's mode. */
2407e4b17023SJohn Marino t &= GET_MODE_MASK (mode);
2408e4b17023SJohn Marino
2409e4b17023SJohn Marino /* t == 1 can be done in zero cost. */
2410e4b17023SJohn Marino if (t == 1)
2411e4b17023SJohn Marino {
2412e4b17023SJohn Marino alg_out->ops = 1;
2413e4b17023SJohn Marino alg_out->cost.cost = 0;
2414e4b17023SJohn Marino alg_out->cost.latency = 0;
2415e4b17023SJohn Marino alg_out->op[0] = alg_m;
2416e4b17023SJohn Marino return;
2417e4b17023SJohn Marino }
2418e4b17023SJohn Marino
2419e4b17023SJohn Marino /* t == 0 sometimes has a cost. If it does and it exceeds our limit,
2420e4b17023SJohn Marino fail now. */
2421e4b17023SJohn Marino if (t == 0)
2422e4b17023SJohn Marino {
2423e4b17023SJohn Marino if (MULT_COST_LESS (cost_limit, zero_cost[speed]))
2424e4b17023SJohn Marino return;
2425e4b17023SJohn Marino else
2426e4b17023SJohn Marino {
2427e4b17023SJohn Marino alg_out->ops = 1;
2428e4b17023SJohn Marino alg_out->cost.cost = zero_cost[speed];
2429e4b17023SJohn Marino alg_out->cost.latency = zero_cost[speed];
2430e4b17023SJohn Marino alg_out->op[0] = alg_zero;
2431e4b17023SJohn Marino return;
2432e4b17023SJohn Marino }
2433e4b17023SJohn Marino }
2434e4b17023SJohn Marino
2435e4b17023SJohn Marino /* We'll be needing a couple extra algorithm structures now. */
2436e4b17023SJohn Marino
2437e4b17023SJohn Marino alg_in = XALLOCA (struct algorithm);
2438e4b17023SJohn Marino best_alg = XALLOCA (struct algorithm);
2439e4b17023SJohn Marino best_cost = *cost_limit;
2440e4b17023SJohn Marino
2441e4b17023SJohn Marino /* Compute the hash index. */
2442e4b17023SJohn Marino hash_index = (t ^ (unsigned int) mode ^ (speed * 256)) % NUM_ALG_HASH_ENTRIES;
2443e4b17023SJohn Marino
2444e4b17023SJohn Marino /* See if we already know what to do for T. */
2445e4b17023SJohn Marino if (alg_hash[hash_index].t == t
2446e4b17023SJohn Marino && alg_hash[hash_index].mode == mode
2447e4b17023SJohn Marino && alg_hash[hash_index].mode == mode
2448e4b17023SJohn Marino && alg_hash[hash_index].speed == speed
2449e4b17023SJohn Marino && alg_hash[hash_index].alg != alg_unknown)
2450e4b17023SJohn Marino {
2451e4b17023SJohn Marino cache_alg = alg_hash[hash_index].alg;
2452e4b17023SJohn Marino
2453e4b17023SJohn Marino if (cache_alg == alg_impossible)
2454e4b17023SJohn Marino {
2455e4b17023SJohn Marino /* The cache tells us that it's impossible to synthesize
2456e4b17023SJohn Marino multiplication by T within alg_hash[hash_index].cost. */
2457e4b17023SJohn Marino if (!CHEAPER_MULT_COST (&alg_hash[hash_index].cost, cost_limit))
2458e4b17023SJohn Marino /* COST_LIMIT is at least as restrictive as the one
2459e4b17023SJohn Marino recorded in the hash table, in which case we have no
2460e4b17023SJohn Marino hope of synthesizing a multiplication. Just
2461e4b17023SJohn Marino return. */
2462e4b17023SJohn Marino return;
2463e4b17023SJohn Marino
2464e4b17023SJohn Marino /* If we get here, COST_LIMIT is less restrictive than the
2465e4b17023SJohn Marino one recorded in the hash table, so we may be able to
2466e4b17023SJohn Marino synthesize a multiplication. Proceed as if we didn't
2467e4b17023SJohn Marino have the cache entry. */
2468e4b17023SJohn Marino }
2469e4b17023SJohn Marino else
2470e4b17023SJohn Marino {
2471e4b17023SJohn Marino if (CHEAPER_MULT_COST (cost_limit, &alg_hash[hash_index].cost))
2472e4b17023SJohn Marino /* The cached algorithm shows that this multiplication
2473e4b17023SJohn Marino requires more cost than COST_LIMIT. Just return. This
2474e4b17023SJohn Marino way, we don't clobber this cache entry with
2475e4b17023SJohn Marino alg_impossible but retain useful information. */
2476e4b17023SJohn Marino return;
2477e4b17023SJohn Marino
2478e4b17023SJohn Marino cache_hit = true;
2479e4b17023SJohn Marino
2480e4b17023SJohn Marino switch (cache_alg)
2481e4b17023SJohn Marino {
2482e4b17023SJohn Marino case alg_shift:
2483e4b17023SJohn Marino goto do_alg_shift;
2484e4b17023SJohn Marino
2485e4b17023SJohn Marino case alg_add_t_m2:
2486e4b17023SJohn Marino case alg_sub_t_m2:
2487e4b17023SJohn Marino goto do_alg_addsub_t_m2;
2488e4b17023SJohn Marino
2489e4b17023SJohn Marino case alg_add_factor:
2490e4b17023SJohn Marino case alg_sub_factor:
2491e4b17023SJohn Marino goto do_alg_addsub_factor;
2492e4b17023SJohn Marino
2493e4b17023SJohn Marino case alg_add_t2_m:
2494e4b17023SJohn Marino goto do_alg_add_t2_m;
2495e4b17023SJohn Marino
2496e4b17023SJohn Marino case alg_sub_t2_m:
2497e4b17023SJohn Marino goto do_alg_sub_t2_m;
2498e4b17023SJohn Marino
2499e4b17023SJohn Marino default:
2500e4b17023SJohn Marino gcc_unreachable ();
2501e4b17023SJohn Marino }
2502e4b17023SJohn Marino }
2503e4b17023SJohn Marino }
2504e4b17023SJohn Marino
2505e4b17023SJohn Marino /* If we have a group of zero bits at the low-order part of T, try
2506e4b17023SJohn Marino multiplying by the remaining bits and then doing a shift. */
2507e4b17023SJohn Marino
2508e4b17023SJohn Marino if ((t & 1) == 0)
2509e4b17023SJohn Marino {
2510e4b17023SJohn Marino do_alg_shift:
2511e4b17023SJohn Marino m = floor_log2 (t & -t); /* m = number of low zero bits */
2512e4b17023SJohn Marino if (m < maxm)
2513e4b17023SJohn Marino {
2514e4b17023SJohn Marino q = t >> m;
2515e4b17023SJohn Marino /* The function expand_shift will choose between a shift and
2516e4b17023SJohn Marino a sequence of additions, so the observed cost is given as
2517e4b17023SJohn Marino MIN (m * add_cost[speed][mode], shift_cost[speed][mode][m]). */
2518e4b17023SJohn Marino op_cost = m * add_cost[speed][mode];
2519e4b17023SJohn Marino if (shift_cost[speed][mode][m] < op_cost)
2520e4b17023SJohn Marino op_cost = shift_cost[speed][mode][m];
2521e4b17023SJohn Marino new_limit.cost = best_cost.cost - op_cost;
2522e4b17023SJohn Marino new_limit.latency = best_cost.latency - op_cost;
2523e4b17023SJohn Marino synth_mult (alg_in, q, &new_limit, mode);
2524e4b17023SJohn Marino
2525e4b17023SJohn Marino alg_in->cost.cost += op_cost;
2526e4b17023SJohn Marino alg_in->cost.latency += op_cost;
2527e4b17023SJohn Marino if (CHEAPER_MULT_COST (&alg_in->cost, &best_cost))
2528e4b17023SJohn Marino {
2529e4b17023SJohn Marino struct algorithm *x;
2530e4b17023SJohn Marino best_cost = alg_in->cost;
2531e4b17023SJohn Marino x = alg_in, alg_in = best_alg, best_alg = x;
2532e4b17023SJohn Marino best_alg->log[best_alg->ops] = m;
2533e4b17023SJohn Marino best_alg->op[best_alg->ops] = alg_shift;
2534e4b17023SJohn Marino }
2535e4b17023SJohn Marino
2536e4b17023SJohn Marino /* See if treating ORIG_T as a signed number yields a better
2537e4b17023SJohn Marino sequence. Try this sequence only for a negative ORIG_T
2538e4b17023SJohn Marino as it would be useless for a non-negative ORIG_T. */
2539e4b17023SJohn Marino if ((HOST_WIDE_INT) orig_t < 0)
2540e4b17023SJohn Marino {
2541e4b17023SJohn Marino /* Shift ORIG_T as follows because a right shift of a
2542e4b17023SJohn Marino negative-valued signed type is implementation
2543e4b17023SJohn Marino defined. */
2544e4b17023SJohn Marino q = ~(~orig_t >> m);
2545e4b17023SJohn Marino /* The function expand_shift will choose between a shift
2546e4b17023SJohn Marino and a sequence of additions, so the observed cost is
2547e4b17023SJohn Marino given as MIN (m * add_cost[speed][mode],
2548e4b17023SJohn Marino shift_cost[speed][mode][m]). */
2549e4b17023SJohn Marino op_cost = m * add_cost[speed][mode];
2550e4b17023SJohn Marino if (shift_cost[speed][mode][m] < op_cost)
2551e4b17023SJohn Marino op_cost = shift_cost[speed][mode][m];
2552e4b17023SJohn Marino new_limit.cost = best_cost.cost - op_cost;
2553e4b17023SJohn Marino new_limit.latency = best_cost.latency - op_cost;
2554e4b17023SJohn Marino synth_mult (alg_in, q, &new_limit, mode);
2555e4b17023SJohn Marino
2556e4b17023SJohn Marino alg_in->cost.cost += op_cost;
2557e4b17023SJohn Marino alg_in->cost.latency += op_cost;
2558e4b17023SJohn Marino if (CHEAPER_MULT_COST (&alg_in->cost, &best_cost))
2559e4b17023SJohn Marino {
2560e4b17023SJohn Marino struct algorithm *x;
2561e4b17023SJohn Marino best_cost = alg_in->cost;
2562e4b17023SJohn Marino x = alg_in, alg_in = best_alg, best_alg = x;
2563e4b17023SJohn Marino best_alg->log[best_alg->ops] = m;
2564e4b17023SJohn Marino best_alg->op[best_alg->ops] = alg_shift;
2565e4b17023SJohn Marino }
2566e4b17023SJohn Marino }
2567e4b17023SJohn Marino }
2568e4b17023SJohn Marino if (cache_hit)
2569e4b17023SJohn Marino goto done;
2570e4b17023SJohn Marino }
2571e4b17023SJohn Marino
2572e4b17023SJohn Marino /* If we have an odd number, add or subtract one. */
2573e4b17023SJohn Marino if ((t & 1) != 0)
2574e4b17023SJohn Marino {
2575e4b17023SJohn Marino unsigned HOST_WIDE_INT w;
2576e4b17023SJohn Marino
2577e4b17023SJohn Marino do_alg_addsub_t_m2:
2578e4b17023SJohn Marino for (w = 1; (w & t) != 0; w <<= 1)
2579e4b17023SJohn Marino ;
2580e4b17023SJohn Marino /* If T was -1, then W will be zero after the loop. This is another
2581e4b17023SJohn Marino case where T ends with ...111. Handling this with (T + 1) and
2582e4b17023SJohn Marino subtract 1 produces slightly better code and results in algorithm
2583e4b17023SJohn Marino selection much faster than treating it like the ...0111 case
2584e4b17023SJohn Marino below. */
2585e4b17023SJohn Marino if (w == 0
2586e4b17023SJohn Marino || (w > 2
2587e4b17023SJohn Marino /* Reject the case where t is 3.
2588e4b17023SJohn Marino Thus we prefer addition in that case. */
2589e4b17023SJohn Marino && t != 3))
2590e4b17023SJohn Marino {
2591e4b17023SJohn Marino /* T ends with ...111. Multiply by (T + 1) and subtract 1. */
2592e4b17023SJohn Marino
2593e4b17023SJohn Marino op_cost = add_cost[speed][mode];
2594e4b17023SJohn Marino new_limit.cost = best_cost.cost - op_cost;
2595e4b17023SJohn Marino new_limit.latency = best_cost.latency - op_cost;
2596e4b17023SJohn Marino synth_mult (alg_in, t + 1, &new_limit, mode);
2597e4b17023SJohn Marino
2598e4b17023SJohn Marino alg_in->cost.cost += op_cost;
2599e4b17023SJohn Marino alg_in->cost.latency += op_cost;
2600e4b17023SJohn Marino if (CHEAPER_MULT_COST (&alg_in->cost, &best_cost))
2601e4b17023SJohn Marino {
2602e4b17023SJohn Marino struct algorithm *x;
2603e4b17023SJohn Marino best_cost = alg_in->cost;
2604e4b17023SJohn Marino x = alg_in, alg_in = best_alg, best_alg = x;
2605e4b17023SJohn Marino best_alg->log[best_alg->ops] = 0;
2606e4b17023SJohn Marino best_alg->op[best_alg->ops] = alg_sub_t_m2;
2607e4b17023SJohn Marino }
2608e4b17023SJohn Marino }
2609e4b17023SJohn Marino else
2610e4b17023SJohn Marino {
2611e4b17023SJohn Marino /* T ends with ...01 or ...011. Multiply by (T - 1) and add 1. */
2612e4b17023SJohn Marino
2613e4b17023SJohn Marino op_cost = add_cost[speed][mode];
2614e4b17023SJohn Marino new_limit.cost = best_cost.cost - op_cost;
2615e4b17023SJohn Marino new_limit.latency = best_cost.latency - op_cost;
2616e4b17023SJohn Marino synth_mult (alg_in, t - 1, &new_limit, mode);
2617e4b17023SJohn Marino
2618e4b17023SJohn Marino alg_in->cost.cost += op_cost;
2619e4b17023SJohn Marino alg_in->cost.latency += op_cost;
2620e4b17023SJohn Marino if (CHEAPER_MULT_COST (&alg_in->cost, &best_cost))
2621e4b17023SJohn Marino {
2622e4b17023SJohn Marino struct algorithm *x;
2623e4b17023SJohn Marino best_cost = alg_in->cost;
2624e4b17023SJohn Marino x = alg_in, alg_in = best_alg, best_alg = x;
2625e4b17023SJohn Marino best_alg->log[best_alg->ops] = 0;
2626e4b17023SJohn Marino best_alg->op[best_alg->ops] = alg_add_t_m2;
2627e4b17023SJohn Marino }
2628e4b17023SJohn Marino }
2629e4b17023SJohn Marino
2630e4b17023SJohn Marino /* We may be able to calculate a * -7, a * -15, a * -31, etc
2631e4b17023SJohn Marino quickly with a - a * n for some appropriate constant n. */
2632e4b17023SJohn Marino m = exact_log2 (-orig_t + 1);
2633e4b17023SJohn Marino if (m >= 0 && m < maxm)
2634e4b17023SJohn Marino {
2635e4b17023SJohn Marino op_cost = shiftsub1_cost[speed][mode][m];
2636e4b17023SJohn Marino new_limit.cost = best_cost.cost - op_cost;
2637e4b17023SJohn Marino new_limit.latency = best_cost.latency - op_cost;
2638e4b17023SJohn Marino synth_mult (alg_in, (unsigned HOST_WIDE_INT) (-orig_t + 1) >> m, &new_limit, mode);
2639e4b17023SJohn Marino
2640e4b17023SJohn Marino alg_in->cost.cost += op_cost;
2641e4b17023SJohn Marino alg_in->cost.latency += op_cost;
2642e4b17023SJohn Marino if (CHEAPER_MULT_COST (&alg_in->cost, &best_cost))
2643e4b17023SJohn Marino {
2644e4b17023SJohn Marino struct algorithm *x;
2645e4b17023SJohn Marino best_cost = alg_in->cost;
2646e4b17023SJohn Marino x = alg_in, alg_in = best_alg, best_alg = x;
2647e4b17023SJohn Marino best_alg->log[best_alg->ops] = m;
2648e4b17023SJohn Marino best_alg->op[best_alg->ops] = alg_sub_t_m2;
2649e4b17023SJohn Marino }
2650e4b17023SJohn Marino }
2651e4b17023SJohn Marino
2652e4b17023SJohn Marino if (cache_hit)
2653e4b17023SJohn Marino goto done;
2654e4b17023SJohn Marino }
2655e4b17023SJohn Marino
2656e4b17023SJohn Marino /* Look for factors of t of the form
2657e4b17023SJohn Marino t = q(2**m +- 1), 2 <= m <= floor(log2(t - 1)).
2658e4b17023SJohn Marino If we find such a factor, we can multiply by t using an algorithm that
2659e4b17023SJohn Marino multiplies by q, shift the result by m and add/subtract it to itself.
2660e4b17023SJohn Marino
2661e4b17023SJohn Marino We search for large factors first and loop down, even if large factors
2662e4b17023SJohn Marino are less probable than small; if we find a large factor we will find a
2663e4b17023SJohn Marino good sequence quickly, and therefore be able to prune (by decreasing
2664e4b17023SJohn Marino COST_LIMIT) the search. */
2665e4b17023SJohn Marino
2666e4b17023SJohn Marino do_alg_addsub_factor:
2667e4b17023SJohn Marino for (m = floor_log2 (t - 1); m >= 2; m--)
2668e4b17023SJohn Marino {
2669e4b17023SJohn Marino unsigned HOST_WIDE_INT d;
2670e4b17023SJohn Marino
2671e4b17023SJohn Marino d = ((unsigned HOST_WIDE_INT) 1 << m) + 1;
2672e4b17023SJohn Marino if (t % d == 0 && t > d && m < maxm
2673e4b17023SJohn Marino && (!cache_hit || cache_alg == alg_add_factor))
2674e4b17023SJohn Marino {
2675e4b17023SJohn Marino /* If the target has a cheap shift-and-add instruction use
2676e4b17023SJohn Marino that in preference to a shift insn followed by an add insn.
2677e4b17023SJohn Marino Assume that the shift-and-add is "atomic" with a latency
2678e4b17023SJohn Marino equal to its cost, otherwise assume that on superscalar
2679e4b17023SJohn Marino hardware the shift may be executed concurrently with the
2680e4b17023SJohn Marino earlier steps in the algorithm. */
2681e4b17023SJohn Marino op_cost = add_cost[speed][mode] + shift_cost[speed][mode][m];
2682e4b17023SJohn Marino if (shiftadd_cost[speed][mode][m] < op_cost)
2683e4b17023SJohn Marino {
2684e4b17023SJohn Marino op_cost = shiftadd_cost[speed][mode][m];
2685e4b17023SJohn Marino op_latency = op_cost;
2686e4b17023SJohn Marino }
2687e4b17023SJohn Marino else
2688e4b17023SJohn Marino op_latency = add_cost[speed][mode];
2689e4b17023SJohn Marino
2690e4b17023SJohn Marino new_limit.cost = best_cost.cost - op_cost;
2691e4b17023SJohn Marino new_limit.latency = best_cost.latency - op_latency;
2692e4b17023SJohn Marino synth_mult (alg_in, t / d, &new_limit, mode);
2693e4b17023SJohn Marino
2694e4b17023SJohn Marino alg_in->cost.cost += op_cost;
2695e4b17023SJohn Marino alg_in->cost.latency += op_latency;
2696e4b17023SJohn Marino if (alg_in->cost.latency < op_cost)
2697e4b17023SJohn Marino alg_in->cost.latency = op_cost;
2698e4b17023SJohn Marino if (CHEAPER_MULT_COST (&alg_in->cost, &best_cost))
2699e4b17023SJohn Marino {
2700e4b17023SJohn Marino struct algorithm *x;
2701e4b17023SJohn Marino best_cost = alg_in->cost;
2702e4b17023SJohn Marino x = alg_in, alg_in = best_alg, best_alg = x;
2703e4b17023SJohn Marino best_alg->log[best_alg->ops] = m;
2704e4b17023SJohn Marino best_alg->op[best_alg->ops] = alg_add_factor;
2705e4b17023SJohn Marino }
2706e4b17023SJohn Marino /* Other factors will have been taken care of in the recursion. */
2707e4b17023SJohn Marino break;
2708e4b17023SJohn Marino }
2709e4b17023SJohn Marino
2710e4b17023SJohn Marino d = ((unsigned HOST_WIDE_INT) 1 << m) - 1;
2711e4b17023SJohn Marino if (t % d == 0 && t > d && m < maxm
2712e4b17023SJohn Marino && (!cache_hit || cache_alg == alg_sub_factor))
2713e4b17023SJohn Marino {
2714e4b17023SJohn Marino /* If the target has a cheap shift-and-subtract insn use
2715e4b17023SJohn Marino that in preference to a shift insn followed by a sub insn.
2716e4b17023SJohn Marino Assume that the shift-and-sub is "atomic" with a latency
2717e4b17023SJohn Marino equal to it's cost, otherwise assume that on superscalar
2718e4b17023SJohn Marino hardware the shift may be executed concurrently with the
2719e4b17023SJohn Marino earlier steps in the algorithm. */
2720e4b17023SJohn Marino op_cost = add_cost[speed][mode] + shift_cost[speed][mode][m];
2721e4b17023SJohn Marino if (shiftsub0_cost[speed][mode][m] < op_cost)
2722e4b17023SJohn Marino {
2723e4b17023SJohn Marino op_cost = shiftsub0_cost[speed][mode][m];
2724e4b17023SJohn Marino op_latency = op_cost;
2725e4b17023SJohn Marino }
2726e4b17023SJohn Marino else
2727e4b17023SJohn Marino op_latency = add_cost[speed][mode];
2728e4b17023SJohn Marino
2729e4b17023SJohn Marino new_limit.cost = best_cost.cost - op_cost;
2730e4b17023SJohn Marino new_limit.latency = best_cost.latency - op_latency;
2731e4b17023SJohn Marino synth_mult (alg_in, t / d, &new_limit, mode);
2732e4b17023SJohn Marino
2733e4b17023SJohn Marino alg_in->cost.cost += op_cost;
2734e4b17023SJohn Marino alg_in->cost.latency += op_latency;
2735e4b17023SJohn Marino if (alg_in->cost.latency < op_cost)
2736e4b17023SJohn Marino alg_in->cost.latency = op_cost;
2737e4b17023SJohn Marino if (CHEAPER_MULT_COST (&alg_in->cost, &best_cost))
2738e4b17023SJohn Marino {
2739e4b17023SJohn Marino struct algorithm *x;
2740e4b17023SJohn Marino best_cost = alg_in->cost;
2741e4b17023SJohn Marino x = alg_in, alg_in = best_alg, best_alg = x;
2742e4b17023SJohn Marino best_alg->log[best_alg->ops] = m;
2743e4b17023SJohn Marino best_alg->op[best_alg->ops] = alg_sub_factor;
2744e4b17023SJohn Marino }
2745e4b17023SJohn Marino break;
2746e4b17023SJohn Marino }
2747e4b17023SJohn Marino }
2748e4b17023SJohn Marino if (cache_hit)
2749e4b17023SJohn Marino goto done;
2750e4b17023SJohn Marino
2751e4b17023SJohn Marino /* Try shift-and-add (load effective address) instructions,
2752e4b17023SJohn Marino i.e. do a*3, a*5, a*9. */
2753e4b17023SJohn Marino if ((t & 1) != 0)
2754e4b17023SJohn Marino {
2755e4b17023SJohn Marino do_alg_add_t2_m:
2756e4b17023SJohn Marino q = t - 1;
2757e4b17023SJohn Marino q = q & -q;
2758e4b17023SJohn Marino m = exact_log2 (q);
2759e4b17023SJohn Marino if (m >= 0 && m < maxm)
2760e4b17023SJohn Marino {
2761e4b17023SJohn Marino op_cost = shiftadd_cost[speed][mode][m];
2762e4b17023SJohn Marino new_limit.cost = best_cost.cost - op_cost;
2763e4b17023SJohn Marino new_limit.latency = best_cost.latency - op_cost;
2764e4b17023SJohn Marino synth_mult (alg_in, (t - 1) >> m, &new_limit, mode);
2765e4b17023SJohn Marino
2766e4b17023SJohn Marino alg_in->cost.cost += op_cost;
2767e4b17023SJohn Marino alg_in->cost.latency += op_cost;
2768e4b17023SJohn Marino if (CHEAPER_MULT_COST (&alg_in->cost, &best_cost))
2769e4b17023SJohn Marino {
2770e4b17023SJohn Marino struct algorithm *x;
2771e4b17023SJohn Marino best_cost = alg_in->cost;
2772e4b17023SJohn Marino x = alg_in, alg_in = best_alg, best_alg = x;
2773e4b17023SJohn Marino best_alg->log[best_alg->ops] = m;
2774e4b17023SJohn Marino best_alg->op[best_alg->ops] = alg_add_t2_m;
2775e4b17023SJohn Marino }
2776e4b17023SJohn Marino }
2777e4b17023SJohn Marino if (cache_hit)
2778e4b17023SJohn Marino goto done;
2779e4b17023SJohn Marino
2780e4b17023SJohn Marino do_alg_sub_t2_m:
2781e4b17023SJohn Marino q = t + 1;
2782e4b17023SJohn Marino q = q & -q;
2783e4b17023SJohn Marino m = exact_log2 (q);
2784e4b17023SJohn Marino if (m >= 0 && m < maxm)
2785e4b17023SJohn Marino {
2786e4b17023SJohn Marino op_cost = shiftsub0_cost[speed][mode][m];
2787e4b17023SJohn Marino new_limit.cost = best_cost.cost - op_cost;
2788e4b17023SJohn Marino new_limit.latency = best_cost.latency - op_cost;
2789e4b17023SJohn Marino synth_mult (alg_in, (t + 1) >> m, &new_limit, mode);
2790e4b17023SJohn Marino
2791e4b17023SJohn Marino alg_in->cost.cost += op_cost;
2792e4b17023SJohn Marino alg_in->cost.latency += op_cost;
2793e4b17023SJohn Marino if (CHEAPER_MULT_COST (&alg_in->cost, &best_cost))
2794e4b17023SJohn Marino {
2795e4b17023SJohn Marino struct algorithm *x;
2796e4b17023SJohn Marino best_cost = alg_in->cost;
2797e4b17023SJohn Marino x = alg_in, alg_in = best_alg, best_alg = x;
2798e4b17023SJohn Marino best_alg->log[best_alg->ops] = m;
2799e4b17023SJohn Marino best_alg->op[best_alg->ops] = alg_sub_t2_m;
2800e4b17023SJohn Marino }
2801e4b17023SJohn Marino }
2802e4b17023SJohn Marino if (cache_hit)
2803e4b17023SJohn Marino goto done;
2804e4b17023SJohn Marino }
2805e4b17023SJohn Marino
2806e4b17023SJohn Marino done:
2807e4b17023SJohn Marino /* If best_cost has not decreased, we have not found any algorithm. */
2808e4b17023SJohn Marino if (!CHEAPER_MULT_COST (&best_cost, cost_limit))
2809e4b17023SJohn Marino {
2810e4b17023SJohn Marino /* We failed to find an algorithm. Record alg_impossible for
2811e4b17023SJohn Marino this case (that is, <T, MODE, COST_LIMIT>) so that next time
2812e4b17023SJohn Marino we are asked to find an algorithm for T within the same or
2813e4b17023SJohn Marino lower COST_LIMIT, we can immediately return to the
2814e4b17023SJohn Marino caller. */
2815e4b17023SJohn Marino alg_hash[hash_index].t = t;
2816e4b17023SJohn Marino alg_hash[hash_index].mode = mode;
2817e4b17023SJohn Marino alg_hash[hash_index].speed = speed;
2818e4b17023SJohn Marino alg_hash[hash_index].alg = alg_impossible;
2819e4b17023SJohn Marino alg_hash[hash_index].cost = *cost_limit;
2820e4b17023SJohn Marino return;
2821e4b17023SJohn Marino }
2822e4b17023SJohn Marino
2823e4b17023SJohn Marino /* Cache the result. */
2824e4b17023SJohn Marino if (!cache_hit)
2825e4b17023SJohn Marino {
2826e4b17023SJohn Marino alg_hash[hash_index].t = t;
2827e4b17023SJohn Marino alg_hash[hash_index].mode = mode;
2828e4b17023SJohn Marino alg_hash[hash_index].speed = speed;
2829e4b17023SJohn Marino alg_hash[hash_index].alg = best_alg->op[best_alg->ops];
2830e4b17023SJohn Marino alg_hash[hash_index].cost.cost = best_cost.cost;
2831e4b17023SJohn Marino alg_hash[hash_index].cost.latency = best_cost.latency;
2832e4b17023SJohn Marino }
2833e4b17023SJohn Marino
2834e4b17023SJohn Marino /* If we are getting a too long sequence for `struct algorithm'
2835e4b17023SJohn Marino to record, make this search fail. */
2836e4b17023SJohn Marino if (best_alg->ops == MAX_BITS_PER_WORD)
2837e4b17023SJohn Marino return;
2838e4b17023SJohn Marino
2839e4b17023SJohn Marino /* Copy the algorithm from temporary space to the space at alg_out.
2840e4b17023SJohn Marino We avoid using structure assignment because the majority of
2841e4b17023SJohn Marino best_alg is normally undefined, and this is a critical function. */
2842e4b17023SJohn Marino alg_out->ops = best_alg->ops + 1;
2843e4b17023SJohn Marino alg_out->cost = best_cost;
2844e4b17023SJohn Marino memcpy (alg_out->op, best_alg->op,
2845e4b17023SJohn Marino alg_out->ops * sizeof *alg_out->op);
2846e4b17023SJohn Marino memcpy (alg_out->log, best_alg->log,
2847e4b17023SJohn Marino alg_out->ops * sizeof *alg_out->log);
2848e4b17023SJohn Marino }
2849e4b17023SJohn Marino
2850e4b17023SJohn Marino /* Find the cheapest way of multiplying a value of mode MODE by VAL.
2851e4b17023SJohn Marino Try three variations:
2852e4b17023SJohn Marino
2853e4b17023SJohn Marino - a shift/add sequence based on VAL itself
2854e4b17023SJohn Marino - a shift/add sequence based on -VAL, followed by a negation
2855e4b17023SJohn Marino - a shift/add sequence based on VAL - 1, followed by an addition.
2856e4b17023SJohn Marino
2857e4b17023SJohn Marino Return true if the cheapest of these cost less than MULT_COST,
2858e4b17023SJohn Marino describing the algorithm in *ALG and final fixup in *VARIANT. */
2859e4b17023SJohn Marino
2860e4b17023SJohn Marino static bool
choose_mult_variant(enum machine_mode mode,HOST_WIDE_INT val,struct algorithm * alg,enum mult_variant * variant,int mult_cost)2861e4b17023SJohn Marino choose_mult_variant (enum machine_mode mode, HOST_WIDE_INT val,
2862e4b17023SJohn Marino struct algorithm *alg, enum mult_variant *variant,
2863e4b17023SJohn Marino int mult_cost)
2864e4b17023SJohn Marino {
2865e4b17023SJohn Marino struct algorithm alg2;
2866e4b17023SJohn Marino struct mult_cost limit;
2867e4b17023SJohn Marino int op_cost;
2868e4b17023SJohn Marino bool speed = optimize_insn_for_speed_p ();
2869e4b17023SJohn Marino
2870e4b17023SJohn Marino /* Fail quickly for impossible bounds. */
2871e4b17023SJohn Marino if (mult_cost < 0)
2872e4b17023SJohn Marino return false;
2873e4b17023SJohn Marino
2874e4b17023SJohn Marino /* Ensure that mult_cost provides a reasonable upper bound.
2875e4b17023SJohn Marino Any constant multiplication can be performed with less
2876e4b17023SJohn Marino than 2 * bits additions. */
2877e4b17023SJohn Marino op_cost = 2 * GET_MODE_BITSIZE (mode) * add_cost[speed][mode];
2878e4b17023SJohn Marino if (mult_cost > op_cost)
2879e4b17023SJohn Marino mult_cost = op_cost;
2880e4b17023SJohn Marino
2881e4b17023SJohn Marino *variant = basic_variant;
2882e4b17023SJohn Marino limit.cost = mult_cost;
2883e4b17023SJohn Marino limit.latency = mult_cost;
2884e4b17023SJohn Marino synth_mult (alg, val, &limit, mode);
2885e4b17023SJohn Marino
2886e4b17023SJohn Marino /* This works only if the inverted value actually fits in an
2887e4b17023SJohn Marino `unsigned int' */
2888e4b17023SJohn Marino if (HOST_BITS_PER_INT >= GET_MODE_BITSIZE (mode))
2889e4b17023SJohn Marino {
2890e4b17023SJohn Marino op_cost = neg_cost[speed][mode];
2891e4b17023SJohn Marino if (MULT_COST_LESS (&alg->cost, mult_cost))
2892e4b17023SJohn Marino {
2893e4b17023SJohn Marino limit.cost = alg->cost.cost - op_cost;
2894e4b17023SJohn Marino limit.latency = alg->cost.latency - op_cost;
2895e4b17023SJohn Marino }
2896e4b17023SJohn Marino else
2897e4b17023SJohn Marino {
2898e4b17023SJohn Marino limit.cost = mult_cost - op_cost;
2899e4b17023SJohn Marino limit.latency = mult_cost - op_cost;
2900e4b17023SJohn Marino }
2901e4b17023SJohn Marino
2902e4b17023SJohn Marino synth_mult (&alg2, -val, &limit, mode);
2903e4b17023SJohn Marino alg2.cost.cost += op_cost;
2904e4b17023SJohn Marino alg2.cost.latency += op_cost;
2905e4b17023SJohn Marino if (CHEAPER_MULT_COST (&alg2.cost, &alg->cost))
2906e4b17023SJohn Marino *alg = alg2, *variant = negate_variant;
2907e4b17023SJohn Marino }
2908e4b17023SJohn Marino
2909e4b17023SJohn Marino /* This proves very useful for division-by-constant. */
2910e4b17023SJohn Marino op_cost = add_cost[speed][mode];
2911e4b17023SJohn Marino if (MULT_COST_LESS (&alg->cost, mult_cost))
2912e4b17023SJohn Marino {
2913e4b17023SJohn Marino limit.cost = alg->cost.cost - op_cost;
2914e4b17023SJohn Marino limit.latency = alg->cost.latency - op_cost;
2915e4b17023SJohn Marino }
2916e4b17023SJohn Marino else
2917e4b17023SJohn Marino {
2918e4b17023SJohn Marino limit.cost = mult_cost - op_cost;
2919e4b17023SJohn Marino limit.latency = mult_cost - op_cost;
2920e4b17023SJohn Marino }
2921e4b17023SJohn Marino
2922e4b17023SJohn Marino synth_mult (&alg2, val - 1, &limit, mode);
2923e4b17023SJohn Marino alg2.cost.cost += op_cost;
2924e4b17023SJohn Marino alg2.cost.latency += op_cost;
2925e4b17023SJohn Marino if (CHEAPER_MULT_COST (&alg2.cost, &alg->cost))
2926e4b17023SJohn Marino *alg = alg2, *variant = add_variant;
2927e4b17023SJohn Marino
2928e4b17023SJohn Marino return MULT_COST_LESS (&alg->cost, mult_cost);
2929e4b17023SJohn Marino }
2930e4b17023SJohn Marino
2931e4b17023SJohn Marino /* A subroutine of expand_mult, used for constant multiplications.
2932e4b17023SJohn Marino Multiply OP0 by VAL in mode MODE, storing the result in TARGET if
2933e4b17023SJohn Marino convenient. Use the shift/add sequence described by ALG and apply
2934e4b17023SJohn Marino the final fixup specified by VARIANT. */
2935e4b17023SJohn Marino
2936e4b17023SJohn Marino static rtx
expand_mult_const(enum machine_mode mode,rtx op0,HOST_WIDE_INT val,rtx target,const struct algorithm * alg,enum mult_variant variant)2937e4b17023SJohn Marino expand_mult_const (enum machine_mode mode, rtx op0, HOST_WIDE_INT val,
2938e4b17023SJohn Marino rtx target, const struct algorithm *alg,
2939e4b17023SJohn Marino enum mult_variant variant)
2940e4b17023SJohn Marino {
2941e4b17023SJohn Marino HOST_WIDE_INT val_so_far;
2942e4b17023SJohn Marino rtx insn, accum, tem;
2943e4b17023SJohn Marino int opno;
2944e4b17023SJohn Marino enum machine_mode nmode;
2945e4b17023SJohn Marino
2946e4b17023SJohn Marino /* Avoid referencing memory over and over and invalid sharing
2947e4b17023SJohn Marino on SUBREGs. */
2948e4b17023SJohn Marino op0 = force_reg (mode, op0);
2949e4b17023SJohn Marino
2950e4b17023SJohn Marino /* ACCUM starts out either as OP0 or as a zero, depending on
2951e4b17023SJohn Marino the first operation. */
2952e4b17023SJohn Marino
2953e4b17023SJohn Marino if (alg->op[0] == alg_zero)
2954e4b17023SJohn Marino {
2955e4b17023SJohn Marino accum = copy_to_mode_reg (mode, const0_rtx);
2956e4b17023SJohn Marino val_so_far = 0;
2957e4b17023SJohn Marino }
2958e4b17023SJohn Marino else if (alg->op[0] == alg_m)
2959e4b17023SJohn Marino {
2960e4b17023SJohn Marino accum = copy_to_mode_reg (mode, op0);
2961e4b17023SJohn Marino val_so_far = 1;
2962e4b17023SJohn Marino }
2963e4b17023SJohn Marino else
2964e4b17023SJohn Marino gcc_unreachable ();
2965e4b17023SJohn Marino
2966e4b17023SJohn Marino for (opno = 1; opno < alg->ops; opno++)
2967e4b17023SJohn Marino {
2968e4b17023SJohn Marino int log = alg->log[opno];
2969e4b17023SJohn Marino rtx shift_subtarget = optimize ? 0 : accum;
2970e4b17023SJohn Marino rtx add_target
2971e4b17023SJohn Marino = (opno == alg->ops - 1 && target != 0 && variant != add_variant
2972e4b17023SJohn Marino && !optimize)
2973e4b17023SJohn Marino ? target : 0;
2974e4b17023SJohn Marino rtx accum_target = optimize ? 0 : accum;
2975e4b17023SJohn Marino rtx accum_inner;
2976e4b17023SJohn Marino
2977e4b17023SJohn Marino switch (alg->op[opno])
2978e4b17023SJohn Marino {
2979e4b17023SJohn Marino case alg_shift:
2980e4b17023SJohn Marino tem = expand_shift (LSHIFT_EXPR, mode, accum, log, NULL_RTX, 0);
2981e4b17023SJohn Marino /* REG_EQUAL note will be attached to the following insn. */
2982e4b17023SJohn Marino emit_move_insn (accum, tem);
2983e4b17023SJohn Marino val_so_far <<= log;
2984e4b17023SJohn Marino break;
2985e4b17023SJohn Marino
2986e4b17023SJohn Marino case alg_add_t_m2:
2987e4b17023SJohn Marino tem = expand_shift (LSHIFT_EXPR, mode, op0, log, NULL_RTX, 0);
2988e4b17023SJohn Marino accum = force_operand (gen_rtx_PLUS (mode, accum, tem),
2989e4b17023SJohn Marino add_target ? add_target : accum_target);
2990e4b17023SJohn Marino val_so_far += (HOST_WIDE_INT) 1 << log;
2991e4b17023SJohn Marino break;
2992e4b17023SJohn Marino
2993e4b17023SJohn Marino case alg_sub_t_m2:
2994e4b17023SJohn Marino tem = expand_shift (LSHIFT_EXPR, mode, op0, log, NULL_RTX, 0);
2995e4b17023SJohn Marino accum = force_operand (gen_rtx_MINUS (mode, accum, tem),
2996e4b17023SJohn Marino add_target ? add_target : accum_target);
2997e4b17023SJohn Marino val_so_far -= (HOST_WIDE_INT) 1 << log;
2998e4b17023SJohn Marino break;
2999e4b17023SJohn Marino
3000e4b17023SJohn Marino case alg_add_t2_m:
3001e4b17023SJohn Marino accum = expand_shift (LSHIFT_EXPR, mode, accum,
3002e4b17023SJohn Marino log, shift_subtarget, 0);
3003e4b17023SJohn Marino accum = force_operand (gen_rtx_PLUS (mode, accum, op0),
3004e4b17023SJohn Marino add_target ? add_target : accum_target);
3005e4b17023SJohn Marino val_so_far = (val_so_far << log) + 1;
3006e4b17023SJohn Marino break;
3007e4b17023SJohn Marino
3008e4b17023SJohn Marino case alg_sub_t2_m:
3009e4b17023SJohn Marino accum = expand_shift (LSHIFT_EXPR, mode, accum,
3010e4b17023SJohn Marino log, shift_subtarget, 0);
3011e4b17023SJohn Marino accum = force_operand (gen_rtx_MINUS (mode, accum, op0),
3012e4b17023SJohn Marino add_target ? add_target : accum_target);
3013e4b17023SJohn Marino val_so_far = (val_so_far << log) - 1;
3014e4b17023SJohn Marino break;
3015e4b17023SJohn Marino
3016e4b17023SJohn Marino case alg_add_factor:
3017e4b17023SJohn Marino tem = expand_shift (LSHIFT_EXPR, mode, accum, log, NULL_RTX, 0);
3018e4b17023SJohn Marino accum = force_operand (gen_rtx_PLUS (mode, accum, tem),
3019e4b17023SJohn Marino add_target ? add_target : accum_target);
3020e4b17023SJohn Marino val_so_far += val_so_far << log;
3021e4b17023SJohn Marino break;
3022e4b17023SJohn Marino
3023e4b17023SJohn Marino case alg_sub_factor:
3024e4b17023SJohn Marino tem = expand_shift (LSHIFT_EXPR, mode, accum, log, NULL_RTX, 0);
3025e4b17023SJohn Marino accum = force_operand (gen_rtx_MINUS (mode, tem, accum),
3026e4b17023SJohn Marino (add_target
3027e4b17023SJohn Marino ? add_target : (optimize ? 0 : tem)));
3028e4b17023SJohn Marino val_so_far = (val_so_far << log) - val_so_far;
3029e4b17023SJohn Marino break;
3030e4b17023SJohn Marino
3031e4b17023SJohn Marino default:
3032e4b17023SJohn Marino gcc_unreachable ();
3033e4b17023SJohn Marino }
3034e4b17023SJohn Marino
3035e4b17023SJohn Marino /* Write a REG_EQUAL note on the last insn so that we can cse
3036e4b17023SJohn Marino multiplication sequences. Note that if ACCUM is a SUBREG,
3037e4b17023SJohn Marino we've set the inner register and must properly indicate
3038e4b17023SJohn Marino that. */
3039e4b17023SJohn Marino
3040e4b17023SJohn Marino tem = op0, nmode = mode;
3041e4b17023SJohn Marino accum_inner = accum;
3042e4b17023SJohn Marino if (GET_CODE (accum) == SUBREG)
3043e4b17023SJohn Marino {
3044e4b17023SJohn Marino accum_inner = SUBREG_REG (accum);
3045e4b17023SJohn Marino nmode = GET_MODE (accum_inner);
3046e4b17023SJohn Marino tem = gen_lowpart (nmode, op0);
3047e4b17023SJohn Marino }
3048e4b17023SJohn Marino
3049e4b17023SJohn Marino insn = get_last_insn ();
3050e4b17023SJohn Marino set_dst_reg_note (insn, REG_EQUAL,
3051e4b17023SJohn Marino gen_rtx_MULT (nmode, tem, GEN_INT (val_so_far)),
3052e4b17023SJohn Marino accum_inner);
3053e4b17023SJohn Marino }
3054e4b17023SJohn Marino
3055e4b17023SJohn Marino if (variant == negate_variant)
3056e4b17023SJohn Marino {
3057e4b17023SJohn Marino val_so_far = -val_so_far;
3058e4b17023SJohn Marino accum = expand_unop (mode, neg_optab, accum, target, 0);
3059e4b17023SJohn Marino }
3060e4b17023SJohn Marino else if (variant == add_variant)
3061e4b17023SJohn Marino {
3062e4b17023SJohn Marino val_so_far = val_so_far + 1;
3063e4b17023SJohn Marino accum = force_operand (gen_rtx_PLUS (mode, accum, op0), target);
3064e4b17023SJohn Marino }
3065e4b17023SJohn Marino
3066e4b17023SJohn Marino /* Compare only the bits of val and val_so_far that are significant
3067e4b17023SJohn Marino in the result mode, to avoid sign-/zero-extension confusion. */
3068e4b17023SJohn Marino val &= GET_MODE_MASK (mode);
3069e4b17023SJohn Marino val_so_far &= GET_MODE_MASK (mode);
3070e4b17023SJohn Marino gcc_assert (val == val_so_far);
3071e4b17023SJohn Marino
3072e4b17023SJohn Marino return accum;
3073e4b17023SJohn Marino }
3074e4b17023SJohn Marino
3075e4b17023SJohn Marino /* Perform a multiplication and return an rtx for the result.
3076e4b17023SJohn Marino MODE is mode of value; OP0 and OP1 are what to multiply (rtx's);
3077e4b17023SJohn Marino TARGET is a suggestion for where to store the result (an rtx).
3078e4b17023SJohn Marino
3079e4b17023SJohn Marino We check specially for a constant integer as OP1.
3080e4b17023SJohn Marino If you want this check for OP0 as well, then before calling
3081e4b17023SJohn Marino you should swap the two operands if OP0 would be constant. */
3082e4b17023SJohn Marino
3083e4b17023SJohn Marino rtx
expand_mult(enum machine_mode mode,rtx op0,rtx op1,rtx target,int unsignedp)3084e4b17023SJohn Marino expand_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target,
3085e4b17023SJohn Marino int unsignedp)
3086e4b17023SJohn Marino {
3087e4b17023SJohn Marino enum mult_variant variant;
3088e4b17023SJohn Marino struct algorithm algorithm;
3089e4b17023SJohn Marino int max_cost;
3090e4b17023SJohn Marino bool speed = optimize_insn_for_speed_p ();
3091e4b17023SJohn Marino
3092e4b17023SJohn Marino /* Handling const0_rtx here allows us to use zero as a rogue value for
3093e4b17023SJohn Marino coeff below. */
3094e4b17023SJohn Marino if (op1 == const0_rtx)
3095e4b17023SJohn Marino return const0_rtx;
3096e4b17023SJohn Marino if (op1 == const1_rtx)
3097e4b17023SJohn Marino return op0;
3098e4b17023SJohn Marino if (op1 == constm1_rtx)
3099e4b17023SJohn Marino return expand_unop (mode,
3100e4b17023SJohn Marino GET_MODE_CLASS (mode) == MODE_INT
3101e4b17023SJohn Marino && !unsignedp && flag_trapv
3102e4b17023SJohn Marino ? negv_optab : neg_optab,
3103e4b17023SJohn Marino op0, target, 0);
3104e4b17023SJohn Marino
3105e4b17023SJohn Marino /* These are the operations that are potentially turned into a sequence
3106e4b17023SJohn Marino of shifts and additions. */
3107e4b17023SJohn Marino if (SCALAR_INT_MODE_P (mode)
3108e4b17023SJohn Marino && (unsignedp || !flag_trapv))
3109e4b17023SJohn Marino {
3110e4b17023SJohn Marino HOST_WIDE_INT coeff = 0;
3111e4b17023SJohn Marino rtx fake_reg = gen_raw_REG (mode, LAST_VIRTUAL_REGISTER + 1);
3112e4b17023SJohn Marino
3113e4b17023SJohn Marino /* synth_mult does an `unsigned int' multiply. As long as the mode is
3114e4b17023SJohn Marino less than or equal in size to `unsigned int' this doesn't matter.
3115e4b17023SJohn Marino If the mode is larger than `unsigned int', then synth_mult works
3116e4b17023SJohn Marino only if the constant value exactly fits in an `unsigned int' without
3117e4b17023SJohn Marino any truncation. This means that multiplying by negative values does
3118e4b17023SJohn Marino not work; results are off by 2^32 on a 32 bit machine. */
3119e4b17023SJohn Marino
3120e4b17023SJohn Marino if (CONST_INT_P (op1))
3121e4b17023SJohn Marino {
3122e4b17023SJohn Marino /* Attempt to handle multiplication of DImode values by negative
3123e4b17023SJohn Marino coefficients, by performing the multiplication by a positive
3124e4b17023SJohn Marino multiplier and then inverting the result. */
3125e4b17023SJohn Marino if (INTVAL (op1) < 0
3126e4b17023SJohn Marino && GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT)
3127e4b17023SJohn Marino {
3128e4b17023SJohn Marino /* Its safe to use -INTVAL (op1) even for INT_MIN, as the
3129e4b17023SJohn Marino result is interpreted as an unsigned coefficient.
3130e4b17023SJohn Marino Exclude cost of op0 from max_cost to match the cost
3131e4b17023SJohn Marino calculation of the synth_mult. */
3132e4b17023SJohn Marino max_cost = (set_src_cost (gen_rtx_MULT (mode, fake_reg, op1),
3133e4b17023SJohn Marino speed)
3134e4b17023SJohn Marino - neg_cost[speed][mode]);
3135e4b17023SJohn Marino if (max_cost > 0
3136e4b17023SJohn Marino && choose_mult_variant (mode, -INTVAL (op1), &algorithm,
3137e4b17023SJohn Marino &variant, max_cost))
3138e4b17023SJohn Marino {
3139e4b17023SJohn Marino rtx temp = expand_mult_const (mode, op0, -INTVAL (op1),
3140e4b17023SJohn Marino NULL_RTX, &algorithm,
3141e4b17023SJohn Marino variant);
3142e4b17023SJohn Marino return expand_unop (mode, neg_optab, temp, target, 0);
3143e4b17023SJohn Marino }
3144e4b17023SJohn Marino }
3145e4b17023SJohn Marino else coeff = INTVAL (op1);
3146e4b17023SJohn Marino }
3147e4b17023SJohn Marino else if (GET_CODE (op1) == CONST_DOUBLE)
3148e4b17023SJohn Marino {
3149e4b17023SJohn Marino /* If we are multiplying in DImode, it may still be a win
3150e4b17023SJohn Marino to try to work with shifts and adds. */
3151e4b17023SJohn Marino if (CONST_DOUBLE_HIGH (op1) == 0
3152e4b17023SJohn Marino && CONST_DOUBLE_LOW (op1) > 0)
3153e4b17023SJohn Marino coeff = CONST_DOUBLE_LOW (op1);
3154e4b17023SJohn Marino else if (CONST_DOUBLE_LOW (op1) == 0
3155e4b17023SJohn Marino && EXACT_POWER_OF_2_OR_ZERO_P (CONST_DOUBLE_HIGH (op1)))
3156e4b17023SJohn Marino {
3157e4b17023SJohn Marino int shift = floor_log2 (CONST_DOUBLE_HIGH (op1))
3158e4b17023SJohn Marino + HOST_BITS_PER_WIDE_INT;
3159e4b17023SJohn Marino return expand_shift (LSHIFT_EXPR, mode, op0,
3160e4b17023SJohn Marino shift, target, unsignedp);
3161e4b17023SJohn Marino }
3162e4b17023SJohn Marino }
3163e4b17023SJohn Marino
3164e4b17023SJohn Marino /* We used to test optimize here, on the grounds that it's better to
3165e4b17023SJohn Marino produce a smaller program when -O is not used. But this causes
3166e4b17023SJohn Marino such a terrible slowdown sometimes that it seems better to always
3167e4b17023SJohn Marino use synth_mult. */
3168e4b17023SJohn Marino if (coeff != 0)
3169e4b17023SJohn Marino {
3170e4b17023SJohn Marino /* Special case powers of two. */
3171e4b17023SJohn Marino if (EXACT_POWER_OF_2_OR_ZERO_P (coeff))
3172e4b17023SJohn Marino return expand_shift (LSHIFT_EXPR, mode, op0,
3173e4b17023SJohn Marino floor_log2 (coeff), target, unsignedp);
3174e4b17023SJohn Marino
3175e4b17023SJohn Marino /* Exclude cost of op0 from max_cost to match the cost
3176e4b17023SJohn Marino calculation of the synth_mult. */
3177e4b17023SJohn Marino max_cost = set_src_cost (gen_rtx_MULT (mode, fake_reg, op1), speed);
3178e4b17023SJohn Marino if (choose_mult_variant (mode, coeff, &algorithm, &variant,
3179e4b17023SJohn Marino max_cost))
3180e4b17023SJohn Marino return expand_mult_const (mode, op0, coeff, target,
3181e4b17023SJohn Marino &algorithm, variant);
3182e4b17023SJohn Marino }
3183e4b17023SJohn Marino }
3184e4b17023SJohn Marino
3185e4b17023SJohn Marino if (GET_CODE (op0) == CONST_DOUBLE)
3186e4b17023SJohn Marino {
3187e4b17023SJohn Marino rtx temp = op0;
3188e4b17023SJohn Marino op0 = op1;
3189e4b17023SJohn Marino op1 = temp;
3190e4b17023SJohn Marino }
3191e4b17023SJohn Marino
3192e4b17023SJohn Marino /* Expand x*2.0 as x+x. */
3193e4b17023SJohn Marino if (GET_CODE (op1) == CONST_DOUBLE
3194e4b17023SJohn Marino && SCALAR_FLOAT_MODE_P (mode))
3195e4b17023SJohn Marino {
3196e4b17023SJohn Marino REAL_VALUE_TYPE d;
3197e4b17023SJohn Marino REAL_VALUE_FROM_CONST_DOUBLE (d, op1);
3198e4b17023SJohn Marino
3199e4b17023SJohn Marino if (REAL_VALUES_EQUAL (d, dconst2))
3200e4b17023SJohn Marino {
3201e4b17023SJohn Marino op0 = force_reg (GET_MODE (op0), op0);
3202e4b17023SJohn Marino return expand_binop (mode, add_optab, op0, op0,
3203e4b17023SJohn Marino target, unsignedp, OPTAB_LIB_WIDEN);
3204e4b17023SJohn Marino }
3205e4b17023SJohn Marino }
3206e4b17023SJohn Marino
3207e4b17023SJohn Marino /* This used to use umul_optab if unsigned, but for non-widening multiply
3208e4b17023SJohn Marino there is no difference between signed and unsigned. */
3209e4b17023SJohn Marino op0 = expand_binop (mode,
3210e4b17023SJohn Marino ! unsignedp
3211e4b17023SJohn Marino && flag_trapv && (GET_MODE_CLASS(mode) == MODE_INT)
3212e4b17023SJohn Marino ? smulv_optab : smul_optab,
3213e4b17023SJohn Marino op0, op1, target, unsignedp, OPTAB_LIB_WIDEN);
3214e4b17023SJohn Marino gcc_assert (op0);
3215e4b17023SJohn Marino return op0;
3216e4b17023SJohn Marino }
3217e4b17023SJohn Marino
3218e4b17023SJohn Marino /* Perform a widening multiplication and return an rtx for the result.
3219e4b17023SJohn Marino MODE is mode of value; OP0 and OP1 are what to multiply (rtx's);
3220e4b17023SJohn Marino TARGET is a suggestion for where to store the result (an rtx).
3221e4b17023SJohn Marino THIS_OPTAB is the optab we should use, it must be either umul_widen_optab
3222e4b17023SJohn Marino or smul_widen_optab.
3223e4b17023SJohn Marino
3224e4b17023SJohn Marino We check specially for a constant integer as OP1, comparing the
3225e4b17023SJohn Marino cost of a widening multiply against the cost of a sequence of shifts
3226e4b17023SJohn Marino and adds. */
3227e4b17023SJohn Marino
3228e4b17023SJohn Marino rtx
expand_widening_mult(enum machine_mode mode,rtx op0,rtx op1,rtx target,int unsignedp,optab this_optab)3229e4b17023SJohn Marino expand_widening_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target,
3230e4b17023SJohn Marino int unsignedp, optab this_optab)
3231e4b17023SJohn Marino {
3232e4b17023SJohn Marino bool speed = optimize_insn_for_speed_p ();
3233e4b17023SJohn Marino rtx cop1;
3234e4b17023SJohn Marino
3235e4b17023SJohn Marino if (CONST_INT_P (op1)
3236e4b17023SJohn Marino && GET_MODE (op0) != VOIDmode
3237e4b17023SJohn Marino && (cop1 = convert_modes (mode, GET_MODE (op0), op1,
3238e4b17023SJohn Marino this_optab == umul_widen_optab))
3239e4b17023SJohn Marino && CONST_INT_P (cop1)
3240e4b17023SJohn Marino && (INTVAL (cop1) >= 0
3241e4b17023SJohn Marino || HWI_COMPUTABLE_MODE_P (mode)))
3242e4b17023SJohn Marino {
3243e4b17023SJohn Marino HOST_WIDE_INT coeff = INTVAL (cop1);
3244e4b17023SJohn Marino int max_cost;
3245e4b17023SJohn Marino enum mult_variant variant;
3246e4b17023SJohn Marino struct algorithm algorithm;
3247e4b17023SJohn Marino
3248e4b17023SJohn Marino /* Special case powers of two. */
3249e4b17023SJohn Marino if (EXACT_POWER_OF_2_OR_ZERO_P (coeff))
3250e4b17023SJohn Marino {
3251e4b17023SJohn Marino op0 = convert_to_mode (mode, op0, this_optab == umul_widen_optab);
3252e4b17023SJohn Marino return expand_shift (LSHIFT_EXPR, mode, op0,
3253e4b17023SJohn Marino floor_log2 (coeff), target, unsignedp);
3254e4b17023SJohn Marino }
3255e4b17023SJohn Marino
3256e4b17023SJohn Marino /* Exclude cost of op0 from max_cost to match the cost
3257e4b17023SJohn Marino calculation of the synth_mult. */
3258e4b17023SJohn Marino max_cost = mul_widen_cost[speed][mode];
3259e4b17023SJohn Marino if (choose_mult_variant (mode, coeff, &algorithm, &variant,
3260e4b17023SJohn Marino max_cost))
3261e4b17023SJohn Marino {
3262e4b17023SJohn Marino op0 = convert_to_mode (mode, op0, this_optab == umul_widen_optab);
3263e4b17023SJohn Marino return expand_mult_const (mode, op0, coeff, target,
3264e4b17023SJohn Marino &algorithm, variant);
3265e4b17023SJohn Marino }
3266e4b17023SJohn Marino }
3267e4b17023SJohn Marino return expand_binop (mode, this_optab, op0, op1, target,
3268e4b17023SJohn Marino unsignedp, OPTAB_LIB_WIDEN);
3269e4b17023SJohn Marino }
3270e4b17023SJohn Marino
3271e4b17023SJohn Marino /* Return the smallest n such that 2**n >= X. */
3272e4b17023SJohn Marino
3273e4b17023SJohn Marino int
ceil_log2(unsigned HOST_WIDE_INT x)3274e4b17023SJohn Marino ceil_log2 (unsigned HOST_WIDE_INT x)
3275e4b17023SJohn Marino {
3276e4b17023SJohn Marino return floor_log2 (x - 1) + 1;
3277e4b17023SJohn Marino }
3278e4b17023SJohn Marino
3279e4b17023SJohn Marino /* Choose a minimal N + 1 bit approximation to 1/D that can be used to
3280e4b17023SJohn Marino replace division by D, and put the least significant N bits of the result
3281e4b17023SJohn Marino in *MULTIPLIER_PTR and return the most significant bit.
3282e4b17023SJohn Marino
3283e4b17023SJohn Marino The width of operations is N (should be <= HOST_BITS_PER_WIDE_INT), the
3284e4b17023SJohn Marino needed precision is in PRECISION (should be <= N).
3285e4b17023SJohn Marino
3286e4b17023SJohn Marino PRECISION should be as small as possible so this function can choose
3287e4b17023SJohn Marino multiplier more freely.
3288e4b17023SJohn Marino
3289e4b17023SJohn Marino The rounded-up logarithm of D is placed in *lgup_ptr. A shift count that
3290e4b17023SJohn Marino is to be used for a final right shift is placed in *POST_SHIFT_PTR.
3291e4b17023SJohn Marino
3292e4b17023SJohn Marino Using this function, x/D will be equal to (x * m) >> (*POST_SHIFT_PTR),
3293e4b17023SJohn Marino where m is the full HOST_BITS_PER_WIDE_INT + 1 bit multiplier. */
3294e4b17023SJohn Marino
3295e4b17023SJohn Marino static
3296e4b17023SJohn Marino unsigned HOST_WIDE_INT
choose_multiplier(unsigned HOST_WIDE_INT d,int n,int precision,rtx * multiplier_ptr,int * post_shift_ptr,int * lgup_ptr)3297e4b17023SJohn Marino choose_multiplier (unsigned HOST_WIDE_INT d, int n, int precision,
3298e4b17023SJohn Marino rtx *multiplier_ptr, int *post_shift_ptr, int *lgup_ptr)
3299e4b17023SJohn Marino {
3300e4b17023SJohn Marino HOST_WIDE_INT mhigh_hi, mlow_hi;
3301e4b17023SJohn Marino unsigned HOST_WIDE_INT mhigh_lo, mlow_lo;
3302e4b17023SJohn Marino int lgup, post_shift;
3303e4b17023SJohn Marino int pow, pow2;
3304e4b17023SJohn Marino unsigned HOST_WIDE_INT nl, dummy1;
3305e4b17023SJohn Marino HOST_WIDE_INT nh, dummy2;
3306e4b17023SJohn Marino
3307e4b17023SJohn Marino /* lgup = ceil(log2(divisor)); */
3308e4b17023SJohn Marino lgup = ceil_log2 (d);
3309e4b17023SJohn Marino
3310e4b17023SJohn Marino gcc_assert (lgup <= n);
3311e4b17023SJohn Marino
3312e4b17023SJohn Marino pow = n + lgup;
3313e4b17023SJohn Marino pow2 = n + lgup - precision;
3314e4b17023SJohn Marino
3315e4b17023SJohn Marino /* We could handle this with some effort, but this case is much
3316e4b17023SJohn Marino better handled directly with a scc insn, so rely on caller using
3317e4b17023SJohn Marino that. */
3318e4b17023SJohn Marino gcc_assert (pow != 2 * HOST_BITS_PER_WIDE_INT);
3319e4b17023SJohn Marino
3320e4b17023SJohn Marino /* mlow = 2^(N + lgup)/d */
3321e4b17023SJohn Marino if (pow >= HOST_BITS_PER_WIDE_INT)
3322e4b17023SJohn Marino {
3323e4b17023SJohn Marino nh = (HOST_WIDE_INT) 1 << (pow - HOST_BITS_PER_WIDE_INT);
3324e4b17023SJohn Marino nl = 0;
3325e4b17023SJohn Marino }
3326e4b17023SJohn Marino else
3327e4b17023SJohn Marino {
3328e4b17023SJohn Marino nh = 0;
3329e4b17023SJohn Marino nl = (unsigned HOST_WIDE_INT) 1 << pow;
3330e4b17023SJohn Marino }
3331e4b17023SJohn Marino div_and_round_double (TRUNC_DIV_EXPR, 1, nl, nh, d, (HOST_WIDE_INT) 0,
3332e4b17023SJohn Marino &mlow_lo, &mlow_hi, &dummy1, &dummy2);
3333e4b17023SJohn Marino
3334e4b17023SJohn Marino /* mhigh = (2^(N + lgup) + 2^N + lgup - precision)/d */
3335e4b17023SJohn Marino if (pow2 >= HOST_BITS_PER_WIDE_INT)
3336e4b17023SJohn Marino nh |= (HOST_WIDE_INT) 1 << (pow2 - HOST_BITS_PER_WIDE_INT);
3337e4b17023SJohn Marino else
3338e4b17023SJohn Marino nl |= (unsigned HOST_WIDE_INT) 1 << pow2;
3339e4b17023SJohn Marino div_and_round_double (TRUNC_DIV_EXPR, 1, nl, nh, d, (HOST_WIDE_INT) 0,
3340e4b17023SJohn Marino &mhigh_lo, &mhigh_hi, &dummy1, &dummy2);
3341e4b17023SJohn Marino
3342e4b17023SJohn Marino gcc_assert (!mhigh_hi || nh - d < d);
3343e4b17023SJohn Marino gcc_assert (mhigh_hi <= 1 && mlow_hi <= 1);
3344e4b17023SJohn Marino /* Assert that mlow < mhigh. */
3345e4b17023SJohn Marino gcc_assert (mlow_hi < mhigh_hi
3346e4b17023SJohn Marino || (mlow_hi == mhigh_hi && mlow_lo < mhigh_lo));
3347e4b17023SJohn Marino
3348e4b17023SJohn Marino /* If precision == N, then mlow, mhigh exceed 2^N
3349e4b17023SJohn Marino (but they do not exceed 2^(N+1)). */
3350e4b17023SJohn Marino
3351e4b17023SJohn Marino /* Reduce to lowest terms. */
3352e4b17023SJohn Marino for (post_shift = lgup; post_shift > 0; post_shift--)
3353e4b17023SJohn Marino {
3354e4b17023SJohn Marino unsigned HOST_WIDE_INT ml_lo = (mlow_hi << (HOST_BITS_PER_WIDE_INT - 1)) | (mlow_lo >> 1);
3355e4b17023SJohn Marino unsigned HOST_WIDE_INT mh_lo = (mhigh_hi << (HOST_BITS_PER_WIDE_INT - 1)) | (mhigh_lo >> 1);
3356e4b17023SJohn Marino if (ml_lo >= mh_lo)
3357e4b17023SJohn Marino break;
3358e4b17023SJohn Marino
3359e4b17023SJohn Marino mlow_hi = 0;
3360e4b17023SJohn Marino mlow_lo = ml_lo;
3361e4b17023SJohn Marino mhigh_hi = 0;
3362e4b17023SJohn Marino mhigh_lo = mh_lo;
3363e4b17023SJohn Marino }
3364e4b17023SJohn Marino
3365e4b17023SJohn Marino *post_shift_ptr = post_shift;
3366e4b17023SJohn Marino *lgup_ptr = lgup;
3367e4b17023SJohn Marino if (n < HOST_BITS_PER_WIDE_INT)
3368e4b17023SJohn Marino {
3369e4b17023SJohn Marino unsigned HOST_WIDE_INT mask = ((unsigned HOST_WIDE_INT) 1 << n) - 1;
3370e4b17023SJohn Marino *multiplier_ptr = GEN_INT (mhigh_lo & mask);
3371e4b17023SJohn Marino return mhigh_lo >= mask;
3372e4b17023SJohn Marino }
3373e4b17023SJohn Marino else
3374e4b17023SJohn Marino {
3375e4b17023SJohn Marino *multiplier_ptr = GEN_INT (mhigh_lo);
3376e4b17023SJohn Marino return mhigh_hi;
3377e4b17023SJohn Marino }
3378e4b17023SJohn Marino }
3379e4b17023SJohn Marino
3380e4b17023SJohn Marino /* Compute the inverse of X mod 2**n, i.e., find Y such that X * Y is
3381e4b17023SJohn Marino congruent to 1 (mod 2**N). */
3382e4b17023SJohn Marino
3383e4b17023SJohn Marino static unsigned HOST_WIDE_INT
invert_mod2n(unsigned HOST_WIDE_INT x,int n)3384e4b17023SJohn Marino invert_mod2n (unsigned HOST_WIDE_INT x, int n)
3385e4b17023SJohn Marino {
3386e4b17023SJohn Marino /* Solve x*y == 1 (mod 2^n), where x is odd. Return y. */
3387e4b17023SJohn Marino
3388e4b17023SJohn Marino /* The algorithm notes that the choice y = x satisfies
3389e4b17023SJohn Marino x*y == 1 mod 2^3, since x is assumed odd.
3390e4b17023SJohn Marino Each iteration doubles the number of bits of significance in y. */
3391e4b17023SJohn Marino
3392e4b17023SJohn Marino unsigned HOST_WIDE_INT mask;
3393e4b17023SJohn Marino unsigned HOST_WIDE_INT y = x;
3394e4b17023SJohn Marino int nbit = 3;
3395e4b17023SJohn Marino
3396e4b17023SJohn Marino mask = (n == HOST_BITS_PER_WIDE_INT
3397e4b17023SJohn Marino ? ~(unsigned HOST_WIDE_INT) 0
3398e4b17023SJohn Marino : ((unsigned HOST_WIDE_INT) 1 << n) - 1);
3399e4b17023SJohn Marino
3400e4b17023SJohn Marino while (nbit < n)
3401e4b17023SJohn Marino {
3402e4b17023SJohn Marino y = y * (2 - x*y) & mask; /* Modulo 2^N */
3403e4b17023SJohn Marino nbit *= 2;
3404e4b17023SJohn Marino }
3405e4b17023SJohn Marino return y;
3406e4b17023SJohn Marino }
3407e4b17023SJohn Marino
3408e4b17023SJohn Marino /* Emit code to adjust ADJ_OPERAND after multiplication of wrong signedness
3409e4b17023SJohn Marino flavor of OP0 and OP1. ADJ_OPERAND is already the high half of the
3410e4b17023SJohn Marino product OP0 x OP1. If UNSIGNEDP is nonzero, adjust the signed product
3411e4b17023SJohn Marino to become unsigned, if UNSIGNEDP is zero, adjust the unsigned product to
3412e4b17023SJohn Marino become signed.
3413e4b17023SJohn Marino
3414e4b17023SJohn Marino The result is put in TARGET if that is convenient.
3415e4b17023SJohn Marino
3416e4b17023SJohn Marino MODE is the mode of operation. */
3417e4b17023SJohn Marino
3418e4b17023SJohn Marino rtx
expand_mult_highpart_adjust(enum machine_mode mode,rtx adj_operand,rtx op0,rtx op1,rtx target,int unsignedp)3419e4b17023SJohn Marino expand_mult_highpart_adjust (enum machine_mode mode, rtx adj_operand, rtx op0,
3420e4b17023SJohn Marino rtx op1, rtx target, int unsignedp)
3421e4b17023SJohn Marino {
3422e4b17023SJohn Marino rtx tem;
3423e4b17023SJohn Marino enum rtx_code adj_code = unsignedp ? PLUS : MINUS;
3424e4b17023SJohn Marino
3425e4b17023SJohn Marino tem = expand_shift (RSHIFT_EXPR, mode, op0,
3426e4b17023SJohn Marino GET_MODE_BITSIZE (mode) - 1, NULL_RTX, 0);
3427e4b17023SJohn Marino tem = expand_and (mode, tem, op1, NULL_RTX);
3428e4b17023SJohn Marino adj_operand
3429e4b17023SJohn Marino = force_operand (gen_rtx_fmt_ee (adj_code, mode, adj_operand, tem),
3430e4b17023SJohn Marino adj_operand);
3431e4b17023SJohn Marino
3432e4b17023SJohn Marino tem = expand_shift (RSHIFT_EXPR, mode, op1,
3433e4b17023SJohn Marino GET_MODE_BITSIZE (mode) - 1, NULL_RTX, 0);
3434e4b17023SJohn Marino tem = expand_and (mode, tem, op0, NULL_RTX);
3435e4b17023SJohn Marino target = force_operand (gen_rtx_fmt_ee (adj_code, mode, adj_operand, tem),
3436e4b17023SJohn Marino target);
3437e4b17023SJohn Marino
3438e4b17023SJohn Marino return target;
3439e4b17023SJohn Marino }
3440e4b17023SJohn Marino
3441e4b17023SJohn Marino /* Subroutine of expand_mult_highpart. Return the MODE high part of OP. */
3442e4b17023SJohn Marino
3443e4b17023SJohn Marino static rtx
extract_high_half(enum machine_mode mode,rtx op)3444e4b17023SJohn Marino extract_high_half (enum machine_mode mode, rtx op)
3445e4b17023SJohn Marino {
3446e4b17023SJohn Marino enum machine_mode wider_mode;
3447e4b17023SJohn Marino
3448e4b17023SJohn Marino if (mode == word_mode)
3449e4b17023SJohn Marino return gen_highpart (mode, op);
3450e4b17023SJohn Marino
3451e4b17023SJohn Marino gcc_assert (!SCALAR_FLOAT_MODE_P (mode));
3452e4b17023SJohn Marino
3453e4b17023SJohn Marino wider_mode = GET_MODE_WIDER_MODE (mode);
3454e4b17023SJohn Marino op = expand_shift (RSHIFT_EXPR, wider_mode, op,
3455e4b17023SJohn Marino GET_MODE_BITSIZE (mode), 0, 1);
3456e4b17023SJohn Marino return convert_modes (mode, wider_mode, op, 0);
3457e4b17023SJohn Marino }
3458e4b17023SJohn Marino
3459e4b17023SJohn Marino /* Like expand_mult_highpart, but only consider using a multiplication
3460e4b17023SJohn Marino optab. OP1 is an rtx for the constant operand. */
3461e4b17023SJohn Marino
3462e4b17023SJohn Marino static rtx
expand_mult_highpart_optab(enum machine_mode mode,rtx op0,rtx op1,rtx target,int unsignedp,int max_cost)3463e4b17023SJohn Marino expand_mult_highpart_optab (enum machine_mode mode, rtx op0, rtx op1,
3464e4b17023SJohn Marino rtx target, int unsignedp, int max_cost)
3465e4b17023SJohn Marino {
3466e4b17023SJohn Marino rtx narrow_op1 = gen_int_mode (INTVAL (op1), mode);
3467e4b17023SJohn Marino enum machine_mode wider_mode;
3468e4b17023SJohn Marino optab moptab;
3469e4b17023SJohn Marino rtx tem;
3470e4b17023SJohn Marino int size;
3471e4b17023SJohn Marino bool speed = optimize_insn_for_speed_p ();
3472e4b17023SJohn Marino
3473e4b17023SJohn Marino gcc_assert (!SCALAR_FLOAT_MODE_P (mode));
3474e4b17023SJohn Marino
3475e4b17023SJohn Marino wider_mode = GET_MODE_WIDER_MODE (mode);
3476e4b17023SJohn Marino size = GET_MODE_BITSIZE (mode);
3477e4b17023SJohn Marino
3478e4b17023SJohn Marino /* Firstly, try using a multiplication insn that only generates the needed
3479e4b17023SJohn Marino high part of the product, and in the sign flavor of unsignedp. */
3480e4b17023SJohn Marino if (mul_highpart_cost[speed][mode] < max_cost)
3481e4b17023SJohn Marino {
3482e4b17023SJohn Marino moptab = unsignedp ? umul_highpart_optab : smul_highpart_optab;
3483e4b17023SJohn Marino tem = expand_binop (mode, moptab, op0, narrow_op1, target,
3484e4b17023SJohn Marino unsignedp, OPTAB_DIRECT);
3485e4b17023SJohn Marino if (tem)
3486e4b17023SJohn Marino return tem;
3487e4b17023SJohn Marino }
3488e4b17023SJohn Marino
3489e4b17023SJohn Marino /* Secondly, same as above, but use sign flavor opposite of unsignedp.
3490e4b17023SJohn Marino Need to adjust the result after the multiplication. */
3491e4b17023SJohn Marino if (size - 1 < BITS_PER_WORD
3492e4b17023SJohn Marino && (mul_highpart_cost[speed][mode] + 2 * shift_cost[speed][mode][size-1]
3493e4b17023SJohn Marino + 4 * add_cost[speed][mode] < max_cost))
3494e4b17023SJohn Marino {
3495e4b17023SJohn Marino moptab = unsignedp ? smul_highpart_optab : umul_highpart_optab;
3496e4b17023SJohn Marino tem = expand_binop (mode, moptab, op0, narrow_op1, target,
3497e4b17023SJohn Marino unsignedp, OPTAB_DIRECT);
3498e4b17023SJohn Marino if (tem)
3499e4b17023SJohn Marino /* We used the wrong signedness. Adjust the result. */
3500e4b17023SJohn Marino return expand_mult_highpart_adjust (mode, tem, op0, narrow_op1,
3501e4b17023SJohn Marino tem, unsignedp);
3502e4b17023SJohn Marino }
3503e4b17023SJohn Marino
3504e4b17023SJohn Marino /* Try widening multiplication. */
3505e4b17023SJohn Marino moptab = unsignedp ? umul_widen_optab : smul_widen_optab;
3506e4b17023SJohn Marino if (widening_optab_handler (moptab, wider_mode, mode) != CODE_FOR_nothing
3507e4b17023SJohn Marino && mul_widen_cost[speed][wider_mode] < max_cost)
3508e4b17023SJohn Marino {
3509e4b17023SJohn Marino tem = expand_binop (wider_mode, moptab, op0, narrow_op1, 0,
3510e4b17023SJohn Marino unsignedp, OPTAB_WIDEN);
3511e4b17023SJohn Marino if (tem)
3512e4b17023SJohn Marino return extract_high_half (mode, tem);
3513e4b17023SJohn Marino }
3514e4b17023SJohn Marino
3515e4b17023SJohn Marino /* Try widening the mode and perform a non-widening multiplication. */
3516e4b17023SJohn Marino if (optab_handler (smul_optab, wider_mode) != CODE_FOR_nothing
3517e4b17023SJohn Marino && size - 1 < BITS_PER_WORD
3518e4b17023SJohn Marino && mul_cost[speed][wider_mode] + shift_cost[speed][mode][size-1] < max_cost)
3519e4b17023SJohn Marino {
3520e4b17023SJohn Marino rtx insns, wop0, wop1;
3521e4b17023SJohn Marino
3522e4b17023SJohn Marino /* We need to widen the operands, for example to ensure the
3523e4b17023SJohn Marino constant multiplier is correctly sign or zero extended.
3524e4b17023SJohn Marino Use a sequence to clean-up any instructions emitted by
3525e4b17023SJohn Marino the conversions if things don't work out. */
3526e4b17023SJohn Marino start_sequence ();
3527e4b17023SJohn Marino wop0 = convert_modes (wider_mode, mode, op0, unsignedp);
3528e4b17023SJohn Marino wop1 = convert_modes (wider_mode, mode, op1, unsignedp);
3529e4b17023SJohn Marino tem = expand_binop (wider_mode, smul_optab, wop0, wop1, 0,
3530e4b17023SJohn Marino unsignedp, OPTAB_WIDEN);
3531e4b17023SJohn Marino insns = get_insns ();
3532e4b17023SJohn Marino end_sequence ();
3533e4b17023SJohn Marino
3534e4b17023SJohn Marino if (tem)
3535e4b17023SJohn Marino {
3536e4b17023SJohn Marino emit_insn (insns);
3537e4b17023SJohn Marino return extract_high_half (mode, tem);
3538e4b17023SJohn Marino }
3539e4b17023SJohn Marino }
3540e4b17023SJohn Marino
3541e4b17023SJohn Marino /* Try widening multiplication of opposite signedness, and adjust. */
3542e4b17023SJohn Marino moptab = unsignedp ? smul_widen_optab : umul_widen_optab;
3543e4b17023SJohn Marino if (widening_optab_handler (moptab, wider_mode, mode) != CODE_FOR_nothing
3544e4b17023SJohn Marino && size - 1 < BITS_PER_WORD
3545e4b17023SJohn Marino && (mul_widen_cost[speed][wider_mode] + 2 * shift_cost[speed][mode][size-1]
3546e4b17023SJohn Marino + 4 * add_cost[speed][mode] < max_cost))
3547e4b17023SJohn Marino {
3548e4b17023SJohn Marino tem = expand_binop (wider_mode, moptab, op0, narrow_op1,
3549e4b17023SJohn Marino NULL_RTX, ! unsignedp, OPTAB_WIDEN);
3550e4b17023SJohn Marino if (tem != 0)
3551e4b17023SJohn Marino {
3552e4b17023SJohn Marino tem = extract_high_half (mode, tem);
3553e4b17023SJohn Marino /* We used the wrong signedness. Adjust the result. */
3554e4b17023SJohn Marino return expand_mult_highpart_adjust (mode, tem, op0, narrow_op1,
3555e4b17023SJohn Marino target, unsignedp);
3556e4b17023SJohn Marino }
3557e4b17023SJohn Marino }
3558e4b17023SJohn Marino
3559e4b17023SJohn Marino return 0;
3560e4b17023SJohn Marino }
3561e4b17023SJohn Marino
3562e4b17023SJohn Marino /* Emit code to multiply OP0 and OP1 (where OP1 is an integer constant),
3563e4b17023SJohn Marino putting the high half of the result in TARGET if that is convenient,
3564e4b17023SJohn Marino and return where the result is. If the operation can not be performed,
3565e4b17023SJohn Marino 0 is returned.
3566e4b17023SJohn Marino
3567e4b17023SJohn Marino MODE is the mode of operation and result.
3568e4b17023SJohn Marino
3569e4b17023SJohn Marino UNSIGNEDP nonzero means unsigned multiply.
3570e4b17023SJohn Marino
3571e4b17023SJohn Marino MAX_COST is the total allowed cost for the expanded RTL. */
3572e4b17023SJohn Marino
3573e4b17023SJohn Marino static rtx
expand_mult_highpart(enum machine_mode mode,rtx op0,rtx op1,rtx target,int unsignedp,int max_cost)3574e4b17023SJohn Marino expand_mult_highpart (enum machine_mode mode, rtx op0, rtx op1,
3575e4b17023SJohn Marino rtx target, int unsignedp, int max_cost)
3576e4b17023SJohn Marino {
3577e4b17023SJohn Marino enum machine_mode wider_mode = GET_MODE_WIDER_MODE (mode);
3578e4b17023SJohn Marino unsigned HOST_WIDE_INT cnst1;
3579e4b17023SJohn Marino int extra_cost;
3580e4b17023SJohn Marino bool sign_adjust = false;
3581e4b17023SJohn Marino enum mult_variant variant;
3582e4b17023SJohn Marino struct algorithm alg;
3583e4b17023SJohn Marino rtx tem;
3584e4b17023SJohn Marino bool speed = optimize_insn_for_speed_p ();
3585e4b17023SJohn Marino
3586e4b17023SJohn Marino gcc_assert (!SCALAR_FLOAT_MODE_P (mode));
3587e4b17023SJohn Marino /* We can't support modes wider than HOST_BITS_PER_INT. */
3588e4b17023SJohn Marino gcc_assert (HWI_COMPUTABLE_MODE_P (mode));
3589e4b17023SJohn Marino
3590e4b17023SJohn Marino cnst1 = INTVAL (op1) & GET_MODE_MASK (mode);
3591e4b17023SJohn Marino
3592e4b17023SJohn Marino /* We can't optimize modes wider than BITS_PER_WORD.
3593e4b17023SJohn Marino ??? We might be able to perform double-word arithmetic if
3594e4b17023SJohn Marino mode == word_mode, however all the cost calculations in
3595e4b17023SJohn Marino synth_mult etc. assume single-word operations. */
3596e4b17023SJohn Marino if (GET_MODE_BITSIZE (wider_mode) > BITS_PER_WORD)
3597e4b17023SJohn Marino return expand_mult_highpart_optab (mode, op0, op1, target,
3598e4b17023SJohn Marino unsignedp, max_cost);
3599e4b17023SJohn Marino
3600e4b17023SJohn Marino extra_cost = shift_cost[speed][mode][GET_MODE_BITSIZE (mode) - 1];
3601e4b17023SJohn Marino
3602e4b17023SJohn Marino /* Check whether we try to multiply by a negative constant. */
3603e4b17023SJohn Marino if (!unsignedp && ((cnst1 >> (GET_MODE_BITSIZE (mode) - 1)) & 1))
3604e4b17023SJohn Marino {
3605e4b17023SJohn Marino sign_adjust = true;
3606e4b17023SJohn Marino extra_cost += add_cost[speed][mode];
3607e4b17023SJohn Marino }
3608e4b17023SJohn Marino
3609e4b17023SJohn Marino /* See whether shift/add multiplication is cheap enough. */
3610e4b17023SJohn Marino if (choose_mult_variant (wider_mode, cnst1, &alg, &variant,
3611e4b17023SJohn Marino max_cost - extra_cost))
3612e4b17023SJohn Marino {
3613e4b17023SJohn Marino /* See whether the specialized multiplication optabs are
3614e4b17023SJohn Marino cheaper than the shift/add version. */
3615e4b17023SJohn Marino tem = expand_mult_highpart_optab (mode, op0, op1, target, unsignedp,
3616e4b17023SJohn Marino alg.cost.cost + extra_cost);
3617e4b17023SJohn Marino if (tem)
3618e4b17023SJohn Marino return tem;
3619e4b17023SJohn Marino
3620e4b17023SJohn Marino tem = convert_to_mode (wider_mode, op0, unsignedp);
3621e4b17023SJohn Marino tem = expand_mult_const (wider_mode, tem, cnst1, 0, &alg, variant);
3622e4b17023SJohn Marino tem = extract_high_half (mode, tem);
3623e4b17023SJohn Marino
3624e4b17023SJohn Marino /* Adjust result for signedness. */
3625e4b17023SJohn Marino if (sign_adjust)
3626e4b17023SJohn Marino tem = force_operand (gen_rtx_MINUS (mode, tem, op0), tem);
3627e4b17023SJohn Marino
3628e4b17023SJohn Marino return tem;
3629e4b17023SJohn Marino }
3630e4b17023SJohn Marino return expand_mult_highpart_optab (mode, op0, op1, target,
3631e4b17023SJohn Marino unsignedp, max_cost);
3632e4b17023SJohn Marino }
3633e4b17023SJohn Marino
3634e4b17023SJohn Marino
3635e4b17023SJohn Marino /* Expand signed modulus of OP0 by a power of two D in mode MODE. */
3636e4b17023SJohn Marino
3637e4b17023SJohn Marino static rtx
expand_smod_pow2(enum machine_mode mode,rtx op0,HOST_WIDE_INT d)3638e4b17023SJohn Marino expand_smod_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
3639e4b17023SJohn Marino {
3640e4b17023SJohn Marino unsigned HOST_WIDE_INT masklow, maskhigh;
3641e4b17023SJohn Marino rtx result, temp, shift, label;
3642e4b17023SJohn Marino int logd;
3643e4b17023SJohn Marino
3644e4b17023SJohn Marino logd = floor_log2 (d);
3645e4b17023SJohn Marino result = gen_reg_rtx (mode);
3646e4b17023SJohn Marino
3647e4b17023SJohn Marino /* Avoid conditional branches when they're expensive. */
3648e4b17023SJohn Marino if (BRANCH_COST (optimize_insn_for_speed_p (), false) >= 2
3649e4b17023SJohn Marino && optimize_insn_for_speed_p ())
3650e4b17023SJohn Marino {
3651e4b17023SJohn Marino rtx signmask = emit_store_flag (result, LT, op0, const0_rtx,
3652e4b17023SJohn Marino mode, 0, -1);
3653e4b17023SJohn Marino if (signmask)
3654e4b17023SJohn Marino {
3655e4b17023SJohn Marino signmask = force_reg (mode, signmask);
3656e4b17023SJohn Marino masklow = ((HOST_WIDE_INT) 1 << logd) - 1;
3657e4b17023SJohn Marino shift = GEN_INT (GET_MODE_BITSIZE (mode) - logd);
3658e4b17023SJohn Marino
3659e4b17023SJohn Marino /* Use the rtx_cost of a LSHIFTRT instruction to determine
3660e4b17023SJohn Marino which instruction sequence to use. If logical right shifts
3661e4b17023SJohn Marino are expensive the use 2 XORs, 2 SUBs and an AND, otherwise
3662e4b17023SJohn Marino use a LSHIFTRT, 1 ADD, 1 SUB and an AND. */
3663e4b17023SJohn Marino
3664e4b17023SJohn Marino temp = gen_rtx_LSHIFTRT (mode, result, shift);
3665e4b17023SJohn Marino if (optab_handler (lshr_optab, mode) == CODE_FOR_nothing
3666e4b17023SJohn Marino || (set_src_cost (temp, optimize_insn_for_speed_p ())
3667e4b17023SJohn Marino > COSTS_N_INSNS (2)))
3668e4b17023SJohn Marino {
3669e4b17023SJohn Marino temp = expand_binop (mode, xor_optab, op0, signmask,
3670e4b17023SJohn Marino NULL_RTX, 1, OPTAB_LIB_WIDEN);
3671e4b17023SJohn Marino temp = expand_binop (mode, sub_optab, temp, signmask,
3672e4b17023SJohn Marino NULL_RTX, 1, OPTAB_LIB_WIDEN);
3673e4b17023SJohn Marino temp = expand_binop (mode, and_optab, temp, GEN_INT (masklow),
3674e4b17023SJohn Marino NULL_RTX, 1, OPTAB_LIB_WIDEN);
3675e4b17023SJohn Marino temp = expand_binop (mode, xor_optab, temp, signmask,
3676e4b17023SJohn Marino NULL_RTX, 1, OPTAB_LIB_WIDEN);
3677e4b17023SJohn Marino temp = expand_binop (mode, sub_optab, temp, signmask,
3678e4b17023SJohn Marino NULL_RTX, 1, OPTAB_LIB_WIDEN);
3679e4b17023SJohn Marino }
3680e4b17023SJohn Marino else
3681e4b17023SJohn Marino {
3682e4b17023SJohn Marino signmask = expand_binop (mode, lshr_optab, signmask, shift,
3683e4b17023SJohn Marino NULL_RTX, 1, OPTAB_LIB_WIDEN);
3684e4b17023SJohn Marino signmask = force_reg (mode, signmask);
3685e4b17023SJohn Marino
3686e4b17023SJohn Marino temp = expand_binop (mode, add_optab, op0, signmask,
3687e4b17023SJohn Marino NULL_RTX, 1, OPTAB_LIB_WIDEN);
3688e4b17023SJohn Marino temp = expand_binop (mode, and_optab, temp, GEN_INT (masklow),
3689e4b17023SJohn Marino NULL_RTX, 1, OPTAB_LIB_WIDEN);
3690e4b17023SJohn Marino temp = expand_binop (mode, sub_optab, temp, signmask,
3691e4b17023SJohn Marino NULL_RTX, 1, OPTAB_LIB_WIDEN);
3692e4b17023SJohn Marino }
3693e4b17023SJohn Marino return temp;
3694e4b17023SJohn Marino }
3695e4b17023SJohn Marino }
3696e4b17023SJohn Marino
3697e4b17023SJohn Marino /* Mask contains the mode's signbit and the significant bits of the
3698e4b17023SJohn Marino modulus. By including the signbit in the operation, many targets
3699e4b17023SJohn Marino can avoid an explicit compare operation in the following comparison
3700e4b17023SJohn Marino against zero. */
3701e4b17023SJohn Marino
3702e4b17023SJohn Marino masklow = ((HOST_WIDE_INT) 1 << logd) - 1;
3703e4b17023SJohn Marino if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
3704e4b17023SJohn Marino {
3705e4b17023SJohn Marino masklow |= (HOST_WIDE_INT) -1 << (GET_MODE_BITSIZE (mode) - 1);
3706e4b17023SJohn Marino maskhigh = -1;
3707e4b17023SJohn Marino }
3708e4b17023SJohn Marino else
3709e4b17023SJohn Marino maskhigh = (HOST_WIDE_INT) -1
3710e4b17023SJohn Marino << (GET_MODE_BITSIZE (mode) - HOST_BITS_PER_WIDE_INT - 1);
3711e4b17023SJohn Marino
3712e4b17023SJohn Marino temp = expand_binop (mode, and_optab, op0,
3713e4b17023SJohn Marino immed_double_const (masklow, maskhigh, mode),
3714e4b17023SJohn Marino result, 1, OPTAB_LIB_WIDEN);
3715e4b17023SJohn Marino if (temp != result)
3716e4b17023SJohn Marino emit_move_insn (result, temp);
3717e4b17023SJohn Marino
3718e4b17023SJohn Marino label = gen_label_rtx ();
3719e4b17023SJohn Marino do_cmp_and_jump (result, const0_rtx, GE, mode, label);
3720e4b17023SJohn Marino
3721e4b17023SJohn Marino temp = expand_binop (mode, sub_optab, result, const1_rtx, result,
3722e4b17023SJohn Marino 0, OPTAB_LIB_WIDEN);
3723e4b17023SJohn Marino masklow = (HOST_WIDE_INT) -1 << logd;
3724e4b17023SJohn Marino maskhigh = -1;
3725e4b17023SJohn Marino temp = expand_binop (mode, ior_optab, temp,
3726e4b17023SJohn Marino immed_double_const (masklow, maskhigh, mode),
3727e4b17023SJohn Marino result, 1, OPTAB_LIB_WIDEN);
3728e4b17023SJohn Marino temp = expand_binop (mode, add_optab, temp, const1_rtx, result,
3729e4b17023SJohn Marino 0, OPTAB_LIB_WIDEN);
3730e4b17023SJohn Marino if (temp != result)
3731e4b17023SJohn Marino emit_move_insn (result, temp);
3732e4b17023SJohn Marino emit_label (label);
3733e4b17023SJohn Marino return result;
3734e4b17023SJohn Marino }
3735e4b17023SJohn Marino
3736e4b17023SJohn Marino /* Expand signed division of OP0 by a power of two D in mode MODE.
3737e4b17023SJohn Marino This routine is only called for positive values of D. */
3738e4b17023SJohn Marino
3739e4b17023SJohn Marino static rtx
expand_sdiv_pow2(enum machine_mode mode,rtx op0,HOST_WIDE_INT d)3740e4b17023SJohn Marino expand_sdiv_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
3741e4b17023SJohn Marino {
3742e4b17023SJohn Marino rtx temp, label;
3743e4b17023SJohn Marino int logd;
3744e4b17023SJohn Marino
3745e4b17023SJohn Marino logd = floor_log2 (d);
3746e4b17023SJohn Marino
3747e4b17023SJohn Marino if (d == 2
3748e4b17023SJohn Marino && BRANCH_COST (optimize_insn_for_speed_p (),
3749e4b17023SJohn Marino false) >= 1)
3750e4b17023SJohn Marino {
3751e4b17023SJohn Marino temp = gen_reg_rtx (mode);
3752e4b17023SJohn Marino temp = emit_store_flag (temp, LT, op0, const0_rtx, mode, 0, 1);
3753e4b17023SJohn Marino temp = expand_binop (mode, add_optab, temp, op0, NULL_RTX,
3754e4b17023SJohn Marino 0, OPTAB_LIB_WIDEN);
3755e4b17023SJohn Marino return expand_shift (RSHIFT_EXPR, mode, temp, logd, NULL_RTX, 0);
3756e4b17023SJohn Marino }
3757e4b17023SJohn Marino
3758e4b17023SJohn Marino #ifdef HAVE_conditional_move
3759e4b17023SJohn Marino if (BRANCH_COST (optimize_insn_for_speed_p (), false)
3760e4b17023SJohn Marino >= 2)
3761e4b17023SJohn Marino {
3762e4b17023SJohn Marino rtx temp2;
3763e4b17023SJohn Marino
3764e4b17023SJohn Marino /* ??? emit_conditional_move forces a stack adjustment via
3765e4b17023SJohn Marino compare_from_rtx so, if the sequence is discarded, it will
3766e4b17023SJohn Marino be lost. Do it now instead. */
3767e4b17023SJohn Marino do_pending_stack_adjust ();
3768e4b17023SJohn Marino
3769e4b17023SJohn Marino start_sequence ();
3770e4b17023SJohn Marino temp2 = copy_to_mode_reg (mode, op0);
3771e4b17023SJohn Marino temp = expand_binop (mode, add_optab, temp2, GEN_INT (d-1),
3772e4b17023SJohn Marino NULL_RTX, 0, OPTAB_LIB_WIDEN);
3773e4b17023SJohn Marino temp = force_reg (mode, temp);
3774e4b17023SJohn Marino
3775e4b17023SJohn Marino /* Construct "temp2 = (temp2 < 0) ? temp : temp2". */
3776e4b17023SJohn Marino temp2 = emit_conditional_move (temp2, LT, temp2, const0_rtx,
3777e4b17023SJohn Marino mode, temp, temp2, mode, 0);
3778e4b17023SJohn Marino if (temp2)
3779e4b17023SJohn Marino {
3780e4b17023SJohn Marino rtx seq = get_insns ();
3781e4b17023SJohn Marino end_sequence ();
3782e4b17023SJohn Marino emit_insn (seq);
3783e4b17023SJohn Marino return expand_shift (RSHIFT_EXPR, mode, temp2, logd, NULL_RTX, 0);
3784e4b17023SJohn Marino }
3785e4b17023SJohn Marino end_sequence ();
3786e4b17023SJohn Marino }
3787e4b17023SJohn Marino #endif
3788e4b17023SJohn Marino
3789e4b17023SJohn Marino if (BRANCH_COST (optimize_insn_for_speed_p (),
3790e4b17023SJohn Marino false) >= 2)
3791e4b17023SJohn Marino {
3792e4b17023SJohn Marino int ushift = GET_MODE_BITSIZE (mode) - logd;
3793e4b17023SJohn Marino
3794e4b17023SJohn Marino temp = gen_reg_rtx (mode);
3795e4b17023SJohn Marino temp = emit_store_flag (temp, LT, op0, const0_rtx, mode, 0, -1);
3796e4b17023SJohn Marino if (shift_cost[optimize_insn_for_speed_p ()][mode][ushift] > COSTS_N_INSNS (1))
3797e4b17023SJohn Marino temp = expand_binop (mode, and_optab, temp, GEN_INT (d - 1),
3798e4b17023SJohn Marino NULL_RTX, 0, OPTAB_LIB_WIDEN);
3799e4b17023SJohn Marino else
3800e4b17023SJohn Marino temp = expand_shift (RSHIFT_EXPR, mode, temp,
3801e4b17023SJohn Marino ushift, NULL_RTX, 1);
3802e4b17023SJohn Marino temp = expand_binop (mode, add_optab, temp, op0, NULL_RTX,
3803e4b17023SJohn Marino 0, OPTAB_LIB_WIDEN);
3804e4b17023SJohn Marino return expand_shift (RSHIFT_EXPR, mode, temp, logd, NULL_RTX, 0);
3805e4b17023SJohn Marino }
3806e4b17023SJohn Marino
3807e4b17023SJohn Marino label = gen_label_rtx ();
3808e4b17023SJohn Marino temp = copy_to_mode_reg (mode, op0);
3809e4b17023SJohn Marino do_cmp_and_jump (temp, const0_rtx, GE, mode, label);
3810e4b17023SJohn Marino expand_inc (temp, GEN_INT (d - 1));
3811e4b17023SJohn Marino emit_label (label);
3812e4b17023SJohn Marino return expand_shift (RSHIFT_EXPR, mode, temp, logd, NULL_RTX, 0);
3813e4b17023SJohn Marino }
3814e4b17023SJohn Marino
3815e4b17023SJohn Marino /* Emit the code to divide OP0 by OP1, putting the result in TARGET
3816e4b17023SJohn Marino if that is convenient, and returning where the result is.
3817e4b17023SJohn Marino You may request either the quotient or the remainder as the result;
3818e4b17023SJohn Marino specify REM_FLAG nonzero to get the remainder.
3819e4b17023SJohn Marino
3820e4b17023SJohn Marino CODE is the expression code for which kind of division this is;
3821e4b17023SJohn Marino it controls how rounding is done. MODE is the machine mode to use.
3822e4b17023SJohn Marino UNSIGNEDP nonzero means do unsigned division. */
3823e4b17023SJohn Marino
3824e4b17023SJohn Marino /* ??? For CEIL_MOD_EXPR, can compute incorrect remainder with ANDI
3825e4b17023SJohn Marino and then correct it by or'ing in missing high bits
3826e4b17023SJohn Marino if result of ANDI is nonzero.
3827e4b17023SJohn Marino For ROUND_MOD_EXPR, can use ANDI and then sign-extend the result.
3828e4b17023SJohn Marino This could optimize to a bfexts instruction.
3829e4b17023SJohn Marino But C doesn't use these operations, so their optimizations are
3830e4b17023SJohn Marino left for later. */
3831e4b17023SJohn Marino /* ??? For modulo, we don't actually need the highpart of the first product,
3832e4b17023SJohn Marino the low part will do nicely. And for small divisors, the second multiply
3833e4b17023SJohn Marino can also be a low-part only multiply or even be completely left out.
3834e4b17023SJohn Marino E.g. to calculate the remainder of a division by 3 with a 32 bit
3835e4b17023SJohn Marino multiply, multiply with 0x55555556 and extract the upper two bits;
3836e4b17023SJohn Marino the result is exact for inputs up to 0x1fffffff.
3837e4b17023SJohn Marino The input range can be reduced by using cross-sum rules.
3838e4b17023SJohn Marino For odd divisors >= 3, the following table gives right shift counts
3839e4b17023SJohn Marino so that if a number is shifted by an integer multiple of the given
3840e4b17023SJohn Marino amount, the remainder stays the same:
3841e4b17023SJohn Marino 2, 4, 3, 6, 10, 12, 4, 8, 18, 6, 11, 20, 18, 0, 5, 10, 12, 0, 12, 20,
3842e4b17023SJohn Marino 14, 12, 23, 21, 8, 0, 20, 18, 0, 0, 6, 12, 0, 22, 0, 18, 20, 30, 0, 0,
3843e4b17023SJohn Marino 0, 8, 0, 11, 12, 10, 36, 0, 30, 0, 0, 12, 0, 0, 0, 0, 44, 12, 24, 0,
3844e4b17023SJohn Marino 20, 0, 7, 14, 0, 18, 36, 0, 0, 46, 60, 0, 42, 0, 15, 24, 20, 0, 0, 33,
3845e4b17023SJohn Marino 0, 20, 0, 0, 18, 0, 60, 0, 0, 0, 0, 0, 40, 18, 0, 0, 12
3846e4b17023SJohn Marino
3847e4b17023SJohn Marino Cross-sum rules for even numbers can be derived by leaving as many bits
3848e4b17023SJohn Marino to the right alone as the divisor has zeros to the right.
3849e4b17023SJohn Marino E.g. if x is an unsigned 32 bit number:
3850e4b17023SJohn Marino (x mod 12) == (((x & 1023) + ((x >> 8) & ~3)) * 0x15555558 >> 2 * 3) >> 28
3851e4b17023SJohn Marino */
3852e4b17023SJohn Marino
3853e4b17023SJohn Marino rtx
expand_divmod(int rem_flag,enum tree_code code,enum machine_mode mode,rtx op0,rtx op1,rtx target,int unsignedp)3854e4b17023SJohn Marino expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
3855e4b17023SJohn Marino rtx op0, rtx op1, rtx target, int unsignedp)
3856e4b17023SJohn Marino {
3857e4b17023SJohn Marino enum machine_mode compute_mode;
3858e4b17023SJohn Marino rtx tquotient;
3859e4b17023SJohn Marino rtx quotient = 0, remainder = 0;
3860e4b17023SJohn Marino rtx last;
3861e4b17023SJohn Marino int size;
3862e4b17023SJohn Marino rtx insn;
3863e4b17023SJohn Marino optab optab1, optab2;
3864e4b17023SJohn Marino int op1_is_constant, op1_is_pow2 = 0;
3865e4b17023SJohn Marino int max_cost, extra_cost;
3866e4b17023SJohn Marino static HOST_WIDE_INT last_div_const = 0;
3867e4b17023SJohn Marino static HOST_WIDE_INT ext_op1;
3868e4b17023SJohn Marino bool speed = optimize_insn_for_speed_p ();
3869e4b17023SJohn Marino
3870e4b17023SJohn Marino op1_is_constant = CONST_INT_P (op1);
3871e4b17023SJohn Marino if (op1_is_constant)
3872e4b17023SJohn Marino {
3873e4b17023SJohn Marino ext_op1 = INTVAL (op1);
3874e4b17023SJohn Marino if (unsignedp)
3875e4b17023SJohn Marino ext_op1 &= GET_MODE_MASK (mode);
3876e4b17023SJohn Marino op1_is_pow2 = ((EXACT_POWER_OF_2_OR_ZERO_P (ext_op1)
3877e4b17023SJohn Marino || (! unsignedp && EXACT_POWER_OF_2_OR_ZERO_P (-ext_op1))));
3878e4b17023SJohn Marino }
3879e4b17023SJohn Marino
3880e4b17023SJohn Marino /*
3881e4b17023SJohn Marino This is the structure of expand_divmod:
3882e4b17023SJohn Marino
3883e4b17023SJohn Marino First comes code to fix up the operands so we can perform the operations
3884e4b17023SJohn Marino correctly and efficiently.
3885e4b17023SJohn Marino
3886e4b17023SJohn Marino Second comes a switch statement with code specific for each rounding mode.
3887e4b17023SJohn Marino For some special operands this code emits all RTL for the desired
3888e4b17023SJohn Marino operation, for other cases, it generates only a quotient and stores it in
3889e4b17023SJohn Marino QUOTIENT. The case for trunc division/remainder might leave quotient = 0,
3890e4b17023SJohn Marino to indicate that it has not done anything.
3891e4b17023SJohn Marino
3892e4b17023SJohn Marino Last comes code that finishes the operation. If QUOTIENT is set and
3893e4b17023SJohn Marino REM_FLAG is set, the remainder is computed as OP0 - QUOTIENT * OP1. If
3894e4b17023SJohn Marino QUOTIENT is not set, it is computed using trunc rounding.
3895e4b17023SJohn Marino
3896e4b17023SJohn Marino We try to generate special code for division and remainder when OP1 is a
3897e4b17023SJohn Marino constant. If |OP1| = 2**n we can use shifts and some other fast
3898e4b17023SJohn Marino operations. For other values of OP1, we compute a carefully selected
3899e4b17023SJohn Marino fixed-point approximation m = 1/OP1, and generate code that multiplies OP0
3900e4b17023SJohn Marino by m.
3901e4b17023SJohn Marino
3902e4b17023SJohn Marino In all cases but EXACT_DIV_EXPR, this multiplication requires the upper
3903e4b17023SJohn Marino half of the product. Different strategies for generating the product are
3904e4b17023SJohn Marino implemented in expand_mult_highpart.
3905e4b17023SJohn Marino
3906e4b17023SJohn Marino If what we actually want is the remainder, we generate that by another
3907e4b17023SJohn Marino by-constant multiplication and a subtraction. */
3908e4b17023SJohn Marino
3909e4b17023SJohn Marino /* We shouldn't be called with OP1 == const1_rtx, but some of the
3910e4b17023SJohn Marino code below will malfunction if we are, so check here and handle
3911e4b17023SJohn Marino the special case if so. */
3912e4b17023SJohn Marino if (op1 == const1_rtx)
3913e4b17023SJohn Marino return rem_flag ? const0_rtx : op0;
3914e4b17023SJohn Marino
3915e4b17023SJohn Marino /* When dividing by -1, we could get an overflow.
3916e4b17023SJohn Marino negv_optab can handle overflows. */
3917e4b17023SJohn Marino if (! unsignedp && op1 == constm1_rtx)
3918e4b17023SJohn Marino {
3919e4b17023SJohn Marino if (rem_flag)
3920e4b17023SJohn Marino return const0_rtx;
3921e4b17023SJohn Marino return expand_unop (mode, flag_trapv && GET_MODE_CLASS(mode) == MODE_INT
3922e4b17023SJohn Marino ? negv_optab : neg_optab, op0, target, 0);
3923e4b17023SJohn Marino }
3924e4b17023SJohn Marino
3925e4b17023SJohn Marino if (target
3926e4b17023SJohn Marino /* Don't use the function value register as a target
3927e4b17023SJohn Marino since we have to read it as well as write it,
3928e4b17023SJohn Marino and function-inlining gets confused by this. */
3929e4b17023SJohn Marino && ((REG_P (target) && REG_FUNCTION_VALUE_P (target))
3930e4b17023SJohn Marino /* Don't clobber an operand while doing a multi-step calculation. */
3931e4b17023SJohn Marino || ((rem_flag || op1_is_constant)
3932e4b17023SJohn Marino && (reg_mentioned_p (target, op0)
3933e4b17023SJohn Marino || (MEM_P (op0) && MEM_P (target))))
3934e4b17023SJohn Marino || reg_mentioned_p (target, op1)
3935e4b17023SJohn Marino || (MEM_P (op1) && MEM_P (target))))
3936e4b17023SJohn Marino target = 0;
3937e4b17023SJohn Marino
3938e4b17023SJohn Marino /* Get the mode in which to perform this computation. Normally it will
3939e4b17023SJohn Marino be MODE, but sometimes we can't do the desired operation in MODE.
3940e4b17023SJohn Marino If so, pick a wider mode in which we can do the operation. Convert
3941e4b17023SJohn Marino to that mode at the start to avoid repeated conversions.
3942e4b17023SJohn Marino
3943e4b17023SJohn Marino First see what operations we need. These depend on the expression
3944e4b17023SJohn Marino we are evaluating. (We assume that divxx3 insns exist under the
3945e4b17023SJohn Marino same conditions that modxx3 insns and that these insns don't normally
3946e4b17023SJohn Marino fail. If these assumptions are not correct, we may generate less
3947e4b17023SJohn Marino efficient code in some cases.)
3948e4b17023SJohn Marino
3949e4b17023SJohn Marino Then see if we find a mode in which we can open-code that operation
3950e4b17023SJohn Marino (either a division, modulus, or shift). Finally, check for the smallest
3951e4b17023SJohn Marino mode for which we can do the operation with a library call. */
3952e4b17023SJohn Marino
3953e4b17023SJohn Marino /* We might want to refine this now that we have division-by-constant
3954e4b17023SJohn Marino optimization. Since expand_mult_highpart tries so many variants, it is
3955e4b17023SJohn Marino not straightforward to generalize this. Maybe we should make an array
3956e4b17023SJohn Marino of possible modes in init_expmed? Save this for GCC 2.7. */
3957e4b17023SJohn Marino
3958e4b17023SJohn Marino optab1 = ((op1_is_pow2 && op1 != const0_rtx)
3959e4b17023SJohn Marino ? (unsignedp ? lshr_optab : ashr_optab)
3960e4b17023SJohn Marino : (unsignedp ? udiv_optab : sdiv_optab));
3961e4b17023SJohn Marino optab2 = ((op1_is_pow2 && op1 != const0_rtx)
3962e4b17023SJohn Marino ? optab1
3963e4b17023SJohn Marino : (unsignedp ? udivmod_optab : sdivmod_optab));
3964e4b17023SJohn Marino
3965e4b17023SJohn Marino for (compute_mode = mode; compute_mode != VOIDmode;
3966e4b17023SJohn Marino compute_mode = GET_MODE_WIDER_MODE (compute_mode))
3967e4b17023SJohn Marino if (optab_handler (optab1, compute_mode) != CODE_FOR_nothing
3968e4b17023SJohn Marino || optab_handler (optab2, compute_mode) != CODE_FOR_nothing)
3969e4b17023SJohn Marino break;
3970e4b17023SJohn Marino
3971e4b17023SJohn Marino if (compute_mode == VOIDmode)
3972e4b17023SJohn Marino for (compute_mode = mode; compute_mode != VOIDmode;
3973e4b17023SJohn Marino compute_mode = GET_MODE_WIDER_MODE (compute_mode))
3974e4b17023SJohn Marino if (optab_libfunc (optab1, compute_mode)
3975e4b17023SJohn Marino || optab_libfunc (optab2, compute_mode))
3976e4b17023SJohn Marino break;
3977e4b17023SJohn Marino
3978e4b17023SJohn Marino /* If we still couldn't find a mode, use MODE, but expand_binop will
3979e4b17023SJohn Marino probably die. */
3980e4b17023SJohn Marino if (compute_mode == VOIDmode)
3981e4b17023SJohn Marino compute_mode = mode;
3982e4b17023SJohn Marino
3983e4b17023SJohn Marino if (target && GET_MODE (target) == compute_mode)
3984e4b17023SJohn Marino tquotient = target;
3985e4b17023SJohn Marino else
3986e4b17023SJohn Marino tquotient = gen_reg_rtx (compute_mode);
3987e4b17023SJohn Marino
3988e4b17023SJohn Marino size = GET_MODE_BITSIZE (compute_mode);
3989e4b17023SJohn Marino #if 0
3990e4b17023SJohn Marino /* It should be possible to restrict the precision to GET_MODE_BITSIZE
3991e4b17023SJohn Marino (mode), and thereby get better code when OP1 is a constant. Do that
3992e4b17023SJohn Marino later. It will require going over all usages of SIZE below. */
3993e4b17023SJohn Marino size = GET_MODE_BITSIZE (mode);
3994e4b17023SJohn Marino #endif
3995e4b17023SJohn Marino
3996e4b17023SJohn Marino /* Only deduct something for a REM if the last divide done was
3997e4b17023SJohn Marino for a different constant. Then set the constant of the last
3998e4b17023SJohn Marino divide. */
3999e4b17023SJohn Marino max_cost = unsignedp ? udiv_cost[speed][compute_mode] : sdiv_cost[speed][compute_mode];
4000e4b17023SJohn Marino if (rem_flag && ! (last_div_const != 0 && op1_is_constant
4001e4b17023SJohn Marino && INTVAL (op1) == last_div_const))
4002e4b17023SJohn Marino max_cost -= mul_cost[speed][compute_mode] + add_cost[speed][compute_mode];
4003e4b17023SJohn Marino
4004e4b17023SJohn Marino last_div_const = ! rem_flag && op1_is_constant ? INTVAL (op1) : 0;
4005e4b17023SJohn Marino
4006e4b17023SJohn Marino /* Now convert to the best mode to use. */
4007e4b17023SJohn Marino if (compute_mode != mode)
4008e4b17023SJohn Marino {
4009e4b17023SJohn Marino op0 = convert_modes (compute_mode, mode, op0, unsignedp);
4010e4b17023SJohn Marino op1 = convert_modes (compute_mode, mode, op1, unsignedp);
4011e4b17023SJohn Marino
4012e4b17023SJohn Marino /* convert_modes may have placed op1 into a register, so we
4013e4b17023SJohn Marino must recompute the following. */
4014e4b17023SJohn Marino op1_is_constant = CONST_INT_P (op1);
4015e4b17023SJohn Marino op1_is_pow2 = (op1_is_constant
4016e4b17023SJohn Marino && ((EXACT_POWER_OF_2_OR_ZERO_P (INTVAL (op1))
4017e4b17023SJohn Marino || (! unsignedp
4018e4b17023SJohn Marino && EXACT_POWER_OF_2_OR_ZERO_P (-INTVAL (op1)))))) ;
4019e4b17023SJohn Marino }
4020e4b17023SJohn Marino
4021e4b17023SJohn Marino /* If one of the operands is a volatile MEM, copy it into a register. */
4022e4b17023SJohn Marino
4023e4b17023SJohn Marino if (MEM_P (op0) && MEM_VOLATILE_P (op0))
4024e4b17023SJohn Marino op0 = force_reg (compute_mode, op0);
4025e4b17023SJohn Marino if (MEM_P (op1) && MEM_VOLATILE_P (op1))
4026e4b17023SJohn Marino op1 = force_reg (compute_mode, op1);
4027e4b17023SJohn Marino
4028e4b17023SJohn Marino /* If we need the remainder or if OP1 is constant, we need to
4029e4b17023SJohn Marino put OP0 in a register in case it has any queued subexpressions. */
4030e4b17023SJohn Marino if (rem_flag || op1_is_constant)
4031e4b17023SJohn Marino op0 = force_reg (compute_mode, op0);
4032e4b17023SJohn Marino
4033e4b17023SJohn Marino last = get_last_insn ();
4034e4b17023SJohn Marino
4035e4b17023SJohn Marino /* Promote floor rounding to trunc rounding for unsigned operations. */
4036e4b17023SJohn Marino if (unsignedp)
4037e4b17023SJohn Marino {
4038e4b17023SJohn Marino if (code == FLOOR_DIV_EXPR)
4039e4b17023SJohn Marino code = TRUNC_DIV_EXPR;
4040e4b17023SJohn Marino if (code == FLOOR_MOD_EXPR)
4041e4b17023SJohn Marino code = TRUNC_MOD_EXPR;
4042e4b17023SJohn Marino if (code == EXACT_DIV_EXPR && op1_is_pow2)
4043e4b17023SJohn Marino code = TRUNC_DIV_EXPR;
4044e4b17023SJohn Marino }
4045e4b17023SJohn Marino
4046e4b17023SJohn Marino if (op1 != const0_rtx)
4047e4b17023SJohn Marino switch (code)
4048e4b17023SJohn Marino {
4049e4b17023SJohn Marino case TRUNC_MOD_EXPR:
4050e4b17023SJohn Marino case TRUNC_DIV_EXPR:
4051e4b17023SJohn Marino if (op1_is_constant)
4052e4b17023SJohn Marino {
4053e4b17023SJohn Marino if (unsignedp)
4054e4b17023SJohn Marino {
4055e4b17023SJohn Marino unsigned HOST_WIDE_INT mh;
4056e4b17023SJohn Marino int pre_shift, post_shift;
4057e4b17023SJohn Marino int dummy;
4058e4b17023SJohn Marino rtx ml;
4059e4b17023SJohn Marino unsigned HOST_WIDE_INT d = (INTVAL (op1)
4060e4b17023SJohn Marino & GET_MODE_MASK (compute_mode));
4061e4b17023SJohn Marino
4062e4b17023SJohn Marino if (EXACT_POWER_OF_2_OR_ZERO_P (d))
4063e4b17023SJohn Marino {
4064e4b17023SJohn Marino pre_shift = floor_log2 (d);
4065e4b17023SJohn Marino if (rem_flag)
4066e4b17023SJohn Marino {
4067e4b17023SJohn Marino remainder
4068e4b17023SJohn Marino = expand_binop (compute_mode, and_optab, op0,
4069e4b17023SJohn Marino GEN_INT (((HOST_WIDE_INT) 1 << pre_shift) - 1),
4070e4b17023SJohn Marino remainder, 1,
4071e4b17023SJohn Marino OPTAB_LIB_WIDEN);
4072e4b17023SJohn Marino if (remainder)
4073e4b17023SJohn Marino return gen_lowpart (mode, remainder);
4074e4b17023SJohn Marino }
4075e4b17023SJohn Marino quotient = expand_shift (RSHIFT_EXPR, compute_mode, op0,
4076e4b17023SJohn Marino pre_shift, tquotient, 1);
4077e4b17023SJohn Marino }
4078e4b17023SJohn Marino else if (size <= HOST_BITS_PER_WIDE_INT)
4079e4b17023SJohn Marino {
4080e4b17023SJohn Marino if (d >= ((unsigned HOST_WIDE_INT) 1 << (size - 1)))
4081e4b17023SJohn Marino {
4082e4b17023SJohn Marino /* Most significant bit of divisor is set; emit an scc
4083e4b17023SJohn Marino insn. */
4084e4b17023SJohn Marino quotient = emit_store_flag_force (tquotient, GEU, op0, op1,
4085e4b17023SJohn Marino compute_mode, 1, 1);
4086e4b17023SJohn Marino }
4087e4b17023SJohn Marino else
4088e4b17023SJohn Marino {
4089e4b17023SJohn Marino /* Find a suitable multiplier and right shift count
4090e4b17023SJohn Marino instead of multiplying with D. */
4091e4b17023SJohn Marino
4092e4b17023SJohn Marino mh = choose_multiplier (d, size, size,
4093e4b17023SJohn Marino &ml, &post_shift, &dummy);
4094e4b17023SJohn Marino
4095e4b17023SJohn Marino /* If the suggested multiplier is more than SIZE bits,
4096e4b17023SJohn Marino we can do better for even divisors, using an
4097e4b17023SJohn Marino initial right shift. */
4098e4b17023SJohn Marino if (mh != 0 && (d & 1) == 0)
4099e4b17023SJohn Marino {
4100e4b17023SJohn Marino pre_shift = floor_log2 (d & -d);
4101e4b17023SJohn Marino mh = choose_multiplier (d >> pre_shift, size,
4102e4b17023SJohn Marino size - pre_shift,
4103e4b17023SJohn Marino &ml, &post_shift, &dummy);
4104e4b17023SJohn Marino gcc_assert (!mh);
4105e4b17023SJohn Marino }
4106e4b17023SJohn Marino else
4107e4b17023SJohn Marino pre_shift = 0;
4108e4b17023SJohn Marino
4109e4b17023SJohn Marino if (mh != 0)
4110e4b17023SJohn Marino {
4111e4b17023SJohn Marino rtx t1, t2, t3, t4;
4112e4b17023SJohn Marino
4113e4b17023SJohn Marino if (post_shift - 1 >= BITS_PER_WORD)
4114e4b17023SJohn Marino goto fail1;
4115e4b17023SJohn Marino
4116e4b17023SJohn Marino extra_cost
4117e4b17023SJohn Marino = (shift_cost[speed][compute_mode][post_shift - 1]
4118e4b17023SJohn Marino + shift_cost[speed][compute_mode][1]
4119e4b17023SJohn Marino + 2 * add_cost[speed][compute_mode]);
4120e4b17023SJohn Marino t1 = expand_mult_highpart (compute_mode, op0, ml,
4121e4b17023SJohn Marino NULL_RTX, 1,
4122e4b17023SJohn Marino max_cost - extra_cost);
4123e4b17023SJohn Marino if (t1 == 0)
4124e4b17023SJohn Marino goto fail1;
4125e4b17023SJohn Marino t2 = force_operand (gen_rtx_MINUS (compute_mode,
4126e4b17023SJohn Marino op0, t1),
4127e4b17023SJohn Marino NULL_RTX);
4128e4b17023SJohn Marino t3 = expand_shift (RSHIFT_EXPR, compute_mode,
4129e4b17023SJohn Marino t2, 1, NULL_RTX, 1);
4130e4b17023SJohn Marino t4 = force_operand (gen_rtx_PLUS (compute_mode,
4131e4b17023SJohn Marino t1, t3),
4132e4b17023SJohn Marino NULL_RTX);
4133e4b17023SJohn Marino quotient = expand_shift
4134e4b17023SJohn Marino (RSHIFT_EXPR, compute_mode, t4,
4135e4b17023SJohn Marino post_shift - 1, tquotient, 1);
4136e4b17023SJohn Marino }
4137e4b17023SJohn Marino else
4138e4b17023SJohn Marino {
4139e4b17023SJohn Marino rtx t1, t2;
4140e4b17023SJohn Marino
4141e4b17023SJohn Marino if (pre_shift >= BITS_PER_WORD
4142e4b17023SJohn Marino || post_shift >= BITS_PER_WORD)
4143e4b17023SJohn Marino goto fail1;
4144e4b17023SJohn Marino
4145e4b17023SJohn Marino t1 = expand_shift
4146e4b17023SJohn Marino (RSHIFT_EXPR, compute_mode, op0,
4147e4b17023SJohn Marino pre_shift, NULL_RTX, 1);
4148e4b17023SJohn Marino extra_cost
4149e4b17023SJohn Marino = (shift_cost[speed][compute_mode][pre_shift]
4150e4b17023SJohn Marino + shift_cost[speed][compute_mode][post_shift]);
4151e4b17023SJohn Marino t2 = expand_mult_highpart (compute_mode, t1, ml,
4152e4b17023SJohn Marino NULL_RTX, 1,
4153e4b17023SJohn Marino max_cost - extra_cost);
4154e4b17023SJohn Marino if (t2 == 0)
4155e4b17023SJohn Marino goto fail1;
4156e4b17023SJohn Marino quotient = expand_shift
4157e4b17023SJohn Marino (RSHIFT_EXPR, compute_mode, t2,
4158e4b17023SJohn Marino post_shift, tquotient, 1);
4159e4b17023SJohn Marino }
4160e4b17023SJohn Marino }
4161e4b17023SJohn Marino }
4162e4b17023SJohn Marino else /* Too wide mode to use tricky code */
4163e4b17023SJohn Marino break;
4164e4b17023SJohn Marino
4165e4b17023SJohn Marino insn = get_last_insn ();
4166e4b17023SJohn Marino if (insn != last)
4167e4b17023SJohn Marino set_dst_reg_note (insn, REG_EQUAL,
4168e4b17023SJohn Marino gen_rtx_UDIV (compute_mode, op0, op1),
4169e4b17023SJohn Marino quotient);
4170e4b17023SJohn Marino }
4171e4b17023SJohn Marino else /* TRUNC_DIV, signed */
4172e4b17023SJohn Marino {
4173e4b17023SJohn Marino unsigned HOST_WIDE_INT ml;
4174e4b17023SJohn Marino int lgup, post_shift;
4175e4b17023SJohn Marino rtx mlr;
4176e4b17023SJohn Marino HOST_WIDE_INT d = INTVAL (op1);
4177e4b17023SJohn Marino unsigned HOST_WIDE_INT abs_d;
4178e4b17023SJohn Marino
4179e4b17023SJohn Marino /* Since d might be INT_MIN, we have to cast to
4180e4b17023SJohn Marino unsigned HOST_WIDE_INT before negating to avoid
4181e4b17023SJohn Marino undefined signed overflow. */
4182e4b17023SJohn Marino abs_d = (d >= 0
4183e4b17023SJohn Marino ? (unsigned HOST_WIDE_INT) d
4184e4b17023SJohn Marino : - (unsigned HOST_WIDE_INT) d);
4185e4b17023SJohn Marino
4186e4b17023SJohn Marino /* n rem d = n rem -d */
4187e4b17023SJohn Marino if (rem_flag && d < 0)
4188e4b17023SJohn Marino {
4189e4b17023SJohn Marino d = abs_d;
4190e4b17023SJohn Marino op1 = gen_int_mode (abs_d, compute_mode);
4191e4b17023SJohn Marino }
4192e4b17023SJohn Marino
4193e4b17023SJohn Marino if (d == 1)
4194e4b17023SJohn Marino quotient = op0;
4195e4b17023SJohn Marino else if (d == -1)
4196e4b17023SJohn Marino quotient = expand_unop (compute_mode, neg_optab, op0,
4197e4b17023SJohn Marino tquotient, 0);
4198e4b17023SJohn Marino else if (HOST_BITS_PER_WIDE_INT >= size
4199e4b17023SJohn Marino && abs_d == (unsigned HOST_WIDE_INT) 1 << (size - 1))
4200e4b17023SJohn Marino {
4201e4b17023SJohn Marino /* This case is not handled correctly below. */
4202e4b17023SJohn Marino quotient = emit_store_flag (tquotient, EQ, op0, op1,
4203e4b17023SJohn Marino compute_mode, 1, 1);
4204e4b17023SJohn Marino if (quotient == 0)
4205e4b17023SJohn Marino goto fail1;
4206e4b17023SJohn Marino }
4207e4b17023SJohn Marino else if (EXACT_POWER_OF_2_OR_ZERO_P (d)
4208e4b17023SJohn Marino && (rem_flag ? smod_pow2_cheap[speed][compute_mode]
4209e4b17023SJohn Marino : sdiv_pow2_cheap[speed][compute_mode])
4210e4b17023SJohn Marino /* We assume that cheap metric is true if the
4211e4b17023SJohn Marino optab has an expander for this mode. */
4212e4b17023SJohn Marino && ((optab_handler ((rem_flag ? smod_optab
4213e4b17023SJohn Marino : sdiv_optab),
4214e4b17023SJohn Marino compute_mode)
4215e4b17023SJohn Marino != CODE_FOR_nothing)
4216e4b17023SJohn Marino || (optab_handler (sdivmod_optab,
4217e4b17023SJohn Marino compute_mode)
4218e4b17023SJohn Marino != CODE_FOR_nothing)))
4219e4b17023SJohn Marino ;
4220e4b17023SJohn Marino else if (EXACT_POWER_OF_2_OR_ZERO_P (abs_d))
4221e4b17023SJohn Marino {
4222e4b17023SJohn Marino if (rem_flag)
4223e4b17023SJohn Marino {
4224e4b17023SJohn Marino remainder = expand_smod_pow2 (compute_mode, op0, d);
4225e4b17023SJohn Marino if (remainder)
4226e4b17023SJohn Marino return gen_lowpart (mode, remainder);
4227e4b17023SJohn Marino }
4228e4b17023SJohn Marino
4229e4b17023SJohn Marino if (sdiv_pow2_cheap[speed][compute_mode]
4230e4b17023SJohn Marino && ((optab_handler (sdiv_optab, compute_mode)
4231e4b17023SJohn Marino != CODE_FOR_nothing)
4232e4b17023SJohn Marino || (optab_handler (sdivmod_optab, compute_mode)
4233e4b17023SJohn Marino != CODE_FOR_nothing)))
4234e4b17023SJohn Marino quotient = expand_divmod (0, TRUNC_DIV_EXPR,
4235e4b17023SJohn Marino compute_mode, op0,
4236e4b17023SJohn Marino gen_int_mode (abs_d,
4237e4b17023SJohn Marino compute_mode),
4238e4b17023SJohn Marino NULL_RTX, 0);
4239e4b17023SJohn Marino else
4240e4b17023SJohn Marino quotient = expand_sdiv_pow2 (compute_mode, op0, abs_d);
4241e4b17023SJohn Marino
4242e4b17023SJohn Marino /* We have computed OP0 / abs(OP1). If OP1 is negative,
4243e4b17023SJohn Marino negate the quotient. */
4244e4b17023SJohn Marino if (d < 0)
4245e4b17023SJohn Marino {
4246e4b17023SJohn Marino insn = get_last_insn ();
4247e4b17023SJohn Marino if (insn != last
4248e4b17023SJohn Marino && abs_d < ((unsigned HOST_WIDE_INT) 1
4249e4b17023SJohn Marino << (HOST_BITS_PER_WIDE_INT - 1)))
4250e4b17023SJohn Marino set_dst_reg_note (insn, REG_EQUAL,
4251e4b17023SJohn Marino gen_rtx_DIV (compute_mode, op0,
4252e4b17023SJohn Marino gen_int_mode
4253e4b17023SJohn Marino (abs_d,
4254e4b17023SJohn Marino compute_mode)),
4255e4b17023SJohn Marino quotient);
4256e4b17023SJohn Marino
4257e4b17023SJohn Marino quotient = expand_unop (compute_mode, neg_optab,
4258e4b17023SJohn Marino quotient, quotient, 0);
4259e4b17023SJohn Marino }
4260e4b17023SJohn Marino }
4261e4b17023SJohn Marino else if (size <= HOST_BITS_PER_WIDE_INT)
4262e4b17023SJohn Marino {
4263e4b17023SJohn Marino choose_multiplier (abs_d, size, size - 1,
4264e4b17023SJohn Marino &mlr, &post_shift, &lgup);
4265e4b17023SJohn Marino ml = (unsigned HOST_WIDE_INT) INTVAL (mlr);
4266e4b17023SJohn Marino if (ml < (unsigned HOST_WIDE_INT) 1 << (size - 1))
4267e4b17023SJohn Marino {
4268e4b17023SJohn Marino rtx t1, t2, t3;
4269e4b17023SJohn Marino
4270e4b17023SJohn Marino if (post_shift >= BITS_PER_WORD
4271e4b17023SJohn Marino || size - 1 >= BITS_PER_WORD)
4272e4b17023SJohn Marino goto fail1;
4273e4b17023SJohn Marino
4274e4b17023SJohn Marino extra_cost = (shift_cost[speed][compute_mode][post_shift]
4275e4b17023SJohn Marino + shift_cost[speed][compute_mode][size - 1]
4276e4b17023SJohn Marino + add_cost[speed][compute_mode]);
4277e4b17023SJohn Marino t1 = expand_mult_highpart (compute_mode, op0, mlr,
4278e4b17023SJohn Marino NULL_RTX, 0,
4279e4b17023SJohn Marino max_cost - extra_cost);
4280e4b17023SJohn Marino if (t1 == 0)
4281e4b17023SJohn Marino goto fail1;
4282e4b17023SJohn Marino t2 = expand_shift
4283e4b17023SJohn Marino (RSHIFT_EXPR, compute_mode, t1,
4284e4b17023SJohn Marino post_shift, NULL_RTX, 0);
4285e4b17023SJohn Marino t3 = expand_shift
4286e4b17023SJohn Marino (RSHIFT_EXPR, compute_mode, op0,
4287e4b17023SJohn Marino size - 1, NULL_RTX, 0);
4288e4b17023SJohn Marino if (d < 0)
4289e4b17023SJohn Marino quotient
4290e4b17023SJohn Marino = force_operand (gen_rtx_MINUS (compute_mode,
4291e4b17023SJohn Marino t3, t2),
4292e4b17023SJohn Marino tquotient);
4293e4b17023SJohn Marino else
4294e4b17023SJohn Marino quotient
4295e4b17023SJohn Marino = force_operand (gen_rtx_MINUS (compute_mode,
4296e4b17023SJohn Marino t2, t3),
4297e4b17023SJohn Marino tquotient);
4298e4b17023SJohn Marino }
4299e4b17023SJohn Marino else
4300e4b17023SJohn Marino {
4301e4b17023SJohn Marino rtx t1, t2, t3, t4;
4302e4b17023SJohn Marino
4303e4b17023SJohn Marino if (post_shift >= BITS_PER_WORD
4304e4b17023SJohn Marino || size - 1 >= BITS_PER_WORD)
4305e4b17023SJohn Marino goto fail1;
4306e4b17023SJohn Marino
4307e4b17023SJohn Marino ml |= (~(unsigned HOST_WIDE_INT) 0) << (size - 1);
4308e4b17023SJohn Marino mlr = gen_int_mode (ml, compute_mode);
4309e4b17023SJohn Marino extra_cost = (shift_cost[speed][compute_mode][post_shift]
4310e4b17023SJohn Marino + shift_cost[speed][compute_mode][size - 1]
4311e4b17023SJohn Marino + 2 * add_cost[speed][compute_mode]);
4312e4b17023SJohn Marino t1 = expand_mult_highpart (compute_mode, op0, mlr,
4313e4b17023SJohn Marino NULL_RTX, 0,
4314e4b17023SJohn Marino max_cost - extra_cost);
4315e4b17023SJohn Marino if (t1 == 0)
4316e4b17023SJohn Marino goto fail1;
4317e4b17023SJohn Marino t2 = force_operand (gen_rtx_PLUS (compute_mode,
4318e4b17023SJohn Marino t1, op0),
4319e4b17023SJohn Marino NULL_RTX);
4320e4b17023SJohn Marino t3 = expand_shift
4321e4b17023SJohn Marino (RSHIFT_EXPR, compute_mode, t2,
4322e4b17023SJohn Marino post_shift, NULL_RTX, 0);
4323e4b17023SJohn Marino t4 = expand_shift
4324e4b17023SJohn Marino (RSHIFT_EXPR, compute_mode, op0,
4325e4b17023SJohn Marino size - 1, NULL_RTX, 0);
4326e4b17023SJohn Marino if (d < 0)
4327e4b17023SJohn Marino quotient
4328e4b17023SJohn Marino = force_operand (gen_rtx_MINUS (compute_mode,
4329e4b17023SJohn Marino t4, t3),
4330e4b17023SJohn Marino tquotient);
4331e4b17023SJohn Marino else
4332e4b17023SJohn Marino quotient
4333e4b17023SJohn Marino = force_operand (gen_rtx_MINUS (compute_mode,
4334e4b17023SJohn Marino t3, t4),
4335e4b17023SJohn Marino tquotient);
4336e4b17023SJohn Marino }
4337e4b17023SJohn Marino }
4338e4b17023SJohn Marino else /* Too wide mode to use tricky code */
4339e4b17023SJohn Marino break;
4340e4b17023SJohn Marino
4341e4b17023SJohn Marino insn = get_last_insn ();
4342e4b17023SJohn Marino if (insn != last)
4343e4b17023SJohn Marino set_dst_reg_note (insn, REG_EQUAL,
4344e4b17023SJohn Marino gen_rtx_DIV (compute_mode, op0, op1),
4345e4b17023SJohn Marino quotient);
4346e4b17023SJohn Marino }
4347e4b17023SJohn Marino break;
4348e4b17023SJohn Marino }
4349e4b17023SJohn Marino fail1:
4350e4b17023SJohn Marino delete_insns_since (last);
4351e4b17023SJohn Marino break;
4352e4b17023SJohn Marino
4353e4b17023SJohn Marino case FLOOR_DIV_EXPR:
4354e4b17023SJohn Marino case FLOOR_MOD_EXPR:
4355e4b17023SJohn Marino /* We will come here only for signed operations. */
4356e4b17023SJohn Marino if (op1_is_constant && HOST_BITS_PER_WIDE_INT >= size)
4357e4b17023SJohn Marino {
4358e4b17023SJohn Marino unsigned HOST_WIDE_INT mh;
4359e4b17023SJohn Marino int pre_shift, lgup, post_shift;
4360e4b17023SJohn Marino HOST_WIDE_INT d = INTVAL (op1);
4361e4b17023SJohn Marino rtx ml;
4362e4b17023SJohn Marino
4363e4b17023SJohn Marino if (d > 0)
4364e4b17023SJohn Marino {
4365e4b17023SJohn Marino /* We could just as easily deal with negative constants here,
4366e4b17023SJohn Marino but it does not seem worth the trouble for GCC 2.6. */
4367e4b17023SJohn Marino if (EXACT_POWER_OF_2_OR_ZERO_P (d))
4368e4b17023SJohn Marino {
4369e4b17023SJohn Marino pre_shift = floor_log2 (d);
4370e4b17023SJohn Marino if (rem_flag)
4371e4b17023SJohn Marino {
4372e4b17023SJohn Marino remainder = expand_binop (compute_mode, and_optab, op0,
4373e4b17023SJohn Marino GEN_INT (((HOST_WIDE_INT) 1 << pre_shift) - 1),
4374e4b17023SJohn Marino remainder, 0, OPTAB_LIB_WIDEN);
4375e4b17023SJohn Marino if (remainder)
4376e4b17023SJohn Marino return gen_lowpart (mode, remainder);
4377e4b17023SJohn Marino }
4378e4b17023SJohn Marino quotient = expand_shift
4379e4b17023SJohn Marino (RSHIFT_EXPR, compute_mode, op0,
4380e4b17023SJohn Marino pre_shift, tquotient, 0);
4381e4b17023SJohn Marino }
4382e4b17023SJohn Marino else
4383e4b17023SJohn Marino {
4384e4b17023SJohn Marino rtx t1, t2, t3, t4;
4385e4b17023SJohn Marino
4386e4b17023SJohn Marino mh = choose_multiplier (d, size, size - 1,
4387e4b17023SJohn Marino &ml, &post_shift, &lgup);
4388e4b17023SJohn Marino gcc_assert (!mh);
4389e4b17023SJohn Marino
4390e4b17023SJohn Marino if (post_shift < BITS_PER_WORD
4391e4b17023SJohn Marino && size - 1 < BITS_PER_WORD)
4392e4b17023SJohn Marino {
4393e4b17023SJohn Marino t1 = expand_shift
4394e4b17023SJohn Marino (RSHIFT_EXPR, compute_mode, op0,
4395e4b17023SJohn Marino size - 1, NULL_RTX, 0);
4396e4b17023SJohn Marino t2 = expand_binop (compute_mode, xor_optab, op0, t1,
4397e4b17023SJohn Marino NULL_RTX, 0, OPTAB_WIDEN);
4398e4b17023SJohn Marino extra_cost = (shift_cost[speed][compute_mode][post_shift]
4399e4b17023SJohn Marino + shift_cost[speed][compute_mode][size - 1]
4400e4b17023SJohn Marino + 2 * add_cost[speed][compute_mode]);
4401e4b17023SJohn Marino t3 = expand_mult_highpart (compute_mode, t2, ml,
4402e4b17023SJohn Marino NULL_RTX, 1,
4403e4b17023SJohn Marino max_cost - extra_cost);
4404e4b17023SJohn Marino if (t3 != 0)
4405e4b17023SJohn Marino {
4406e4b17023SJohn Marino t4 = expand_shift
4407e4b17023SJohn Marino (RSHIFT_EXPR, compute_mode, t3,
4408e4b17023SJohn Marino post_shift, NULL_RTX, 1);
4409e4b17023SJohn Marino quotient = expand_binop (compute_mode, xor_optab,
4410e4b17023SJohn Marino t4, t1, tquotient, 0,
4411e4b17023SJohn Marino OPTAB_WIDEN);
4412e4b17023SJohn Marino }
4413e4b17023SJohn Marino }
4414e4b17023SJohn Marino }
4415e4b17023SJohn Marino }
4416e4b17023SJohn Marino else
4417e4b17023SJohn Marino {
4418e4b17023SJohn Marino rtx nsign, t1, t2, t3, t4;
4419e4b17023SJohn Marino t1 = force_operand (gen_rtx_PLUS (compute_mode,
4420e4b17023SJohn Marino op0, constm1_rtx), NULL_RTX);
4421e4b17023SJohn Marino t2 = expand_binop (compute_mode, ior_optab, op0, t1, NULL_RTX,
4422e4b17023SJohn Marino 0, OPTAB_WIDEN);
4423e4b17023SJohn Marino nsign = expand_shift
4424e4b17023SJohn Marino (RSHIFT_EXPR, compute_mode, t2,
4425e4b17023SJohn Marino size - 1, NULL_RTX, 0);
4426e4b17023SJohn Marino t3 = force_operand (gen_rtx_MINUS (compute_mode, t1, nsign),
4427e4b17023SJohn Marino NULL_RTX);
4428e4b17023SJohn Marino t4 = expand_divmod (0, TRUNC_DIV_EXPR, compute_mode, t3, op1,
4429e4b17023SJohn Marino NULL_RTX, 0);
4430e4b17023SJohn Marino if (t4)
4431e4b17023SJohn Marino {
4432e4b17023SJohn Marino rtx t5;
4433e4b17023SJohn Marino t5 = expand_unop (compute_mode, one_cmpl_optab, nsign,
4434e4b17023SJohn Marino NULL_RTX, 0);
4435e4b17023SJohn Marino quotient = force_operand (gen_rtx_PLUS (compute_mode,
4436e4b17023SJohn Marino t4, t5),
4437e4b17023SJohn Marino tquotient);
4438e4b17023SJohn Marino }
4439e4b17023SJohn Marino }
4440e4b17023SJohn Marino }
4441e4b17023SJohn Marino
4442e4b17023SJohn Marino if (quotient != 0)
4443e4b17023SJohn Marino break;
4444e4b17023SJohn Marino delete_insns_since (last);
4445e4b17023SJohn Marino
4446e4b17023SJohn Marino /* Try using an instruction that produces both the quotient and
4447e4b17023SJohn Marino remainder, using truncation. We can easily compensate the quotient
4448e4b17023SJohn Marino or remainder to get floor rounding, once we have the remainder.
4449e4b17023SJohn Marino Notice that we compute also the final remainder value here,
4450e4b17023SJohn Marino and return the result right away. */
4451e4b17023SJohn Marino if (target == 0 || GET_MODE (target) != compute_mode)
4452e4b17023SJohn Marino target = gen_reg_rtx (compute_mode);
4453e4b17023SJohn Marino
4454e4b17023SJohn Marino if (rem_flag)
4455e4b17023SJohn Marino {
4456e4b17023SJohn Marino remainder
4457e4b17023SJohn Marino = REG_P (target) ? target : gen_reg_rtx (compute_mode);
4458e4b17023SJohn Marino quotient = gen_reg_rtx (compute_mode);
4459e4b17023SJohn Marino }
4460e4b17023SJohn Marino else
4461e4b17023SJohn Marino {
4462e4b17023SJohn Marino quotient
4463e4b17023SJohn Marino = REG_P (target) ? target : gen_reg_rtx (compute_mode);
4464e4b17023SJohn Marino remainder = gen_reg_rtx (compute_mode);
4465e4b17023SJohn Marino }
4466e4b17023SJohn Marino
4467e4b17023SJohn Marino if (expand_twoval_binop (sdivmod_optab, op0, op1,
4468e4b17023SJohn Marino quotient, remainder, 0))
4469e4b17023SJohn Marino {
4470e4b17023SJohn Marino /* This could be computed with a branch-less sequence.
4471e4b17023SJohn Marino Save that for later. */
4472e4b17023SJohn Marino rtx tem;
4473e4b17023SJohn Marino rtx label = gen_label_rtx ();
4474e4b17023SJohn Marino do_cmp_and_jump (remainder, const0_rtx, EQ, compute_mode, label);
4475e4b17023SJohn Marino tem = expand_binop (compute_mode, xor_optab, op0, op1,
4476e4b17023SJohn Marino NULL_RTX, 0, OPTAB_WIDEN);
4477e4b17023SJohn Marino do_cmp_and_jump (tem, const0_rtx, GE, compute_mode, label);
4478e4b17023SJohn Marino expand_dec (quotient, const1_rtx);
4479e4b17023SJohn Marino expand_inc (remainder, op1);
4480e4b17023SJohn Marino emit_label (label);
4481e4b17023SJohn Marino return gen_lowpart (mode, rem_flag ? remainder : quotient);
4482e4b17023SJohn Marino }
4483e4b17023SJohn Marino
4484e4b17023SJohn Marino /* No luck with division elimination or divmod. Have to do it
4485e4b17023SJohn Marino by conditionally adjusting op0 *and* the result. */
4486e4b17023SJohn Marino {
4487e4b17023SJohn Marino rtx label1, label2, label3, label4, label5;
4488e4b17023SJohn Marino rtx adjusted_op0;
4489e4b17023SJohn Marino rtx tem;
4490e4b17023SJohn Marino
4491e4b17023SJohn Marino quotient = gen_reg_rtx (compute_mode);
4492e4b17023SJohn Marino adjusted_op0 = copy_to_mode_reg (compute_mode, op0);
4493e4b17023SJohn Marino label1 = gen_label_rtx ();
4494e4b17023SJohn Marino label2 = gen_label_rtx ();
4495e4b17023SJohn Marino label3 = gen_label_rtx ();
4496e4b17023SJohn Marino label4 = gen_label_rtx ();
4497e4b17023SJohn Marino label5 = gen_label_rtx ();
4498e4b17023SJohn Marino do_cmp_and_jump (op1, const0_rtx, LT, compute_mode, label2);
4499e4b17023SJohn Marino do_cmp_and_jump (adjusted_op0, const0_rtx, LT, compute_mode, label1);
4500e4b17023SJohn Marino tem = expand_binop (compute_mode, sdiv_optab, adjusted_op0, op1,
4501e4b17023SJohn Marino quotient, 0, OPTAB_LIB_WIDEN);
4502e4b17023SJohn Marino if (tem != quotient)
4503e4b17023SJohn Marino emit_move_insn (quotient, tem);
4504e4b17023SJohn Marino emit_jump_insn (gen_jump (label5));
4505e4b17023SJohn Marino emit_barrier ();
4506e4b17023SJohn Marino emit_label (label1);
4507e4b17023SJohn Marino expand_inc (adjusted_op0, const1_rtx);
4508e4b17023SJohn Marino emit_jump_insn (gen_jump (label4));
4509e4b17023SJohn Marino emit_barrier ();
4510e4b17023SJohn Marino emit_label (label2);
4511e4b17023SJohn Marino do_cmp_and_jump (adjusted_op0, const0_rtx, GT, compute_mode, label3);
4512e4b17023SJohn Marino tem = expand_binop (compute_mode, sdiv_optab, adjusted_op0, op1,
4513e4b17023SJohn Marino quotient, 0, OPTAB_LIB_WIDEN);
4514e4b17023SJohn Marino if (tem != quotient)
4515e4b17023SJohn Marino emit_move_insn (quotient, tem);
4516e4b17023SJohn Marino emit_jump_insn (gen_jump (label5));
4517e4b17023SJohn Marino emit_barrier ();
4518e4b17023SJohn Marino emit_label (label3);
4519e4b17023SJohn Marino expand_dec (adjusted_op0, const1_rtx);
4520e4b17023SJohn Marino emit_label (label4);
4521e4b17023SJohn Marino tem = expand_binop (compute_mode, sdiv_optab, adjusted_op0, op1,
4522e4b17023SJohn Marino quotient, 0, OPTAB_LIB_WIDEN);
4523e4b17023SJohn Marino if (tem != quotient)
4524e4b17023SJohn Marino emit_move_insn (quotient, tem);
4525e4b17023SJohn Marino expand_dec (quotient, const1_rtx);
4526e4b17023SJohn Marino emit_label (label5);
4527e4b17023SJohn Marino }
4528e4b17023SJohn Marino break;
4529e4b17023SJohn Marino
4530e4b17023SJohn Marino case CEIL_DIV_EXPR:
4531e4b17023SJohn Marino case CEIL_MOD_EXPR:
4532e4b17023SJohn Marino if (unsignedp)
4533e4b17023SJohn Marino {
4534e4b17023SJohn Marino if (op1_is_constant && EXACT_POWER_OF_2_OR_ZERO_P (INTVAL (op1)))
4535e4b17023SJohn Marino {
4536e4b17023SJohn Marino rtx t1, t2, t3;
4537e4b17023SJohn Marino unsigned HOST_WIDE_INT d = INTVAL (op1);
4538e4b17023SJohn Marino t1 = expand_shift (RSHIFT_EXPR, compute_mode, op0,
4539e4b17023SJohn Marino floor_log2 (d), tquotient, 1);
4540e4b17023SJohn Marino t2 = expand_binop (compute_mode, and_optab, op0,
4541e4b17023SJohn Marino GEN_INT (d - 1),
4542e4b17023SJohn Marino NULL_RTX, 1, OPTAB_LIB_WIDEN);
4543e4b17023SJohn Marino t3 = gen_reg_rtx (compute_mode);
4544e4b17023SJohn Marino t3 = emit_store_flag (t3, NE, t2, const0_rtx,
4545e4b17023SJohn Marino compute_mode, 1, 1);
4546e4b17023SJohn Marino if (t3 == 0)
4547e4b17023SJohn Marino {
4548e4b17023SJohn Marino rtx lab;
4549e4b17023SJohn Marino lab = gen_label_rtx ();
4550e4b17023SJohn Marino do_cmp_and_jump (t2, const0_rtx, EQ, compute_mode, lab);
4551e4b17023SJohn Marino expand_inc (t1, const1_rtx);
4552e4b17023SJohn Marino emit_label (lab);
4553e4b17023SJohn Marino quotient = t1;
4554e4b17023SJohn Marino }
4555e4b17023SJohn Marino else
4556e4b17023SJohn Marino quotient = force_operand (gen_rtx_PLUS (compute_mode,
4557e4b17023SJohn Marino t1, t3),
4558e4b17023SJohn Marino tquotient);
4559e4b17023SJohn Marino break;
4560e4b17023SJohn Marino }
4561e4b17023SJohn Marino
4562e4b17023SJohn Marino /* Try using an instruction that produces both the quotient and
4563e4b17023SJohn Marino remainder, using truncation. We can easily compensate the
4564e4b17023SJohn Marino quotient or remainder to get ceiling rounding, once we have the
4565e4b17023SJohn Marino remainder. Notice that we compute also the final remainder
4566e4b17023SJohn Marino value here, and return the result right away. */
4567e4b17023SJohn Marino if (target == 0 || GET_MODE (target) != compute_mode)
4568e4b17023SJohn Marino target = gen_reg_rtx (compute_mode);
4569e4b17023SJohn Marino
4570e4b17023SJohn Marino if (rem_flag)
4571e4b17023SJohn Marino {
4572e4b17023SJohn Marino remainder = (REG_P (target)
4573e4b17023SJohn Marino ? target : gen_reg_rtx (compute_mode));
4574e4b17023SJohn Marino quotient = gen_reg_rtx (compute_mode);
4575e4b17023SJohn Marino }
4576e4b17023SJohn Marino else
4577e4b17023SJohn Marino {
4578e4b17023SJohn Marino quotient = (REG_P (target)
4579e4b17023SJohn Marino ? target : gen_reg_rtx (compute_mode));
4580e4b17023SJohn Marino remainder = gen_reg_rtx (compute_mode);
4581e4b17023SJohn Marino }
4582e4b17023SJohn Marino
4583e4b17023SJohn Marino if (expand_twoval_binop (udivmod_optab, op0, op1, quotient,
4584e4b17023SJohn Marino remainder, 1))
4585e4b17023SJohn Marino {
4586e4b17023SJohn Marino /* This could be computed with a branch-less sequence.
4587e4b17023SJohn Marino Save that for later. */
4588e4b17023SJohn Marino rtx label = gen_label_rtx ();
4589e4b17023SJohn Marino do_cmp_and_jump (remainder, const0_rtx, EQ,
4590e4b17023SJohn Marino compute_mode, label);
4591e4b17023SJohn Marino expand_inc (quotient, const1_rtx);
4592e4b17023SJohn Marino expand_dec (remainder, op1);
4593e4b17023SJohn Marino emit_label (label);
4594e4b17023SJohn Marino return gen_lowpart (mode, rem_flag ? remainder : quotient);
4595e4b17023SJohn Marino }
4596e4b17023SJohn Marino
4597e4b17023SJohn Marino /* No luck with division elimination or divmod. Have to do it
4598e4b17023SJohn Marino by conditionally adjusting op0 *and* the result. */
4599e4b17023SJohn Marino {
4600e4b17023SJohn Marino rtx label1, label2;
4601e4b17023SJohn Marino rtx adjusted_op0, tem;
4602e4b17023SJohn Marino
4603e4b17023SJohn Marino quotient = gen_reg_rtx (compute_mode);
4604e4b17023SJohn Marino adjusted_op0 = copy_to_mode_reg (compute_mode, op0);
4605e4b17023SJohn Marino label1 = gen_label_rtx ();
4606e4b17023SJohn Marino label2 = gen_label_rtx ();
4607e4b17023SJohn Marino do_cmp_and_jump (adjusted_op0, const0_rtx, NE,
4608e4b17023SJohn Marino compute_mode, label1);
4609e4b17023SJohn Marino emit_move_insn (quotient, const0_rtx);
4610e4b17023SJohn Marino emit_jump_insn (gen_jump (label2));
4611e4b17023SJohn Marino emit_barrier ();
4612e4b17023SJohn Marino emit_label (label1);
4613e4b17023SJohn Marino expand_dec (adjusted_op0, const1_rtx);
4614e4b17023SJohn Marino tem = expand_binop (compute_mode, udiv_optab, adjusted_op0, op1,
4615e4b17023SJohn Marino quotient, 1, OPTAB_LIB_WIDEN);
4616e4b17023SJohn Marino if (tem != quotient)
4617e4b17023SJohn Marino emit_move_insn (quotient, tem);
4618e4b17023SJohn Marino expand_inc (quotient, const1_rtx);
4619e4b17023SJohn Marino emit_label (label2);
4620e4b17023SJohn Marino }
4621e4b17023SJohn Marino }
4622e4b17023SJohn Marino else /* signed */
4623e4b17023SJohn Marino {
4624e4b17023SJohn Marino if (op1_is_constant && EXACT_POWER_OF_2_OR_ZERO_P (INTVAL (op1))
4625e4b17023SJohn Marino && INTVAL (op1) >= 0)
4626e4b17023SJohn Marino {
4627e4b17023SJohn Marino /* This is extremely similar to the code for the unsigned case
4628e4b17023SJohn Marino above. For 2.7 we should merge these variants, but for
4629e4b17023SJohn Marino 2.6.1 I don't want to touch the code for unsigned since that
4630e4b17023SJohn Marino get used in C. The signed case will only be used by other
4631e4b17023SJohn Marino languages (Ada). */
4632e4b17023SJohn Marino
4633e4b17023SJohn Marino rtx t1, t2, t3;
4634e4b17023SJohn Marino unsigned HOST_WIDE_INT d = INTVAL (op1);
4635e4b17023SJohn Marino t1 = expand_shift (RSHIFT_EXPR, compute_mode, op0,
4636e4b17023SJohn Marino floor_log2 (d), tquotient, 0);
4637e4b17023SJohn Marino t2 = expand_binop (compute_mode, and_optab, op0,
4638e4b17023SJohn Marino GEN_INT (d - 1),
4639e4b17023SJohn Marino NULL_RTX, 1, OPTAB_LIB_WIDEN);
4640e4b17023SJohn Marino t3 = gen_reg_rtx (compute_mode);
4641e4b17023SJohn Marino t3 = emit_store_flag (t3, NE, t2, const0_rtx,
4642e4b17023SJohn Marino compute_mode, 1, 1);
4643e4b17023SJohn Marino if (t3 == 0)
4644e4b17023SJohn Marino {
4645e4b17023SJohn Marino rtx lab;
4646e4b17023SJohn Marino lab = gen_label_rtx ();
4647e4b17023SJohn Marino do_cmp_and_jump (t2, const0_rtx, EQ, compute_mode, lab);
4648e4b17023SJohn Marino expand_inc (t1, const1_rtx);
4649e4b17023SJohn Marino emit_label (lab);
4650e4b17023SJohn Marino quotient = t1;
4651e4b17023SJohn Marino }
4652e4b17023SJohn Marino else
4653e4b17023SJohn Marino quotient = force_operand (gen_rtx_PLUS (compute_mode,
4654e4b17023SJohn Marino t1, t3),
4655e4b17023SJohn Marino tquotient);
4656e4b17023SJohn Marino break;
4657e4b17023SJohn Marino }
4658e4b17023SJohn Marino
4659e4b17023SJohn Marino /* Try using an instruction that produces both the quotient and
4660e4b17023SJohn Marino remainder, using truncation. We can easily compensate the
4661e4b17023SJohn Marino quotient or remainder to get ceiling rounding, once we have the
4662e4b17023SJohn Marino remainder. Notice that we compute also the final remainder
4663e4b17023SJohn Marino value here, and return the result right away. */
4664e4b17023SJohn Marino if (target == 0 || GET_MODE (target) != compute_mode)
4665e4b17023SJohn Marino target = gen_reg_rtx (compute_mode);
4666e4b17023SJohn Marino if (rem_flag)
4667e4b17023SJohn Marino {
4668e4b17023SJohn Marino remainder= (REG_P (target)
4669e4b17023SJohn Marino ? target : gen_reg_rtx (compute_mode));
4670e4b17023SJohn Marino quotient = gen_reg_rtx (compute_mode);
4671e4b17023SJohn Marino }
4672e4b17023SJohn Marino else
4673e4b17023SJohn Marino {
4674e4b17023SJohn Marino quotient = (REG_P (target)
4675e4b17023SJohn Marino ? target : gen_reg_rtx (compute_mode));
4676e4b17023SJohn Marino remainder = gen_reg_rtx (compute_mode);
4677e4b17023SJohn Marino }
4678e4b17023SJohn Marino
4679e4b17023SJohn Marino if (expand_twoval_binop (sdivmod_optab, op0, op1, quotient,
4680e4b17023SJohn Marino remainder, 0))
4681e4b17023SJohn Marino {
4682e4b17023SJohn Marino /* This could be computed with a branch-less sequence.
4683e4b17023SJohn Marino Save that for later. */
4684e4b17023SJohn Marino rtx tem;
4685e4b17023SJohn Marino rtx label = gen_label_rtx ();
4686e4b17023SJohn Marino do_cmp_and_jump (remainder, const0_rtx, EQ,
4687e4b17023SJohn Marino compute_mode, label);
4688e4b17023SJohn Marino tem = expand_binop (compute_mode, xor_optab, op0, op1,
4689e4b17023SJohn Marino NULL_RTX, 0, OPTAB_WIDEN);
4690e4b17023SJohn Marino do_cmp_and_jump (tem, const0_rtx, LT, compute_mode, label);
4691e4b17023SJohn Marino expand_inc (quotient, const1_rtx);
4692e4b17023SJohn Marino expand_dec (remainder, op1);
4693e4b17023SJohn Marino emit_label (label);
4694e4b17023SJohn Marino return gen_lowpart (mode, rem_flag ? remainder : quotient);
4695e4b17023SJohn Marino }
4696e4b17023SJohn Marino
4697e4b17023SJohn Marino /* No luck with division elimination or divmod. Have to do it
4698e4b17023SJohn Marino by conditionally adjusting op0 *and* the result. */
4699e4b17023SJohn Marino {
4700e4b17023SJohn Marino rtx label1, label2, label3, label4, label5;
4701e4b17023SJohn Marino rtx adjusted_op0;
4702e4b17023SJohn Marino rtx tem;
4703e4b17023SJohn Marino
4704e4b17023SJohn Marino quotient = gen_reg_rtx (compute_mode);
4705e4b17023SJohn Marino adjusted_op0 = copy_to_mode_reg (compute_mode, op0);
4706e4b17023SJohn Marino label1 = gen_label_rtx ();
4707e4b17023SJohn Marino label2 = gen_label_rtx ();
4708e4b17023SJohn Marino label3 = gen_label_rtx ();
4709e4b17023SJohn Marino label4 = gen_label_rtx ();
4710e4b17023SJohn Marino label5 = gen_label_rtx ();
4711e4b17023SJohn Marino do_cmp_and_jump (op1, const0_rtx, LT, compute_mode, label2);
4712e4b17023SJohn Marino do_cmp_and_jump (adjusted_op0, const0_rtx, GT,
4713e4b17023SJohn Marino compute_mode, label1);
4714e4b17023SJohn Marino tem = expand_binop (compute_mode, sdiv_optab, adjusted_op0, op1,
4715e4b17023SJohn Marino quotient, 0, OPTAB_LIB_WIDEN);
4716e4b17023SJohn Marino if (tem != quotient)
4717e4b17023SJohn Marino emit_move_insn (quotient, tem);
4718e4b17023SJohn Marino emit_jump_insn (gen_jump (label5));
4719e4b17023SJohn Marino emit_barrier ();
4720e4b17023SJohn Marino emit_label (label1);
4721e4b17023SJohn Marino expand_dec (adjusted_op0, const1_rtx);
4722e4b17023SJohn Marino emit_jump_insn (gen_jump (label4));
4723e4b17023SJohn Marino emit_barrier ();
4724e4b17023SJohn Marino emit_label (label2);
4725e4b17023SJohn Marino do_cmp_and_jump (adjusted_op0, const0_rtx, LT,
4726e4b17023SJohn Marino compute_mode, label3);
4727e4b17023SJohn Marino tem = expand_binop (compute_mode, sdiv_optab, adjusted_op0, op1,
4728e4b17023SJohn Marino quotient, 0, OPTAB_LIB_WIDEN);
4729e4b17023SJohn Marino if (tem != quotient)
4730e4b17023SJohn Marino emit_move_insn (quotient, tem);
4731e4b17023SJohn Marino emit_jump_insn (gen_jump (label5));
4732e4b17023SJohn Marino emit_barrier ();
4733e4b17023SJohn Marino emit_label (label3);
4734e4b17023SJohn Marino expand_inc (adjusted_op0, const1_rtx);
4735e4b17023SJohn Marino emit_label (label4);
4736e4b17023SJohn Marino tem = expand_binop (compute_mode, sdiv_optab, adjusted_op0, op1,
4737e4b17023SJohn Marino quotient, 0, OPTAB_LIB_WIDEN);
4738e4b17023SJohn Marino if (tem != quotient)
4739e4b17023SJohn Marino emit_move_insn (quotient, tem);
4740e4b17023SJohn Marino expand_inc (quotient, const1_rtx);
4741e4b17023SJohn Marino emit_label (label5);
4742e4b17023SJohn Marino }
4743e4b17023SJohn Marino }
4744e4b17023SJohn Marino break;
4745e4b17023SJohn Marino
4746e4b17023SJohn Marino case EXACT_DIV_EXPR:
4747e4b17023SJohn Marino if (op1_is_constant && HOST_BITS_PER_WIDE_INT >= size)
4748e4b17023SJohn Marino {
4749e4b17023SJohn Marino HOST_WIDE_INT d = INTVAL (op1);
4750e4b17023SJohn Marino unsigned HOST_WIDE_INT ml;
4751e4b17023SJohn Marino int pre_shift;
4752e4b17023SJohn Marino rtx t1;
4753e4b17023SJohn Marino
4754e4b17023SJohn Marino pre_shift = floor_log2 (d & -d);
4755e4b17023SJohn Marino ml = invert_mod2n (d >> pre_shift, size);
4756e4b17023SJohn Marino t1 = expand_shift (RSHIFT_EXPR, compute_mode, op0,
4757e4b17023SJohn Marino pre_shift, NULL_RTX, unsignedp);
4758e4b17023SJohn Marino quotient = expand_mult (compute_mode, t1,
4759e4b17023SJohn Marino gen_int_mode (ml, compute_mode),
4760e4b17023SJohn Marino NULL_RTX, 1);
4761e4b17023SJohn Marino
4762e4b17023SJohn Marino insn = get_last_insn ();
4763e4b17023SJohn Marino set_dst_reg_note (insn, REG_EQUAL,
4764e4b17023SJohn Marino gen_rtx_fmt_ee (unsignedp ? UDIV : DIV,
4765e4b17023SJohn Marino compute_mode, op0, op1),
4766e4b17023SJohn Marino quotient);
4767e4b17023SJohn Marino }
4768e4b17023SJohn Marino break;
4769e4b17023SJohn Marino
4770e4b17023SJohn Marino case ROUND_DIV_EXPR:
4771e4b17023SJohn Marino case ROUND_MOD_EXPR:
4772e4b17023SJohn Marino if (unsignedp)
4773e4b17023SJohn Marino {
4774e4b17023SJohn Marino rtx tem;
4775e4b17023SJohn Marino rtx label;
4776e4b17023SJohn Marino label = gen_label_rtx ();
4777e4b17023SJohn Marino quotient = gen_reg_rtx (compute_mode);
4778e4b17023SJohn Marino remainder = gen_reg_rtx (compute_mode);
4779e4b17023SJohn Marino if (expand_twoval_binop (udivmod_optab, op0, op1, quotient, remainder, 1) == 0)
4780e4b17023SJohn Marino {
4781e4b17023SJohn Marino rtx tem;
4782e4b17023SJohn Marino quotient = expand_binop (compute_mode, udiv_optab, op0, op1,
4783e4b17023SJohn Marino quotient, 1, OPTAB_LIB_WIDEN);
4784e4b17023SJohn Marino tem = expand_mult (compute_mode, quotient, op1, NULL_RTX, 1);
4785e4b17023SJohn Marino remainder = expand_binop (compute_mode, sub_optab, op0, tem,
4786e4b17023SJohn Marino remainder, 1, OPTAB_LIB_WIDEN);
4787e4b17023SJohn Marino }
4788e4b17023SJohn Marino tem = plus_constant (op1, -1);
4789e4b17023SJohn Marino tem = expand_shift (RSHIFT_EXPR, compute_mode, tem, 1, NULL_RTX, 1);
4790e4b17023SJohn Marino do_cmp_and_jump (remainder, tem, LEU, compute_mode, label);
4791e4b17023SJohn Marino expand_inc (quotient, const1_rtx);
4792e4b17023SJohn Marino expand_dec (remainder, op1);
4793e4b17023SJohn Marino emit_label (label);
4794e4b17023SJohn Marino }
4795e4b17023SJohn Marino else
4796e4b17023SJohn Marino {
4797e4b17023SJohn Marino rtx abs_rem, abs_op1, tem, mask;
4798e4b17023SJohn Marino rtx label;
4799e4b17023SJohn Marino label = gen_label_rtx ();
4800e4b17023SJohn Marino quotient = gen_reg_rtx (compute_mode);
4801e4b17023SJohn Marino remainder = gen_reg_rtx (compute_mode);
4802e4b17023SJohn Marino if (expand_twoval_binop (sdivmod_optab, op0, op1, quotient, remainder, 0) == 0)
4803e4b17023SJohn Marino {
4804e4b17023SJohn Marino rtx tem;
4805e4b17023SJohn Marino quotient = expand_binop (compute_mode, sdiv_optab, op0, op1,
4806e4b17023SJohn Marino quotient, 0, OPTAB_LIB_WIDEN);
4807e4b17023SJohn Marino tem = expand_mult (compute_mode, quotient, op1, NULL_RTX, 0);
4808e4b17023SJohn Marino remainder = expand_binop (compute_mode, sub_optab, op0, tem,
4809e4b17023SJohn Marino remainder, 0, OPTAB_LIB_WIDEN);
4810e4b17023SJohn Marino }
4811e4b17023SJohn Marino abs_rem = expand_abs (compute_mode, remainder, NULL_RTX, 1, 0);
4812e4b17023SJohn Marino abs_op1 = expand_abs (compute_mode, op1, NULL_RTX, 1, 0);
4813e4b17023SJohn Marino tem = expand_shift (LSHIFT_EXPR, compute_mode, abs_rem,
4814e4b17023SJohn Marino 1, NULL_RTX, 1);
4815e4b17023SJohn Marino do_cmp_and_jump (tem, abs_op1, LTU, compute_mode, label);
4816e4b17023SJohn Marino tem = expand_binop (compute_mode, xor_optab, op0, op1,
4817e4b17023SJohn Marino NULL_RTX, 0, OPTAB_WIDEN);
4818e4b17023SJohn Marino mask = expand_shift (RSHIFT_EXPR, compute_mode, tem,
4819e4b17023SJohn Marino size - 1, NULL_RTX, 0);
4820e4b17023SJohn Marino tem = expand_binop (compute_mode, xor_optab, mask, const1_rtx,
4821e4b17023SJohn Marino NULL_RTX, 0, OPTAB_WIDEN);
4822e4b17023SJohn Marino tem = expand_binop (compute_mode, sub_optab, tem, mask,
4823e4b17023SJohn Marino NULL_RTX, 0, OPTAB_WIDEN);
4824e4b17023SJohn Marino expand_inc (quotient, tem);
4825e4b17023SJohn Marino tem = expand_binop (compute_mode, xor_optab, mask, op1,
4826e4b17023SJohn Marino NULL_RTX, 0, OPTAB_WIDEN);
4827e4b17023SJohn Marino tem = expand_binop (compute_mode, sub_optab, tem, mask,
4828e4b17023SJohn Marino NULL_RTX, 0, OPTAB_WIDEN);
4829e4b17023SJohn Marino expand_dec (remainder, tem);
4830e4b17023SJohn Marino emit_label (label);
4831e4b17023SJohn Marino }
4832e4b17023SJohn Marino return gen_lowpart (mode, rem_flag ? remainder : quotient);
4833e4b17023SJohn Marino
4834e4b17023SJohn Marino default:
4835e4b17023SJohn Marino gcc_unreachable ();
4836e4b17023SJohn Marino }
4837e4b17023SJohn Marino
4838e4b17023SJohn Marino if (quotient == 0)
4839e4b17023SJohn Marino {
4840e4b17023SJohn Marino if (target && GET_MODE (target) != compute_mode)
4841e4b17023SJohn Marino target = 0;
4842e4b17023SJohn Marino
4843e4b17023SJohn Marino if (rem_flag)
4844e4b17023SJohn Marino {
4845e4b17023SJohn Marino /* Try to produce the remainder without producing the quotient.
4846e4b17023SJohn Marino If we seem to have a divmod pattern that does not require widening,
4847e4b17023SJohn Marino don't try widening here. We should really have a WIDEN argument
4848e4b17023SJohn Marino to expand_twoval_binop, since what we'd really like to do here is
4849e4b17023SJohn Marino 1) try a mod insn in compute_mode
4850e4b17023SJohn Marino 2) try a divmod insn in compute_mode
4851e4b17023SJohn Marino 3) try a div insn in compute_mode and multiply-subtract to get
4852e4b17023SJohn Marino remainder
4853e4b17023SJohn Marino 4) try the same things with widening allowed. */
4854e4b17023SJohn Marino remainder
4855e4b17023SJohn Marino = sign_expand_binop (compute_mode, umod_optab, smod_optab,
4856e4b17023SJohn Marino op0, op1, target,
4857e4b17023SJohn Marino unsignedp,
4858e4b17023SJohn Marino ((optab_handler (optab2, compute_mode)
4859e4b17023SJohn Marino != CODE_FOR_nothing)
4860e4b17023SJohn Marino ? OPTAB_DIRECT : OPTAB_WIDEN));
4861e4b17023SJohn Marino if (remainder == 0)
4862e4b17023SJohn Marino {
4863e4b17023SJohn Marino /* No luck there. Can we do remainder and divide at once
4864e4b17023SJohn Marino without a library call? */
4865e4b17023SJohn Marino remainder = gen_reg_rtx (compute_mode);
4866e4b17023SJohn Marino if (! expand_twoval_binop ((unsignedp
4867e4b17023SJohn Marino ? udivmod_optab
4868e4b17023SJohn Marino : sdivmod_optab),
4869e4b17023SJohn Marino op0, op1,
4870e4b17023SJohn Marino NULL_RTX, remainder, unsignedp))
4871e4b17023SJohn Marino remainder = 0;
4872e4b17023SJohn Marino }
4873e4b17023SJohn Marino
4874e4b17023SJohn Marino if (remainder)
4875e4b17023SJohn Marino return gen_lowpart (mode, remainder);
4876e4b17023SJohn Marino }
4877e4b17023SJohn Marino
4878e4b17023SJohn Marino /* Produce the quotient. Try a quotient insn, but not a library call.
4879e4b17023SJohn Marino If we have a divmod in this mode, use it in preference to widening
4880e4b17023SJohn Marino the div (for this test we assume it will not fail). Note that optab2
4881e4b17023SJohn Marino is set to the one of the two optabs that the call below will use. */
4882e4b17023SJohn Marino quotient
4883e4b17023SJohn Marino = sign_expand_binop (compute_mode, udiv_optab, sdiv_optab,
4884e4b17023SJohn Marino op0, op1, rem_flag ? NULL_RTX : target,
4885e4b17023SJohn Marino unsignedp,
4886e4b17023SJohn Marino ((optab_handler (optab2, compute_mode)
4887e4b17023SJohn Marino != CODE_FOR_nothing)
4888e4b17023SJohn Marino ? OPTAB_DIRECT : OPTAB_WIDEN));
4889e4b17023SJohn Marino
4890e4b17023SJohn Marino if (quotient == 0)
4891e4b17023SJohn Marino {
4892e4b17023SJohn Marino /* No luck there. Try a quotient-and-remainder insn,
4893e4b17023SJohn Marino keeping the quotient alone. */
4894e4b17023SJohn Marino quotient = gen_reg_rtx (compute_mode);
4895e4b17023SJohn Marino if (! expand_twoval_binop (unsignedp ? udivmod_optab : sdivmod_optab,
4896e4b17023SJohn Marino op0, op1,
4897e4b17023SJohn Marino quotient, NULL_RTX, unsignedp))
4898e4b17023SJohn Marino {
4899e4b17023SJohn Marino quotient = 0;
4900e4b17023SJohn Marino if (! rem_flag)
4901e4b17023SJohn Marino /* Still no luck. If we are not computing the remainder,
4902e4b17023SJohn Marino use a library call for the quotient. */
4903e4b17023SJohn Marino quotient = sign_expand_binop (compute_mode,
4904e4b17023SJohn Marino udiv_optab, sdiv_optab,
4905e4b17023SJohn Marino op0, op1, target,
4906e4b17023SJohn Marino unsignedp, OPTAB_LIB_WIDEN);
4907e4b17023SJohn Marino }
4908e4b17023SJohn Marino }
4909e4b17023SJohn Marino }
4910e4b17023SJohn Marino
4911e4b17023SJohn Marino if (rem_flag)
4912e4b17023SJohn Marino {
4913e4b17023SJohn Marino if (target && GET_MODE (target) != compute_mode)
4914e4b17023SJohn Marino target = 0;
4915e4b17023SJohn Marino
4916e4b17023SJohn Marino if (quotient == 0)
4917e4b17023SJohn Marino {
4918e4b17023SJohn Marino /* No divide instruction either. Use library for remainder. */
4919e4b17023SJohn Marino remainder = sign_expand_binop (compute_mode, umod_optab, smod_optab,
4920e4b17023SJohn Marino op0, op1, target,
4921e4b17023SJohn Marino unsignedp, OPTAB_LIB_WIDEN);
4922e4b17023SJohn Marino /* No remainder function. Try a quotient-and-remainder
4923e4b17023SJohn Marino function, keeping the remainder. */
4924e4b17023SJohn Marino if (!remainder)
4925e4b17023SJohn Marino {
4926e4b17023SJohn Marino remainder = gen_reg_rtx (compute_mode);
4927e4b17023SJohn Marino if (!expand_twoval_binop_libfunc
4928e4b17023SJohn Marino (unsignedp ? udivmod_optab : sdivmod_optab,
4929e4b17023SJohn Marino op0, op1,
4930e4b17023SJohn Marino NULL_RTX, remainder,
4931e4b17023SJohn Marino unsignedp ? UMOD : MOD))
4932e4b17023SJohn Marino remainder = NULL_RTX;
4933e4b17023SJohn Marino }
4934e4b17023SJohn Marino }
4935e4b17023SJohn Marino else
4936e4b17023SJohn Marino {
4937e4b17023SJohn Marino /* We divided. Now finish doing X - Y * (X / Y). */
4938e4b17023SJohn Marino remainder = expand_mult (compute_mode, quotient, op1,
4939e4b17023SJohn Marino NULL_RTX, unsignedp);
4940e4b17023SJohn Marino remainder = expand_binop (compute_mode, sub_optab, op0,
4941e4b17023SJohn Marino remainder, target, unsignedp,
4942e4b17023SJohn Marino OPTAB_LIB_WIDEN);
4943e4b17023SJohn Marino }
4944e4b17023SJohn Marino }
4945e4b17023SJohn Marino
4946e4b17023SJohn Marino return gen_lowpart (mode, rem_flag ? remainder : quotient);
4947e4b17023SJohn Marino }
4948e4b17023SJohn Marino
4949e4b17023SJohn Marino /* Return a tree node with data type TYPE, describing the value of X.
4950e4b17023SJohn Marino Usually this is an VAR_DECL, if there is no obvious better choice.
4951e4b17023SJohn Marino X may be an expression, however we only support those expressions
4952e4b17023SJohn Marino generated by loop.c. */
4953e4b17023SJohn Marino
4954e4b17023SJohn Marino tree
make_tree(tree type,rtx x)4955e4b17023SJohn Marino make_tree (tree type, rtx x)
4956e4b17023SJohn Marino {
4957e4b17023SJohn Marino tree t;
4958e4b17023SJohn Marino
4959e4b17023SJohn Marino switch (GET_CODE (x))
4960e4b17023SJohn Marino {
4961e4b17023SJohn Marino case CONST_INT:
4962e4b17023SJohn Marino {
4963e4b17023SJohn Marino HOST_WIDE_INT hi = 0;
4964e4b17023SJohn Marino
4965e4b17023SJohn Marino if (INTVAL (x) < 0
4966e4b17023SJohn Marino && !(TYPE_UNSIGNED (type)
4967e4b17023SJohn Marino && (GET_MODE_BITSIZE (TYPE_MODE (type))
4968e4b17023SJohn Marino < HOST_BITS_PER_WIDE_INT)))
4969e4b17023SJohn Marino hi = -1;
4970e4b17023SJohn Marino
4971e4b17023SJohn Marino t = build_int_cst_wide (type, INTVAL (x), hi);
4972e4b17023SJohn Marino
4973e4b17023SJohn Marino return t;
4974e4b17023SJohn Marino }
4975e4b17023SJohn Marino
4976e4b17023SJohn Marino case CONST_DOUBLE:
4977e4b17023SJohn Marino if (GET_MODE (x) == VOIDmode)
4978e4b17023SJohn Marino t = build_int_cst_wide (type,
4979e4b17023SJohn Marino CONST_DOUBLE_LOW (x), CONST_DOUBLE_HIGH (x));
4980e4b17023SJohn Marino else
4981e4b17023SJohn Marino {
4982e4b17023SJohn Marino REAL_VALUE_TYPE d;
4983e4b17023SJohn Marino
4984e4b17023SJohn Marino REAL_VALUE_FROM_CONST_DOUBLE (d, x);
4985e4b17023SJohn Marino t = build_real (type, d);
4986e4b17023SJohn Marino }
4987e4b17023SJohn Marino
4988e4b17023SJohn Marino return t;
4989e4b17023SJohn Marino
4990e4b17023SJohn Marino case CONST_VECTOR:
4991e4b17023SJohn Marino {
4992e4b17023SJohn Marino int units = CONST_VECTOR_NUNITS (x);
4993e4b17023SJohn Marino tree itype = TREE_TYPE (type);
4994e4b17023SJohn Marino tree t = NULL_TREE;
4995e4b17023SJohn Marino int i;
4996e4b17023SJohn Marino
4997e4b17023SJohn Marino
4998e4b17023SJohn Marino /* Build a tree with vector elements. */
4999e4b17023SJohn Marino for (i = units - 1; i >= 0; --i)
5000e4b17023SJohn Marino {
5001e4b17023SJohn Marino rtx elt = CONST_VECTOR_ELT (x, i);
5002e4b17023SJohn Marino t = tree_cons (NULL_TREE, make_tree (itype, elt), t);
5003e4b17023SJohn Marino }
5004e4b17023SJohn Marino
5005e4b17023SJohn Marino return build_vector (type, t);
5006e4b17023SJohn Marino }
5007e4b17023SJohn Marino
5008e4b17023SJohn Marino case PLUS:
5009e4b17023SJohn Marino return fold_build2 (PLUS_EXPR, type, make_tree (type, XEXP (x, 0)),
5010e4b17023SJohn Marino make_tree (type, XEXP (x, 1)));
5011e4b17023SJohn Marino
5012e4b17023SJohn Marino case MINUS:
5013e4b17023SJohn Marino return fold_build2 (MINUS_EXPR, type, make_tree (type, XEXP (x, 0)),
5014e4b17023SJohn Marino make_tree (type, XEXP (x, 1)));
5015e4b17023SJohn Marino
5016e4b17023SJohn Marino case NEG:
5017e4b17023SJohn Marino return fold_build1 (NEGATE_EXPR, type, make_tree (type, XEXP (x, 0)));
5018e4b17023SJohn Marino
5019e4b17023SJohn Marino case MULT:
5020e4b17023SJohn Marino return fold_build2 (MULT_EXPR, type, make_tree (type, XEXP (x, 0)),
5021e4b17023SJohn Marino make_tree (type, XEXP (x, 1)));
5022e4b17023SJohn Marino
5023e4b17023SJohn Marino case ASHIFT:
5024e4b17023SJohn Marino return fold_build2 (LSHIFT_EXPR, type, make_tree (type, XEXP (x, 0)),
5025e4b17023SJohn Marino make_tree (type, XEXP (x, 1)));
5026e4b17023SJohn Marino
5027e4b17023SJohn Marino case LSHIFTRT:
5028e4b17023SJohn Marino t = unsigned_type_for (type);
5029e4b17023SJohn Marino return fold_convert (type, build2 (RSHIFT_EXPR, t,
5030e4b17023SJohn Marino make_tree (t, XEXP (x, 0)),
5031e4b17023SJohn Marino make_tree (type, XEXP (x, 1))));
5032e4b17023SJohn Marino
5033e4b17023SJohn Marino case ASHIFTRT:
5034e4b17023SJohn Marino t = signed_type_for (type);
5035e4b17023SJohn Marino return fold_convert (type, build2 (RSHIFT_EXPR, t,
5036e4b17023SJohn Marino make_tree (t, XEXP (x, 0)),
5037e4b17023SJohn Marino make_tree (type, XEXP (x, 1))));
5038e4b17023SJohn Marino
5039e4b17023SJohn Marino case DIV:
5040e4b17023SJohn Marino if (TREE_CODE (type) != REAL_TYPE)
5041e4b17023SJohn Marino t = signed_type_for (type);
5042e4b17023SJohn Marino else
5043e4b17023SJohn Marino t = type;
5044e4b17023SJohn Marino
5045e4b17023SJohn Marino return fold_convert (type, build2 (TRUNC_DIV_EXPR, t,
5046e4b17023SJohn Marino make_tree (t, XEXP (x, 0)),
5047e4b17023SJohn Marino make_tree (t, XEXP (x, 1))));
5048e4b17023SJohn Marino case UDIV:
5049e4b17023SJohn Marino t = unsigned_type_for (type);
5050e4b17023SJohn Marino return fold_convert (type, build2 (TRUNC_DIV_EXPR, t,
5051e4b17023SJohn Marino make_tree (t, XEXP (x, 0)),
5052e4b17023SJohn Marino make_tree (t, XEXP (x, 1))));
5053e4b17023SJohn Marino
5054e4b17023SJohn Marino case SIGN_EXTEND:
5055e4b17023SJohn Marino case ZERO_EXTEND:
5056e4b17023SJohn Marino t = lang_hooks.types.type_for_mode (GET_MODE (XEXP (x, 0)),
5057e4b17023SJohn Marino GET_CODE (x) == ZERO_EXTEND);
5058e4b17023SJohn Marino return fold_convert (type, make_tree (t, XEXP (x, 0)));
5059e4b17023SJohn Marino
5060e4b17023SJohn Marino case CONST:
5061e4b17023SJohn Marino return make_tree (type, XEXP (x, 0));
5062e4b17023SJohn Marino
5063e4b17023SJohn Marino case SYMBOL_REF:
5064e4b17023SJohn Marino t = SYMBOL_REF_DECL (x);
5065e4b17023SJohn Marino if (t)
5066e4b17023SJohn Marino return fold_convert (type, build_fold_addr_expr (t));
5067e4b17023SJohn Marino /* else fall through. */
5068e4b17023SJohn Marino
5069e4b17023SJohn Marino default:
5070e4b17023SJohn Marino t = build_decl (RTL_LOCATION (x), VAR_DECL, NULL_TREE, type);
5071e4b17023SJohn Marino
5072e4b17023SJohn Marino /* If TYPE is a POINTER_TYPE, we might need to convert X from
5073e4b17023SJohn Marino address mode to pointer mode. */
5074e4b17023SJohn Marino if (POINTER_TYPE_P (type))
5075e4b17023SJohn Marino x = convert_memory_address_addr_space
5076e4b17023SJohn Marino (TYPE_MODE (type), x, TYPE_ADDR_SPACE (TREE_TYPE (type)));
5077e4b17023SJohn Marino
5078e4b17023SJohn Marino /* Note that we do *not* use SET_DECL_RTL here, because we do not
5079e4b17023SJohn Marino want set_decl_rtl to go adjusting REG_ATTRS for this temporary. */
5080e4b17023SJohn Marino t->decl_with_rtl.rtl = x;
5081e4b17023SJohn Marino
5082e4b17023SJohn Marino return t;
5083e4b17023SJohn Marino }
5084e4b17023SJohn Marino }
5085e4b17023SJohn Marino
5086e4b17023SJohn Marino /* Compute the logical-and of OP0 and OP1, storing it in TARGET
5087e4b17023SJohn Marino and returning TARGET.
5088e4b17023SJohn Marino
5089e4b17023SJohn Marino If TARGET is 0, a pseudo-register or constant is returned. */
5090e4b17023SJohn Marino
5091e4b17023SJohn Marino rtx
expand_and(enum machine_mode mode,rtx op0,rtx op1,rtx target)5092e4b17023SJohn Marino expand_and (enum machine_mode mode, rtx op0, rtx op1, rtx target)
5093e4b17023SJohn Marino {
5094e4b17023SJohn Marino rtx tem = 0;
5095e4b17023SJohn Marino
5096e4b17023SJohn Marino if (GET_MODE (op0) == VOIDmode && GET_MODE (op1) == VOIDmode)
5097e4b17023SJohn Marino tem = simplify_binary_operation (AND, mode, op0, op1);
5098e4b17023SJohn Marino if (tem == 0)
5099e4b17023SJohn Marino tem = expand_binop (mode, and_optab, op0, op1, target, 0, OPTAB_LIB_WIDEN);
5100e4b17023SJohn Marino
5101e4b17023SJohn Marino if (target == 0)
5102e4b17023SJohn Marino target = tem;
5103e4b17023SJohn Marino else if (tem != target)
5104e4b17023SJohn Marino emit_move_insn (target, tem);
5105e4b17023SJohn Marino return target;
5106e4b17023SJohn Marino }
5107e4b17023SJohn Marino
5108e4b17023SJohn Marino /* Helper function for emit_store_flag. */
5109e4b17023SJohn Marino static rtx
emit_cstore(rtx target,enum insn_code icode,enum rtx_code code,enum machine_mode mode,enum machine_mode compare_mode,int unsignedp,rtx x,rtx y,int normalizep,enum machine_mode target_mode)5110e4b17023SJohn Marino emit_cstore (rtx target, enum insn_code icode, enum rtx_code code,
5111e4b17023SJohn Marino enum machine_mode mode, enum machine_mode compare_mode,
5112e4b17023SJohn Marino int unsignedp, rtx x, rtx y, int normalizep,
5113e4b17023SJohn Marino enum machine_mode target_mode)
5114e4b17023SJohn Marino {
5115e4b17023SJohn Marino struct expand_operand ops[4];
5116e4b17023SJohn Marino rtx op0, last, comparison, subtarget;
5117e4b17023SJohn Marino enum machine_mode result_mode = insn_data[(int) icode].operand[0].mode;
5118e4b17023SJohn Marino
5119e4b17023SJohn Marino last = get_last_insn ();
5120e4b17023SJohn Marino x = prepare_operand (icode, x, 2, mode, compare_mode, unsignedp);
5121e4b17023SJohn Marino y = prepare_operand (icode, y, 3, mode, compare_mode, unsignedp);
5122e4b17023SJohn Marino if (!x || !y)
5123e4b17023SJohn Marino {
5124e4b17023SJohn Marino delete_insns_since (last);
5125e4b17023SJohn Marino return NULL_RTX;
5126e4b17023SJohn Marino }
5127e4b17023SJohn Marino
5128e4b17023SJohn Marino if (target_mode == VOIDmode)
5129e4b17023SJohn Marino target_mode = result_mode;
5130e4b17023SJohn Marino if (!target)
5131e4b17023SJohn Marino target = gen_reg_rtx (target_mode);
5132e4b17023SJohn Marino
5133e4b17023SJohn Marino comparison = gen_rtx_fmt_ee (code, result_mode, x, y);
5134e4b17023SJohn Marino
5135e4b17023SJohn Marino create_output_operand (&ops[0], optimize ? NULL_RTX : target, result_mode);
5136e4b17023SJohn Marino create_fixed_operand (&ops[1], comparison);
5137e4b17023SJohn Marino create_fixed_operand (&ops[2], x);
5138e4b17023SJohn Marino create_fixed_operand (&ops[3], y);
5139e4b17023SJohn Marino if (!maybe_expand_insn (icode, 4, ops))
5140e4b17023SJohn Marino {
5141e4b17023SJohn Marino delete_insns_since (last);
5142e4b17023SJohn Marino return NULL_RTX;
5143e4b17023SJohn Marino }
5144e4b17023SJohn Marino subtarget = ops[0].value;
5145e4b17023SJohn Marino
5146e4b17023SJohn Marino /* If we are converting to a wider mode, first convert to
5147e4b17023SJohn Marino TARGET_MODE, then normalize. This produces better combining
5148e4b17023SJohn Marino opportunities on machines that have a SIGN_EXTRACT when we are
5149e4b17023SJohn Marino testing a single bit. This mostly benefits the 68k.
5150e4b17023SJohn Marino
5151e4b17023SJohn Marino If STORE_FLAG_VALUE does not have the sign bit set when
5152e4b17023SJohn Marino interpreted in MODE, we can do this conversion as unsigned, which
5153e4b17023SJohn Marino is usually more efficient. */
5154e4b17023SJohn Marino if (GET_MODE_SIZE (target_mode) > GET_MODE_SIZE (result_mode))
5155e4b17023SJohn Marino {
5156e4b17023SJohn Marino convert_move (target, subtarget,
5157e4b17023SJohn Marino val_signbit_known_clear_p (result_mode,
5158e4b17023SJohn Marino STORE_FLAG_VALUE));
5159e4b17023SJohn Marino op0 = target;
5160e4b17023SJohn Marino result_mode = target_mode;
5161e4b17023SJohn Marino }
5162e4b17023SJohn Marino else
5163e4b17023SJohn Marino op0 = subtarget;
5164e4b17023SJohn Marino
5165e4b17023SJohn Marino /* If we want to keep subexpressions around, don't reuse our last
5166e4b17023SJohn Marino target. */
5167e4b17023SJohn Marino if (optimize)
5168e4b17023SJohn Marino subtarget = 0;
5169e4b17023SJohn Marino
5170e4b17023SJohn Marino /* Now normalize to the proper value in MODE. Sometimes we don't
5171e4b17023SJohn Marino have to do anything. */
5172e4b17023SJohn Marino if (normalizep == 0 || normalizep == STORE_FLAG_VALUE)
5173e4b17023SJohn Marino ;
5174e4b17023SJohn Marino /* STORE_FLAG_VALUE might be the most negative number, so write
5175e4b17023SJohn Marino the comparison this way to avoid a compiler-time warning. */
5176e4b17023SJohn Marino else if (- normalizep == STORE_FLAG_VALUE)
5177e4b17023SJohn Marino op0 = expand_unop (result_mode, neg_optab, op0, subtarget, 0);
5178e4b17023SJohn Marino
5179e4b17023SJohn Marino /* We don't want to use STORE_FLAG_VALUE < 0 below since this makes
5180e4b17023SJohn Marino it hard to use a value of just the sign bit due to ANSI integer
5181e4b17023SJohn Marino constant typing rules. */
5182e4b17023SJohn Marino else if (val_signbit_known_set_p (result_mode, STORE_FLAG_VALUE))
5183e4b17023SJohn Marino op0 = expand_shift (RSHIFT_EXPR, result_mode, op0,
5184e4b17023SJohn Marino GET_MODE_BITSIZE (result_mode) - 1, subtarget,
5185e4b17023SJohn Marino normalizep == 1);
5186e4b17023SJohn Marino else
5187e4b17023SJohn Marino {
5188e4b17023SJohn Marino gcc_assert (STORE_FLAG_VALUE & 1);
5189e4b17023SJohn Marino
5190e4b17023SJohn Marino op0 = expand_and (result_mode, op0, const1_rtx, subtarget);
5191e4b17023SJohn Marino if (normalizep == -1)
5192e4b17023SJohn Marino op0 = expand_unop (result_mode, neg_optab, op0, op0, 0);
5193e4b17023SJohn Marino }
5194e4b17023SJohn Marino
5195e4b17023SJohn Marino /* If we were converting to a smaller mode, do the conversion now. */
5196e4b17023SJohn Marino if (target_mode != result_mode)
5197e4b17023SJohn Marino {
5198e4b17023SJohn Marino convert_move (target, op0, 0);
5199e4b17023SJohn Marino return target;
5200e4b17023SJohn Marino }
5201e4b17023SJohn Marino else
5202e4b17023SJohn Marino return op0;
5203e4b17023SJohn Marino }
5204e4b17023SJohn Marino
5205e4b17023SJohn Marino
5206e4b17023SJohn Marino /* A subroutine of emit_store_flag only including "tricks" that do not
5207e4b17023SJohn Marino need a recursive call. These are kept separate to avoid infinite
5208e4b17023SJohn Marino loops. */
5209e4b17023SJohn Marino
5210e4b17023SJohn Marino static rtx
emit_store_flag_1(rtx target,enum rtx_code code,rtx op0,rtx op1,enum machine_mode mode,int unsignedp,int normalizep,enum machine_mode target_mode)5211e4b17023SJohn Marino emit_store_flag_1 (rtx target, enum rtx_code code, rtx op0, rtx op1,
5212e4b17023SJohn Marino enum machine_mode mode, int unsignedp, int normalizep,
5213e4b17023SJohn Marino enum machine_mode target_mode)
5214e4b17023SJohn Marino {
5215e4b17023SJohn Marino rtx subtarget;
5216e4b17023SJohn Marino enum insn_code icode;
5217e4b17023SJohn Marino enum machine_mode compare_mode;
5218e4b17023SJohn Marino enum mode_class mclass;
5219e4b17023SJohn Marino enum rtx_code scode;
5220e4b17023SJohn Marino rtx tem;
5221e4b17023SJohn Marino
5222e4b17023SJohn Marino if (unsignedp)
5223e4b17023SJohn Marino code = unsigned_condition (code);
5224e4b17023SJohn Marino scode = swap_condition (code);
5225e4b17023SJohn Marino
5226e4b17023SJohn Marino /* If one operand is constant, make it the second one. Only do this
5227e4b17023SJohn Marino if the other operand is not constant as well. */
5228e4b17023SJohn Marino
5229e4b17023SJohn Marino if (swap_commutative_operands_p (op0, op1))
5230e4b17023SJohn Marino {
5231e4b17023SJohn Marino tem = op0;
5232e4b17023SJohn Marino op0 = op1;
5233e4b17023SJohn Marino op1 = tem;
5234e4b17023SJohn Marino code = swap_condition (code);
5235e4b17023SJohn Marino }
5236e4b17023SJohn Marino
5237e4b17023SJohn Marino if (mode == VOIDmode)
5238e4b17023SJohn Marino mode = GET_MODE (op0);
5239e4b17023SJohn Marino
5240e4b17023SJohn Marino /* For some comparisons with 1 and -1, we can convert this to
5241e4b17023SJohn Marino comparisons with zero. This will often produce more opportunities for
5242e4b17023SJohn Marino store-flag insns. */
5243e4b17023SJohn Marino
5244e4b17023SJohn Marino switch (code)
5245e4b17023SJohn Marino {
5246e4b17023SJohn Marino case LT:
5247e4b17023SJohn Marino if (op1 == const1_rtx)
5248e4b17023SJohn Marino op1 = const0_rtx, code = LE;
5249e4b17023SJohn Marino break;
5250e4b17023SJohn Marino case LE:
5251e4b17023SJohn Marino if (op1 == constm1_rtx)
5252e4b17023SJohn Marino op1 = const0_rtx, code = LT;
5253e4b17023SJohn Marino break;
5254e4b17023SJohn Marino case GE:
5255e4b17023SJohn Marino if (op1 == const1_rtx)
5256e4b17023SJohn Marino op1 = const0_rtx, code = GT;
5257e4b17023SJohn Marino break;
5258e4b17023SJohn Marino case GT:
5259e4b17023SJohn Marino if (op1 == constm1_rtx)
5260e4b17023SJohn Marino op1 = const0_rtx, code = GE;
5261e4b17023SJohn Marino break;
5262e4b17023SJohn Marino case GEU:
5263e4b17023SJohn Marino if (op1 == const1_rtx)
5264e4b17023SJohn Marino op1 = const0_rtx, code = NE;
5265e4b17023SJohn Marino break;
5266e4b17023SJohn Marino case LTU:
5267e4b17023SJohn Marino if (op1 == const1_rtx)
5268e4b17023SJohn Marino op1 = const0_rtx, code = EQ;
5269e4b17023SJohn Marino break;
5270e4b17023SJohn Marino default:
5271e4b17023SJohn Marino break;
5272e4b17023SJohn Marino }
5273e4b17023SJohn Marino
5274e4b17023SJohn Marino /* If we are comparing a double-word integer with zero or -1, we can
5275e4b17023SJohn Marino convert the comparison into one involving a single word. */
5276e4b17023SJohn Marino if (GET_MODE_BITSIZE (mode) == BITS_PER_WORD * 2
5277e4b17023SJohn Marino && GET_MODE_CLASS (mode) == MODE_INT
5278e4b17023SJohn Marino && (!MEM_P (op0) || ! MEM_VOLATILE_P (op0)))
5279e4b17023SJohn Marino {
5280e4b17023SJohn Marino if ((code == EQ || code == NE)
5281e4b17023SJohn Marino && (op1 == const0_rtx || op1 == constm1_rtx))
5282e4b17023SJohn Marino {
5283e4b17023SJohn Marino rtx op00, op01;
5284e4b17023SJohn Marino
5285e4b17023SJohn Marino /* Do a logical OR or AND of the two words and compare the
5286e4b17023SJohn Marino result. */
5287e4b17023SJohn Marino op00 = simplify_gen_subreg (word_mode, op0, mode, 0);
5288e4b17023SJohn Marino op01 = simplify_gen_subreg (word_mode, op0, mode, UNITS_PER_WORD);
5289e4b17023SJohn Marino tem = expand_binop (word_mode,
5290e4b17023SJohn Marino op1 == const0_rtx ? ior_optab : and_optab,
5291e4b17023SJohn Marino op00, op01, NULL_RTX, unsignedp,
5292e4b17023SJohn Marino OPTAB_DIRECT);
5293e4b17023SJohn Marino
5294e4b17023SJohn Marino if (tem != 0)
5295e4b17023SJohn Marino tem = emit_store_flag (NULL_RTX, code, tem, op1, word_mode,
5296e4b17023SJohn Marino unsignedp, normalizep);
5297e4b17023SJohn Marino }
5298e4b17023SJohn Marino else if ((code == LT || code == GE) && op1 == const0_rtx)
5299e4b17023SJohn Marino {
5300e4b17023SJohn Marino rtx op0h;
5301e4b17023SJohn Marino
5302e4b17023SJohn Marino /* If testing the sign bit, can just test on high word. */
5303e4b17023SJohn Marino op0h = simplify_gen_subreg (word_mode, op0, mode,
5304e4b17023SJohn Marino subreg_highpart_offset (word_mode,
5305e4b17023SJohn Marino mode));
5306e4b17023SJohn Marino tem = emit_store_flag (NULL_RTX, code, op0h, op1, word_mode,
5307e4b17023SJohn Marino unsignedp, normalizep);
5308e4b17023SJohn Marino }
5309e4b17023SJohn Marino else
5310e4b17023SJohn Marino tem = NULL_RTX;
5311e4b17023SJohn Marino
5312e4b17023SJohn Marino if (tem)
5313e4b17023SJohn Marino {
5314e4b17023SJohn Marino if (target_mode == VOIDmode || GET_MODE (tem) == target_mode)
5315e4b17023SJohn Marino return tem;
5316e4b17023SJohn Marino if (!target)
5317e4b17023SJohn Marino target = gen_reg_rtx (target_mode);
5318e4b17023SJohn Marino
5319e4b17023SJohn Marino convert_move (target, tem,
5320e4b17023SJohn Marino !val_signbit_known_set_p (word_mode,
5321e4b17023SJohn Marino (normalizep ? normalizep
5322e4b17023SJohn Marino : STORE_FLAG_VALUE)));
5323e4b17023SJohn Marino return target;
5324e4b17023SJohn Marino }
5325e4b17023SJohn Marino }
5326e4b17023SJohn Marino
5327e4b17023SJohn Marino /* If this is A < 0 or A >= 0, we can do this by taking the ones
5328e4b17023SJohn Marino complement of A (for GE) and shifting the sign bit to the low bit. */
5329e4b17023SJohn Marino if (op1 == const0_rtx && (code == LT || code == GE)
5330e4b17023SJohn Marino && GET_MODE_CLASS (mode) == MODE_INT
5331e4b17023SJohn Marino && (normalizep || STORE_FLAG_VALUE == 1
5332e4b17023SJohn Marino || val_signbit_p (mode, STORE_FLAG_VALUE)))
5333e4b17023SJohn Marino {
5334e4b17023SJohn Marino subtarget = target;
5335e4b17023SJohn Marino
5336e4b17023SJohn Marino if (!target)
5337e4b17023SJohn Marino target_mode = mode;
5338e4b17023SJohn Marino
5339e4b17023SJohn Marino /* If the result is to be wider than OP0, it is best to convert it
5340e4b17023SJohn Marino first. If it is to be narrower, it is *incorrect* to convert it
5341e4b17023SJohn Marino first. */
5342e4b17023SJohn Marino else if (GET_MODE_SIZE (target_mode) > GET_MODE_SIZE (mode))
5343e4b17023SJohn Marino {
5344e4b17023SJohn Marino op0 = convert_modes (target_mode, mode, op0, 0);
5345e4b17023SJohn Marino mode = target_mode;
5346e4b17023SJohn Marino }
5347e4b17023SJohn Marino
5348e4b17023SJohn Marino if (target_mode != mode)
5349e4b17023SJohn Marino subtarget = 0;
5350e4b17023SJohn Marino
5351e4b17023SJohn Marino if (code == GE)
5352e4b17023SJohn Marino op0 = expand_unop (mode, one_cmpl_optab, op0,
5353e4b17023SJohn Marino ((STORE_FLAG_VALUE == 1 || normalizep)
5354e4b17023SJohn Marino ? 0 : subtarget), 0);
5355e4b17023SJohn Marino
5356e4b17023SJohn Marino if (STORE_FLAG_VALUE == 1 || normalizep)
5357e4b17023SJohn Marino /* If we are supposed to produce a 0/1 value, we want to do
5358e4b17023SJohn Marino a logical shift from the sign bit to the low-order bit; for
5359e4b17023SJohn Marino a -1/0 value, we do an arithmetic shift. */
5360e4b17023SJohn Marino op0 = expand_shift (RSHIFT_EXPR, mode, op0,
5361e4b17023SJohn Marino GET_MODE_BITSIZE (mode) - 1,
5362e4b17023SJohn Marino subtarget, normalizep != -1);
5363e4b17023SJohn Marino
5364e4b17023SJohn Marino if (mode != target_mode)
5365e4b17023SJohn Marino op0 = convert_modes (target_mode, mode, op0, 0);
5366e4b17023SJohn Marino
5367e4b17023SJohn Marino return op0;
5368e4b17023SJohn Marino }
5369e4b17023SJohn Marino
5370e4b17023SJohn Marino mclass = GET_MODE_CLASS (mode);
5371e4b17023SJohn Marino for (compare_mode = mode; compare_mode != VOIDmode;
5372e4b17023SJohn Marino compare_mode = GET_MODE_WIDER_MODE (compare_mode))
5373e4b17023SJohn Marino {
5374e4b17023SJohn Marino enum machine_mode optab_mode = mclass == MODE_CC ? CCmode : compare_mode;
5375e4b17023SJohn Marino icode = optab_handler (cstore_optab, optab_mode);
5376e4b17023SJohn Marino if (icode != CODE_FOR_nothing)
5377e4b17023SJohn Marino {
5378e4b17023SJohn Marino do_pending_stack_adjust ();
5379e4b17023SJohn Marino tem = emit_cstore (target, icode, code, mode, compare_mode,
5380e4b17023SJohn Marino unsignedp, op0, op1, normalizep, target_mode);
5381e4b17023SJohn Marino if (tem)
5382e4b17023SJohn Marino return tem;
5383e4b17023SJohn Marino
5384e4b17023SJohn Marino if (GET_MODE_CLASS (mode) == MODE_FLOAT)
5385e4b17023SJohn Marino {
5386e4b17023SJohn Marino tem = emit_cstore (target, icode, scode, mode, compare_mode,
5387e4b17023SJohn Marino unsignedp, op1, op0, normalizep, target_mode);
5388e4b17023SJohn Marino if (tem)
5389e4b17023SJohn Marino return tem;
5390e4b17023SJohn Marino }
5391e4b17023SJohn Marino break;
5392e4b17023SJohn Marino }
5393e4b17023SJohn Marino }
5394e4b17023SJohn Marino
5395e4b17023SJohn Marino return 0;
5396e4b17023SJohn Marino }
5397e4b17023SJohn Marino
5398e4b17023SJohn Marino /* Emit a store-flags instruction for comparison CODE on OP0 and OP1
5399e4b17023SJohn Marino and storing in TARGET. Normally return TARGET.
5400e4b17023SJohn Marino Return 0 if that cannot be done.
5401e4b17023SJohn Marino
5402e4b17023SJohn Marino MODE is the mode to use for OP0 and OP1 should they be CONST_INTs. If
5403e4b17023SJohn Marino it is VOIDmode, they cannot both be CONST_INT.
5404e4b17023SJohn Marino
5405e4b17023SJohn Marino UNSIGNEDP is for the case where we have to widen the operands
5406e4b17023SJohn Marino to perform the operation. It says to use zero-extension.
5407e4b17023SJohn Marino
5408e4b17023SJohn Marino NORMALIZEP is 1 if we should convert the result to be either zero
5409e4b17023SJohn Marino or one. Normalize is -1 if we should convert the result to be
5410e4b17023SJohn Marino either zero or -1. If NORMALIZEP is zero, the result will be left
5411e4b17023SJohn Marino "raw" out of the scc insn. */
5412e4b17023SJohn Marino
5413e4b17023SJohn Marino rtx
emit_store_flag(rtx target,enum rtx_code code,rtx op0,rtx op1,enum machine_mode mode,int unsignedp,int normalizep)5414e4b17023SJohn Marino emit_store_flag (rtx target, enum rtx_code code, rtx op0, rtx op1,
5415e4b17023SJohn Marino enum machine_mode mode, int unsignedp, int normalizep)
5416e4b17023SJohn Marino {
5417e4b17023SJohn Marino enum machine_mode target_mode = target ? GET_MODE (target) : VOIDmode;
5418e4b17023SJohn Marino enum rtx_code rcode;
5419e4b17023SJohn Marino rtx subtarget;
5420e4b17023SJohn Marino rtx tem, last, trueval;
5421e4b17023SJohn Marino
5422e4b17023SJohn Marino tem = emit_store_flag_1 (target, code, op0, op1, mode, unsignedp, normalizep,
5423e4b17023SJohn Marino target_mode);
5424e4b17023SJohn Marino if (tem)
5425e4b17023SJohn Marino return tem;
5426e4b17023SJohn Marino
5427e4b17023SJohn Marino /* If we reached here, we can't do this with a scc insn, however there
5428e4b17023SJohn Marino are some comparisons that can be done in other ways. Don't do any
5429e4b17023SJohn Marino of these cases if branches are very cheap. */
5430e4b17023SJohn Marino if (BRANCH_COST (optimize_insn_for_speed_p (), false) == 0)
5431e4b17023SJohn Marino return 0;
5432e4b17023SJohn Marino
5433e4b17023SJohn Marino /* See what we need to return. We can only return a 1, -1, or the
5434e4b17023SJohn Marino sign bit. */
5435e4b17023SJohn Marino
5436e4b17023SJohn Marino if (normalizep == 0)
5437e4b17023SJohn Marino {
5438e4b17023SJohn Marino if (STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1)
5439e4b17023SJohn Marino normalizep = STORE_FLAG_VALUE;
5440e4b17023SJohn Marino
5441e4b17023SJohn Marino else if (val_signbit_p (mode, STORE_FLAG_VALUE))
5442e4b17023SJohn Marino ;
5443e4b17023SJohn Marino else
5444e4b17023SJohn Marino return 0;
5445e4b17023SJohn Marino }
5446e4b17023SJohn Marino
5447e4b17023SJohn Marino last = get_last_insn ();
5448e4b17023SJohn Marino
5449e4b17023SJohn Marino /* If optimizing, use different pseudo registers for each insn, instead
5450e4b17023SJohn Marino of reusing the same pseudo. This leads to better CSE, but slows
5451e4b17023SJohn Marino down the compiler, since there are more pseudos */
5452e4b17023SJohn Marino subtarget = (!optimize
5453e4b17023SJohn Marino && (target_mode == mode)) ? target : NULL_RTX;
5454e4b17023SJohn Marino trueval = GEN_INT (normalizep ? normalizep : STORE_FLAG_VALUE);
5455e4b17023SJohn Marino
5456e4b17023SJohn Marino /* For floating-point comparisons, try the reverse comparison or try
5457e4b17023SJohn Marino changing the "orderedness" of the comparison. */
5458e4b17023SJohn Marino if (GET_MODE_CLASS (mode) == MODE_FLOAT)
5459e4b17023SJohn Marino {
5460e4b17023SJohn Marino enum rtx_code first_code;
5461e4b17023SJohn Marino bool and_them;
5462e4b17023SJohn Marino
5463e4b17023SJohn Marino rcode = reverse_condition_maybe_unordered (code);
5464e4b17023SJohn Marino if (can_compare_p (rcode, mode, ccp_store_flag)
5465e4b17023SJohn Marino && (code == ORDERED || code == UNORDERED
5466e4b17023SJohn Marino || (! HONOR_NANS (mode) && (code == LTGT || code == UNEQ))
5467e4b17023SJohn Marino || (! HONOR_SNANS (mode) && (code == EQ || code == NE))))
5468e4b17023SJohn Marino {
5469e4b17023SJohn Marino int want_add = ((STORE_FLAG_VALUE == 1 && normalizep == -1)
5470e4b17023SJohn Marino || (STORE_FLAG_VALUE == -1 && normalizep == 1));
5471e4b17023SJohn Marino
5472e4b17023SJohn Marino /* For the reverse comparison, use either an addition or a XOR. */
5473e4b17023SJohn Marino if (want_add
5474e4b17023SJohn Marino && rtx_cost (GEN_INT (normalizep), PLUS, 1,
5475e4b17023SJohn Marino optimize_insn_for_speed_p ()) == 0)
5476e4b17023SJohn Marino {
5477e4b17023SJohn Marino tem = emit_store_flag_1 (subtarget, rcode, op0, op1, mode, 0,
5478e4b17023SJohn Marino STORE_FLAG_VALUE, target_mode);
5479e4b17023SJohn Marino if (tem)
5480e4b17023SJohn Marino return expand_binop (target_mode, add_optab, tem,
5481e4b17023SJohn Marino GEN_INT (normalizep),
5482e4b17023SJohn Marino target, 0, OPTAB_WIDEN);
5483e4b17023SJohn Marino }
5484e4b17023SJohn Marino else if (!want_add
5485e4b17023SJohn Marino && rtx_cost (trueval, XOR, 1,
5486e4b17023SJohn Marino optimize_insn_for_speed_p ()) == 0)
5487e4b17023SJohn Marino {
5488e4b17023SJohn Marino tem = emit_store_flag_1 (subtarget, rcode, op0, op1, mode, 0,
5489e4b17023SJohn Marino normalizep, target_mode);
5490e4b17023SJohn Marino if (tem)
5491e4b17023SJohn Marino return expand_binop (target_mode, xor_optab, tem, trueval,
5492e4b17023SJohn Marino target, INTVAL (trueval) >= 0, OPTAB_WIDEN);
5493e4b17023SJohn Marino }
5494e4b17023SJohn Marino }
5495e4b17023SJohn Marino
5496e4b17023SJohn Marino delete_insns_since (last);
5497e4b17023SJohn Marino
5498e4b17023SJohn Marino /* Cannot split ORDERED and UNORDERED, only try the above trick. */
5499e4b17023SJohn Marino if (code == ORDERED || code == UNORDERED)
5500e4b17023SJohn Marino return 0;
5501e4b17023SJohn Marino
5502e4b17023SJohn Marino and_them = split_comparison (code, mode, &first_code, &code);
5503e4b17023SJohn Marino
5504e4b17023SJohn Marino /* If there are no NaNs, the first comparison should always fall through.
5505e4b17023SJohn Marino Effectively change the comparison to the other one. */
5506e4b17023SJohn Marino if (!HONOR_NANS (mode))
5507e4b17023SJohn Marino {
5508e4b17023SJohn Marino gcc_assert (first_code == (and_them ? ORDERED : UNORDERED));
5509e4b17023SJohn Marino return emit_store_flag_1 (target, code, op0, op1, mode, 0, normalizep,
5510e4b17023SJohn Marino target_mode);
5511e4b17023SJohn Marino }
5512e4b17023SJohn Marino
5513e4b17023SJohn Marino #ifdef HAVE_conditional_move
5514e4b17023SJohn Marino /* Try using a setcc instruction for ORDERED/UNORDERED, followed by a
5515e4b17023SJohn Marino conditional move. */
5516e4b17023SJohn Marino tem = emit_store_flag_1 (subtarget, first_code, op0, op1, mode, 0,
5517e4b17023SJohn Marino normalizep, target_mode);
5518e4b17023SJohn Marino if (tem == 0)
5519e4b17023SJohn Marino return 0;
5520e4b17023SJohn Marino
5521e4b17023SJohn Marino if (and_them)
5522e4b17023SJohn Marino tem = emit_conditional_move (target, code, op0, op1, mode,
5523e4b17023SJohn Marino tem, const0_rtx, GET_MODE (tem), 0);
5524e4b17023SJohn Marino else
5525e4b17023SJohn Marino tem = emit_conditional_move (target, code, op0, op1, mode,
5526e4b17023SJohn Marino trueval, tem, GET_MODE (tem), 0);
5527e4b17023SJohn Marino
5528e4b17023SJohn Marino if (tem == 0)
5529e4b17023SJohn Marino delete_insns_since (last);
5530e4b17023SJohn Marino return tem;
5531e4b17023SJohn Marino #else
5532e4b17023SJohn Marino return 0;
5533e4b17023SJohn Marino #endif
5534e4b17023SJohn Marino }
5535e4b17023SJohn Marino
5536e4b17023SJohn Marino /* The remaining tricks only apply to integer comparisons. */
5537e4b17023SJohn Marino
5538e4b17023SJohn Marino if (GET_MODE_CLASS (mode) != MODE_INT)
5539e4b17023SJohn Marino return 0;
5540e4b17023SJohn Marino
5541e4b17023SJohn Marino /* If this is an equality comparison of integers, we can try to exclusive-or
5542e4b17023SJohn Marino (or subtract) the two operands and use a recursive call to try the
5543e4b17023SJohn Marino comparison with zero. Don't do any of these cases if branches are
5544e4b17023SJohn Marino very cheap. */
5545e4b17023SJohn Marino
5546e4b17023SJohn Marino if ((code == EQ || code == NE) && op1 != const0_rtx)
5547e4b17023SJohn Marino {
5548e4b17023SJohn Marino tem = expand_binop (mode, xor_optab, op0, op1, subtarget, 1,
5549e4b17023SJohn Marino OPTAB_WIDEN);
5550e4b17023SJohn Marino
5551e4b17023SJohn Marino if (tem == 0)
5552e4b17023SJohn Marino tem = expand_binop (mode, sub_optab, op0, op1, subtarget, 1,
5553e4b17023SJohn Marino OPTAB_WIDEN);
5554e4b17023SJohn Marino if (tem != 0)
5555e4b17023SJohn Marino tem = emit_store_flag (target, code, tem, const0_rtx,
5556e4b17023SJohn Marino mode, unsignedp, normalizep);
5557e4b17023SJohn Marino if (tem != 0)
5558e4b17023SJohn Marino return tem;
5559e4b17023SJohn Marino
5560e4b17023SJohn Marino delete_insns_since (last);
5561e4b17023SJohn Marino }
5562e4b17023SJohn Marino
5563e4b17023SJohn Marino /* For integer comparisons, try the reverse comparison. However, for
5564e4b17023SJohn Marino small X and if we'd have anyway to extend, implementing "X != 0"
5565e4b17023SJohn Marino as "-(int)X >> 31" is still cheaper than inverting "(int)X == 0". */
5566e4b17023SJohn Marino rcode = reverse_condition (code);
5567e4b17023SJohn Marino if (can_compare_p (rcode, mode, ccp_store_flag)
5568e4b17023SJohn Marino && ! (optab_handler (cstore_optab, mode) == CODE_FOR_nothing
5569e4b17023SJohn Marino && code == NE
5570e4b17023SJohn Marino && GET_MODE_SIZE (mode) < UNITS_PER_WORD
5571e4b17023SJohn Marino && op1 == const0_rtx))
5572e4b17023SJohn Marino {
5573e4b17023SJohn Marino int want_add = ((STORE_FLAG_VALUE == 1 && normalizep == -1)
5574e4b17023SJohn Marino || (STORE_FLAG_VALUE == -1 && normalizep == 1));
5575e4b17023SJohn Marino
5576e4b17023SJohn Marino /* Again, for the reverse comparison, use either an addition or a XOR. */
5577e4b17023SJohn Marino if (want_add
5578e4b17023SJohn Marino && rtx_cost (GEN_INT (normalizep), PLUS, 1,
5579e4b17023SJohn Marino optimize_insn_for_speed_p ()) == 0)
5580e4b17023SJohn Marino {
5581e4b17023SJohn Marino tem = emit_store_flag_1 (subtarget, rcode, op0, op1, mode, 0,
5582e4b17023SJohn Marino STORE_FLAG_VALUE, target_mode);
5583e4b17023SJohn Marino if (tem != 0)
5584e4b17023SJohn Marino tem = expand_binop (target_mode, add_optab, tem,
5585e4b17023SJohn Marino GEN_INT (normalizep), target, 0, OPTAB_WIDEN);
5586e4b17023SJohn Marino }
5587e4b17023SJohn Marino else if (!want_add
5588e4b17023SJohn Marino && rtx_cost (trueval, XOR, 1,
5589e4b17023SJohn Marino optimize_insn_for_speed_p ()) == 0)
5590e4b17023SJohn Marino {
5591e4b17023SJohn Marino tem = emit_store_flag_1 (subtarget, rcode, op0, op1, mode, 0,
5592e4b17023SJohn Marino normalizep, target_mode);
5593e4b17023SJohn Marino if (tem != 0)
5594e4b17023SJohn Marino tem = expand_binop (target_mode, xor_optab, tem, trueval, target,
5595e4b17023SJohn Marino INTVAL (trueval) >= 0, OPTAB_WIDEN);
5596e4b17023SJohn Marino }
5597e4b17023SJohn Marino
5598e4b17023SJohn Marino if (tem != 0)
5599e4b17023SJohn Marino return tem;
5600e4b17023SJohn Marino delete_insns_since (last);
5601e4b17023SJohn Marino }
5602e4b17023SJohn Marino
5603e4b17023SJohn Marino /* Some other cases we can do are EQ, NE, LE, and GT comparisons with
5604e4b17023SJohn Marino the constant zero. Reject all other comparisons at this point. Only
5605e4b17023SJohn Marino do LE and GT if branches are expensive since they are expensive on
5606e4b17023SJohn Marino 2-operand machines. */
5607e4b17023SJohn Marino
5608e4b17023SJohn Marino if (op1 != const0_rtx
5609e4b17023SJohn Marino || (code != EQ && code != NE
5610e4b17023SJohn Marino && (BRANCH_COST (optimize_insn_for_speed_p (),
5611e4b17023SJohn Marino false) <= 1 || (code != LE && code != GT))))
5612e4b17023SJohn Marino return 0;
5613e4b17023SJohn Marino
5614e4b17023SJohn Marino /* Try to put the result of the comparison in the sign bit. Assume we can't
5615e4b17023SJohn Marino do the necessary operation below. */
5616e4b17023SJohn Marino
5617e4b17023SJohn Marino tem = 0;
5618e4b17023SJohn Marino
5619e4b17023SJohn Marino /* To see if A <= 0, compute (A | (A - 1)). A <= 0 iff that result has
5620e4b17023SJohn Marino the sign bit set. */
5621e4b17023SJohn Marino
5622e4b17023SJohn Marino if (code == LE)
5623e4b17023SJohn Marino {
5624e4b17023SJohn Marino /* This is destructive, so SUBTARGET can't be OP0. */
5625e4b17023SJohn Marino if (rtx_equal_p (subtarget, op0))
5626e4b17023SJohn Marino subtarget = 0;
5627e4b17023SJohn Marino
5628e4b17023SJohn Marino tem = expand_binop (mode, sub_optab, op0, const1_rtx, subtarget, 0,
5629e4b17023SJohn Marino OPTAB_WIDEN);
5630e4b17023SJohn Marino if (tem)
5631e4b17023SJohn Marino tem = expand_binop (mode, ior_optab, op0, tem, subtarget, 0,
5632e4b17023SJohn Marino OPTAB_WIDEN);
5633e4b17023SJohn Marino }
5634e4b17023SJohn Marino
5635e4b17023SJohn Marino /* To see if A > 0, compute (((signed) A) << BITS) - A, where BITS is the
5636e4b17023SJohn Marino number of bits in the mode of OP0, minus one. */
5637e4b17023SJohn Marino
5638e4b17023SJohn Marino if (code == GT)
5639e4b17023SJohn Marino {
5640e4b17023SJohn Marino if (rtx_equal_p (subtarget, op0))
5641e4b17023SJohn Marino subtarget = 0;
5642e4b17023SJohn Marino
5643e4b17023SJohn Marino tem = expand_shift (RSHIFT_EXPR, mode, op0,
5644e4b17023SJohn Marino GET_MODE_BITSIZE (mode) - 1,
5645e4b17023SJohn Marino subtarget, 0);
5646e4b17023SJohn Marino tem = expand_binop (mode, sub_optab, tem, op0, subtarget, 0,
5647e4b17023SJohn Marino OPTAB_WIDEN);
5648e4b17023SJohn Marino }
5649e4b17023SJohn Marino
5650e4b17023SJohn Marino if (code == EQ || code == NE)
5651e4b17023SJohn Marino {
5652e4b17023SJohn Marino /* For EQ or NE, one way to do the comparison is to apply an operation
5653e4b17023SJohn Marino that converts the operand into a positive number if it is nonzero
5654e4b17023SJohn Marino or zero if it was originally zero. Then, for EQ, we subtract 1 and
5655e4b17023SJohn Marino for NE we negate. This puts the result in the sign bit. Then we
5656e4b17023SJohn Marino normalize with a shift, if needed.
5657e4b17023SJohn Marino
5658e4b17023SJohn Marino Two operations that can do the above actions are ABS and FFS, so try
5659e4b17023SJohn Marino them. If that doesn't work, and MODE is smaller than a full word,
5660e4b17023SJohn Marino we can use zero-extension to the wider mode (an unsigned conversion)
5661e4b17023SJohn Marino as the operation. */
5662e4b17023SJohn Marino
5663e4b17023SJohn Marino /* Note that ABS doesn't yield a positive number for INT_MIN, but
5664e4b17023SJohn Marino that is compensated by the subsequent overflow when subtracting
5665e4b17023SJohn Marino one / negating. */
5666e4b17023SJohn Marino
5667e4b17023SJohn Marino if (optab_handler (abs_optab, mode) != CODE_FOR_nothing)
5668e4b17023SJohn Marino tem = expand_unop (mode, abs_optab, op0, subtarget, 1);
5669e4b17023SJohn Marino else if (optab_handler (ffs_optab, mode) != CODE_FOR_nothing)
5670e4b17023SJohn Marino tem = expand_unop (mode, ffs_optab, op0, subtarget, 1);
5671e4b17023SJohn Marino else if (GET_MODE_SIZE (mode) < UNITS_PER_WORD)
5672e4b17023SJohn Marino {
5673e4b17023SJohn Marino tem = convert_modes (word_mode, mode, op0, 1);
5674e4b17023SJohn Marino mode = word_mode;
5675e4b17023SJohn Marino }
5676e4b17023SJohn Marino
5677e4b17023SJohn Marino if (tem != 0)
5678e4b17023SJohn Marino {
5679e4b17023SJohn Marino if (code == EQ)
5680e4b17023SJohn Marino tem = expand_binop (mode, sub_optab, tem, const1_rtx, subtarget,
5681e4b17023SJohn Marino 0, OPTAB_WIDEN);
5682e4b17023SJohn Marino else
5683e4b17023SJohn Marino tem = expand_unop (mode, neg_optab, tem, subtarget, 0);
5684e4b17023SJohn Marino }
5685e4b17023SJohn Marino
5686e4b17023SJohn Marino /* If we couldn't do it that way, for NE we can "or" the two's complement
5687e4b17023SJohn Marino of the value with itself. For EQ, we take the one's complement of
5688e4b17023SJohn Marino that "or", which is an extra insn, so we only handle EQ if branches
5689e4b17023SJohn Marino are expensive. */
5690e4b17023SJohn Marino
5691e4b17023SJohn Marino if (tem == 0
5692e4b17023SJohn Marino && (code == NE
5693e4b17023SJohn Marino || BRANCH_COST (optimize_insn_for_speed_p (),
5694e4b17023SJohn Marino false) > 1))
5695e4b17023SJohn Marino {
5696e4b17023SJohn Marino if (rtx_equal_p (subtarget, op0))
5697e4b17023SJohn Marino subtarget = 0;
5698e4b17023SJohn Marino
5699e4b17023SJohn Marino tem = expand_unop (mode, neg_optab, op0, subtarget, 0);
5700e4b17023SJohn Marino tem = expand_binop (mode, ior_optab, tem, op0, subtarget, 0,
5701e4b17023SJohn Marino OPTAB_WIDEN);
5702e4b17023SJohn Marino
5703e4b17023SJohn Marino if (tem && code == EQ)
5704e4b17023SJohn Marino tem = expand_unop (mode, one_cmpl_optab, tem, subtarget, 0);
5705e4b17023SJohn Marino }
5706e4b17023SJohn Marino }
5707e4b17023SJohn Marino
5708e4b17023SJohn Marino if (tem && normalizep)
5709e4b17023SJohn Marino tem = expand_shift (RSHIFT_EXPR, mode, tem,
5710e4b17023SJohn Marino GET_MODE_BITSIZE (mode) - 1,
5711e4b17023SJohn Marino subtarget, normalizep == 1);
5712e4b17023SJohn Marino
5713e4b17023SJohn Marino if (tem)
5714e4b17023SJohn Marino {
5715e4b17023SJohn Marino if (!target)
5716e4b17023SJohn Marino ;
5717e4b17023SJohn Marino else if (GET_MODE (tem) != target_mode)
5718e4b17023SJohn Marino {
5719e4b17023SJohn Marino convert_move (target, tem, 0);
5720e4b17023SJohn Marino tem = target;
5721e4b17023SJohn Marino }
5722e4b17023SJohn Marino else if (!subtarget)
5723e4b17023SJohn Marino {
5724e4b17023SJohn Marino emit_move_insn (target, tem);
5725e4b17023SJohn Marino tem = target;
5726e4b17023SJohn Marino }
5727e4b17023SJohn Marino }
5728e4b17023SJohn Marino else
5729e4b17023SJohn Marino delete_insns_since (last);
5730e4b17023SJohn Marino
5731e4b17023SJohn Marino return tem;
5732e4b17023SJohn Marino }
5733e4b17023SJohn Marino
5734e4b17023SJohn Marino /* Like emit_store_flag, but always succeeds. */
5735e4b17023SJohn Marino
5736e4b17023SJohn Marino rtx
emit_store_flag_force(rtx target,enum rtx_code code,rtx op0,rtx op1,enum machine_mode mode,int unsignedp,int normalizep)5737e4b17023SJohn Marino emit_store_flag_force (rtx target, enum rtx_code code, rtx op0, rtx op1,
5738e4b17023SJohn Marino enum machine_mode mode, int unsignedp, int normalizep)
5739e4b17023SJohn Marino {
5740e4b17023SJohn Marino rtx tem, label;
5741e4b17023SJohn Marino rtx trueval, falseval;
5742e4b17023SJohn Marino
5743e4b17023SJohn Marino /* First see if emit_store_flag can do the job. */
5744e4b17023SJohn Marino tem = emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep);
5745e4b17023SJohn Marino if (tem != 0)
5746e4b17023SJohn Marino return tem;
5747e4b17023SJohn Marino
5748e4b17023SJohn Marino if (!target)
5749e4b17023SJohn Marino target = gen_reg_rtx (word_mode);
5750e4b17023SJohn Marino
5751e4b17023SJohn Marino /* If this failed, we have to do this with set/compare/jump/set code.
5752e4b17023SJohn Marino For foo != 0, if foo is in OP0, just replace it with 1 if nonzero. */
5753e4b17023SJohn Marino trueval = normalizep ? GEN_INT (normalizep) : const1_rtx;
5754e4b17023SJohn Marino if (code == NE
5755e4b17023SJohn Marino && GET_MODE_CLASS (mode) == MODE_INT
5756e4b17023SJohn Marino && REG_P (target)
5757e4b17023SJohn Marino && op0 == target
5758e4b17023SJohn Marino && op1 == const0_rtx)
5759e4b17023SJohn Marino {
5760e4b17023SJohn Marino label = gen_label_rtx ();
5761e4b17023SJohn Marino do_compare_rtx_and_jump (target, const0_rtx, EQ, unsignedp,
5762e4b17023SJohn Marino mode, NULL_RTX, NULL_RTX, label, -1);
5763e4b17023SJohn Marino emit_move_insn (target, trueval);
5764e4b17023SJohn Marino emit_label (label);
5765e4b17023SJohn Marino return target;
5766e4b17023SJohn Marino }
5767e4b17023SJohn Marino
5768e4b17023SJohn Marino if (!REG_P (target)
5769e4b17023SJohn Marino || reg_mentioned_p (target, op0) || reg_mentioned_p (target, op1))
5770e4b17023SJohn Marino target = gen_reg_rtx (GET_MODE (target));
5771e4b17023SJohn Marino
5772e4b17023SJohn Marino /* Jump in the right direction if the target cannot implement CODE
5773e4b17023SJohn Marino but can jump on its reverse condition. */
5774e4b17023SJohn Marino falseval = const0_rtx;
5775e4b17023SJohn Marino if (! can_compare_p (code, mode, ccp_jump)
5776e4b17023SJohn Marino && (! FLOAT_MODE_P (mode)
5777e4b17023SJohn Marino || code == ORDERED || code == UNORDERED
5778e4b17023SJohn Marino || (! HONOR_NANS (mode) && (code == LTGT || code == UNEQ))
5779e4b17023SJohn Marino || (! HONOR_SNANS (mode) && (code == EQ || code == NE))))
5780e4b17023SJohn Marino {
5781e4b17023SJohn Marino enum rtx_code rcode;
5782e4b17023SJohn Marino if (FLOAT_MODE_P (mode))
5783e4b17023SJohn Marino rcode = reverse_condition_maybe_unordered (code);
5784e4b17023SJohn Marino else
5785e4b17023SJohn Marino rcode = reverse_condition (code);
5786e4b17023SJohn Marino
5787e4b17023SJohn Marino /* Canonicalize to UNORDERED for the libcall. */
5788e4b17023SJohn Marino if (can_compare_p (rcode, mode, ccp_jump)
5789e4b17023SJohn Marino || (code == ORDERED && ! can_compare_p (ORDERED, mode, ccp_jump)))
5790e4b17023SJohn Marino {
5791e4b17023SJohn Marino falseval = trueval;
5792e4b17023SJohn Marino trueval = const0_rtx;
5793e4b17023SJohn Marino code = rcode;
5794e4b17023SJohn Marino }
5795e4b17023SJohn Marino }
5796e4b17023SJohn Marino
5797e4b17023SJohn Marino emit_move_insn (target, trueval);
5798e4b17023SJohn Marino label = gen_label_rtx ();
5799e4b17023SJohn Marino do_compare_rtx_and_jump (op0, op1, code, unsignedp, mode, NULL_RTX,
5800e4b17023SJohn Marino NULL_RTX, label, -1);
5801e4b17023SJohn Marino
5802e4b17023SJohn Marino emit_move_insn (target, falseval);
5803e4b17023SJohn Marino emit_label (label);
5804e4b17023SJohn Marino
5805e4b17023SJohn Marino return target;
5806e4b17023SJohn Marino }
5807e4b17023SJohn Marino
5808e4b17023SJohn Marino /* Perform possibly multi-word comparison and conditional jump to LABEL
5809e4b17023SJohn Marino if ARG1 OP ARG2 true where ARG1 and ARG2 are of mode MODE. This is
5810e4b17023SJohn Marino now a thin wrapper around do_compare_rtx_and_jump. */
5811e4b17023SJohn Marino
5812e4b17023SJohn Marino static void
do_cmp_and_jump(rtx arg1,rtx arg2,enum rtx_code op,enum machine_mode mode,rtx label)5813e4b17023SJohn Marino do_cmp_and_jump (rtx arg1, rtx arg2, enum rtx_code op, enum machine_mode mode,
5814e4b17023SJohn Marino rtx label)
5815e4b17023SJohn Marino {
5816e4b17023SJohn Marino int unsignedp = (op == LTU || op == LEU || op == GTU || op == GEU);
5817e4b17023SJohn Marino do_compare_rtx_and_jump (arg1, arg2, op, unsignedp, mode,
5818e4b17023SJohn Marino NULL_RTX, NULL_RTX, label, -1);
5819e4b17023SJohn Marino }
5820