Home | History | Annotate | Line # | Download | only in arm
      1 /* Dependency checks for instruction scheduling, shared between ARM and
      2    AARCH64.
      3 
      4    Copyright (C) 1991-2024 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 #include "aarch-common.h"
     40 #include "aarch-common-protos.h"
     41 
     42 /* Return TRUE if X is either an arithmetic shift left, or
     43    is a multiplication by a power of two.  */
     44 bool
     45 arm_rtx_shift_left_p (rtx x)
     46 {
     47   enum rtx_code code = GET_CODE (x);
     48 
     49   if (code == MULT && CONST_INT_P (XEXP (x, 1))
     50       && exact_log2 (INTVAL (XEXP (x, 1))) > 0)
     51     return true;
     52 
     53   if (code == ASHIFT)
     54     return true;
     55 
     56   return false;
     57 }
     58 
     59 static rtx_code shift_rtx_codes[] =
     60   { ASHIFT, ROTATE, ASHIFTRT, LSHIFTRT,
     61     ROTATERT, ZERO_EXTEND, SIGN_EXTEND };
     62 
     63 /* Traverse PATTERN looking for a sub-rtx with RTX_CODE CODE.
     64    If FIND_ANY_SHIFT then we are interested in anything which can
     65    reasonably be described as a SHIFT RTX.  */
     66 static rtx
     67 arm_find_sub_rtx_with_code (rtx pattern, rtx_code code, bool find_any_shift)
     68 {
     69   subrtx_var_iterator::array_type array;
     70   FOR_EACH_SUBRTX_VAR (iter, array, pattern, NONCONST)
     71     {
     72       rtx x = *iter;
     73       if (find_any_shift)
     74 	{
     75 	  /* Left shifts might have been canonicalized to a MULT of some
     76 	     power of two.  Make sure we catch them.  */
     77 	  if (arm_rtx_shift_left_p (x))
     78 	    return x;
     79 	  else
     80 	    for (unsigned int i = 0; i < ARRAY_SIZE (shift_rtx_codes); i++)
     81 	      if (GET_CODE (x) == shift_rtx_codes[i])
     82 		return x;
     83 	}
     84 
     85       if (GET_CODE (x) == code)
     86 	return x;
     87     }
     88   return NULL_RTX;
     89 }
     90 
     91 /* Traverse PATTERN looking for any sub-rtx which looks like a shift.  */
     92 static rtx
     93 arm_find_shift_sub_rtx (rtx pattern)
     94 {
     95   return arm_find_sub_rtx_with_code (pattern, ASHIFT, true);
     96 }
     97 
     98 /* PRODUCER and CONSUMER are two potentially dependant RTX.  PRODUCER
     99    (possibly) contains a SET which will provide a result we can access
    100    using the SET_DEST macro.  We will place the RTX which would be
    101    written by PRODUCER in SET_SOURCE.
    102    Similarly, CONSUMER (possibly) contains a SET which has an operand
    103    we can access using SET_SRC.  We place this operand in
    104    SET_DESTINATION.
    105 
    106    Return nonzero if we found the SET RTX we expected.  */
    107 static int
    108 arm_get_set_operands (rtx producer, rtx consumer,
    109 		      rtx *set_source, rtx *set_destination)
    110 {
    111   rtx set_producer = arm_find_sub_rtx_with_code (PATTERN (producer),
    112 						 SET, false);
    113   rtx set_consumer = arm_find_sub_rtx_with_code (PATTERN (consumer),
    114 						 SET, false);
    115 
    116   if (set_producer && set_consumer)
    117     {
    118       *set_source = SET_DEST (set_producer);
    119       *set_destination = SET_SRC (set_consumer);
    120       return 1;
    121     }
    122   return 0;
    123 }
    124 
    125 bool
    126 aarch_rev16_shright_mask_imm_p (rtx val, machine_mode mode)
    127 {
    128   return CONST_INT_P (val)
    129          && INTVAL (val)
    130             == trunc_int_for_mode (HOST_WIDE_INT_C (0xff00ff00ff00ff),
    131                                    mode);
    132 }
    133 
    134 bool
    135 aarch_rev16_shleft_mask_imm_p (rtx val, machine_mode mode)
    136 {
    137   return CONST_INT_P (val)
    138          && INTVAL (val)
    139             == trunc_int_for_mode (HOST_WIDE_INT_C (0xff00ff00ff00ff00),
    140                                    mode);
    141 }
    142 
    143 
    144 static bool
    145 aarch_rev16_p_1 (rtx lhs, rtx rhs, machine_mode mode)
    146 {
    147   if (GET_CODE (lhs) == AND
    148          && GET_CODE (XEXP (lhs, 0)) == ASHIFT
    149             && CONST_INT_P (XEXP (XEXP (lhs, 0), 1))
    150             && INTVAL (XEXP (XEXP (lhs, 0), 1)) == 8
    151             && REG_P (XEXP (XEXP (lhs, 0), 0))
    152          && CONST_INT_P (XEXP (lhs, 1))
    153       && GET_CODE (rhs) == AND
    154          && GET_CODE (XEXP (rhs, 0)) == LSHIFTRT
    155             && REG_P (XEXP (XEXP (rhs, 0), 0))
    156             && CONST_INT_P (XEXP (XEXP (rhs, 0), 1))
    157             && INTVAL (XEXP (XEXP (rhs, 0), 1)) == 8
    158          && CONST_INT_P (XEXP (rhs, 1))
    159       && REGNO (XEXP (XEXP (rhs, 0), 0)) == REGNO (XEXP (XEXP (lhs, 0), 0)))
    160 
    161     {
    162       rtx lhs_mask = XEXP (lhs, 1);
    163       rtx rhs_mask = XEXP (rhs, 1);
    164 
    165       return aarch_rev16_shright_mask_imm_p (rhs_mask, mode)
    166              && aarch_rev16_shleft_mask_imm_p (lhs_mask, mode);
    167     }
    168 
    169   return false;
    170 }
    171 
    172 /* Recognise a sequence of bitwise operations corresponding to a rev16 operation.
    173    These will be of the form:
    174      ((x >> 8) & 0x00ff00ff)
    175    | ((x << 8) & 0xff00ff00)
    176    for SImode and with similar but wider bitmasks for DImode.
    177    The two sub-expressions of the IOR can appear on either side so check both
    178    permutations with the help of aarch_rev16_p_1 above.  */
    179 
    180 bool
    181 aarch_rev16_p (rtx x)
    182 {
    183   rtx left_sub_rtx, right_sub_rtx;
    184   bool is_rev = false;
    185 
    186   if (GET_CODE (x) != IOR)
    187     return false;
    188 
    189   left_sub_rtx = XEXP (x, 0);
    190   right_sub_rtx = XEXP (x, 1);
    191 
    192   /* There are no canonicalisation rules for the position of the two shifts
    193      involved in a rev, so try both permutations.  */
    194   is_rev = aarch_rev16_p_1 (left_sub_rtx, right_sub_rtx, GET_MODE (x));
    195 
    196   if (!is_rev)
    197     is_rev = aarch_rev16_p_1 (right_sub_rtx, left_sub_rtx, GET_MODE (x));
    198 
    199   return is_rev;
    200 }
    201 
    202 /* Return non-zero if the RTX representing a memory model is a memory model
    203    that needs acquire semantics.  */
    204 bool
    205 aarch_mm_needs_acquire (rtx const_int)
    206 {
    207   enum memmodel model = memmodel_from_int (INTVAL (const_int));
    208   return !(is_mm_relaxed (model)
    209 	   || is_mm_consume (model)
    210 	   || is_mm_release (model));
    211 }
    212 
    213 /* Return non-zero if the RTX representing a memory model is a memory model
    214    that needs release semantics.  */
    215 bool
    216 aarch_mm_needs_release (rtx const_int)
    217 {
    218   enum memmodel model = memmodel_from_int (INTVAL (const_int));
    219   return !(is_mm_relaxed (model)
    220 	   || is_mm_consume (model)
    221 	   || is_mm_acquire (model));
    222 }
    223 
    224 /* Return nonzero if the CONSUMER instruction (a load) does need
    225    PRODUCER's value to calculate the address.  */
    226 int
    227 arm_early_load_addr_dep (rtx producer, rtx consumer)
    228 {
    229   rtx value, addr;
    230 
    231   if (!arm_get_set_operands (producer, consumer, &value, &addr))
    232     return 0;
    233 
    234   return reg_overlap_mentioned_p (value, addr);
    235 }
    236 
    237 /* Return nonzero if the CONSUMER instruction (a load) does need
    238    a Pmode PRODUCER's value to calculate the address.  */
    239 
    240 int
    241 arm_early_load_addr_dep_ptr (rtx producer, rtx consumer)
    242 {
    243   rtx value = arm_find_sub_rtx_with_code (PATTERN (producer), SET, false);
    244   rtx addr = arm_find_sub_rtx_with_code (PATTERN (consumer), SET, false);
    245 
    246   if (!value || !addr || !MEM_P (SET_SRC (value)))
    247     return 0;
    248 
    249   value = SET_DEST (value);
    250   addr = SET_SRC (addr);
    251 
    252   return GET_MODE (value) == Pmode && reg_overlap_mentioned_p (value, addr);
    253 }
    254 
    255 /* Return nonzero if the CONSUMER instruction (an ALU op) does not
    256    have an early register shift value or amount dependency on the
    257    result of PRODUCER.  */
    258 int
    259 arm_no_early_alu_shift_dep (rtx producer, rtx consumer)
    260 {
    261   rtx value, op;
    262   rtx early_op;
    263 
    264   if (!arm_get_set_operands (producer, consumer, &value, &op))
    265     return 0;
    266 
    267   if ((early_op = arm_find_shift_sub_rtx (op)))
    268     return !reg_overlap_mentioned_p (value, early_op);
    269 
    270   return 0;
    271 }
    272 
    273 /* Return nonzero if the CONSUMER instruction (an ALU op) does not
    274    have an early register shift value dependency on the result of
    275    PRODUCER.  */
    276 int
    277 arm_no_early_alu_shift_value_dep (rtx producer, rtx consumer)
    278 {
    279   rtx value, op;
    280   rtx early_op;
    281 
    282   if (!arm_get_set_operands (producer, consumer, &value, &op))
    283     return 0;
    284 
    285   if ((early_op = arm_find_shift_sub_rtx (op)))
    286     /* We want to check the value being shifted.  */
    287     if (!reg_overlap_mentioned_p (value, XEXP (early_op, 0)))
    288       return 1;
    289 
    290   return 0;
    291 }
    292 
    293 /* Return nonzero if the CONSUMER (a mul or mac op) does not
    294    have an early register mult dependency on the result of
    295    PRODUCER.  */
    296 int
    297 arm_no_early_mul_dep (rtx producer, rtx consumer)
    298 {
    299   rtx value, op;
    300 
    301   if (!arm_get_set_operands (producer, consumer, &value, &op))
    302     return 0;
    303 
    304   if (GET_CODE (op) == PLUS || GET_CODE (op) == MINUS)
    305     {
    306       if (GET_CODE (XEXP (op, 0)) == MULT)
    307 	return !reg_overlap_mentioned_p (value, XEXP (op, 0));
    308       else
    309 	return !reg_overlap_mentioned_p (value, XEXP (op, 1));
    310     }
    311 
    312   return 0;
    313 }
    314 
    315 /* Return nonzero if the CONSUMER instruction (a store) does not need
    316    PRODUCER's value to calculate the address.  */
    317 
    318 int
    319 arm_no_early_store_addr_dep (rtx producer, rtx consumer)
    320 {
    321   rtx value = arm_find_sub_rtx_with_code (PATTERN (producer), SET, false);
    322   rtx addr = arm_find_sub_rtx_with_code (PATTERN (consumer), SET, false);
    323 
    324   if (value)
    325     value = SET_DEST (value);
    326 
    327   if (addr)
    328     addr = SET_DEST (addr);
    329 
    330   if (!value || !addr)
    331     return 0;
    332 
    333   return !reg_overlap_mentioned_p (value, addr);
    334 }
    335 
    336 /* Return nonzero if the CONSUMER instruction (a store) does need
    337    PRODUCER's value to calculate the address.  */
    338 
    339 int
    340 arm_early_store_addr_dep (rtx producer, rtx consumer)
    341 {
    342   return !arm_no_early_store_addr_dep (producer, consumer);
    343 }
    344 
    345 /* Return nonzero if the CONSUMER instruction (a store) does need
    346    a Pmode PRODUCER's value to calculate the address.  */
    347 
    348 int
    349 arm_early_store_addr_dep_ptr (rtx producer, rtx consumer)
    350 {
    351   rtx value = arm_find_sub_rtx_with_code (PATTERN (producer), SET, false);
    352   rtx addr = arm_find_sub_rtx_with_code (PATTERN (consumer), SET, false);
    353 
    354   if (!value || !addr || !MEM_P (SET_SRC (value)))
    355     return 0;
    356 
    357   value = SET_DEST (value);
    358   addr = SET_DEST (addr);
    359 
    360   return GET_MODE (value) == Pmode && reg_overlap_mentioned_p (value, addr);
    361 }
    362 
    363 /* Return non-zero iff the consumer (a multiply-accumulate or a
    364    multiple-subtract instruction) has an accumulator dependency on the
    365    result of the producer and no other dependency on that result.  It
    366    does not check if the producer is multiply-accumulate instruction.  */
    367 int
    368 arm_mac_accumulator_is_result (rtx producer, rtx consumer)
    369 {
    370   rtx result;
    371   rtx op0, op1, acc;
    372 
    373   producer = PATTERN (producer);
    374   consumer = PATTERN (consumer);
    375 
    376   if (GET_CODE (producer) == COND_EXEC)
    377     producer = COND_EXEC_CODE (producer);
    378   if (GET_CODE (consumer) == COND_EXEC)
    379     consumer = COND_EXEC_CODE (consumer);
    380 
    381   if (GET_CODE (producer) != SET)
    382     return 0;
    383 
    384   result = XEXP (producer, 0);
    385 
    386   if (GET_CODE (consumer) != SET)
    387     return 0;
    388 
    389   /* Check that the consumer is of the form
    390      (set (...) (plus (mult ...) (...)))
    391      or
    392      (set (...) (minus (...) (mult ...))).  */
    393   if (GET_CODE (XEXP (consumer, 1)) == PLUS)
    394     {
    395       if (GET_CODE (XEXP (XEXP (consumer, 1), 0)) != MULT)
    396         return 0;
    397 
    398       op0 = XEXP (XEXP (XEXP (consumer, 1), 0), 0);
    399       op1 = XEXP (XEXP (XEXP (consumer, 1), 0), 1);
    400       acc = XEXP (XEXP (consumer, 1), 1);
    401     }
    402   else if (GET_CODE (XEXP (consumer, 1)) == MINUS)
    403     {
    404       if (GET_CODE (XEXP (XEXP (consumer, 1), 1)) != MULT)
    405         return 0;
    406 
    407       op0 = XEXP (XEXP (XEXP (consumer, 1), 1), 0);
    408       op1 = XEXP (XEXP (XEXP (consumer, 1), 1), 1);
    409       acc = XEXP (XEXP (consumer, 1), 0);
    410     }
    411   else
    412     return 0;
    413 
    414   return (reg_overlap_mentioned_p (result, acc)
    415           && !reg_overlap_mentioned_p (result, op0)
    416           && !reg_overlap_mentioned_p (result, op1));
    417 }
    418 
    419 /* Return non-zero if the destination of PRODUCER feeds the accumulator
    420    operand of an MLA-like operation.  */
    421 
    422 int
    423 aarch_accumulator_forwarding (rtx_insn *producer, rtx_insn *consumer)
    424 {
    425   rtx producer_set = single_set (producer);
    426   rtx consumer_set = single_set (consumer);
    427 
    428   /* We are looking for a SET feeding a SET.  */
    429   if (!producer_set || !consumer_set)
    430     return 0;
    431 
    432   rtx dest = SET_DEST (producer_set);
    433   rtx mla = SET_SRC (consumer_set);
    434 
    435   /* We're looking for a register SET.  */
    436   if (!REG_P (dest))
    437     return 0;
    438 
    439   rtx accumulator;
    440 
    441   /* Strip a zero_extend.  */
    442   if (GET_CODE (mla) == ZERO_EXTEND)
    443     mla = XEXP (mla, 0);
    444 
    445   switch (GET_CODE (mla))
    446     {
    447     case PLUS:
    448       /* Possibly an MADD.  */
    449       if (GET_CODE (XEXP (mla, 0)) == MULT)
    450 	accumulator = XEXP (mla, 1);
    451       else
    452 	return 0;
    453       break;
    454     case MINUS:
    455       /* Possibly an MSUB.  */
    456       if (GET_CODE (XEXP (mla, 1)) == MULT)
    457 	accumulator = XEXP (mla, 0);
    458       else
    459 	return 0;
    460       break;
    461     case FMA:
    462 	{
    463 	  /* Possibly an FMADD/FMSUB/FNMADD/FNMSUB.  */
    464 	  if (REG_P (XEXP (mla, 1))
    465 	      && REG_P (XEXP (mla, 2))
    466 	      && (REG_P (XEXP (mla, 0))
    467 		  || GET_CODE (XEXP (mla, 0)) == NEG))
    468 
    469 	    {
    470 	      /* FMADD/FMSUB.  */
    471 	      accumulator = XEXP (mla, 2);
    472 	    }
    473 	  else if (REG_P (XEXP (mla, 1))
    474 		   && GET_CODE (XEXP (mla, 2)) == NEG
    475 		   && (REG_P (XEXP (mla, 0))
    476 		       || GET_CODE (XEXP (mla, 0)) == NEG))
    477 	    {
    478 	      /* FNMADD/FNMSUB.  */
    479 	      accumulator = XEXP (XEXP (mla, 2), 0);
    480 	    }
    481 	  else
    482 	    return 0;
    483 	  break;
    484 	}
    485       default:
    486 	/* Not an MLA-like operation.  */
    487 	return 0;
    488     }
    489 
    490   if (SUBREG_P (accumulator))
    491     accumulator = SUBREG_REG (accumulator);
    492 
    493   if (!REG_P (accumulator))
    494     return 0;
    495 
    496   return (REGNO (dest) == REGNO (accumulator));
    497 }
    498 
    499 /* Return non-zero if the consumer (a multiply-accumulate instruction)
    500    has an accumulator dependency on the result of the producer (a
    501    multiplication instruction) and no other dependency on that result.  */
    502 int
    503 arm_mac_accumulator_is_mul_result (rtx producer, rtx consumer)
    504 {
    505   rtx mul = PATTERN (producer);
    506   rtx mac = PATTERN (consumer);
    507   rtx mul_result;
    508   rtx mac_op0, mac_op1, mac_acc;
    509 
    510   if (GET_CODE (mul) == COND_EXEC)
    511     mul = COND_EXEC_CODE (mul);
    512   if (GET_CODE (mac) == COND_EXEC)
    513     mac = COND_EXEC_CODE (mac);
    514 
    515   /* Check that mul is of the form (set (...) (mult ...))
    516      and mla is of the form (set (...) (plus (mult ...) (...))).  */
    517   if ((GET_CODE (mul) != SET || GET_CODE (XEXP (mul, 1)) != MULT)
    518       || (GET_CODE (mac) != SET || GET_CODE (XEXP (mac, 1)) != PLUS
    519           || GET_CODE (XEXP (XEXP (mac, 1), 0)) != MULT))
    520     return 0;
    521 
    522   mul_result = XEXP (mul, 0);
    523   mac_op0 = XEXP (XEXP (XEXP (mac, 1), 0), 0);
    524   mac_op1 = XEXP (XEXP (XEXP (mac, 1), 0), 1);
    525   mac_acc = XEXP (XEXP (mac, 1), 1);
    526 
    527   return (reg_overlap_mentioned_p (mul_result, mac_acc)
    528           && !reg_overlap_mentioned_p (mul_result, mac_op0)
    529           && !reg_overlap_mentioned_p (mul_result, mac_op1));
    530 }
    531 
    532 /* Worker function for TARGET_MD_ASM_ADJUST.
    533    We implement asm flag outputs.  */
    534 
    535 rtx_insn *
    536 arm_md_asm_adjust (vec<rtx> &outputs, vec<rtx> & /*inputs*/,
    537 		   vec<machine_mode> & /*input_modes*/,
    538 		   vec<const char *> &constraints,
    539 		   vec<rtx> & /*uses*/, vec<rtx> & /*clobbers*/,
    540 		   HARD_REG_SET & /*clobbered_regs*/, location_t loc)
    541 {
    542   bool saw_asm_flag = false;
    543 
    544   start_sequence ();
    545   for (unsigned i = 0, n = outputs.length (); i < n; ++i)
    546     {
    547       const char *con = constraints[i];
    548       if (!startswith (con, "=@cc"))
    549 	continue;
    550       con += 4;
    551       if (strchr (con, ',') != NULL)
    552 	{
    553 	  error_at (loc, "alternatives not allowed in %<asm%> flag output");
    554 	  continue;
    555 	}
    556 
    557       machine_mode mode;
    558       rtx_code code;
    559       int con01 = 0;
    560 
    561 #define C(X, Y)  (unsigned char)(X) * 256 + (unsigned char)(Y)
    562 
    563       /* All of the condition codes are two characters.  */
    564       if (con[0] != 0 && con[1] != 0 && con[2] == 0)
    565 	con01 = C(con[0], con[1]);
    566 
    567       switch (con01)
    568 	{
    569 	case C('c', 'c'):
    570 	case C('l', 'o'):
    571 	  mode = CC_Cmode, code = GEU;
    572 	  break;
    573 	case C('c', 's'):
    574 	case C('h', 's'):
    575 	  mode = CC_Cmode, code = LTU;
    576 	  break;
    577 	case C('e', 'q'):
    578 	  mode = CC_NZmode, code = EQ;
    579 	  break;
    580 	case C('g', 'e'):
    581 	  mode = CCmode, code = GE;
    582 	  break;
    583 	case C('g', 't'):
    584 	  mode = CCmode, code = GT;
    585 	  break;
    586 	case C('h', 'i'):
    587 	  mode = CCmode, code = GTU;
    588 	  break;
    589 	case C('l', 'e'):
    590 	  mode = CCmode, code = LE;
    591 	  break;
    592 	case C('l', 's'):
    593 	  mode = CCmode, code = LEU;
    594 	  break;
    595 	case C('l', 't'):
    596 	  mode = CCmode, code = LT;
    597 	  break;
    598 	case C('m', 'i'):
    599 	  mode = CC_NZmode, code = LT;
    600 	  break;
    601 	case C('n', 'e'):
    602 	  mode = CC_NZmode, code = NE;
    603 	  break;
    604 	case C('p', 'l'):
    605 	  mode = CC_NZmode, code = GE;
    606 	  break;
    607 	case C('v', 'c'):
    608 	  mode = CC_Vmode, code = EQ;
    609 	  break;
    610 	case C('v', 's'):
    611 	  mode = CC_Vmode, code = NE;
    612 	  break;
    613 	default:
    614 	  error_at (loc, "unknown %<asm%> flag output %qs", constraints[i]);
    615 	  continue;
    616 	}
    617 
    618 #undef C
    619 
    620       rtx dest = outputs[i];
    621       machine_mode dest_mode = GET_MODE (dest);
    622       if (!SCALAR_INT_MODE_P (dest_mode))
    623 	{
    624 	  error_at (loc, "invalid type for %<asm%> flag output");
    625 	  continue;
    626 	}
    627 
    628       if (!saw_asm_flag)
    629 	{
    630 	  /* This is the first asm flag output.  Here we put the flags
    631 	     register in as the real output and adjust the condition to
    632 	     allow it.  */
    633 	  constraints[i] = "=c";
    634 	  outputs[i] = gen_rtx_REG (CCmode, CC_REGNUM);
    635 	  saw_asm_flag = true;
    636 	}
    637       else
    638 	{
    639 	  /* We don't need the flags register as output twice.  */
    640 	  constraints[i] = "=X";
    641 	  outputs[i] = gen_rtx_SCRATCH (word_mode);
    642 	}
    643 
    644       rtx x = gen_rtx_REG (mode, CC_REGNUM);
    645       x = gen_rtx_fmt_ee (code, word_mode, x, const0_rtx);
    646 
    647       if (dest_mode == word_mode && REG_P (dest))
    648 	emit_insn (gen_rtx_SET (dest, x));
    649       else
    650 	{
    651 	  rtx tmp = gen_reg_rtx (word_mode);
    652 	  emit_insn (gen_rtx_SET (tmp, x));
    653 
    654 	  tmp = convert_modes (dest_mode, word_mode, tmp, true);
    655 	  emit_move_insn (dest, tmp);
    656 	}
    657     }
    658   rtx_insn *seq = get_insns ();
    659   end_sequence ();
    660 
    661   return saw_asm_flag ? seq : NULL;
    662 }
    663 
    664 /* In-place split *str at delim, return *str and set *str to the tail
    665    of the string or NULL if the end is reached.  */
    666 
    667 static char *
    668 next_tok (char **str, int delim)
    669 {
    670   char *tok = *str;
    671   for (char *p = tok; p && *p != '\0'; p++)
    672     {
    673       if (*p == delim)
    674 	{
    675 	  *p = '\0';
    676 	  *str = p + 1;
    677 	  return tok;
    678 	}
    679     }
    680   *str = NULL;
    681   return tok;
    682 }
    683 
    684 /* Parses CONST_STR according to branch protection features specified in
    685    TYPES.  The first type resets the settings, the last type is marked with
    686    name == NULL.  On failure an error message is printed referencing OPT as
    687    the source of the options.  Returns true on success.  */
    688 
    689 bool
    690 aarch_validate_mbranch_protection (
    691   const struct aarch_branch_protect_type *types, const char *const_str,
    692   const char *opt)
    693 {
    694   char *str_root = xstrdup (const_str);
    695   char *next_str = str_root;
    696   char *str = next_tok (&next_str, '+');
    697   char *alone_str = NULL;
    698   bool reject_alone = false;
    699   bool res = true;
    700 
    701   /* First entry is "none" and it is used to reset the state.  */
    702   types->handler ();
    703 
    704   while (str)
    705     {
    706       const aarch_branch_protect_type *type = types;
    707       for (; type->name; type++)
    708 	if (strcmp (str, type->name) == 0)
    709 	  break;
    710       if (type->name == NULL)
    711 	{
    712 	  res = false;
    713 	  if (strcmp (str, "") == 0)
    714 	    error ("missing feature or flag for %<%s%>", opt);
    715 	  else
    716 	    error ("invalid argument %<%s%> for %<%s%>", str, opt);
    717 	  break;
    718 	}
    719 
    720       if (type->alone && alone_str == NULL)
    721 	alone_str = str;
    722       else
    723 	reject_alone = true;
    724       if (reject_alone && alone_str != NULL)
    725 	{
    726 	  res = false;
    727 	  error ("argument %<%s%> can only appear alone in %<%s%>",
    728 		 alone_str, opt);
    729 	  break;
    730 	}
    731 
    732       type->handler ();
    733       str = next_tok (&next_str, '+');
    734       if (type->subtypes == NULL)
    735 	continue;
    736 
    737       /* Loop through tokens until we find one that isn't a subtype.  */
    738       while (str)
    739 	{
    740 	  const aarch_branch_protect_type *subtype = type->subtypes;
    741 	  for (; subtype->name; subtype++)
    742 	    if (strcmp (str, subtype->name) == 0)
    743 	      break;
    744 	  if (subtype->name == NULL)
    745 	    break;
    746 
    747 	  subtype->handler ();
    748 	  str = next_tok (&next_str, '+');
    749 	}
    750     }
    751 
    752   free (str_root);
    753   return res;
    754 }
    755