+ return NULL;
+
+ memcpy (save, affix, 2);
+ memmove (affix, affix + 2, (end - affix) - 2);
+ opcode = hash_find_n (arm_ops_hsh, base, (end - base) - 2);
+ memmove (affix + 2, affix, (end - affix) - 2);
+ memcpy (affix, save, 2);
+
+ if (opcode
+ && (opcode->tag == OT_cinfix3
+ || opcode->tag == OT_cinfix3_deprecated
+ || opcode->tag == OT_csuf_or_in3
+ || opcode->tag == OT_cinfix3_legacy))
+ {
+ /* Step CM. */
+ if (warn_on_deprecated && unified_syntax
+ && (opcode->tag == OT_cinfix3
+ || opcode->tag == OT_cinfix3_deprecated))
+ as_warn (_("conditional infixes are deprecated in unified syntax"));
+
+ inst.cond = cond->value;
+ return opcode;
+ }
+
+ return NULL;
+}
+
+/* This function generates an initial IT instruction, leaving its block
+ virtually open for the new instructions. Eventually,
+ the mask will be updated by now_it_add_mask () each time
+ a new instruction needs to be included in the IT block.
+ Finally, the block is closed with close_automatic_it_block ().
+ The block closure can be requested either from md_assemble (),
+ a tencode (), or due to a label hook. */
+
+static void
+new_automatic_it_block (int cond)
+{
+ now_it.state = AUTOMATIC_IT_BLOCK;
+ now_it.mask = 0x18;
+ now_it.cc = cond;
+ now_it.block_length = 1;
+ mapping_state (MAP_THUMB);
+ now_it.insn = output_it_inst (cond, now_it.mask, NULL);
+}
+
+/* Close an automatic IT block.
+ See comments in new_automatic_it_block (). */
+
+static void
+close_automatic_it_block (void)
+{
+ now_it.mask = 0x10;
+ now_it.block_length = 0;
+}
+
+/* Update the mask of the current automatically-generated IT
+ instruction. See comments in new_automatic_it_block (). */
+
+static void
+now_it_add_mask (int cond)
+{
+#define CLEAR_BIT(value, nbit) ((value) & ~(1 << (nbit)))
+#define SET_BIT_VALUE(value, bitvalue, nbit) (CLEAR_BIT (value, nbit) \
+ | ((bitvalue) << (nbit)))
+ const int resulting_bit = (cond & 1);
+
+ now_it.mask &= 0xf;
+ now_it.mask = SET_BIT_VALUE (now_it.mask,
+ resulting_bit,
+ (5 - now_it.block_length));
+ now_it.mask = SET_BIT_VALUE (now_it.mask,
+ 1,
+ ((5 - now_it.block_length) - 1) );
+ output_it_inst (now_it.cc, now_it.mask, now_it.insn);
+
+#undef CLEAR_BIT
+#undef SET_BIT_VALUE
+}
+
+/* The IT blocks handling machinery is accessed through the these functions:
+ it_fsm_pre_encode () from md_assemble ()
+ set_it_insn_type () optional, from the tencode functions
+ set_it_insn_type_last () ditto
+ in_it_block () ditto
+ it_fsm_post_encode () from md_assemble ()
+ force_automatic_it_block_close () from label habdling functions
+
+ Rationale:
+ 1) md_assemble () calls it_fsm_pre_encode () before calling tencode (),
+ initializing the IT insn type with a generic initial value depending
+ on the inst.condition.
+ 2) During the tencode function, two things may happen:
+ a) The tencode function overrides the IT insn type by
+ calling either set_it_insn_type (type) or set_it_insn_type_last ().
+ b) The tencode function queries the IT block state by
+ calling in_it_block () (i.e. to determine narrow/not narrow mode).
+
+ Both set_it_insn_type and in_it_block run the internal FSM state
+ handling function (handle_it_state), because: a) setting the IT insn
+ type may incur in an invalid state (exiting the function),
+ and b) querying the state requires the FSM to be updated.
+ Specifically we want to avoid creating an IT block for conditional
+ branches, so it_fsm_pre_encode is actually a guess and we can't
+ determine whether an IT block is required until the tencode () routine
+ has decided what type of instruction this actually it.
+ Because of this, if set_it_insn_type and in_it_block have to be used,
+ set_it_insn_type has to be called first.
+
+ set_it_insn_type_last () is a wrapper of set_it_insn_type (type), that
+ determines the insn IT type depending on the inst.cond code.
+ When a tencode () routine encodes an instruction that can be
+ either outside an IT block, or, in the case of being inside, has to be
+ the last one, set_it_insn_type_last () will determine the proper
+ IT instruction type based on the inst.cond code. Otherwise,
+ set_it_insn_type can be called for overriding that logic or
+ for covering other cases.
+
+ Calling handle_it_state () may not transition the IT block state to
+ OUTSIDE_IT_BLOCK immediatelly, since the (current) state could be
+ still queried. Instead, if the FSM determines that the state should
+ be transitioned to OUTSIDE_IT_BLOCK, a flag is marked to be closed
+ after the tencode () function: that's what it_fsm_post_encode () does.
+
+ Since in_it_block () calls the state handling function to get an
+ updated state, an error may occur (due to invalid insns combination).
+ In that case, inst.error is set.
+ Therefore, inst.error has to be checked after the execution of
+ the tencode () routine.
+
+ 3) Back in md_assemble(), it_fsm_post_encode () is called to commit
+ any pending state change (if any) that didn't take place in
+ handle_it_state () as explained above. */
+
+static void
+it_fsm_pre_encode (void)
+{
+ if (inst.cond != COND_ALWAYS)
+ inst.it_insn_type = INSIDE_IT_INSN;
+ else
+ inst.it_insn_type = OUTSIDE_IT_INSN;
+
+ now_it.state_handled = 0;
+}
+
+/* IT state FSM handling function. */
+
+static int
+handle_it_state (void)
+{
+ now_it.state_handled = 1;
+
+ switch (now_it.state)
+ {
+ case OUTSIDE_IT_BLOCK:
+ switch (inst.it_insn_type)
+ {
+ case OUTSIDE_IT_INSN:
+ break;
+
+ case INSIDE_IT_INSN:
+ case INSIDE_IT_LAST_INSN:
+ if (thumb_mode == 0)
+ {
+ if (unified_syntax
+ && !(implicit_it_mode & IMPLICIT_IT_MODE_ARM))
+ as_tsktsk (_("Warning: conditional outside an IT block"\
+ " for Thumb."));
+ }
+ else
+ {
+ if ((implicit_it_mode & IMPLICIT_IT_MODE_THUMB)
+ && ARM_CPU_HAS_FEATURE (cpu_variant, arm_arch_t2))
+ {
+ /* Automatically generate the IT instruction. */
+ new_automatic_it_block (inst.cond);
+ if (inst.it_insn_type == INSIDE_IT_LAST_INSN)
+ close_automatic_it_block ();
+ }
+ else
+ {
+ inst.error = BAD_OUT_IT;
+ return FAIL;
+ }
+ }
+ break;
+
+ case IF_INSIDE_IT_LAST_INSN:
+ case NEUTRAL_IT_INSN:
+ break;
+
+ case IT_INSN:
+ now_it.state = MANUAL_IT_BLOCK;
+ now_it.block_length = 0;
+ break;
+ }
+ break;
+
+ case AUTOMATIC_IT_BLOCK:
+ /* Three things may happen now:
+ a) We should increment current it block size;
+ b) We should close current it block (closing insn or 4 insns);
+ c) We should close current it block and start a new one (due
+ to incompatible conditions or
+ 4 insns-length block reached). */
+
+ switch (inst.it_insn_type)
+ {
+ case OUTSIDE_IT_INSN:
+ /* The closure of the block shall happen immediatelly,
+ so any in_it_block () call reports the block as closed. */
+ force_automatic_it_block_close ();
+ break;
+
+ case INSIDE_IT_INSN:
+ case INSIDE_IT_LAST_INSN:
+ case IF_INSIDE_IT_LAST_INSN:
+ now_it.block_length++;
+
+ if (now_it.block_length > 4
+ || !now_it_compatible (inst.cond))
+ {
+ force_automatic_it_block_close ();
+ if (inst.it_insn_type != IF_INSIDE_IT_LAST_INSN)
+ new_automatic_it_block (inst.cond);
+ }
+ else
+ {
+ now_it_add_mask (inst.cond);
+ }
+
+ if (now_it.state == AUTOMATIC_IT_BLOCK
+ && (inst.it_insn_type == INSIDE_IT_LAST_INSN
+ || inst.it_insn_type == IF_INSIDE_IT_LAST_INSN))
+ close_automatic_it_block ();
+ break;
+
+ case NEUTRAL_IT_INSN:
+ now_it.block_length++;
+
+ if (now_it.block_length > 4)
+ force_automatic_it_block_close ();
+ else
+ now_it_add_mask (now_it.cc & 1);
+ break;
+
+ case IT_INSN:
+ close_automatic_it_block ();
+ now_it.state = MANUAL_IT_BLOCK;
+ break;
+ }
+ break;
+
+ case MANUAL_IT_BLOCK:
+ {
+ /* Check conditional suffixes. */
+ const int cond = now_it.cc ^ ((now_it.mask >> 4) & 1) ^ 1;
+ int is_last;
+ now_it.mask <<= 1;
+ now_it.mask &= 0x1f;
+ is_last = (now_it.mask == 0x10);
+
+ switch (inst.it_insn_type)
+ {
+ case OUTSIDE_IT_INSN:
+ inst.error = BAD_NOT_IT;
+ return FAIL;
+
+ case INSIDE_IT_INSN:
+ if (cond != inst.cond)
+ {
+ inst.error = BAD_IT_COND;
+ return FAIL;
+ }
+ break;
+
+ case INSIDE_IT_LAST_INSN:
+ case IF_INSIDE_IT_LAST_INSN:
+ if (cond != inst.cond)
+ {
+ inst.error = BAD_IT_COND;
+ return FAIL;
+ }
+ if (!is_last)
+ {
+ inst.error = BAD_BRANCH;
+ return FAIL;
+ }
+ break;
+
+ case NEUTRAL_IT_INSN:
+ /* The BKPT instruction is unconditional even in an IT block. */
+ break;
+
+ case IT_INSN:
+ inst.error = BAD_IT_IT;
+ return FAIL;
+ }
+ }
+ break;
+ }
+
+ return SUCCESS;
+}
+
+static void
+it_fsm_post_encode (void)
+{
+ int is_last;