xref: /dflybsd-src/contrib/gcc-4.7/gcc/expmed.c (revision 81fc95a5293ee307c688a350a3feb4734aaddbb4)
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