aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gas/ChangeLog58
-rw-r--r--gas/config/tc-arm.c938
-rw-r--r--gas/config/tc-arm.h21
-rw-r--r--gas/doc/c-arm.texi5
-rw-r--r--gas/testsuite/ChangeLog23
-rw-r--r--gas/testsuite/gas/arm/thumb2_it.d58
-rw-r--r--gas/testsuite/gas/arm/thumb2_it_bad.d1
-rw-r--r--gas/testsuite/gas/arm/thumb2_it_bad.l2
8 files changed, 850 insertions, 256 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog
index 0e6f874..074e239 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,9 +1,65 @@
+2009-06-22 Daniel Gutson <dgutson@codesourcery.com>
+
+ * config/tc-arm.c (implicit_it_mode): New enum.
+ (implicit_it_mode): New global.
+ (it_instruction_type): New enum.
+ (arm_parse_it_mode): New function.
+ (arm_long_opts): New option added.
+ (arm_it): New field.
+ (it_state): New enum.
+ (now_it): New macro.
+ (check_it_blocks_finished): New function.
+ (insns[]): Use the IT Thumb opcodes for ARM too.
+ (arm_cleanup): Call check_it_blocks_finished.
+ (now_it_compatible): New function.
+ (conditional_insn): New function.
+ (set_it_insn_type): New macro.
+ (set_it_insn_type_last): New macro.
+ (do_it): Call automatic IT machinery functions.
+ (do_t_add_sub): Likewise
+ (do_t_arit3): Likewise.
+ (do_t_arit3c): Likewise.
+ (do_t_blx): Likewise.
+ (do_t_branch): Likewise.
+ (do_t_bkpt): Likewise.
+ (do_t_branch23): Likewise.
+ (do_t_bx): Likewise.
+ (do_t_bxj): Likewise.
+ (do_t_cps): Likewise.
+ (do_t_cpsi): Likewise.
+ (do_t_cbz): Likewise.
+ (do_t_it): Likewise.
+ (encode_thumb2_ldmstm): Likewise.
+ (do_t_ldst): Likewise.
+ (do_t_mov_cmp): Likewise.
+ (do_t_mvn_tst): Likewise.
+ (do_t_mul): Likewise.
+ (do_t_neg): Likewise.
+ (do_t_setend): Likewise.
+ (do_t_shift): Likewise.
+ (do_t_tb): Likewise.
+ (output_it_inst): New function.
+ (new_automatic_it_block): New function.
+ (close_automatic_it_block): New function.
+ (now_it_add_mask): New function.
+ (it_fsm_pre_encode): New function.
+ (handle_it_state): New function.
+ (it_fsm_post_encode): New function.
+ (force_automatic_it_block_close): New function.
+ (in_it_block): New function.
+ (md_assemble): Call automatic IT block machinery functions.
+ (arm_frob_label): Likewise.
+ (arm_opts): New element.
+ * config/tc-arm.h (it_state): New enum.
+ (current_it): New struct.
+ (arm_segment_info_type): New member added.
+ * doc/c-arm.texi: New option -mimplicit-it documented.
+
2009-06-20 Alan Modra <amodra@bigpond.net.au>
PR 10302
* doc/as.texinfo (Section <ELF "M,S" flag>): Clarify tail merge.
-=======
2009-06-19 Martin Schwidefsky <schwidefsky@de.ibm.com>
* config/tc-s390.c (md_gather_operands): Accept an instruction
diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c
index 1190696..c3f775c 100644
--- a/gas/config/tc-arm.c
+++ b/gas/config/tc-arm.c
@@ -265,6 +265,16 @@ static int thumb_mode = 0;
tc_frag_data field of a frag. */
#define MODE_RECORDED (1 << 4)
+/* Specifies the intrinsic IT insn behavior mode. */
+enum implicit_it_mode
+{
+ IMPLICIT_IT_MODE_NEVER = 0x00,
+ IMPLICIT_IT_MODE_ARM = 0x01,
+ IMPLICIT_IT_MODE_THUMB = 0x02,
+ IMPLICIT_IT_MODE_ALWAYS = (IMPLICIT_IT_MODE_ARM | IMPLICIT_IT_MODE_THUMB)
+};
+static int implicit_it_mode = IMPLICIT_IT_MODE_ARM;
+
/* If unified_syntax is true, we are processing the new unified
ARM/Thumb syntax. Important differences from the old ARM mode:
@@ -315,6 +325,18 @@ struct neon_type
unsigned elems;
};
+enum it_instruction_type
+{
+ OUTSIDE_IT_INSN,
+ INSIDE_IT_INSN,
+ INSIDE_IT_LAST_INSN,
+ IF_INSIDE_IT_LAST_INSN, /* Either outside or inside;
+ if inside, should be the last one. */
+ NEUTRAL_IT_INSN, /* This could be either inside or outside,
+ i.e. BKPT and NOP. */
+ IT_INSN /* The IT insn has been parsed. */
+};
+
struct arm_it
{
const char * error;
@@ -337,6 +359,8 @@ struct arm_it
int pc_rel;
} reloc;
+ enum it_instruction_type it_insn_type;
+
struct
{
unsigned reg;
@@ -674,6 +698,9 @@ struct asm_opcode
#define BAD_BRANCH _("branch must be last instruction in IT block")
#define BAD_NOT_IT _("instruction not allowed in IT block")
#define BAD_FPU _("selected FPU does not support instruction")
+#define BAD_OUT_IT _("thumb conditional instruction should be in IT block")
+#define BAD_IT_COND _("incorrect condition in IT block")
+#define BAD_IT_IT _("IT falling in the range of a previous IT block")
static struct hash_control *arm_ops_hsh;
static struct hash_control *arm_cond_hsh;
@@ -695,7 +722,7 @@ static struct hash_control *arm_barrier_opt_hsh;
symbolS * last_label_seen;
static int label_is_thumb_function_name = FALSE;
-
+
/* Literal pool structure. Held on a per-section
and per-sub-section basis. */
@@ -714,10 +741,49 @@ typedef struct literal_pool
/* Pointer to a linked list of literal pools. */
literal_pool * list_of_pools = NULL;
-/* State variables for IT block handling. */
-static bfd_boolean current_it_mask = 0;
-static int current_cc;
-
+#ifdef OBJ_ELF
+# define now_it seg_info (now_seg)->tc_segment_info_data.current_it
+#else
+static struct current_it now_it;
+#endif
+
+static inline int
+now_it_compatible (int cond)
+{
+ return (cond & ~1) == (now_it.cc & ~1);
+}
+
+static inline int
+conditional_insn (void)
+{
+ return inst.cond != COND_ALWAYS;
+}
+
+static int in_it_block (void);
+
+static int handle_it_state (void);
+
+static void force_automatic_it_block_close (void);
+
+#define set_it_insn_type(type) \
+ do \
+ { \
+ inst.it_insn_type = type; \
+ if (handle_it_state () == FAIL) \
+ return; \
+ } \
+ while (0)
+
+#define set_it_insn_type_last() \
+ do \
+ { \
+ if (inst.cond == COND_ALWAYS) \
+ set_it_insn_type (IF_INSIDE_IT_LAST_INSN); \
+ else \
+ set_it_insn_type (INSIDE_IT_LAST_INSN); \
+ } \
+ while (0)
+
/* Pure syntax. */
/* This array holds the chars that always start a comment. If the
@@ -1431,6 +1497,7 @@ parse_scalar (char **ccp, int elsize, struct neon_type_el *type)
}
/* Parse an ARM register list. Returns the bitmask, or FAIL. */
+
static long
parse_reg_list (char ** strp)
{
@@ -5068,7 +5135,7 @@ parse_cond (char **str)
n = 0;
while (ISALPHA (*q) && n < 3)
{
- cond[n] = TOLOWER(*q);
+ cond[n] = TOLOWER (*q);
q++;
n++;
}
@@ -5516,69 +5583,90 @@ parse_operands (char *str, const unsigned char *pattern)
enum arm_reg_type rtype;
parse_operand_result result;
-#define po_char_or_fail(chr) do { \
- if (skip_past_char (&str, chr) == FAIL) \
- goto bad_args; \
-} while (0)
+#define po_char_or_fail(chr) \
+ do \
+ { \
+ if (skip_past_char (&str, chr) == FAIL) \
+ goto bad_args; \
+ } \
+ while (0)
-#define po_reg_or_fail(regtype) do { \
- val = arm_typed_reg_parse (&str, regtype, &rtype, \
- &inst.operands[i].vectype); \
- if (val == FAIL) \
+#define po_reg_or_fail(regtype) \
+ do \
{ \
- first_error (_(reg_expected_msgs[regtype])); \
- goto failure; \
+ val = arm_typed_reg_parse (& str, regtype, & rtype, \
+ & inst.operands[i].vectype); \
+ if (val == FAIL) \
+ { \
+ first_error (_(reg_expected_msgs[regtype])); \
+ goto failure; \
+ } \
+ inst.operands[i].reg = val; \
+ inst.operands[i].isreg = 1; \
+ inst.operands[i].isquad = (rtype == REG_TYPE_NQ); \
+ inst.operands[i].issingle = (rtype == REG_TYPE_VFS); \
+ inst.operands[i].isvec = (rtype == REG_TYPE_VFS \
+ || rtype == REG_TYPE_VFD \
+ || rtype == REG_TYPE_NQ); \
} \
- inst.operands[i].reg = val; \
- inst.operands[i].isreg = 1; \
- inst.operands[i].isquad = (rtype == REG_TYPE_NQ); \
- inst.operands[i].issingle = (rtype == REG_TYPE_VFS); \
- inst.operands[i].isvec = (rtype == REG_TYPE_VFS \
- || rtype == REG_TYPE_VFD \
- || rtype == REG_TYPE_NQ); \
-} while (0)
-
-#define po_reg_or_goto(regtype, label) do { \
- val = arm_typed_reg_parse (&str, regtype, &rtype, \
- &inst.operands[i].vectype); \
- if (val == FAIL) \
- goto label; \
+ while (0)
+
+#define po_reg_or_goto(regtype, label) \
+ do \
+ { \
+ val = arm_typed_reg_parse (& str, regtype, & rtype, \
+ & inst.operands[i].vectype); \
+ if (val == FAIL) \
+ goto label; \
\
- inst.operands[i].reg = val; \
- inst.operands[i].isreg = 1; \
- inst.operands[i].isquad = (rtype == REG_TYPE_NQ); \
- inst.operands[i].issingle = (rtype == REG_TYPE_VFS); \
- inst.operands[i].isvec = (rtype == REG_TYPE_VFS \
- || rtype == REG_TYPE_VFD \
- || rtype == REG_TYPE_NQ); \
-} while (0)
-
-#define po_imm_or_fail(min, max, popt) do { \
- if (parse_immediate (&str, &val, min, max, popt) == FAIL) \
- goto failure; \
- inst.operands[i].imm = val; \
-} while (0)
-
-#define po_scalar_or_goto(elsz, label) do { \
- val = parse_scalar (&str, elsz, &inst.operands[i].vectype); \
- if (val == FAIL) \
- goto label; \
- inst.operands[i].reg = val; \
- inst.operands[i].isscalar = 1; \
-} while (0)
-
-#define po_misc_or_fail(expr) do { \
- if (expr) \
- goto failure; \
-} while (0)
-
-#define po_misc_or_fail_no_backtrack(expr) do { \
- result = expr; \
- if (result == PARSE_OPERAND_FAIL_NO_BACKTRACK)\
- backtrack_pos = 0; \
- if (result != PARSE_OPERAND_SUCCESS) \
- goto failure; \
-} while (0)
+ inst.operands[i].reg = val; \
+ inst.operands[i].isreg = 1; \
+ inst.operands[i].isquad = (rtype == REG_TYPE_NQ); \
+ inst.operands[i].issingle = (rtype == REG_TYPE_VFS); \
+ inst.operands[i].isvec = (rtype == REG_TYPE_VFS \
+ || rtype == REG_TYPE_VFD \
+ || rtype == REG_TYPE_NQ); \
+ } \
+ while (0)
+
+#define po_imm_or_fail(min, max, popt) \
+ do \
+ { \
+ if (parse_immediate (&str, &val, min, max, popt) == FAIL) \
+ goto failure; \
+ inst.operands[i].imm = val; \
+ } \
+ while (0)
+
+#define po_scalar_or_goto(elsz, label) \
+ do \
+ { \
+ val = parse_scalar (& str, elsz, & inst.operands[i].vectype); \
+ if (val == FAIL) \
+ goto label; \
+ inst.operands[i].reg = val; \
+ inst.operands[i].isscalar = 1; \
+ } \
+ while (0)
+
+#define po_misc_or_fail(expr) \
+ do \
+ { \
+ if (expr) \
+ goto failure; \
+ } \
+ while (0)
+
+#define po_misc_or_fail_no_backtrack(expr) \
+ do \
+ { \
+ result = expr; \
+ if (result == PARSE_OPERAND_FAIL_NO_BACKTRACK) \
+ backtrack_pos = 0; \
+ if (result != PARSE_OPERAND_SUCCESS) \
+ goto failure; \
+ } \
+ while (0)
skip_whitespace (str);
@@ -5844,11 +5932,11 @@ parse_operands (char *str, const unsigned char *pattern)
po_misc_or_fail (parse_half (&str));
break;
- /* Register or expression */
+ /* Register or expression. */
case OP_RR_EXr: po_reg_or_goto (REG_TYPE_RN, EXPr); break;
case OP_RR_EXi: po_reg_or_goto (REG_TYPE_RN, EXPi); break;
- /* Register or immediate */
+ /* Register or immediate. */
case OP_RRnpc_I0: po_reg_or_goto (REG_TYPE_RN, I0); break;
I0: po_imm_or_fail (0, 0, FALSE); break;
@@ -5869,7 +5957,7 @@ parse_operands (char *str, const unsigned char *pattern)
case OP_RIWR_I32z: po_reg_or_goto (REG_TYPE_MMXWR, I32z); break;
I32z: po_imm_or_fail (0, 32, FALSE); break;
- /* Two kinds of register */
+ /* Two kinds of register. */
case OP_RIWR_RIWC:
{
struct reg_entry *rege = arm_reg_parse_multi (&str);
@@ -5948,7 +6036,7 @@ parse_operands (char *str, const unsigned char *pattern)
po_misc_or_fail (parse_tb (&str));
break;
- /* Register lists */
+ /* Register lists. */
case OP_REGLST:
val = parse_reg_list (&str);
if (*str == '^')
@@ -6120,15 +6208,18 @@ parse_operands (char *str, const unsigned char *pattern)
#undef po_reg_or_goto
#undef po_imm_or_fail
#undef po_scalar_or_fail
-
+
/* Shorthand macro for instruction encoding functions issuing errors. */
-#define constraint(expr, err) do { \
- if (expr) \
+#define constraint(expr, err) \
+ do \
{ \
- inst.error = err; \
- return; \
+ if (expr) \
+ { \
+ inst.error = err; \
+ return; \
+ } \
} \
-} while (0)
+ while (0)
/* Reject "bad registers" for Thumb-2 instructions. Many Thumb-2
instructions are unpredictable if these registers are used. This
@@ -6960,8 +7051,17 @@ static void
do_it (void)
{
/* There is no IT instruction in ARM mode. We
- process it but do not generate code for it. */
+ process it to do the validation as if in
+ thumb mode, just in case the code gets
+ assembled for thumb using the unified syntax. */
+
inst.size = 0;
+ if (unified_syntax)
+ {
+ set_it_insn_type (IT_INSN);
+ now_it.mask = (inst.instruction & 0xf) | 0x10;
+ now_it.cc = inst.operands[0].imm;
+ }
}
static void
@@ -8482,6 +8582,9 @@ do_t_add_sub (void)
? inst.operands[1].reg /* Rd, Rs, foo */
: inst.operands[0].reg); /* Rd, foo -> Rd, Rd, foo */
+ if (Rd == REG_PC)
+ set_it_insn_type_last ();
+
if (unified_syntax)
{
bfd_boolean flags;
@@ -8491,9 +8594,9 @@ do_t_add_sub (void)
flags = (inst.instruction == T_MNEM_adds
|| inst.instruction == T_MNEM_subs);
if (flags)
- narrow = (current_it_mask == 0);
+ narrow = !in_it_block ();
else
- narrow = (current_it_mask != 0);
+ narrow = in_it_block ();
if (!inst.operands[2].isreg)
{
int add;
@@ -8745,9 +8848,9 @@ do_t_arit3 (void)
/* See if we can do this with a 16-bit instruction. */
if (THUMB_SETS_FLAGS (inst.instruction))
- narrow = current_it_mask == 0;
+ narrow = !in_it_block ();
else
- narrow = current_it_mask != 0;
+ narrow = in_it_block ();
if (Rd > 7 || Rn > 7 || Rs > 7)
narrow = FALSE;
@@ -8833,9 +8936,9 @@ do_t_arit3c (void)
/* See if we can do this with a 16-bit instruction. */
if (THUMB_SETS_FLAGS (inst.instruction))
- narrow = current_it_mask == 0;
+ narrow = !in_it_block ();
else
- narrow = current_it_mask != 0;
+ narrow = in_it_block ();
if (Rd > 7 || Rn > 7 || Rs > 7)
narrow = FALSE;
@@ -8988,7 +9091,8 @@ do_t_bfx (void)
static void
do_t_blx (void)
{
- constraint (current_it_mask && current_it_mask != 0x10, BAD_BRANCH);
+ set_it_insn_type_last ();
+
if (inst.operands[0].isreg)
{
constraint (inst.operands[0].reg == REG_PC, BAD_PC);
@@ -9010,13 +9114,14 @@ do_t_branch (void)
int opcode;
int cond;
- if (current_it_mask)
+ cond = inst.cond;
+ set_it_insn_type (IF_INSIDE_IT_LAST_INSN);
+
+ if (in_it_block ())
{
/* Conditional branches inside IT blocks are encoded as unconditional
branches. */
cond = COND_ALWAYS;
- /* A branch must be the last instruction in an IT block. */
- constraint (current_it_mask != 0x10, BAD_BRANCH);
}
else
cond = inst.cond;
@@ -9066,13 +9171,14 @@ do_t_bkpt (void)
constraint (inst.operands[0].imm > 255,
_("immediate value out of range"));
inst.instruction |= inst.operands[0].imm;
+ set_it_insn_type (NEUTRAL_IT_INSN);
}
}
static void
do_t_branch23 (void)
{
- constraint (current_it_mask && current_it_mask != 0x10, BAD_BRANCH);
+ set_it_insn_type_last ();
inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH23;
inst.reloc.pc_rel = 1;
@@ -9093,7 +9199,7 @@ do_t_branch23 (void)
static void
do_t_bx (void)
{
- constraint (current_it_mask && current_it_mask != 0x10, BAD_BRANCH);
+ set_it_insn_type_last ();
inst.instruction |= inst.operands[0].reg << 3;
/* ??? FIXME: Should add a hacky reloc here if reg is REG_PC. The reloc
should cause the alignment to be checked once it is known. This is
@@ -9105,7 +9211,7 @@ do_t_bxj (void)
{
int Rm;
- constraint (current_it_mask && current_it_mask != 0x10, BAD_BRANCH);
+ set_it_insn_type_last ();
Rm = inst.operands[0].reg;
reject_bad_reg (Rm);
inst.instruction |= Rm << 16;
@@ -9131,14 +9237,14 @@ do_t_clz (void)
static void
do_t_cps (void)
{
- constraint (current_it_mask, BAD_NOT_IT);
+ set_it_insn_type (OUTSIDE_IT_INSN);
inst.instruction |= inst.operands[0].imm;
}
static void
do_t_cpsi (void)
{
- constraint (current_it_mask, BAD_NOT_IT);
+ set_it_insn_type (OUTSIDE_IT_INSN);
if (unified_syntax
&& (inst.operands[1].present || inst.size_req == 4)
&& ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v6_notm))
@@ -9185,7 +9291,7 @@ do_t_cpy (void)
static void
do_t_cbz (void)
{
- constraint (current_it_mask, BAD_NOT_IT);
+ set_it_insn_type (OUTSIDE_IT_INSN);
constraint (inst.operands[0].reg > 7, BAD_HIREG);
inst.instruction |= inst.operands[0].reg;
inst.reloc.pc_rel = 1;
@@ -9231,9 +9337,9 @@ do_t_it (void)
{
unsigned int cond = inst.operands[0].imm;
- constraint (current_it_mask, BAD_NOT_IT);
- current_it_mask = (inst.instruction & 0xf) | 0x10;
- current_cc = cond;
+ set_it_insn_type (IT_INSN);
+ now_it.mask = (inst.instruction & 0xf) | 0x10;
+ now_it.cc = cond;
/* If the condition is a negative condition, invert the mask. */
if ((cond & 0x1) == 0x0)
@@ -9268,9 +9374,13 @@ encode_thumb2_ldmstm (int base, unsigned mask, bfd_boolean writeback)
inst.error = _("SP not allowed in register list");
if (load)
{
- if (mask & (1 << 14)
- && mask & (1 << 15))
- inst.error = _("LR and PC should not both be in register list");
+ if (mask & (1 << 15))
+ {
+ if (mask & (1 << 14))
+ inst.error = _("LR and PC should not both be in register list");
+ else
+ set_it_insn_type_last ();
+ }
if ((mask & (1 << base)) != 0
&& writeback)
@@ -9446,6 +9556,11 @@ do_t_ldst (void)
unsigned long opcode;
int Rn;
+ if (inst.operands[0].isreg
+ && !inst.operands[0].preind
+ && inst.operands[0].reg == REG_PC)
+ set_it_insn_type_last ();
+
opcode = inst.instruction;
if (unified_syntax)
{
@@ -9666,6 +9781,9 @@ do_t_mov_cmp (void)
Rn = inst.operands[0].reg;
Rm = inst.operands[1].reg;
+ if (Rn == REG_PC)
+ set_it_insn_type_last ();
+
if (unified_syntax)
{
int r0off = (inst.instruction == T_MNEM_mov
@@ -9676,7 +9794,7 @@ do_t_mov_cmp (void)
low_regs = (Rn <= 7 && Rm <= 7);
opcode = inst.instruction;
- if (current_it_mask)
+ if (in_it_block ())
narrow = opcode != T_MNEM_movs;
else
narrow = opcode != T_MNEM_movs || low_regs;
@@ -9731,7 +9849,7 @@ do_t_mov_cmp (void)
if (!inst.operands[1].isreg)
{
/* Immediate operand. */
- if (current_it_mask == 0 && opcode == T_MNEM_mov)
+ if (!in_it_block () && opcode == T_MNEM_mov)
narrow = 0;
if (low_regs && narrow)
{
@@ -9757,7 +9875,7 @@ do_t_mov_cmp (void)
/* Register shifts are encoded as separate shift instructions. */
bfd_boolean flags = (inst.instruction == T_MNEM_movs);
- if (current_it_mask)
+ if (in_it_block ())
narrow = !flags;
else
narrow = flags;
@@ -9813,7 +9931,7 @@ do_t_mov_cmp (void)
&& (inst.instruction == T_MNEM_mov
|| inst.instruction == T_MNEM_movs))
{
- if (current_it_mask)
+ if (in_it_block ())
narrow = (inst.instruction == T_MNEM_mov);
else
narrow = (inst.instruction == T_MNEM_movs);
@@ -9975,9 +10093,9 @@ do_t_mvn_tst (void)
else if (inst.instruction == T_MNEM_cmn)
narrow = TRUE;
else if (THUMB_SETS_FLAGS (inst.instruction))
- narrow = (current_it_mask == 0);
+ narrow = !in_it_block ();
else
- narrow = (current_it_mask != 0);
+ narrow = in_it_block ();
if (!inst.operands[1].isreg)
{
@@ -10116,9 +10234,9 @@ do_t_mul (void)
|| Rm > 7)
narrow = FALSE;
else if (inst.instruction == T_MNEM_muls)
- narrow = (current_it_mask == 0);
+ narrow = !in_it_block ();
else
- narrow = (current_it_mask != 0);
+ narrow = in_it_block ();
}
else
{
@@ -10143,8 +10261,8 @@ do_t_mul (void)
}
else
{
- constraint(inst.instruction != T_MNEM_mul,
- _("Thumb-2 MUL must not set flags"));
+ constraint (inst.instruction != T_MNEM_mul,
+ _("Thumb-2 MUL must not set flags"));
/* 32-bit MUL. */
inst.instruction = THUMB_OP32 (inst.instruction);
inst.instruction |= Rd << 8;
@@ -10184,6 +10302,8 @@ do_t_mull (void)
static void
do_t_nop (void)
{
+ set_it_insn_type (NEUTRAL_IT_INSN);
+
if (unified_syntax)
{
if (inst.size_req == 4 || inst.operands[0].imm > 15)
@@ -10220,9 +10340,9 @@ do_t_neg (void)
bfd_boolean narrow;
if (THUMB_SETS_FLAGS (inst.instruction))
- narrow = (current_it_mask == 0);
+ narrow = !in_it_block ();
else
- narrow = (current_it_mask != 0);
+ narrow = in_it_block ();
if (inst.operands[0].reg > 7 || inst.operands[1].reg > 7)
narrow = FALSE;
if (inst.size_req == 4)
@@ -10446,9 +10566,9 @@ do_t_rsb (void)
bfd_boolean narrow;
if ((inst.instruction & 0x00100000) != 0)
- narrow = (current_it_mask == 0);
+ narrow = !in_it_block ();
else
- narrow = (current_it_mask != 0);
+ narrow = in_it_block ();
if (Rd > 7 || Rs > 7)
narrow = FALSE;
@@ -10482,7 +10602,7 @@ do_t_rsb (void)
static void
do_t_setend (void)
{
- constraint (current_it_mask, BAD_NOT_IT);
+ set_it_insn_type (OUTSIDE_IT_INSN);
if (inst.operands[0].imm)
inst.instruction |= 0x8;
}
@@ -10512,9 +10632,9 @@ do_t_shift (void)
}
if (THUMB_SETS_FLAGS (inst.instruction))
- narrow = (current_it_mask == 0);
+ narrow = !in_it_block ();
else
- narrow = (current_it_mask != 0);
+ narrow = in_it_block ();
if (inst.operands[0].reg > 7 || inst.operands[1].reg > 7)
narrow = FALSE;
if (!inst.operands[2].isreg && shift_kind == SHIFT_ROR)
@@ -10813,7 +10933,7 @@ do_t_tb (void)
int half;
half = (inst.instruction & 0x10) != 0;
- constraint (current_it_mask && current_it_mask != 0x10, BAD_BRANCH);
+ set_it_insn_type_last ();
constraint (inst.operands[0].immisreg,
_("instruction requires register index"));
@@ -10878,7 +10998,7 @@ struct neon_tab_entry
X(vcge, 0x0000310, 0x1000e00, 0x1b10080), \
X(vcgt, 0x0000300, 0x1200e00, 0x1b10000), \
/* Register variants of the following two instructions are encoded as
- vcge / vcgt with the operands reversed. */ \
+ vcge / vcgt with the operands reversed. */ \
X(vclt, 0x0000300, 0x1200e00, 0x1b10200), \
X(vcle, 0x0000310, 0x1000e00, 0x1b10180), \
X(vmla, 0x0000900, 0x0000d10, 0x0800040), \
@@ -14425,6 +14545,28 @@ output_inst (const char * str)
dwarf2_emit_insn (inst.size);
}
+static char *
+output_it_inst (int cond, int mask, char * to)
+{
+ unsigned long instruction = 0xbf00;
+
+ mask &= 0xf;
+ instruction |= mask;
+ instruction |= cond << 4;
+
+ if (to == NULL)
+ {
+ to = frag_more (2);
+#ifdef OBJ_ELF
+ dwarf2_emit_insn (2);
+#endif
+ }
+
+ md_number_to_chars (to, instruction, 2);
+
+ return to;
+}
+
/* Tag values used in struct asm_opcode's tag field. */
enum opcode_tag
{
@@ -14670,6 +14812,320 @@ opcode_lookup (char **str)
return 0;
}
+/* 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;
+ 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;
+
+ if (!now_it.state_handled)
+ handle_it_state ();
+
+ is_last = (now_it.mask == 0x10);
+ if (is_last)
+ {
+ now_it.state = OUTSIDE_IT_BLOCK;
+ now_it.mask = 0;
+ }
+}
+
+static void
+force_automatic_it_block_close (void)
+{
+ if (now_it.state == AUTOMATIC_IT_BLOCK)
+ {
+ close_automatic_it_block ();
+ now_it.state = OUTSIDE_IT_BLOCK;
+ now_it.mask = 0;
+ }
+}
+
+static int
+in_it_block (void)
+{
+ if (!now_it.state_handled)
+ handle_it_state ();
+
+ return now_it.state != OUTSIDE_IT_BLOCK;
+}
+
void
md_assemble (char *str)
{
@@ -14734,41 +15190,24 @@ md_assemble (char *str)
/* Implicit require narrow instructions on Thumb-1. This avoids
relaxation accidentally introducing Thumb-2 instructions. */
if (opcode->tencode != do_t_blx && opcode->tencode != do_t_branch23
- && !(ARM_CPU_HAS_FEATURE(*opcode->tvariant, arm_ext_msr)
- || ARM_CPU_HAS_FEATURE(*opcode->tvariant, arm_ext_barrier)))
+ && !(ARM_CPU_HAS_FEATURE (*opcode->tvariant, arm_ext_msr)
+ || ARM_CPU_HAS_FEATURE (*opcode->tvariant, arm_ext_barrier)))
inst.size_req = 2;
}
- /* Check conditional suffixes. */
- if (current_it_mask)
- {
- int cond;
- cond = current_cc ^ ((current_it_mask >> 4) & 1) ^ 1;
- current_it_mask <<= 1;
- current_it_mask &= 0x1f;
- /* The BKPT instruction is unconditional even in an IT block. */
- if (!inst.error
- && cond != inst.cond && opcode->tencode != do_t_bkpt)
- {
- as_bad (_("incorrect condition in IT block"));
- return;
- }
- }
- else if (inst.cond != COND_ALWAYS && opcode->tencode != do_t_branch)
- {
- as_bad (_("thumb conditional instruction not in IT block"));
- return;
- }
-
mapping_state (MAP_THUMB);
inst.instruction = opcode->tvalue;
if (!parse_operands (p, opcode->operands))
- opcode->tencode ();
+ {
+ /* Prepare the it_insn_type for those encodings that don't set
+ it. */
+ it_fsm_pre_encode ();
- /* Clear current_it_mask at the end of an IT block. */
- if (current_it_mask == 0x10)
- current_it_mask = 0;
+ opcode->tencode ();
+
+ it_fsm_post_encode ();
+ }
if (!(inst.error || inst.relax))
{
@@ -14793,8 +15232,8 @@ md_assemble (char *str)
This is overly pessimistic for relaxable instructions. */
if (((inst.size == 4 && (inst.instruction & 0xf800e800) != 0xf000e800)
|| inst.relax)
- && !(ARM_CPU_HAS_FEATURE(*opcode->tvariant, arm_ext_msr)
- || ARM_CPU_HAS_FEATURE(*opcode->tvariant, arm_ext_barrier)))
+ && !(ARM_CPU_HAS_FEATURE (*opcode->tvariant, arm_ext_msr)
+ || ARM_CPU_HAS_FEATURE (*opcode->tvariant, arm_ext_barrier)))
ARM_MERGE_FEATURE_SETS (thumb_arch_used, thumb_arch_used,
arm_ext_v6t2);
}
@@ -14827,7 +15266,11 @@ md_assemble (char *str)
inst.instruction |= inst.cond << 28;
inst.size = INSN_SIZE;
if (!parse_operands (p, opcode->operands))
- opcode->aencode ();
+ {
+ it_fsm_pre_encode ();
+ opcode->aencode ();
+ it_fsm_post_encode ();
+ }
/* Arm mode bx is marked as both v4T and v5 because it's still required
on a hypothetical non-thumb v5 core. */
if (is_bx)
@@ -14845,6 +15288,25 @@ md_assemble (char *str)
output_inst (str);
}
+static void
+check_it_blocks_finished (void)
+{
+#ifdef OBJ_ELF
+ asection *sect;
+
+ for (sect = stdoutput->sections; sect != NULL; sect = sect->next)
+ if (seg_info (sect)->tc_segment_info_data.current_it.state
+ == MANUAL_IT_BLOCK)
+ {
+ as_warn (_("section '%s' finished with an open IT block."),
+ sect->name);
+ }
+#else
+ if (now_it.state == MANUAL_IT_BLOCK)
+ as_warn (_("file finished with an open IT block."));
+#endif
+}
+
/* Various frobbings of labels and their addresses. */
void
@@ -14864,6 +15326,8 @@ arm_frob_label (symbolS * sym)
ARM_SET_INTERWORK (sym, support_interwork);
#endif
+ force_automatic_it_block_close ();
+
/* Note - do not allow local symbols (.Lxxx) to be labelled
as Thumb functions. This is because these labels, whilst
they exist inside Thumb code, are not the entry points for
@@ -15229,9 +15693,9 @@ static struct asm_barrier_opt barrier_opt_names[] =
/* Two variants of the above - TCE for a numeric Thumb opcode, tCE for
a T_MNEM_xyz enumerator. */
#define TCE(mnem, aop, top, nops, ops, ae, te) \
- TxCE(mnem, aop, 0x##top, nops, ops, ae, te)
+ TxCE (mnem, aop, 0x##top, nops, ops, ae, te)
#define tCE(mnem, aop, top, nops, ops, ae, te) \
- TxCE(mnem, aop, T_MNEM_##top, nops, ops, ae, te)
+ TxCE (mnem, aop, T_MNEM_##top, nops, ops, ae, te)
/* Second most common sort of mnemonic: has a Thumb variant, takes a conditional
infix after the third character. */
@@ -15242,45 +15706,45 @@ static struct asm_barrier_opt barrier_opt_names[] =
{ #mnem, OPS##nops ops, OT_cinfix3_deprecated, 0x##op, top, ARM_VARIANT, \
THUMB_VARIANT, do_##ae, do_##te }
#define TC3(mnem, aop, top, nops, ops, ae, te) \
- TxC3(mnem, aop, 0x##top, nops, ops, ae, te)
+ TxC3 (mnem, aop, 0x##top, nops, ops, ae, te)
#define TC3w(mnem, aop, top, nops, ops, ae, te) \
- TxC3w(mnem, aop, 0x##top, nops, ops, ae, te)
+ TxC3w (mnem, aop, 0x##top, nops, ops, ae, te)
#define tC3(mnem, aop, top, nops, ops, ae, te) \
- TxC3(mnem, aop, T_MNEM_##top, nops, ops, ae, te)
+ TxC3 (mnem, aop, T_MNEM_##top, nops, ops, ae, te)
#define tC3w(mnem, aop, top, nops, ops, ae, te) \
- TxC3w(mnem, aop, T_MNEM_##top, nops, ops, ae, te)
+ TxC3w (mnem, aop, T_MNEM_##top, nops, ops, ae, te)
/* Mnemonic with a conditional infix in an unusual place. Each and every variant has to
appear in the condition table. */
#define TxCM_(m1, m2, m3, op, top, nops, ops, ae, te) \
- { #m1 #m2 #m3, OPS##nops ops, sizeof(#m2) == 1 ? OT_odd_infix_unc : OT_odd_infix_0 + sizeof(#m1) - 1, \
+ { #m1 #m2 #m3, OPS##nops ops, sizeof (#m2) == 1 ? OT_odd_infix_unc : OT_odd_infix_0 + sizeof (#m1) - 1, \
0x##op, top, ARM_VARIANT, THUMB_VARIANT, do_##ae, do_##te }
#define TxCM(m1, m2, op, top, nops, ops, ae, te) \
- TxCM_(m1, , m2, op, top, nops, ops, ae, te), \
- TxCM_(m1, eq, m2, op, top, nops, ops, ae, te), \
- TxCM_(m1, ne, m2, op, top, nops, ops, ae, te), \
- TxCM_(m1, cs, m2, op, top, nops, ops, ae, te), \
- TxCM_(m1, hs, m2, op, top, nops, ops, ae, te), \
- TxCM_(m1, cc, m2, op, top, nops, ops, ae, te), \
- TxCM_(m1, ul, m2, op, top, nops, ops, ae, te), \
- TxCM_(m1, lo, m2, op, top, nops, ops, ae, te), \
- TxCM_(m1, mi, m2, op, top, nops, ops, ae, te), \
- TxCM_(m1, pl, m2, op, top, nops, ops, ae, te), \
- TxCM_(m1, vs, m2, op, top, nops, ops, ae, te), \
- TxCM_(m1, vc, m2, op, top, nops, ops, ae, te), \
- TxCM_(m1, hi, m2, op, top, nops, ops, ae, te), \
- TxCM_(m1, ls, m2, op, top, nops, ops, ae, te), \
- TxCM_(m1, ge, m2, op, top, nops, ops, ae, te), \
- TxCM_(m1, lt, m2, op, top, nops, ops, ae, te), \
- TxCM_(m1, gt, m2, op, top, nops, ops, ae, te), \
- TxCM_(m1, le, m2, op, top, nops, ops, ae, te), \
- TxCM_(m1, al, m2, op, top, nops, ops, ae, te)
+ TxCM_ (m1, , m2, op, top, nops, ops, ae, te), \
+ TxCM_ (m1, eq, m2, op, top, nops, ops, ae, te), \
+ TxCM_ (m1, ne, m2, op, top, nops, ops, ae, te), \
+ TxCM_ (m1, cs, m2, op, top, nops, ops, ae, te), \
+ TxCM_ (m1, hs, m2, op, top, nops, ops, ae, te), \
+ TxCM_ (m1, cc, m2, op, top, nops, ops, ae, te), \
+ TxCM_ (m1, ul, m2, op, top, nops, ops, ae, te), \
+ TxCM_ (m1, lo, m2, op, top, nops, ops, ae, te), \
+ TxCM_ (m1, mi, m2, op, top, nops, ops, ae, te), \
+ TxCM_ (m1, pl, m2, op, top, nops, ops, ae, te), \
+ TxCM_ (m1, vs, m2, op, top, nops, ops, ae, te), \
+ TxCM_ (m1, vc, m2, op, top, nops, ops, ae, te), \
+ TxCM_ (m1, hi, m2, op, top, nops, ops, ae, te), \
+ TxCM_ (m1, ls, m2, op, top, nops, ops, ae, te), \
+ TxCM_ (m1, ge, m2, op, top, nops, ops, ae, te), \
+ TxCM_ (m1, lt, m2, op, top, nops, ops, ae, te), \
+ TxCM_ (m1, gt, m2, op, top, nops, ops, ae, te), \
+ TxCM_ (m1, le, m2, op, top, nops, ops, ae, te), \
+ TxCM_ (m1, al, m2, op, top, nops, ops, ae, te)
#define TCM(m1,m2, aop, top, nops, ops, ae, te) \
- TxCM(m1,m2, aop, 0x##top, nops, ops, ae, te)
-#define tCM(m1,m2, aop, top, nops, ops, ae, te) \
- TxCM(m1,m2, aop, T_MNEM_##top, nops, ops, ae, te)
+ TxCM (m1,m2, aop, 0x##top, nops, ops, ae, te)
+#define tCM(m1,m2, aop, top, nops, ops, ae, te) \
+ TxCM (m1,m2, aop, T_MNEM_##top, nops, ops, ae, te)
/* Mnemonic that cannot be conditionalized. The ARM condition-code
field is still 0xE. Many of the Thumb variants can be executed
@@ -15327,29 +15791,29 @@ static struct asm_barrier_opt barrier_opt_names[] =
#define xCM_(m1, m2, m3, op, nops, ops, ae) \
{ #m1 #m2 #m3, OPS##nops ops, \
- sizeof(#m2) == 1 ? OT_odd_infix_unc : OT_odd_infix_0 + sizeof(#m1) - 1, \
+ sizeof (#m2) == 1 ? OT_odd_infix_unc : OT_odd_infix_0 + sizeof (#m1) - 1, \
0x##op, 0x0, ARM_VARIANT, 0, do_##ae, NULL }
#define CM(m1, m2, op, nops, ops, ae) \
- xCM_(m1, , m2, op, nops, ops, ae), \
- xCM_(m1, eq, m2, op, nops, ops, ae), \
- xCM_(m1, ne, m2, op, nops, ops, ae), \
- xCM_(m1, cs, m2, op, nops, ops, ae), \
- xCM_(m1, hs, m2, op, nops, ops, ae), \
- xCM_(m1, cc, m2, op, nops, ops, ae), \
- xCM_(m1, ul, m2, op, nops, ops, ae), \
- xCM_(m1, lo, m2, op, nops, ops, ae), \
- xCM_(m1, mi, m2, op, nops, ops, ae), \
- xCM_(m1, pl, m2, op, nops, ops, ae), \
- xCM_(m1, vs, m2, op, nops, ops, ae), \
- xCM_(m1, vc, m2, op, nops, ops, ae), \
- xCM_(m1, hi, m2, op, nops, ops, ae), \
- xCM_(m1, ls, m2, op, nops, ops, ae), \
- xCM_(m1, ge, m2, op, nops, ops, ae), \
- xCM_(m1, lt, m2, op, nops, ops, ae), \
- xCM_(m1, gt, m2, op, nops, ops, ae), \
- xCM_(m1, le, m2, op, nops, ops, ae), \
- xCM_(m1, al, m2, op, nops, ops, ae)
+ xCM_ (m1, , m2, op, nops, ops, ae), \
+ xCM_ (m1, eq, m2, op, nops, ops, ae), \
+ xCM_ (m1, ne, m2, op, nops, ops, ae), \
+ xCM_ (m1, cs, m2, op, nops, ops, ae), \
+ xCM_ (m1, hs, m2, op, nops, ops, ae), \
+ xCM_ (m1, cc, m2, op, nops, ops, ae), \
+ xCM_ (m1, ul, m2, op, nops, ops, ae), \
+ xCM_ (m1, lo, m2, op, nops, ops, ae), \
+ xCM_ (m1, mi, m2, op, nops, ops, ae), \
+ xCM_ (m1, pl, m2, op, nops, ops, ae), \
+ xCM_ (m1, vs, m2, op, nops, ops, ae), \
+ xCM_ (m1, vc, m2, op, nops, ops, ae), \
+ xCM_ (m1, hi, m2, op, nops, ops, ae), \
+ xCM_ (m1, ls, m2, op, nops, ops, ae), \
+ xCM_ (m1, ge, m2, op, nops, ops, ae), \
+ xCM_ (m1, lt, m2, op, nops, ops, ae), \
+ xCM_ (m1, gt, m2, op, nops, ops, ae), \
+ xCM_ (m1, le, m2, op, nops, ops, ae), \
+ xCM_ (m1, al, m2, op, nops, ops, ae)
#define UE(mnem, op, nops, ops, ae) \
{ #mnem, OPS##nops ops, OT_unconditional, 0x##op, 0, ARM_VARIANT, 0, do_##ae, NULL }
@@ -15377,10 +15841,10 @@ static struct asm_barrier_opt barrier_opt_names[] =
THUMB_VARIANT, do_##enc, do_##enc }
#define NCE(mnem, op, nops, ops, enc) \
- NCE_tag(mnem, op, nops, ops, enc, OT_csuffix)
+ NCE_tag (mnem, op, nops, ops, enc, OT_csuffix)
#define NCEF(mnem, op, nops, ops, enc) \
- NCE_tag(mnem, op, nops, ops, enc, OT_csuffixF)
+ NCE_tag (mnem, op, nops, ops, enc, OT_csuffixF)
/* Neon insn with conditional suffix for the ARM version, overloaded types. */
#define nCE_tag(mnem, op, nops, ops, enc, tag) \
@@ -15388,15 +15852,15 @@ static struct asm_barrier_opt barrier_opt_names[] =
ARM_VARIANT, THUMB_VARIANT, do_##enc, do_##enc }
#define nCE(mnem, op, nops, ops, enc) \
- nCE_tag(mnem, op, nops, ops, enc, OT_csuffix)
+ nCE_tag (mnem, op, nops, ops, enc, OT_csuffix)
#define nCEF(mnem, op, nops, ops, enc) \
- nCE_tag(mnem, op, nops, ops, enc, OT_csuffixF)
+ nCE_tag (mnem, op, nops, ops, enc, OT_csuffixF)
#define do_0 0
/* Thumb-only, unconditional. */
-#define UT(mnem, op, nops, ops, te) TUE(mnem, 0, op, nops, ops, 0, te)
+#define UT(mnem, op, nops, ops, te) TUE (mnem, 0, op, nops, ops, 0, te)
static const struct asm_opcode insns[] =
{
@@ -15818,24 +16282,26 @@ static const struct asm_opcode insns[] =
UT(cbnz, b900, 2, (RR, EXP), t_cbz),
UT(cbz, b100, 2, (RR, EXP), t_cbz),
- /* ARM does not really have an IT instruction, so always allow it. */
+ /* ARM does not really have an IT instruction, so always allow it. The opcode
+ is copied from Thumb in order to allow warnings
+ in -mimplicit-it=[never | arm] modes. */
#undef ARM_VARIANT
#define ARM_VARIANT &arm_ext_v1
- TUE(it, 0, bf08, 1, (COND), it, t_it),
- TUE(itt, 0, bf0c, 1, (COND), it, t_it),
- TUE(ite, 0, bf04, 1, (COND), it, t_it),
- TUE(ittt, 0, bf0e, 1, (COND), it, t_it),
- TUE(itet, 0, bf06, 1, (COND), it, t_it),
- TUE(itte, 0, bf0a, 1, (COND), it, t_it),
- TUE(itee, 0, bf02, 1, (COND), it, t_it),
- TUE(itttt, 0, bf0f, 1, (COND), it, t_it),
- TUE(itett, 0, bf07, 1, (COND), it, t_it),
- TUE(ittet, 0, bf0b, 1, (COND), it, t_it),
- TUE(iteet, 0, bf03, 1, (COND), it, t_it),
- TUE(ittte, 0, bf0d, 1, (COND), it, t_it),
- TUE(itete, 0, bf05, 1, (COND), it, t_it),
- TUE(ittee, 0, bf09, 1, (COND), it, t_it),
- TUE(iteee, 0, bf01, 1, (COND), it, t_it),
+ TUE(it, bf08, bf08, 1, (COND), it, t_it),
+ TUE(itt, bf0c, bf0c, 1, (COND), it, t_it),
+ TUE(ite, bf04, bf04, 1, (COND), it, t_it),
+ TUE(ittt, bf0e, bf0e, 1, (COND), it, t_it),
+ TUE(itet, bf06, bf06, 1, (COND), it, t_it),
+ TUE(itte, bf0a, bf0a, 1, (COND), it, t_it),
+ TUE(itee, bf02, bf02, 1, (COND), it, t_it),
+ TUE(itttt, bf0f, bf0f, 1, (COND), it, t_it),
+ TUE(itett, bf07, bf07, 1, (COND), it, t_it),
+ TUE(ittet, bf0b, bf0b, 1, (COND), it, t_it),
+ TUE(iteet, bf03, bf03, 1, (COND), it, t_it),
+ TUE(ittte, bf0d, bf0d, 1, (COND), it, t_it),
+ TUE(itete, bf05, bf05, 1, (COND), it, t_it),
+ TUE(ittee, bf09, bf09, 1, (COND), it, t_it),
+ TUE(iteee, bf01, bf01, 1, (COND), it, t_it),
/* ARM/Thumb-2 instructions with no Thumb-1 equivalent. */
TC3(rrx, 01a00060, ea4f0030, 2, (RR, RR), rd_rm, t_rrx),
TC3(rrxs, 01b00060, ea5f0030, 2, (RR, RR), rd_rm, t_rrx),
@@ -20246,15 +20712,14 @@ armelf_frob_symbol (symbolS * symp,
/* MD interface: Finalization. */
-/* A good place to do this, although this was probably not intended
- for this kind of use. We need to dump the literal pool before
- references are made to a null symbol pointer. */
-
void
arm_cleanup (void)
{
literal_pool * pool;
+ /* Ensure that all the IT blocks are properly closed. */
+ check_it_blocks_finished ();
+
for (pool = list_of_pools; pool; pool = pool->next)
{
/* Put it at the end of the relevant section. */
@@ -20927,10 +21392,10 @@ static const struct arm_cpu_option_table arm_cpus[] =
{"arm1156t2f-s", ARM_ARCH_V6T2, FPU_ARCH_VFP_V2, NULL},
{"arm1176jz-s", ARM_ARCH_V6ZK, FPU_NONE, NULL},
{"arm1176jzf-s", ARM_ARCH_V6ZK, FPU_ARCH_VFP_V2, NULL},
- {"cortex-a8", ARM_ARCH_V7A, ARM_FEATURE(0, FPU_VFP_V3
+ {"cortex-a8", ARM_ARCH_V7A, ARM_FEATURE (0, FPU_VFP_V3
| FPU_NEON_EXT_V1),
NULL},
- {"cortex-a9", ARM_ARCH_V7A, ARM_FEATURE(0, FPU_VFP_V3
+ {"cortex-a9", ARM_ARCH_V7A, ARM_FEATURE (0, FPU_VFP_V3
| FPU_NEON_EXT_V1),
NULL},
{"cortex-r4", ARM_ARCH_V7R, FPU_NONE, NULL},
@@ -20944,7 +21409,7 @@ static const struct arm_cpu_option_table arm_cpus[] =
{"iwmmxt2", ARM_ARCH_IWMMXT2,FPU_ARCH_VFP_V2, NULL},
{"i80200", ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2, NULL},
/* Maverick */
- {"ep9312", ARM_FEATURE(ARM_AEXT_V4T, ARM_CEXT_MAVERICK), FPU_ARCH_MAVERICK, "ARM920T"},
+ {"ep9312", ARM_FEATURE (ARM_AEXT_V4T, ARM_CEXT_MAVERICK), FPU_ARCH_MAVERICK, "ARM920T"},
{NULL, ARM_ARCH_NONE, ARM_ARCH_NONE, NULL}
};
@@ -21264,6 +21729,29 @@ arm_parse_eabi (char * str)
}
#endif
+static int
+arm_parse_it_mode (char * str)
+{
+ int ret = 1;
+
+ if (streq ("arm", str))
+ implicit_it_mode = IMPLICIT_IT_MODE_ARM;
+ else if (streq ("thumb", str))
+ implicit_it_mode = IMPLICIT_IT_MODE_THUMB;
+ else if (streq ("always", str))
+ implicit_it_mode = IMPLICIT_IT_MODE_ALWAYS;
+ else if (streq ("never", str))
+ implicit_it_mode = IMPLICIT_IT_MODE_NEVER;
+ else
+ {
+ as_bad (_("unknown implicit IT mode `%s', should be "\
+ "arm, thumb, always, or never."), str);
+ ret = 0;
+ }
+
+ return ret;
+}
+
struct arm_long_option_table arm_long_opts[] =
{
{"mcpu=", N_("<cpu name>\t assemble for CPU <cpu name>"),
@@ -21278,6 +21766,8 @@ struct arm_long_option_table arm_long_opts[] =
{"meabi=", N_("<ver>\t\t assemble for eabi version <ver>"),
arm_parse_eabi, NULL},
#endif
+ {"mimplicit-it=", N_("<mode>\t controls implicit insertion of IT instructions"),
+ arm_parse_it_mode, NULL},
{NULL, NULL, 0, NULL}
};
diff --git a/gas/config/tc-arm.h b/gas/config/tc-arm.h
index 13bc86a..05841df 100644
--- a/gas/config/tc-arm.h
+++ b/gas/config/tc-arm.h
@@ -82,7 +82,7 @@ struct fix;
#define TC_FORCE_RELOCATION(FIX) arm_force_relocation (FIX)
#define md_relax_frag(segment, fragp, stretch) \
- arm_relax_frag(segment, fragp, stretch)
+ arm_relax_frag (segment, fragp, stretch)
extern int arm_relax_frag (asection *, struct frag *, long);
#define md_optimize_expr(l,o,r) arm_optimize_expr (l, o, r)
@@ -123,6 +123,7 @@ bfd_boolean arm_is_eabi (void);
#define ARM_IS_THUMB(s) (ARM_GET_FLAG (s) & ARM_FLAG_THUMB)
#define ARM_IS_INTERWORK(s) (ARM_GET_FLAG (s) & ARM_FLAG_INTERWORK)
+
#ifdef OBJ_ELF
/* For ELF objects THUMB_IS_FUNC is inferred from
@@ -141,6 +142,7 @@ bfd_boolean arm_is_eabi (void);
#else
+
#define THUMB_IS_FUNC(s) (ARM_GET_FLAG (s) & THUMB_FLAG_FUNC)
#define ARM_IS_FUNC(s) (!THUMB_IS_FUNC (s) \
&& (symbol_get_bfdsym (s)->flags & BSF_FUNCTION))
@@ -151,6 +153,7 @@ bfd_boolean arm_is_eabi (void);
#define THUMB_SET_FUNC(s,t) ((t) ? ARM_SET_FLAG (s, THUMB_FLAG_FUNC) : ARM_RESET_FLAG (s, THUMB_FLAG_FUNC))
void arm_copy_symbol_attributes (symbolS *, symbolS *);
+
#ifndef TC_COPY_SYMBOL_ATTRIBUTES
#define TC_COPY_SYMBOL_ATTRIBUTES(DEST, SRC) \
(arm_copy_symbol_attributes (DEST, SRC))
@@ -212,6 +215,21 @@ void arm_copy_symbol_attributes (symbolS *, symbolS *);
/* Registers are generally saved at negative offsets to the CFA. */
#define DWARF2_CIE_DATA_ALIGNMENT (-4)
+/* State variables for IT block handling. */
+enum it_state
+{
+ OUTSIDE_IT_BLOCK, MANUAL_IT_BLOCK, AUTOMATIC_IT_BLOCK
+};
+struct current_it
+{
+ int mask;
+ enum it_state state;
+ int cc;
+ int block_length;
+ char *insn;
+ int state_handled;
+};
+
#ifdef OBJ_ELF
# define obj_frob_symbol(sym, punt) armelf_frob_symbol ((sym), & (punt))
# define md_elf_section_change_hook() arm_elf_change_section ()
@@ -239,6 +257,7 @@ struct arm_segment_info_type
{
enum mstate mapstate;
unsigned int marked_pr_dependency;
+ struct current_it current_it;
};
/* We want .cfi_* pseudo-ops for generating unwind info. */
diff --git a/gas/doc/c-arm.texi b/gas/doc/c-arm.texi
index cc97700..7accce8 100644
--- a/gas/doc/c-arm.texi
+++ b/gas/doc/c-arm.texi
@@ -227,6 +227,11 @@ instructions; that is, it should behave as though the file starts with a
This option specifies that the output generated by the assembler should
be marked as supporting interworking.
+@cindex @code{-mauto-it} command line option, ARM
+@item -mauto-it
+This option enables the automatic generation of IT instructions for
+conditional instructions not covered by an IT block.
+
@cindex @code{-mapcs} command line option, ARM
@item -mapcs @code{[26|32]}
This option specifies that the output generated by the assembler should
diff --git a/gas/testsuite/ChangeLog b/gas/testsuite/ChangeLog
index bb40027..9ab0ef3 100644
--- a/gas/testsuite/ChangeLog
+++ b/gas/testsuite/ChangeLog
@@ -1,3 +1,26 @@
+2009-06-22 Daniel Gutson <dgutson@codesourcery.com>
+
+ * gas/arm/arm-it-auto.d: New test.
+ * gas/arm/arm-it-auto.s: New file.
+ * gas/arm/arm-it-auto-2.d: New test case.
+ * gas/arm/arm-it-auto-2.s: New file.
+ * gas/arm/arm-it-auto-3.d: New test case.
+ * gas/arm/arm-it-auto-3.s: New file.
+ * gas/arm/arm-it-bad.d: New test case.
+ * gas/arm/arm-it-bad.l: New file.
+ * gas/arm/arm-it-bad.s: New file.
+ * gas/arm/arm-it-bad-2.d: New test case.
+ * gas/arm/arm-it-bad-2.l: New file.
+ * gas/arm/arm-it-bad-2.s: New file.
+ * gas/arm/arm-it-bad-3.d: New test case.
+ * gas/arm/arm-it-bad-3.l: New file.
+ * gas/arm/arm-it-bad-3.s: New file.
+ * gas/arm/thumb2_it_auto.d: New test.
+ * gas/arm/thumb2_it_bad.l: Error message updated.
+ * gas/arm/thumb2_it_bad_auto.d: New test.
+ * gas/arm/thumb2_it.d: Comment added.
+ * gas/arm/thumb2_it_bad.d: Comment added.
+
2009-06-19 Alan Modra <amodra@bigpond.net.au>
* gas/cfi/cfi-common-7.s: Skip a multiple of four.
diff --git a/gas/testsuite/gas/arm/thumb2_it.d b/gas/testsuite/gas/arm/thumb2_it.d
index 30a390b..6e6bdb8 100644
--- a/gas/testsuite/gas/arm/thumb2_it.d
+++ b/gas/testsuite/gas/arm/thumb2_it.d
@@ -1,62 +1,62 @@
# name: Mixed 16 and 32-bit Thumb conditional instructions
# as: -march=armv6kt2
+#skip: *-*-*aout*
# objdump: -dr --prefix-addresses --show-raw-insn
-# Many of these patterns use "(eq|s)". These should be changed to just "eq"
-# once the disassembler is fixed. Likewise for "(eq)?"
+# Modifications to this file shall be mirrored to thumb2_it_auto.d
.*: +file format .*arm.*
Disassembly of section .text:
0+000 <[^>]+> bf05 ittet eq
-0+002 <[^>]+> 1880 add(eq|s) r0, r0, r2
-0+004 <[^>]+> 4440 add(eq)? r0, r8
-0+006 <[^>]+> 1888 add(ne|s) r0, r1, r2
-0+008 <[^>]+> eb11 0002 adds(eq)?.w r0, r1, r2
+0+002 <[^>]+> 1880 addeq r0, r0, r2
+0+004 <[^>]+> 4440 addeq r0, r8
+0+006 <[^>]+> 1888 addne r0, r1, r2
+0+008 <[^>]+> eb11 0002 addseq.w r0, r1, r2
0+00c <[^>]+> 4410 add r0, r2
0+00e <[^>]+> 4440 add r0, r8
0+010 <[^>]+> 1880 adds r0, r0, r2
0+012 <[^>]+> eb10 0008 adds.w r0, r0, r8
0+016 <[^>]+> 1888 adds r0, r1, r2
0+018 <[^>]+> bf0a itet eq
-0+01a <[^>]+> 4310 orr(eq|s) r0, r2
-0+01c <[^>]+> ea40 0008 orr(ne)?.w r0, r0, r8
-0+020 <[^>]+> ea50 0002 orrs(eq)?.w r0, r0, r2
+0+01a <[^>]+> 4310 orreq r0, r2
+0+01c <[^>]+> ea40 0008 orrne.w r0, r0, r8
+0+020 <[^>]+> ea50 0002 orrseq.w r0, r0, r2
0+024 <[^>]+> ea40 0002 orr.w r0, r0, r2
0+028 <[^>]+> ea40 0008 orr.w r0, r0, r8
0+02c <[^>]+> 4310 orrs r0, r2
0+02e <[^>]+> bf01 itttt eq
-0+030 <[^>]+> 4090 lsl(eq|s) r0, r2
-0+032 <[^>]+> fa00 f008 lsl(eq)?.w r0, r0, r8
-0+036 <[^>]+> fa01 f002 lsl(eq)?.w r0, r1, r2
-0+03a <[^>]+> fa10 f002 lsls(eq)?.w r0, r0, r2
+0+030 <[^>]+> 4090 lsleq r0, r2
+0+032 <[^>]+> fa00 f008 lsleq.w r0, r0, r8
+0+036 <[^>]+> fa01 f002 lsleq.w r0, r1, r2
+0+03a <[^>]+> fa10 f002 lslseq.w r0, r0, r2
0+03e <[^>]+> bf02 ittt eq
-0+040 <[^>]+> 0048 lsl(eq|s) r0, r1, #1
-0+042 <[^>]+> ea4f 0048 mov(eq)?.w r0, r8, lsl #1
-0+046 <[^>]+> ea5f 0040 movs(eq)?.w r0, r0, lsl #1
+0+040 <[^>]+> 0048 lsleq r0, r1, #1
+0+042 <[^>]+> ea4f 0048 moveq.w r0, r8, lsl #1
+0+046 <[^>]+> ea5f 0040 movseq.w r0, r0, lsl #1
0+04a <[^>]+> fa00 f002 lsl.w r0, r0, r2
0+04e <[^>]+> 4090 lsls r0, r2
0+050 <[^>]+> ea4f 0041 mov.w r0, r1, lsl #1
0+054 <[^>]+> 0048 lsls r0, r1, #1
0+056 <[^>]+> bf01 itttt eq
-0+058 <[^>]+> 4288 cmp(eq)? r0, r1
-0+05a <[^>]+> 4540 cmp(eq)? r0, r8
-0+05c <[^>]+> 4608 mov(eq)? r0, r1
-0+05e <[^>]+> ea5f 0001 movs(eq)?.w r0, r1
+0+058 <[^>]+> 4288 cmpeq r0, r1
+0+05a <[^>]+> 4540 cmpeq r0, r8
+0+05c <[^>]+> 4608 moveq r0, r1
+0+05e <[^>]+> ea5f 0001 movseq.w r0, r1
0+062 <[^>]+> bf08 it eq
-0+064 <[^>]+> 4640 mov(eq)? r0, r8
-0+066 <[^>]+> 4608 mov(eq)? r0, r1
+0+064 <[^>]+> 4640 moveq r0, r8
+0+066 <[^>]+> 4608 mov r0, r1
0+068 <[^>]+> 1c08 adds r0, r1, #0
0+06a <[^>]+> ea5f 0008 movs.w r0, r8
0+06e <[^>]+> bf01 itttt eq
-0+070 <[^>]+> 43c8 mvn(eq|s) r0, r1
-0+072 <[^>]+> ea6f 0008 mvn(eq)?.w r0, r8
-0+076 <[^>]+> ea7f 0001 mvns(eq)?.w r0, r1
-0+07a <[^>]+> 42c8 cmn(eq)? r0, r1
+0+070 <[^>]+> 43c8 mvneq r0, r1
+0+072 <[^>]+> ea6f 0008 mvneq.w r0, r8
+0+076 <[^>]+> ea7f 0001 mvnseq.w r0, r1
+0+07a <[^>]+> 42c8 cmneq r0, r1
0+07c <[^>]+> ea6f 0001 mvn.w r0, r1
0+080 <[^>]+> 43c8 mvns r0, r1
0+082 <[^>]+> bf02 ittt eq
-0+084 <[^>]+> 4248 neg(eq|s) r0, r1
-0+086 <[^>]+> f1c8 0000 rsb(eq)? r0, r8, #0 ; 0x0
-0+08a <[^>]+> f1d1 0000 rsbs(eq)? r0, r1, #0 ; 0x0
+0+084 <[^>]+> 4248 negeq r0, r1
+0+086 <[^>]+> f1c8 0000 rsbeq r0, r8, #0 ; 0x0
+0+08a <[^>]+> f1d1 0000 rsbseq r0, r1, #0 ; 0x0
0+08e <[^>]+> f1c1 0000 rsb r0, r1, #0 ; 0x0
0+092 <[^>]+> 4248 negs r0, r1
diff --git a/gas/testsuite/gas/arm/thumb2_it_bad.d b/gas/testsuite/gas/arm/thumb2_it_bad.d
index 1cca8b9..0b841ed 100644
--- a/gas/testsuite/gas/arm/thumb2_it_bad.d
+++ b/gas/testsuite/gas/arm/thumb2_it_bad.d
@@ -1,3 +1,4 @@
#name: Invalid IT instructions
#as:
#error-output: thumb2_it_bad.l
+# Modifications to this test shall be mirrored to thumb2_it_bad_auto.d.
diff --git a/gas/testsuite/gas/arm/thumb2_it_bad.l b/gas/testsuite/gas/arm/thumb2_it_bad.l
index e2e96cd..aa1f658 100644
--- a/gas/testsuite/gas/arm/thumb2_it_bad.l
+++ b/gas/testsuite/gas/arm/thumb2_it_bad.l
@@ -9,4 +9,4 @@
[^:]*:17: Error: instruction not allowed in IT block -- `cpseq #0x10'
[^:]*:19: Error: instruction is always unconditional -- `bkpteq 0'
[^:]*:20: Error: instruction not allowed in IT block -- `setendeq le'
-[^:]*:22: Error: instruction not allowed in IT block -- `iteq eq'
+[^:]*:22: Error: IT falling in the range of a previous IT block -- `iteq eq'