1 /* IR-agnostic target query functions relating to optabs
2    Copyright (C) 1987-2016 Free Software Foundation, Inc.
3 
4 This file is part of GCC.
5 
6 GCC is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 3, or (at your option) any later
9 version.
10 
11 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GCC; see the file COPYING3.  If not see
18 <http://www.gnu.org/licenses/>.  */
19 
20 
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "target.h"
25 #include "insn-codes.h"
26 #include "optabs-query.h"
27 #include "optabs-libfuncs.h"
28 #include "insn-config.h"
29 #include "rtl.h"
30 #include "recog.h"
31 
32 struct target_optabs default_target_optabs;
33 struct target_optabs *this_fn_optabs = &default_target_optabs;
34 #if SWITCHABLE_TARGET
35 struct target_optabs *this_target_optabs = &default_target_optabs;
36 #endif
37 
38 /* Return the insn used to perform conversion OP from mode FROM_MODE
39    to mode TO_MODE; return CODE_FOR_nothing if the target does not have
40    such an insn, or if it is unsuitable for optimization type OPT_TYPE.  */
41 
42 insn_code
convert_optab_handler(convert_optab optab,machine_mode to_mode,machine_mode from_mode,optimization_type opt_type)43 convert_optab_handler (convert_optab optab, machine_mode to_mode,
44 		       machine_mode from_mode, optimization_type opt_type)
45 {
46   insn_code icode = convert_optab_handler (optab, to_mode, from_mode);
47   if (icode == CODE_FOR_nothing
48       || !targetm.optab_supported_p (optab, to_mode, from_mode, opt_type))
49     return CODE_FOR_nothing;
50   return icode;
51 }
52 
53 /* Return the insn used to implement mode MODE of OP; return
54    CODE_FOR_nothing if the target does not have such an insn,
55    or if it is unsuitable for optimization type OPT_TYPE.  */
56 
57 insn_code
direct_optab_handler(convert_optab optab,machine_mode mode,optimization_type opt_type)58 direct_optab_handler (convert_optab optab, machine_mode mode,
59 		      optimization_type opt_type)
60 {
61   insn_code icode = direct_optab_handler (optab, mode);
62   if (icode == CODE_FOR_nothing
63       || !targetm.optab_supported_p (optab, mode, mode, opt_type))
64     return CODE_FOR_nothing;
65   return icode;
66 }
67 
68 /* Enumerates the possible types of structure operand to an
69    extraction_insn.  */
70 enum extraction_type { ET_unaligned_mem, ET_reg };
71 
72 /* Check whether insv, extv or extzv pattern ICODE can be used for an
73    insertion or extraction of type TYPE on a structure of mode MODE.
74    Return true if so and fill in *INSN accordingly.  STRUCT_OP is the
75    operand number of the structure (the first sign_extract or zero_extract
76    operand) and FIELD_OP is the operand number of the field (the other
77    side of the set from the sign_extract or zero_extract).  */
78 
79 static bool
get_traditional_extraction_insn(extraction_insn * insn,enum extraction_type type,machine_mode mode,enum insn_code icode,int struct_op,int field_op)80 get_traditional_extraction_insn (extraction_insn *insn,
81 				 enum extraction_type type,
82 				 machine_mode mode,
83 				 enum insn_code icode,
84 				 int struct_op, int field_op)
85 {
86   const struct insn_data_d *data = &insn_data[icode];
87 
88   machine_mode struct_mode = data->operand[struct_op].mode;
89   if (struct_mode == VOIDmode)
90     struct_mode = word_mode;
91   if (mode != struct_mode)
92     return false;
93 
94   machine_mode field_mode = data->operand[field_op].mode;
95   if (field_mode == VOIDmode)
96     field_mode = word_mode;
97 
98   machine_mode pos_mode = data->operand[struct_op + 2].mode;
99   if (pos_mode == VOIDmode)
100     pos_mode = word_mode;
101 
102   insn->icode = icode;
103   insn->field_mode = field_mode;
104   insn->struct_mode = (type == ET_unaligned_mem ? byte_mode : struct_mode);
105   insn->pos_mode = pos_mode;
106   return true;
107 }
108 
109 /* Return true if an optab exists to perform an insertion or extraction
110    of type TYPE in mode MODE.  Describe the instruction in *INSN if so.
111 
112    REG_OPTAB is the optab to use for register structures and
113    MISALIGN_OPTAB is the optab to use for misaligned memory structures.
114    POS_OP is the operand number of the bit position.  */
115 
116 static bool
get_optab_extraction_insn(struct extraction_insn * insn,enum extraction_type type,machine_mode mode,direct_optab reg_optab,direct_optab misalign_optab,int pos_op)117 get_optab_extraction_insn (struct extraction_insn *insn,
118 			   enum extraction_type type,
119 			   machine_mode mode, direct_optab reg_optab,
120 			   direct_optab misalign_optab, int pos_op)
121 {
122   direct_optab optab = (type == ET_unaligned_mem ? misalign_optab : reg_optab);
123   enum insn_code icode = direct_optab_handler (optab, mode);
124   if (icode == CODE_FOR_nothing)
125     return false;
126 
127   const struct insn_data_d *data = &insn_data[icode];
128 
129   insn->icode = icode;
130   insn->field_mode = mode;
131   insn->struct_mode = (type == ET_unaligned_mem ? BLKmode : mode);
132   insn->pos_mode = data->operand[pos_op].mode;
133   if (insn->pos_mode == VOIDmode)
134     insn->pos_mode = word_mode;
135   return true;
136 }
137 
138 /* Return true if an instruction exists to perform an insertion or
139    extraction (PATTERN says which) of type TYPE in mode MODE.
140    Describe the instruction in *INSN if so.  */
141 
142 static bool
get_extraction_insn(extraction_insn * insn,enum extraction_pattern pattern,enum extraction_type type,machine_mode mode)143 get_extraction_insn (extraction_insn *insn,
144 		     enum extraction_pattern pattern,
145 		     enum extraction_type type,
146 		     machine_mode mode)
147 {
148   switch (pattern)
149     {
150     case EP_insv:
151       if (targetm.have_insv ()
152 	  && get_traditional_extraction_insn (insn, type, mode,
153 					      targetm.code_for_insv, 0, 3))
154 	return true;
155       return get_optab_extraction_insn (insn, type, mode, insv_optab,
156 					insvmisalign_optab, 2);
157 
158     case EP_extv:
159       if (targetm.have_extv ()
160 	  && get_traditional_extraction_insn (insn, type, mode,
161 					      targetm.code_for_extv, 1, 0))
162 	return true;
163       return get_optab_extraction_insn (insn, type, mode, extv_optab,
164 					extvmisalign_optab, 3);
165 
166     case EP_extzv:
167       if (targetm.have_extzv ()
168 	  && get_traditional_extraction_insn (insn, type, mode,
169 					      targetm.code_for_extzv, 1, 0))
170 	return true;
171       return get_optab_extraction_insn (insn, type, mode, extzv_optab,
172 					extzvmisalign_optab, 3);
173 
174     default:
175       gcc_unreachable ();
176     }
177 }
178 
179 /* Return true if an instruction exists to access a field of mode
180    FIELDMODE in a structure that has STRUCT_BITS significant bits.
181    Describe the "best" such instruction in *INSN if so.  PATTERN and
182    TYPE describe the type of insertion or extraction we want to perform.
183 
184    For an insertion, the number of significant structure bits includes
185    all bits of the target.  For an extraction, it need only include the
186    most significant bit of the field.  Larger widths are acceptable
187    in both cases.  */
188 
189 static bool
get_best_extraction_insn(extraction_insn * insn,enum extraction_pattern pattern,enum extraction_type type,unsigned HOST_WIDE_INT struct_bits,machine_mode field_mode)190 get_best_extraction_insn (extraction_insn *insn,
191 			  enum extraction_pattern pattern,
192 			  enum extraction_type type,
193 			  unsigned HOST_WIDE_INT struct_bits,
194 			  machine_mode field_mode)
195 {
196   machine_mode mode = smallest_mode_for_size (struct_bits, MODE_INT);
197   while (mode != VOIDmode)
198     {
199       if (get_extraction_insn (insn, pattern, type, mode))
200 	{
201 	  while (mode != VOIDmode
202 		 && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (field_mode)
203 		 && !TRULY_NOOP_TRUNCATION_MODES_P (insn->field_mode,
204 						    field_mode))
205 	    {
206 	      get_extraction_insn (insn, pattern, type, mode);
207 	      mode = GET_MODE_WIDER_MODE (mode);
208 	    }
209 	  return true;
210 	}
211       mode = GET_MODE_WIDER_MODE (mode);
212     }
213   return false;
214 }
215 
216 /* Return true if an instruction exists to access a field of mode
217    FIELDMODE in a register structure that has STRUCT_BITS significant bits.
218    Describe the "best" such instruction in *INSN if so.  PATTERN describes
219    the type of insertion or extraction we want to perform.
220 
221    For an insertion, the number of significant structure bits includes
222    all bits of the target.  For an extraction, it need only include the
223    most significant bit of the field.  Larger widths are acceptable
224    in both cases.  */
225 
226 bool
get_best_reg_extraction_insn(extraction_insn * insn,enum extraction_pattern pattern,unsigned HOST_WIDE_INT struct_bits,machine_mode field_mode)227 get_best_reg_extraction_insn (extraction_insn *insn,
228 			      enum extraction_pattern pattern,
229 			      unsigned HOST_WIDE_INT struct_bits,
230 			      machine_mode field_mode)
231 {
232   return get_best_extraction_insn (insn, pattern, ET_reg, struct_bits,
233 				   field_mode);
234 }
235 
236 /* Return true if an instruction exists to access a field of BITSIZE
237    bits starting BITNUM bits into a memory structure.  Describe the
238    "best" such instruction in *INSN if so.  PATTERN describes the type
239    of insertion or extraction we want to perform and FIELDMODE is the
240    natural mode of the extracted field.
241 
242    The instructions considered here only access bytes that overlap
243    the bitfield; they do not touch any surrounding bytes.  */
244 
245 bool
get_best_mem_extraction_insn(extraction_insn * insn,enum extraction_pattern pattern,HOST_WIDE_INT bitsize,HOST_WIDE_INT bitnum,machine_mode field_mode)246 get_best_mem_extraction_insn (extraction_insn *insn,
247 			      enum extraction_pattern pattern,
248 			      HOST_WIDE_INT bitsize, HOST_WIDE_INT bitnum,
249 			      machine_mode field_mode)
250 {
251   unsigned HOST_WIDE_INT struct_bits = (bitnum % BITS_PER_UNIT
252 					+ bitsize
253 					+ BITS_PER_UNIT - 1);
254   struct_bits -= struct_bits % BITS_PER_UNIT;
255   return get_best_extraction_insn (insn, pattern, ET_unaligned_mem,
256 				   struct_bits, field_mode);
257 }
258 
259 /* Return the insn code used to extend FROM_MODE to TO_MODE.
260    UNSIGNEDP specifies zero-extension instead of sign-extension.  If
261    no such operation exists, CODE_FOR_nothing will be returned.  */
262 
263 enum insn_code
can_extend_p(machine_mode to_mode,machine_mode from_mode,int unsignedp)264 can_extend_p (machine_mode to_mode, machine_mode from_mode,
265 	      int unsignedp)
266 {
267   if (unsignedp < 0 && targetm.have_ptr_extend ())
268     return targetm.code_for_ptr_extend;
269 
270   convert_optab tab = unsignedp ? zext_optab : sext_optab;
271   return convert_optab_handler (tab, to_mode, from_mode);
272 }
273 
274 /* Return the insn code to convert fixed-point mode FIXMODE to floating-point
275    mode FLTMODE, or CODE_FOR_nothing if no such instruction exists.
276    UNSIGNEDP specifies whether FIXMODE is unsigned.  */
277 
278 enum insn_code
can_float_p(machine_mode fltmode,machine_mode fixmode,int unsignedp)279 can_float_p (machine_mode fltmode, machine_mode fixmode,
280 	     int unsignedp)
281 {
282   convert_optab tab = unsignedp ? ufloat_optab : sfloat_optab;
283   return convert_optab_handler (tab, fltmode, fixmode);
284 }
285 
286 /* Return the insn code to convert floating-point mode FLTMODE to fixed-point
287    mode FIXMODE, or CODE_FOR_nothing if no such instruction exists.
288    UNSIGNEDP specifies whether FIXMODE is unsigned.
289 
290    On a successful return, set *TRUNCP_PTR to true if it is necessary to
291    output an explicit FTRUNC before the instruction.  */
292 
293 enum insn_code
can_fix_p(machine_mode fixmode,machine_mode fltmode,int unsignedp,bool * truncp_ptr)294 can_fix_p (machine_mode fixmode, machine_mode fltmode,
295 	   int unsignedp, bool *truncp_ptr)
296 {
297   convert_optab tab;
298   enum insn_code icode;
299 
300   tab = unsignedp ? ufixtrunc_optab : sfixtrunc_optab;
301   icode = convert_optab_handler (tab, fixmode, fltmode);
302   if (icode != CODE_FOR_nothing)
303     {
304       *truncp_ptr = false;
305       return icode;
306     }
307 
308   /* FIXME: This requires a port to define both FIX and FTRUNC pattern
309      for this to work.  We need to rework the fix* and ftrunc* patterns
310      and documentation.  */
311   tab = unsignedp ? ufix_optab : sfix_optab;
312   icode = convert_optab_handler (tab, fixmode, fltmode);
313   if (icode != CODE_FOR_nothing
314       && optab_handler (ftrunc_optab, fltmode) != CODE_FOR_nothing)
315     {
316       *truncp_ptr = true;
317       return icode;
318     }
319 
320   return CODE_FOR_nothing;
321 }
322 
323 /* Return nonzero if a conditional move of mode MODE is supported.
324 
325    This function is for combine so it can tell whether an insn that looks
326    like a conditional move is actually supported by the hardware.  If we
327    guess wrong we lose a bit on optimization, but that's it.  */
328 /* ??? sparc64 supports conditionally moving integers values based on fp
329    comparisons, and vice versa.  How do we handle them?  */
330 
331 bool
can_conditionally_move_p(machine_mode mode)332 can_conditionally_move_p (machine_mode mode)
333 {
334   return direct_optab_handler (movcc_optab, mode) != CODE_FOR_nothing;
335 }
336 
337 /* Return true if VEC_PERM_EXPR of arbitrary input vectors can be
338    expanded using SIMD extensions of the CPU.  SEL may be NULL, which
339    stands for an unknown constant.  Note that additional permutations
340    representing whole-vector shifts may also be handled via the vec_shr
341    optab, but only where the second input vector is entirely constant
342    zeroes; this case is not dealt with here.  */
343 
344 bool
can_vec_perm_p(machine_mode mode,bool variable,const unsigned char * sel)345 can_vec_perm_p (machine_mode mode, bool variable,
346 		const unsigned char *sel)
347 {
348   machine_mode qimode;
349 
350   /* If the target doesn't implement a vector mode for the vector type,
351      then no operations are supported.  */
352   if (!VECTOR_MODE_P (mode))
353     return false;
354 
355   if (!variable)
356     {
357       if (direct_optab_handler (vec_perm_const_optab, mode) != CODE_FOR_nothing
358 	  && (sel == NULL
359 	      || targetm.vectorize.vec_perm_const_ok == NULL
360 	      || targetm.vectorize.vec_perm_const_ok (mode, sel)))
361 	return true;
362     }
363 
364   if (direct_optab_handler (vec_perm_optab, mode) != CODE_FOR_nothing)
365     return true;
366 
367   /* We allow fallback to a QI vector mode, and adjust the mask.  */
368   if (GET_MODE_INNER (mode) == QImode)
369     return false;
370   qimode = mode_for_vector (QImode, GET_MODE_SIZE (mode));
371   if (!VECTOR_MODE_P (qimode))
372     return false;
373 
374   /* ??? For completeness, we ought to check the QImode version of
375       vec_perm_const_optab.  But all users of this implicit lowering
376       feature implement the variable vec_perm_optab.  */
377   if (direct_optab_handler (vec_perm_optab, qimode) == CODE_FOR_nothing)
378     return false;
379 
380   /* In order to support the lowering of variable permutations,
381      we need to support shifts and adds.  */
382   if (variable)
383     {
384       if (GET_MODE_UNIT_SIZE (mode) > 2
385 	  && optab_handler (ashl_optab, mode) == CODE_FOR_nothing
386 	  && optab_handler (vashl_optab, mode) == CODE_FOR_nothing)
387 	return false;
388       if (optab_handler (add_optab, qimode) == CODE_FOR_nothing)
389 	return false;
390     }
391 
392   return true;
393 }
394 
395 /* Like optab_handler, but for widening_operations that have a
396    TO_MODE and a FROM_MODE.  */
397 
398 enum insn_code
widening_optab_handler(optab op,machine_mode to_mode,machine_mode from_mode)399 widening_optab_handler (optab op, machine_mode to_mode,
400 			machine_mode from_mode)
401 {
402   unsigned scode = (op << 16) | to_mode;
403   if (to_mode != from_mode && from_mode != VOIDmode)
404     {
405       /* ??? Why does find_widening_optab_handler_and_mode attempt to
406 	 widen things that can't be widened?  E.g. add_optab... */
407       if (op > LAST_CONV_OPTAB)
408 	return CODE_FOR_nothing;
409       scode |= from_mode << 8;
410     }
411   return raw_optab_handler (scode);
412 }
413 
414 /* Find a widening optab even if it doesn't widen as much as we want.
415    E.g. if from_mode is HImode, and to_mode is DImode, and there is no
416    direct HI->SI insn, then return SI->DI, if that exists.
417    If PERMIT_NON_WIDENING is non-zero then this can be used with
418    non-widening optabs also.  */
419 
420 enum insn_code
find_widening_optab_handler_and_mode(optab op,machine_mode to_mode,machine_mode from_mode,int permit_non_widening,machine_mode * found_mode)421 find_widening_optab_handler_and_mode (optab op, machine_mode to_mode,
422 				      machine_mode from_mode,
423 				      int permit_non_widening,
424 				      machine_mode *found_mode)
425 {
426   for (; (permit_non_widening || from_mode != to_mode)
427 	 && GET_MODE_SIZE (from_mode) <= GET_MODE_SIZE (to_mode)
428 	 && from_mode != VOIDmode;
429        from_mode = GET_MODE_WIDER_MODE (from_mode))
430     {
431       enum insn_code handler = widening_optab_handler (op, to_mode,
432 						       from_mode);
433 
434       if (handler != CODE_FOR_nothing)
435 	{
436 	  if (found_mode)
437 	    *found_mode = from_mode;
438 	  return handler;
439 	}
440     }
441 
442   return CODE_FOR_nothing;
443 }
444 
445 /* Return non-zero if a highpart multiply is supported of can be synthisized.
446    For the benefit of expand_mult_highpart, the return value is 1 for direct,
447    2 for even/odd widening, and 3 for hi/lo widening.  */
448 
449 int
can_mult_highpart_p(machine_mode mode,bool uns_p)450 can_mult_highpart_p (machine_mode mode, bool uns_p)
451 {
452   optab op;
453   unsigned char *sel;
454   unsigned i, nunits;
455 
456   op = uns_p ? umul_highpart_optab : smul_highpart_optab;
457   if (optab_handler (op, mode) != CODE_FOR_nothing)
458     return 1;
459 
460   /* If the mode is an integral vector, synth from widening operations.  */
461   if (GET_MODE_CLASS (mode) != MODE_VECTOR_INT)
462     return 0;
463 
464   nunits = GET_MODE_NUNITS (mode);
465   sel = XALLOCAVEC (unsigned char, nunits);
466 
467   op = uns_p ? vec_widen_umult_even_optab : vec_widen_smult_even_optab;
468   if (optab_handler (op, mode) != CODE_FOR_nothing)
469     {
470       op = uns_p ? vec_widen_umult_odd_optab : vec_widen_smult_odd_optab;
471       if (optab_handler (op, mode) != CODE_FOR_nothing)
472 	{
473 	  for (i = 0; i < nunits; ++i)
474 	    sel[i] = !BYTES_BIG_ENDIAN + (i & ~1) + ((i & 1) ? nunits : 0);
475 	  if (can_vec_perm_p (mode, false, sel))
476 	    return 2;
477 	}
478     }
479 
480   op = uns_p ? vec_widen_umult_hi_optab : vec_widen_smult_hi_optab;
481   if (optab_handler (op, mode) != CODE_FOR_nothing)
482     {
483       op = uns_p ? vec_widen_umult_lo_optab : vec_widen_smult_lo_optab;
484       if (optab_handler (op, mode) != CODE_FOR_nothing)
485 	{
486 	  for (i = 0; i < nunits; ++i)
487 	    sel[i] = 2 * i + (BYTES_BIG_ENDIAN ? 0 : 1);
488 	  if (can_vec_perm_p (mode, false, sel))
489 	    return 3;
490 	}
491     }
492 
493   return 0;
494 }
495 
496 /* Return true if target supports vector masked load/store for mode.  */
497 
498 bool
can_vec_mask_load_store_p(machine_mode mode,machine_mode mask_mode,bool is_load)499 can_vec_mask_load_store_p (machine_mode mode,
500 			   machine_mode mask_mode,
501 			   bool is_load)
502 {
503   optab op = is_load ? maskload_optab : maskstore_optab;
504   machine_mode vmode;
505   unsigned int vector_sizes;
506 
507   /* If mode is vector mode, check it directly.  */
508   if (VECTOR_MODE_P (mode))
509     return convert_optab_handler (op, mode, mask_mode) != CODE_FOR_nothing;
510 
511   /* Otherwise, return true if there is some vector mode with
512      the mask load/store supported.  */
513 
514   /* See if there is any chance the mask load or store might be
515      vectorized.  If not, punt.  */
516   vmode = targetm.vectorize.preferred_simd_mode (mode);
517   if (!VECTOR_MODE_P (vmode))
518     return false;
519 
520   mask_mode = targetm.vectorize.get_mask_mode (GET_MODE_NUNITS (vmode),
521 					       GET_MODE_SIZE (vmode));
522   if (mask_mode == VOIDmode)
523     return false;
524 
525   if (convert_optab_handler (op, vmode, mask_mode) != CODE_FOR_nothing)
526     return true;
527 
528   vector_sizes = targetm.vectorize.autovectorize_vector_sizes ();
529   while (vector_sizes != 0)
530     {
531       unsigned int cur = 1 << floor_log2 (vector_sizes);
532       vector_sizes &= ~cur;
533       if (cur <= GET_MODE_SIZE (mode))
534 	continue;
535       vmode = mode_for_vector (mode, cur / GET_MODE_SIZE (mode));
536       mask_mode = targetm.vectorize.get_mask_mode (GET_MODE_NUNITS (vmode),
537 						   cur);
538       if (VECTOR_MODE_P (vmode)
539 	  && convert_optab_handler (op, vmode, mask_mode) != CODE_FOR_nothing)
540 	return true;
541     }
542   return false;
543 }
544 
545 /* Return true if there is a compare_and_swap pattern.  */
546 
547 bool
can_compare_and_swap_p(machine_mode mode,bool allow_libcall)548 can_compare_and_swap_p (machine_mode mode, bool allow_libcall)
549 {
550   enum insn_code icode;
551 
552   /* Check for __atomic_compare_and_swap.  */
553   icode = direct_optab_handler (atomic_compare_and_swap_optab, mode);
554   if (icode != CODE_FOR_nothing)
555     return true;
556 
557   /* Check for __sync_compare_and_swap.  */
558   icode = optab_handler (sync_compare_and_swap_optab, mode);
559   if (icode != CODE_FOR_nothing)
560     return true;
561   if (allow_libcall && optab_libfunc (sync_compare_and_swap_optab, mode))
562     return true;
563 
564   /* No inline compare and swap.  */
565   return false;
566 }
567 
568 /* Return true if an atomic exchange can be performed.  */
569 
570 bool
can_atomic_exchange_p(machine_mode mode,bool allow_libcall)571 can_atomic_exchange_p (machine_mode mode, bool allow_libcall)
572 {
573   enum insn_code icode;
574 
575   /* Check for __atomic_exchange.  */
576   icode = direct_optab_handler (atomic_exchange_optab, mode);
577   if (icode != CODE_FOR_nothing)
578     return true;
579 
580   /* Don't check __sync_test_and_set, as on some platforms that
581      has reduced functionality.  Targets that really do support
582      a proper exchange should simply be updated to the __atomics.  */
583 
584   return can_compare_and_swap_p (mode, allow_libcall);
585 }
586 
587 /* Determine whether "1 << x" is relatively cheap in word_mode.  */
588 
589 bool
lshift_cheap_p(bool speed_p)590 lshift_cheap_p (bool speed_p)
591 {
592   /* FIXME: This should be made target dependent via this "this_target"
593      mechanism, similar to e.g. can_copy_init_p in gcse.c.  */
594   static bool init[2] = { false, false };
595   static bool cheap[2] = { true, true };
596 
597   /* If the targer has no lshift in word_mode, the operation will most
598      probably not be cheap.  ??? Does GCC even work for such targets?  */
599   if (optab_handler (ashl_optab, word_mode) == CODE_FOR_nothing)
600     return false;
601 
602   if (!init[speed_p])
603     {
604       rtx reg = gen_raw_REG (word_mode, 10000);
605       int cost = set_src_cost (gen_rtx_ASHIFT (word_mode, const1_rtx, reg),
606 			       word_mode, speed_p);
607       cheap[speed_p] = cost < COSTS_N_INSNS (3);
608       init[speed_p] = true;
609     }
610 
611   return cheap[speed_p];
612 }
613