1 /* Dependency checks for instruction scheduling, shared between ARM and
2    AARCH64.
3 
4    Copyright (C) 1991-2021 Free Software Foundation, Inc.
5    Contributed by ARM Ltd.
6 
7    This file is part of GCC.
8 
9    GCC is free software; you can redistribute it and/or modify it
10    under the terms of the GNU General Public License as published
11    by the Free Software Foundation; either version 3, or (at your
12    option) any later version.
13 
14    GCC is distributed in the hope that it will be useful, but WITHOUT
15    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
17    License for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with GCC; see the file COPYING3.  If not see
21    <http://www.gnu.org/licenses/>.  */
22 
23 
24 #define IN_TARGET_CODE 1
25 
26 #include "config.h"
27 #include "system.h"
28 #include "coretypes.h"
29 #include "insn-modes.h"
30 #include "tm.h"
31 #include "rtl.h"
32 #include "rtl-iter.h"
33 #include "memmodel.h"
34 #include "diagnostic.h"
35 #include "tree.h"
36 #include "expr.h"
37 #include "function.h"
38 #include "emit-rtl.h"
39 
40 /* Return TRUE if X is either an arithmetic shift left, or
41    is a multiplication by a power of two.  */
42 bool
arm_rtx_shift_left_p(rtx x)43 arm_rtx_shift_left_p (rtx x)
44 {
45   enum rtx_code code = GET_CODE (x);
46 
47   if (code == MULT && CONST_INT_P (XEXP (x, 1))
48       && exact_log2 (INTVAL (XEXP (x, 1))) > 0)
49     return true;
50 
51   if (code == ASHIFT)
52     return true;
53 
54   return false;
55 }
56 
57 static rtx_code shift_rtx_codes[] =
58   { ASHIFT, ROTATE, ASHIFTRT, LSHIFTRT,
59     ROTATERT, ZERO_EXTEND, SIGN_EXTEND };
60 
61 /* Traverse PATTERN looking for a sub-rtx with RTX_CODE CODE.
62    If FIND_ANY_SHIFT then we are interested in anything which can
63    reasonably be described as a SHIFT RTX.  */
64 static rtx
arm_find_sub_rtx_with_code(rtx pattern,rtx_code code,bool find_any_shift)65 arm_find_sub_rtx_with_code (rtx pattern, rtx_code code, bool find_any_shift)
66 {
67   subrtx_var_iterator::array_type array;
68   FOR_EACH_SUBRTX_VAR (iter, array, pattern, NONCONST)
69     {
70       rtx x = *iter;
71       if (find_any_shift)
72 	{
73 	  /* Left shifts might have been canonicalized to a MULT of some
74 	     power of two.  Make sure we catch them.  */
75 	  if (arm_rtx_shift_left_p (x))
76 	    return x;
77 	  else
78 	    for (unsigned int i = 0; i < ARRAY_SIZE (shift_rtx_codes); i++)
79 	      if (GET_CODE (x) == shift_rtx_codes[i])
80 		return x;
81 	}
82 
83       if (GET_CODE (x) == code)
84 	return x;
85     }
86   return NULL_RTX;
87 }
88 
89 /* Traverse PATTERN looking for any sub-rtx which looks like a shift.  */
90 static rtx
arm_find_shift_sub_rtx(rtx pattern)91 arm_find_shift_sub_rtx (rtx pattern)
92 {
93   return arm_find_sub_rtx_with_code (pattern, ASHIFT, true);
94 }
95 
96 /* PRODUCER and CONSUMER are two potentially dependant RTX.  PRODUCER
97    (possibly) contains a SET which will provide a result we can access
98    using the SET_DEST macro.  We will place the RTX which would be
99    written by PRODUCER in SET_SOURCE.
100    Similarly, CONSUMER (possibly) contains a SET which has an operand
101    we can access using SET_SRC.  We place this operand in
102    SET_DESTINATION.
103 
104    Return nonzero if we found the SET RTX we expected.  */
105 static int
arm_get_set_operands(rtx producer,rtx consumer,rtx * set_source,rtx * set_destination)106 arm_get_set_operands (rtx producer, rtx consumer,
107 		      rtx *set_source, rtx *set_destination)
108 {
109   rtx set_producer = arm_find_sub_rtx_with_code (PATTERN (producer),
110 						 SET, false);
111   rtx set_consumer = arm_find_sub_rtx_with_code (PATTERN (consumer),
112 						 SET, false);
113 
114   if (set_producer && set_consumer)
115     {
116       *set_source = SET_DEST (set_producer);
117       *set_destination = SET_SRC (set_consumer);
118       return 1;
119     }
120   return 0;
121 }
122 
123 bool
aarch_rev16_shright_mask_imm_p(rtx val,machine_mode mode)124 aarch_rev16_shright_mask_imm_p (rtx val, machine_mode mode)
125 {
126   return CONST_INT_P (val)
127          && INTVAL (val)
128             == trunc_int_for_mode (HOST_WIDE_INT_C (0xff00ff00ff00ff),
129                                    mode);
130 }
131 
132 bool
aarch_rev16_shleft_mask_imm_p(rtx val,machine_mode mode)133 aarch_rev16_shleft_mask_imm_p (rtx val, machine_mode mode)
134 {
135   return CONST_INT_P (val)
136          && INTVAL (val)
137             == trunc_int_for_mode (HOST_WIDE_INT_C (0xff00ff00ff00ff00),
138                                    mode);
139 }
140 
141 
142 static bool
aarch_rev16_p_1(rtx lhs,rtx rhs,machine_mode mode)143 aarch_rev16_p_1 (rtx lhs, rtx rhs, machine_mode mode)
144 {
145   if (GET_CODE (lhs) == AND
146          && GET_CODE (XEXP (lhs, 0)) == ASHIFT
147             && CONST_INT_P (XEXP (XEXP (lhs, 0), 1))
148             && INTVAL (XEXP (XEXP (lhs, 0), 1)) == 8
149             && REG_P (XEXP (XEXP (lhs, 0), 0))
150          && CONST_INT_P (XEXP (lhs, 1))
151       && GET_CODE (rhs) == AND
152          && GET_CODE (XEXP (rhs, 0)) == LSHIFTRT
153             && REG_P (XEXP (XEXP (rhs, 0), 0))
154             && CONST_INT_P (XEXP (XEXP (rhs, 0), 1))
155             && INTVAL (XEXP (XEXP (rhs, 0), 1)) == 8
156          && CONST_INT_P (XEXP (rhs, 1))
157       && REGNO (XEXP (XEXP (rhs, 0), 0)) == REGNO (XEXP (XEXP (lhs, 0), 0)))
158 
159     {
160       rtx lhs_mask = XEXP (lhs, 1);
161       rtx rhs_mask = XEXP (rhs, 1);
162 
163       return aarch_rev16_shright_mask_imm_p (rhs_mask, mode)
164              && aarch_rev16_shleft_mask_imm_p (lhs_mask, mode);
165     }
166 
167   return false;
168 }
169 
170 /* Recognise a sequence of bitwise operations corresponding to a rev16 operation.
171    These will be of the form:
172      ((x >> 8) & 0x00ff00ff)
173    | ((x << 8) & 0xff00ff00)
174    for SImode and with similar but wider bitmasks for DImode.
175    The two sub-expressions of the IOR can appear on either side so check both
176    permutations with the help of aarch_rev16_p_1 above.  */
177 
178 bool
aarch_rev16_p(rtx x)179 aarch_rev16_p (rtx x)
180 {
181   rtx left_sub_rtx, right_sub_rtx;
182   bool is_rev = false;
183 
184   if (GET_CODE (x) != IOR)
185     return false;
186 
187   left_sub_rtx = XEXP (x, 0);
188   right_sub_rtx = XEXP (x, 1);
189 
190   /* There are no canonicalisation rules for the position of the two shifts
191      involved in a rev, so try both permutations.  */
192   is_rev = aarch_rev16_p_1 (left_sub_rtx, right_sub_rtx, GET_MODE (x));
193 
194   if (!is_rev)
195     is_rev = aarch_rev16_p_1 (right_sub_rtx, left_sub_rtx, GET_MODE (x));
196 
197   return is_rev;
198 }
199 
200 /* Return non-zero if the RTX representing a memory model is a memory model
201    that needs acquire semantics.  */
202 bool
aarch_mm_needs_acquire(rtx const_int)203 aarch_mm_needs_acquire (rtx const_int)
204 {
205   enum memmodel model = memmodel_from_int (INTVAL (const_int));
206   return !(is_mm_relaxed (model)
207 	   || is_mm_consume (model)
208 	   || is_mm_release (model));
209 }
210 
211 /* Return non-zero if the RTX representing a memory model is a memory model
212    that needs release semantics.  */
213 bool
aarch_mm_needs_release(rtx const_int)214 aarch_mm_needs_release (rtx const_int)
215 {
216   enum memmodel model = memmodel_from_int (INTVAL (const_int));
217   return !(is_mm_relaxed (model)
218 	   || is_mm_consume (model)
219 	   || is_mm_acquire (model));
220 }
221 
222 /* Return nonzero if the CONSUMER instruction (a load) does need
223    PRODUCER's value to calculate the address.  */
224 int
arm_early_load_addr_dep(rtx producer,rtx consumer)225 arm_early_load_addr_dep (rtx producer, rtx consumer)
226 {
227   rtx value, addr;
228 
229   if (!arm_get_set_operands (producer, consumer, &value, &addr))
230     return 0;
231 
232   return reg_overlap_mentioned_p (value, addr);
233 }
234 
235 /* Return nonzero if the CONSUMER instruction (a load) does need
236    a Pmode PRODUCER's value to calculate the address.  */
237 
238 int
arm_early_load_addr_dep_ptr(rtx producer,rtx consumer)239 arm_early_load_addr_dep_ptr (rtx producer, rtx consumer)
240 {
241   rtx value = arm_find_sub_rtx_with_code (PATTERN (producer), SET, false);
242   rtx addr = arm_find_sub_rtx_with_code (PATTERN (consumer), SET, false);
243 
244   if (!value || !addr || !MEM_P (SET_SRC (value)))
245     return 0;
246 
247   value = SET_DEST (value);
248   addr = SET_SRC (addr);
249 
250   return GET_MODE (value) == Pmode && reg_overlap_mentioned_p (value, addr);
251 }
252 
253 /* Return nonzero if the CONSUMER instruction (an ALU op) does not
254    have an early register shift value or amount dependency on the
255    result of PRODUCER.  */
256 int
arm_no_early_alu_shift_dep(rtx producer,rtx consumer)257 arm_no_early_alu_shift_dep (rtx producer, rtx consumer)
258 {
259   rtx value, op;
260   rtx early_op;
261 
262   if (!arm_get_set_operands (producer, consumer, &value, &op))
263     return 0;
264 
265   if ((early_op = arm_find_shift_sub_rtx (op)))
266     return !reg_overlap_mentioned_p (value, early_op);
267 
268   return 0;
269 }
270 
271 /* Return nonzero if the CONSUMER instruction (an ALU op) does not
272    have an early register shift value dependency on the result of
273    PRODUCER.  */
274 int
arm_no_early_alu_shift_value_dep(rtx producer,rtx consumer)275 arm_no_early_alu_shift_value_dep (rtx producer, rtx consumer)
276 {
277   rtx value, op;
278   rtx early_op;
279 
280   if (!arm_get_set_operands (producer, consumer, &value, &op))
281     return 0;
282 
283   if ((early_op = arm_find_shift_sub_rtx (op)))
284     /* We want to check the value being shifted.  */
285     if (!reg_overlap_mentioned_p (value, XEXP (early_op, 0)))
286       return 1;
287 
288   return 0;
289 }
290 
291 /* Return nonzero if the CONSUMER (a mul or mac op) does not
292    have an early register mult dependency on the result of
293    PRODUCER.  */
294 int
arm_no_early_mul_dep(rtx producer,rtx consumer)295 arm_no_early_mul_dep (rtx producer, rtx consumer)
296 {
297   rtx value, op;
298 
299   if (!arm_get_set_operands (producer, consumer, &value, &op))
300     return 0;
301 
302   if (GET_CODE (op) == PLUS || GET_CODE (op) == MINUS)
303     {
304       if (GET_CODE (XEXP (op, 0)) == MULT)
305 	return !reg_overlap_mentioned_p (value, XEXP (op, 0));
306       else
307 	return !reg_overlap_mentioned_p (value, XEXP (op, 1));
308     }
309 
310   return 0;
311 }
312 
313 /* Return nonzero if the CONSUMER instruction (a store) does not need
314    PRODUCER's value to calculate the address.  */
315 
316 int
arm_no_early_store_addr_dep(rtx producer,rtx consumer)317 arm_no_early_store_addr_dep (rtx producer, rtx consumer)
318 {
319   rtx value = arm_find_sub_rtx_with_code (PATTERN (producer), SET, false);
320   rtx addr = arm_find_sub_rtx_with_code (PATTERN (consumer), SET, false);
321 
322   if (value)
323     value = SET_DEST (value);
324 
325   if (addr)
326     addr = SET_DEST (addr);
327 
328   if (!value || !addr)
329     return 0;
330 
331   return !reg_overlap_mentioned_p (value, addr);
332 }
333 
334 /* Return nonzero if the CONSUMER instruction (a store) does need
335    PRODUCER's value to calculate the address.  */
336 
337 int
arm_early_store_addr_dep(rtx producer,rtx consumer)338 arm_early_store_addr_dep (rtx producer, rtx consumer)
339 {
340   return !arm_no_early_store_addr_dep (producer, consumer);
341 }
342 
343 /* Return nonzero if the CONSUMER instruction (a store) does need
344    a Pmode PRODUCER's value to calculate the address.  */
345 
346 int
arm_early_store_addr_dep_ptr(rtx producer,rtx consumer)347 arm_early_store_addr_dep_ptr (rtx producer, rtx consumer)
348 {
349   rtx value = arm_find_sub_rtx_with_code (PATTERN (producer), SET, false);
350   rtx addr = arm_find_sub_rtx_with_code (PATTERN (consumer), SET, false);
351 
352   if (!value || !addr || !MEM_P (SET_SRC (value)))
353     return 0;
354 
355   value = SET_DEST (value);
356   addr = SET_DEST (addr);
357 
358   return GET_MODE (value) == Pmode && reg_overlap_mentioned_p (value, addr);
359 }
360 
361 /* Return non-zero iff the consumer (a multiply-accumulate or a
362    multiple-subtract instruction) has an accumulator dependency on the
363    result of the producer and no other dependency on that result.  It
364    does not check if the producer is multiply-accumulate instruction.  */
365 int
arm_mac_accumulator_is_result(rtx producer,rtx consumer)366 arm_mac_accumulator_is_result (rtx producer, rtx consumer)
367 {
368   rtx result;
369   rtx op0, op1, acc;
370 
371   producer = PATTERN (producer);
372   consumer = PATTERN (consumer);
373 
374   if (GET_CODE (producer) == COND_EXEC)
375     producer = COND_EXEC_CODE (producer);
376   if (GET_CODE (consumer) == COND_EXEC)
377     consumer = COND_EXEC_CODE (consumer);
378 
379   if (GET_CODE (producer) != SET)
380     return 0;
381 
382   result = XEXP (producer, 0);
383 
384   if (GET_CODE (consumer) != SET)
385     return 0;
386 
387   /* Check that the consumer is of the form
388      (set (...) (plus (mult ...) (...)))
389      or
390      (set (...) (minus (...) (mult ...))).  */
391   if (GET_CODE (XEXP (consumer, 1)) == PLUS)
392     {
393       if (GET_CODE (XEXP (XEXP (consumer, 1), 0)) != MULT)
394         return 0;
395 
396       op0 = XEXP (XEXP (XEXP (consumer, 1), 0), 0);
397       op1 = XEXP (XEXP (XEXP (consumer, 1), 0), 1);
398       acc = XEXP (XEXP (consumer, 1), 1);
399     }
400   else if (GET_CODE (XEXP (consumer, 1)) == MINUS)
401     {
402       if (GET_CODE (XEXP (XEXP (consumer, 1), 1)) != MULT)
403         return 0;
404 
405       op0 = XEXP (XEXP (XEXP (consumer, 1), 1), 0);
406       op1 = XEXP (XEXP (XEXP (consumer, 1), 1), 1);
407       acc = XEXP (XEXP (consumer, 1), 0);
408     }
409   else
410     return 0;
411 
412   return (reg_overlap_mentioned_p (result, acc)
413           && !reg_overlap_mentioned_p (result, op0)
414           && !reg_overlap_mentioned_p (result, op1));
415 }
416 
417 /* Return non-zero if the destination of PRODUCER feeds the accumulator
418    operand of an MLA-like operation.  */
419 
420 int
aarch_accumulator_forwarding(rtx_insn * producer,rtx_insn * consumer)421 aarch_accumulator_forwarding (rtx_insn *producer, rtx_insn *consumer)
422 {
423   rtx producer_set = single_set (producer);
424   rtx consumer_set = single_set (consumer);
425 
426   /* We are looking for a SET feeding a SET.  */
427   if (!producer_set || !consumer_set)
428     return 0;
429 
430   rtx dest = SET_DEST (producer_set);
431   rtx mla = SET_SRC (consumer_set);
432 
433   /* We're looking for a register SET.  */
434   if (!REG_P (dest))
435     return 0;
436 
437   rtx accumulator;
438 
439   /* Strip a zero_extend.  */
440   if (GET_CODE (mla) == ZERO_EXTEND)
441     mla = XEXP (mla, 0);
442 
443   switch (GET_CODE (mla))
444     {
445     case PLUS:
446       /* Possibly an MADD.  */
447       if (GET_CODE (XEXP (mla, 0)) == MULT)
448 	accumulator = XEXP (mla, 1);
449       else
450 	return 0;
451       break;
452     case MINUS:
453       /* Possibly an MSUB.  */
454       if (GET_CODE (XEXP (mla, 1)) == MULT)
455 	accumulator = XEXP (mla, 0);
456       else
457 	return 0;
458       break;
459     case FMA:
460 	{
461 	  /* Possibly an FMADD/FMSUB/FNMADD/FNMSUB.  */
462 	  if (REG_P (XEXP (mla, 1))
463 	      && REG_P (XEXP (mla, 2))
464 	      && (REG_P (XEXP (mla, 0))
465 		  || GET_CODE (XEXP (mla, 0)) == NEG))
466 
467 	    {
468 	      /* FMADD/FMSUB.  */
469 	      accumulator = XEXP (mla, 2);
470 	    }
471 	  else if (REG_P (XEXP (mla, 1))
472 		   && GET_CODE (XEXP (mla, 2)) == NEG
473 		   && (REG_P (XEXP (mla, 0))
474 		       || GET_CODE (XEXP (mla, 0)) == NEG))
475 	    {
476 	      /* FNMADD/FNMSUB.  */
477 	      accumulator = XEXP (XEXP (mla, 2), 0);
478 	    }
479 	  else
480 	    return 0;
481 	  break;
482 	}
483       default:
484 	/* Not an MLA-like operation.  */
485 	return 0;
486     }
487 
488   if (SUBREG_P (accumulator))
489     accumulator = SUBREG_REG (accumulator);
490 
491   if (!REG_P (accumulator))
492     return 0;
493 
494   return (REGNO (dest) == REGNO (accumulator));
495 }
496 
497 /* Return non-zero if the consumer (a multiply-accumulate instruction)
498    has an accumulator dependency on the result of the producer (a
499    multiplication instruction) and no other dependency on that result.  */
500 int
arm_mac_accumulator_is_mul_result(rtx producer,rtx consumer)501 arm_mac_accumulator_is_mul_result (rtx producer, rtx consumer)
502 {
503   rtx mul = PATTERN (producer);
504   rtx mac = PATTERN (consumer);
505   rtx mul_result;
506   rtx mac_op0, mac_op1, mac_acc;
507 
508   if (GET_CODE (mul) == COND_EXEC)
509     mul = COND_EXEC_CODE (mul);
510   if (GET_CODE (mac) == COND_EXEC)
511     mac = COND_EXEC_CODE (mac);
512 
513   /* Check that mul is of the form (set (...) (mult ...))
514      and mla is of the form (set (...) (plus (mult ...) (...))).  */
515   if ((GET_CODE (mul) != SET || GET_CODE (XEXP (mul, 1)) != MULT)
516       || (GET_CODE (mac) != SET || GET_CODE (XEXP (mac, 1)) != PLUS
517           || GET_CODE (XEXP (XEXP (mac, 1), 0)) != MULT))
518     return 0;
519 
520   mul_result = XEXP (mul, 0);
521   mac_op0 = XEXP (XEXP (XEXP (mac, 1), 0), 0);
522   mac_op1 = XEXP (XEXP (XEXP (mac, 1), 0), 1);
523   mac_acc = XEXP (XEXP (mac, 1), 1);
524 
525   return (reg_overlap_mentioned_p (mul_result, mac_acc)
526           && !reg_overlap_mentioned_p (mul_result, mac_op0)
527           && !reg_overlap_mentioned_p (mul_result, mac_op1));
528 }
529 
530 /* Worker function for TARGET_MD_ASM_ADJUST.
531    We implement asm flag outputs.  */
532 
533 rtx_insn *
arm_md_asm_adjust(vec<rtx> & outputs,vec<rtx> &,vec<machine_mode> &,vec<const char * > & constraints,vec<rtx> &,HARD_REG_SET &,location_t loc)534 arm_md_asm_adjust (vec<rtx> &outputs, vec<rtx> & /*inputs*/,
535 		   vec<machine_mode> & /*input_modes*/,
536 		   vec<const char *> &constraints, vec<rtx> & /*clobbers*/,
537 		   HARD_REG_SET & /*clobbered_regs*/, location_t loc)
538 {
539   bool saw_asm_flag = false;
540 
541   start_sequence ();
542   for (unsigned i = 0, n = outputs.length (); i < n; ++i)
543     {
544       const char *con = constraints[i];
545       if (!startswith (con, "=@cc"))
546 	continue;
547       con += 4;
548       if (strchr (con, ',') != NULL)
549 	{
550 	  error_at (loc, "alternatives not allowed in %<asm%> flag output");
551 	  continue;
552 	}
553 
554       machine_mode mode;
555       rtx_code code;
556       int con01 = 0;
557 
558 #define C(X, Y)  (unsigned char)(X) * 256 + (unsigned char)(Y)
559 
560       /* All of the condition codes are two characters.  */
561       if (con[0] != 0 && con[1] != 0 && con[2] == 0)
562 	con01 = C(con[0], con[1]);
563 
564       switch (con01)
565 	{
566 	case C('c', 'c'):
567 	case C('l', 'o'):
568 	  mode = CC_Cmode, code = GEU;
569 	  break;
570 	case C('c', 's'):
571 	case C('h', 's'):
572 	  mode = CC_Cmode, code = LTU;
573 	  break;
574 	case C('e', 'q'):
575 	  mode = CC_NZmode, code = EQ;
576 	  break;
577 	case C('g', 'e'):
578 	  mode = CCmode, code = GE;
579 	  break;
580 	case C('g', 't'):
581 	  mode = CCmode, code = GT;
582 	  break;
583 	case C('h', 'i'):
584 	  mode = CCmode, code = GTU;
585 	  break;
586 	case C('l', 'e'):
587 	  mode = CCmode, code = LE;
588 	  break;
589 	case C('l', 's'):
590 	  mode = CCmode, code = LEU;
591 	  break;
592 	case C('l', 't'):
593 	  mode = CCmode, code = LT;
594 	  break;
595 	case C('m', 'i'):
596 	  mode = CC_NZmode, code = LT;
597 	  break;
598 	case C('n', 'e'):
599 	  mode = CC_NZmode, code = NE;
600 	  break;
601 	case C('p', 'l'):
602 	  mode = CC_NZmode, code = GE;
603 	  break;
604 	case C('v', 'c'):
605 	  mode = CC_Vmode, code = EQ;
606 	  break;
607 	case C('v', 's'):
608 	  mode = CC_Vmode, code = NE;
609 	  break;
610 	default:
611 	  error_at (loc, "unknown %<asm%> flag output %qs", constraints[i]);
612 	  continue;
613 	}
614 
615 #undef C
616 
617       rtx dest = outputs[i];
618       machine_mode dest_mode = GET_MODE (dest);
619       if (!SCALAR_INT_MODE_P (dest_mode))
620 	{
621 	  error_at (loc, "invalid type for %<asm%> flag output");
622 	  continue;
623 	}
624 
625       if (!saw_asm_flag)
626 	{
627 	  /* This is the first asm flag output.  Here we put the flags
628 	     register in as the real output and adjust the condition to
629 	     allow it.  */
630 	  constraints[i] = "=c";
631 	  outputs[i] = gen_rtx_REG (CCmode, CC_REGNUM);
632 	  saw_asm_flag = true;
633 	}
634       else
635 	{
636 	  /* We don't need the flags register as output twice.  */
637 	  constraints[i] = "=X";
638 	  outputs[i] = gen_rtx_SCRATCH (word_mode);
639 	}
640 
641       rtx x = gen_rtx_REG (mode, CC_REGNUM);
642       x = gen_rtx_fmt_ee (code, word_mode, x, const0_rtx);
643 
644       if (dest_mode == word_mode)
645 	emit_insn (gen_rtx_SET (dest, x));
646       else
647 	{
648 	  rtx tmp = gen_reg_rtx (word_mode);
649 	  emit_insn (gen_rtx_SET (tmp, x));
650 
651 	  tmp = convert_modes (dest_mode, word_mode, tmp, true);
652 	  emit_move_insn (dest, tmp);
653 	}
654     }
655   rtx_insn *seq = get_insns ();
656   end_sequence ();
657 
658   return saw_asm_flag ? seq : NULL;
659 }
660