This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[Fwd: Re: [PATCH 2] New option for automatically generating IT instructions and enhancing validations]
- From: Daniel Gutson <dgutson at codesourcery dot com>
- To: Nick Clifton <nickc at redhat dot com>, binutils at sourceware dot org, Richard Earnshaw <rearnsha at arm dot com>
- Date: Fri, 19 Jun 2009 16:52:19 -0300
- Subject: [Fwd: Re: [PATCH 2] New option for automatically generating IT instructions and enhancing validations]
Resending, since the previous mail was considered spam :(
Daniel.
-------- Original Message --------
Subject: Re: [PATCH 2] New option for automatically generating IT
instructions and enhancing validations
Date: Fri, 19 Jun 2009 16:46:47 -0300
From: Daniel Gutson <dgutson@codesourcery.com>
Organization: CodeSourcery
To: Nick Clifton <nickc@redhat.com>
CC: binutils@sourceware.org, Richard Earnshaw <rearnsha@arm.com>
References: <4A2ED642.1000900@codesourcery.com>
<4A3A7E94.7010100@redhat.com>
Nick, my bad. Fixed in this patch.
The ChangeLog is the same.
Please note that I'd need this committed before submitting the
.inst/.iword directive patch, since the latter interacts with the IT
machinery.
Thanks!,
Daniel.
Nick Clifton wrote:
Hi Daniel,
this is the last version of the patch for the automatic IT
instructions generation.
Sorry - there is still a problem with this patch: It breaks the
building of non-ELF based ARM targets, eg arm-wince-pe.
Please could you fix this and then resubmit the patch.
Cheers
Nick
? align64.patch
? nonelf.patch
? patch2.patch
? patch3.patch
Index: gas/config/tc-arm.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-arm.c,v
retrieving revision 1.387
diff -u -p -r1.387 tc-arm.c
--- gas/config/tc-arm.c 18 Jun 2009 16:36:02 -0000 1.387
+++ gas/config/tc-arm.c 19 Jun 2009 19:35:05 -0000
@@ -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_
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,45 @@ 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
@@ -6120,7 +6182,7 @@ parse_operands (char *str, const unsigne
#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) \
@@ -6960,8 +7022,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 +8553,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 +8565,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 +8819,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 +8907,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 +9062,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 +9085,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 +9142,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 +9170,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 +9182,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 +9208,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 +9262,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 +9308,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 +9345,13 @@ encode_thumb2_ldmstm (int base, unsigned
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 +9527,13 @@ 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 +9754,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 +9767,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 +9822,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 +9848,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 +9904,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 +10066,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 +10207,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
{
@@ -10184,6 +10275,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 +10313,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 +10539,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 +10575,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 +10605,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 +10906,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"));
@@ -14425,6 +14518,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 +14785,316 @@ 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)
{
@@ -14739,36 +15164,19 @@ md_assemble (char *str)
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 ();
+
+ opcode->tencode ();
- /* Clear current_it_mask at the end of an IT block. */
- if (current_it_mask == 0x10)
- current_it_mask = 0;
+ it_fsm_post_encode ();
+ }
if (!(inst.error || inst.relax))
{
@@ -14827,7 +15235,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 +15257,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 +15295,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
@@ -15818,24 +16251,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 +20681,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. */
@@ -21264,6 +21698,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 +21735,8 @@ struct arm_long_option_table arm_long_op
{"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}
};
Index: gas/config/tc-arm.h
===================================================================
RCS file: /cvs/src/src/gas/config/tc-arm.h,v
retrieving revision 1.50
diff -u -p -r1.50 tc-arm.h
--- gas/config/tc-arm.h 5 May 2009 11:41:31 -0000 1.50
+++ gas/config/tc-arm.h 19 Jun 2009 19:35:05 -0000
@@ -212,6 +212,21 @@ void arm_copy_symbol_attributes (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 +254,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. */
Index: gas/doc/c-arm.texi
===================================================================
RCS file: /cvs/src/src/gas/doc/c-arm.texi,v
retrieving revision 1.56
diff -u -p -r1.56 c-arm.texi
--- gas/doc/c-arm.texi 2 Apr 2009 09:43:56 -0000 1.56
+++ gas/doc/c-arm.texi 19 Jun 2009 19:35:05 -0000
@@ -227,6 +227,11 @@ instructions; that is, it should behave
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
Index: gas/testsuite/gas/arm/arm-it-auto-2.d
===================================================================
RCS file: gas/testsuite/gas/arm/arm-it-auto-2.d
diff -N gas/testsuite/gas/arm/arm-it-auto-2.d
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gas/testsuite/gas/arm/arm-it-auto-2.d 19 Jun 2009 19:35:05 -0000
@@ -0,0 +1,15 @@
+#name: ARM IT automatic instruction generation 2
+#as: -mthumb -march=armv7a -mimplicit-it=always
+#objdump: -d --prefix-addresses --show-raw-insn
+#skip: *-*-*coff *-*-pe *-*-wince *-*-*aout* *-*-netbsd *-*-riscix*
+
+.*: +file format .*arm.*
+
+Disassembly of section .text:
+00000000 <.text> 3a40 subs r2, #64
+00000002 <.text\+0x2> bfa1 itttt ge
+00000004 <.text\+0x4> e8a0 500a stmiage.w r0!, {r1, r3, ip, lr}
+00000008 <.text\+0x8> e8a0 500a stmiage.w r0!, {r1, r3, ip, lr}
+0000000c <.text\+0xc> e8a0 500a stmiage.w r0!, {r1, r3, ip, lr}
+00000010 <.text\+0x10> e8a0 500a stmiage.w r0!, {r1, r3, ip, lr}
+00000014 <.text\+0x14> dcf4 bgt.n 00000000 <.text>
Index: gas/testsuite/gas/arm/arm-it-auto-2.s
===================================================================
RCS file: gas/testsuite/gas/arm/arm-it-auto-2.s
diff -N gas/testsuite/gas/arm/arm-it-auto-2.s
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gas/testsuite/gas/arm/arm-it-auto-2.s 19 Jun 2009 19:35:05 -0000
@@ -0,0 +1,8 @@
+.syntax unified
+2: subs r2, r2, #64
+ @ IT generated automatically
+ stmge r0!, {r1, r3, ip, lr} @ 64 bytes at a time.
+ stmge r0!, {r1, r3, ip, lr}
+ stmge r0!, {r1, r3, ip, lr}
+ stmge r0!, {r1, r3, ip, lr}
+ bgt 2b @ This should not generate a new IT block
Index: gas/testsuite/gas/arm/arm-it-auto-3.d
===================================================================
RCS file: gas/testsuite/gas/arm/arm-it-auto-3.d
diff -N gas/testsuite/gas/arm/arm-it-auto-3.d
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gas/testsuite/gas/arm/arm-it-auto-3.d 19 Jun 2009 19:35:05 -0000
@@ -0,0 +1,15 @@
+#name: ARM IT automatic instruction generation 3
+#as: -mthumb -march=armv7a -mimplicit-it=always
+#objdump: -d --prefix-addresses --show-raw-insn
+#skip: *-*-*coff *-*-pe *-*-wince *-*-*aout* *-*-netbsd *-*-riscix*
+
+.*: +file format .*arm.*
+
+Disassembly of section .text.one:
+00000000 <.text.one> 2800 cmp r0, #0
+00000002 <.text.one\+0x2> bf08 it eq
+00000004 <.text.one\+0x4> 3102 addeq r1, #2
+
+Disassembly of section .text.two:
+00000000 <.text.two> bf08 it eq
+00000002 <.text.two\+0x2> 3103 addeq r1, #3
Index: gas/testsuite/gas/arm/arm-it-auto-3.s
===================================================================
RCS file: gas/testsuite/gas/arm/arm-it-auto-3.s
diff -N gas/testsuite/gas/arm/arm-it-auto-3.s
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gas/testsuite/gas/arm/arm-it-auto-3.s 19 Jun 2009 19:35:05 -0000
@@ -0,0 +1,10 @@
+ .syntax unified
+ .thumb
+ .section .text.one
+ cmp r0, #0
+ addeq r1, #2
+ .data
+ .word 33
+ .section .text.two
+ addeq r1, #3
+
Index: gas/testsuite/gas/arm/arm-it-auto.d
===================================================================
RCS file: gas/testsuite/gas/arm/arm-it-auto.d
diff -N gas/testsuite/gas/arm/arm-it-auto.d
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gas/testsuite/gas/arm/arm-it-auto.d 19 Jun 2009 19:35:05 -0000
@@ -0,0 +1,81 @@
+#name: ARM IT automatic instruction generation
+#as: -mthumb -march=armv7 -mimplicit-it=always
+#objdump: -d --prefix-addresses --show-raw-insn
+#skip: *-*-*coff *-*-pe *-*-wince *-*-*aout* *-*-netbsd *-*-riscix*
+
+.*: +file format .*arm.*
+
+Disassembly of section .text:
+00000000 <main> f000 f821 bl 00000046 <main\+0x46>
+00000004 <main\+0x4> f000 f80c bl 00000020 <main\+0x20>
+00000008 <main\+0x8> f000 f813 bl 00000032 <main\+0x32>
+0000000c <main\+0xc> d142 bne.n 00000094 <main\+0x94>
+0000000e <main\+0xe> bf18 it ne
+00000010 <main\+0x10> 4487 addne pc, r0
+00000012 <main\+0x12> bf18 it ne
+00000014 <main\+0x14> e8d0 f001 tbbne \[r0, r1\]
+00000018 <main\+0x18> bf08 it eq
+0000001a <main\+0x1a> e8d1 f010 tbheq \[r1, r0, lsl #1\]
+0000001e <main\+0x1e> bf0a itet eq
+00000020 <main\+0x20> 2002 moveq r0, #2
+00000022 <main\+0x22> 2003 movne r0, #3
+00000024 <main\+0x24> 2004 moveq r0, #4
+00000026 <main\+0x26> bf16 itet ne
+00000028 <main\+0x28> 2002 movne r0, #2
+0000002a <main\+0x2a> 2003 moveq r0, #3
+0000002c <main\+0x2c> 2004 movne r0, #4
+0000002e <main\+0x2e> bf18 it ne
+00000030 <main\+0x30> 2001 movne r0, #1
+00000032 <main\+0x32> bf0c ite eq
+00000034 <main\+0x34> 2002 moveq r0, #2
+00000036 <main\+0x36> f8d1 f000 ldrne.w pc, \[r1\]
+0000003a <main\+0x3a> bf18 it ne
+0000003c <main\+0x3c> f000 f82a blne 00000094 <main\+0x94>
+00000040 <main\+0x40> bfb8 it lt
+00000042 <main\+0x42> f000 f828 bllt 00000096 <main\+0x96>
+00000046 <main\+0x46> bf17 itett ne
+00000048 <main\+0x48> 202d movne r0, #45
+0000004a <main\+0x4a> 2005 moveq r0, #5
+0000004c <main\+0x4c> 2006 movne r0, #6
+0000004e <main\+0x4e> 4487 addne pc, r0
+00000050 <main\+0x50> bf0d iteet eq
+00000052 <main\+0x52> 2007 moveq r0, #7
+00000054 <main\+0x54> 2008 movne r0, #8
+00000056 <main\+0x56> 2003 movne r0, #3
+00000058 <main\+0x58> 2004 moveq r0, #4
+0000005a <main\+0x5a> bf0b itete eq
+0000005c <main\+0x5c> 2005 moveq r0, #5
+0000005e <main\+0x5e> 2006 movne r0, #6
+00000060 <main\+0x60> 2007 moveq r0, #7
+00000062 <main\+0x62> 2008 movne r0, #8
+00000064 <main\+0x64> bf0c ite eq
+00000066 <main\+0x66> 2005 moveq r0, #5
+00000068 <main\+0x68> 2006 movne r0, #6
+0000006a <main\+0x6a> 4687 mov pc, r0
+0000006c <main\+0x6c> bf0b itete eq
+0000006e <main\+0x6e> 2007 moveq r0, #7
+00000070 <main\+0x70> 2008 movne r0, #8
+00000072 <main\+0x72> 2005 moveq r0, #5
+00000074 <main\+0x74> 2006 movne r0, #6
+00000076 <main\+0x76> 4487 add pc, r0
+00000078 <main\+0x78> bf0c ite eq
+0000007a <main\+0x7a> 2007 moveq r0, #7
+0000007c <main\+0x7c> 2008 movne r0, #8
+0000007e <main\+0x7e> bfcc ite gt
+00000080 <main\+0x80> 2009 movgt r0, #9
+00000082 <main\+0x82> 200a movle r0, #10
+00000084 <main\+0x84> bf08 it eq
+00000086 <main\+0x86> 200b moveq r0, #11
+00000088 <main\+0x88> bfd8 it le
+0000008a <main\+0x8a> 200c movle r0, #12
+0000008c <main\+0x8c> bf18 it ne
+0000008e <main\+0x8e> 200d movne r0, #13
+00000090 <main\+0x90> f7ff fffe bl 00000000 <f>
+00000094 <f\+0x94> bd10 pop {r4, pc}
+00000096 <f\+0x96> f7ff fffe bl 00000000 <f>
+0000009a <f\+0x9a> bfb8 it lt
+0000009c <f\+0x9c> 2000 movlt r0, #0
+0000009e <f\+0x9e> 4348 muls r0, r1
+000000a0 <f\+0xa0> bfb8 it lt
+000000a2 <f\+0xa2> 2000 movlt r0, #0
+000000a4 <f\+0xa4> 4348 muls r0, r1
Index: gas/testsuite/gas/arm/arm-it-auto.s
===================================================================
RCS file: gas/testsuite/gas/arm/arm-it-auto.s
diff -N gas/testsuite/gas/arm/arm-it-auto.s
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gas/testsuite/gas/arm/arm-it-auto.s 19 Jun 2009 19:35:05 -0000
@@ -0,0 +1,110 @@
+ .syntax unified
+ .arch armv7
+ .thumb
+main:
+
+@These branches are to see the labels in the generated file
+ bl .L888
+ bl .L111
+ bl .L777
+
+@No IT block here:
+ bne .L4
+
+@The following groups should be an IT block each.
+@it ne
+ addne.n pc, r0
+
+@it ne
+ tbbne [r0, r1]
+
+@it eq
+ tbheq [r1, r0]
+
+@The following group should be left as is:
+ itet eq
+.L111: moveq r0, #2
+ movne r0, #3
+ moveq r0, #4
+
+@Same, reverted condition:
+ itet ne
+ movne r0, #2
+ moveq r0, #3
+ movne r0, #4
+
+
+@Two groups shall be generated, due to the label:
+ movne r0, #1
+@ second group, the label should be at the IT insn
+.L777: moveq r0, #2
+ ldrne pc, [r1]
+
+@it ne
+ blne .L4
+
+@it lt
+ bllt .L9
+
+@itett ne
+.L888: movne r0, #45
+ moveq r0, #5
+ movne r0, #6
+ addne.n pc, r0
+
+@iteet eq
+ moveq r0, #7
+ movne r0, #8
+ movne r0, #3
+ moveq r0, #4
+
+@itete eq
+ moveq r0, #5
+ movne r0, #6
+ moveq r0, #7
+ movne r0, #8
+
+@ite eq - this group finishes due to the mov.n pc, rn
+ moveq r0, #5
+ movne r0, #6
+ mov.n pc, r0
+
+@itete eq
+ moveq r0, #7
+ movne r0, #8
+ moveq r0, #5
+ movne r0, #6
+
+@this shall not generate an IT block
+ add.n pc, r0
+
+@ite eq - testing condition change (eq -> gt)
+ moveq r0, #7
+ movne r0, #8
+
+@ite gt (group shall finish due to another condition change)
+ movgt r0, #9
+ movle r0, #10
+
+@it eq
+ moveq r0, #11
+
+@it le
+ movle r0, #12
+
+@it ne
+ movne r0, #13
+
+ bl f
+.L4:
+ pop {r4, pc}
+.L9:
+ bl f
+
+@Only the movlt shall be enclosed in the IT block
+movlt r0, #0
+muls r0, r0, r1
+
+@Same here:
+movlt r0, #0
+muls r0, r0, r1
Index: gas/testsuite/gas/arm/arm-it-bad-2.d
===================================================================
RCS file: gas/testsuite/gas/arm/arm-it-bad-2.d
diff -N gas/testsuite/gas/arm/arm-it-bad-2.d
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gas/testsuite/gas/arm/arm-it-bad-2.d 19 Jun 2009 19:35:05 -0000
@@ -0,0 +1,3 @@
+#name: Test unclosed IT block validation.
+#as: -march=armv7a
+#error-output: arm-it-bad-2.l
Index: gas/testsuite/gas/arm/arm-it-bad-2.l
===================================================================
RCS file: gas/testsuite/gas/arm/arm-it-bad-2.l
diff -N gas/testsuite/gas/arm/arm-it-bad-2.l
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gas/testsuite/gas/arm/arm-it-bad-2.l 19 Jun 2009 19:35:05 -0000
@@ -0,0 +1,3 @@
+[^:]*: Assembler messages:
+[^:]*:9: Warning: section '.text' finished with an open IT block.
+[^:]*:9: Warning: section 'second' finished with an open IT block.
Index: gas/testsuite/gas/arm/arm-it-bad-2.s
===================================================================
RCS file: gas/testsuite/gas/arm/arm-it-bad-2.s
diff -N gas/testsuite/gas/arm/arm-it-bad-2.s
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gas/testsuite/gas/arm/arm-it-bad-2.s 19 Jun 2009 19:35:05 -0000
@@ -0,0 +1,9 @@
+ .syntax unified
+ .text
+ cmp r0, #0
+ itt eq
+ moveq r0, r1
+.section second
+ itt ne
+ movne r0, r1
+
Index: gas/testsuite/gas/arm/arm-it-bad-3.d
===================================================================
RCS file: gas/testsuite/gas/arm/arm-it-bad-3.d
diff -N gas/testsuite/gas/arm/arm-it-bad-3.d
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gas/testsuite/gas/arm/arm-it-bad-3.d 19 Jun 2009 19:35:05 -0000
@@ -0,0 +1,3 @@
+#name: Test automatic IT generation in Thumb-1 architectures.
+#as: -mimplicit-it=always
+#error-output: arm-it-bad-3.l
Index: gas/testsuite/gas/arm/arm-it-bad-3.l
===================================================================
RCS file: gas/testsuite/gas/arm/arm-it-bad-3.l
diff -N gas/testsuite/gas/arm/arm-it-bad-3.l
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gas/testsuite/gas/arm/arm-it-bad-3.l 19 Jun 2009 19:35:05 -0000
@@ -0,0 +1,3 @@
+[^:]*: Assembler messages:
+[^:]*:4: Error: thumb conditional instruction should be in IT block -- `moveq r1,r8'
+[^:]*:5: Error: thumb conditional instruction should be in IT block -- `movne r1,r9'
Index: gas/testsuite/gas/arm/arm-it-bad-3.s
===================================================================
RCS file: gas/testsuite/gas/arm/arm-it-bad-3.s
diff -N gas/testsuite/gas/arm/arm-it-bad-3.s
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gas/testsuite/gas/arm/arm-it-bad-3.s 19 Jun 2009 19:35:05 -0000
@@ -0,0 +1,6 @@
+.syntax unified
+.arch armv6
+.thumb
+moveq r1, r8
+movne r1, r9
+
Index: gas/testsuite/gas/arm/arm-it-bad.d
===================================================================
RCS file: gas/testsuite/gas/arm/arm-it-bad.d
diff -N gas/testsuite/gas/arm/arm-it-bad.d
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gas/testsuite/gas/arm/arm-it-bad.d 19 Jun 2009 19:35:05 -0000
@@ -0,0 +1,3 @@
+#name: Test IT block validation in ARM mode.
+#as: -march=armv7a -mimplicit-it=never
+#error-output: arm-it-bad.l
Index: gas/testsuite/gas/arm/arm-it-bad.l
===================================================================
RCS file: gas/testsuite/gas/arm/arm-it-bad.l
diff -N gas/testsuite/gas/arm/arm-it-bad.l
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gas/testsuite/gas/arm/arm-it-bad.l 19 Jun 2009 19:35:05 -0000
@@ -0,0 +1,3 @@
+[^:]*: Assembler messages:
+[^:]*:8: Error: incorrect condition in IT block -- `moveq r0,r1'
+[^:]*:10: Warning: conditional outside an IT block for Thumb.
Index: gas/testsuite/gas/arm/arm-it-bad.s
===================================================================
RCS file: gas/testsuite/gas/arm/arm-it-bad.s
diff -N gas/testsuite/gas/arm/arm-it-bad.s
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gas/testsuite/gas/arm/arm-it-bad.s 19 Jun 2009 19:35:05 -0000
@@ -0,0 +1,10 @@
+ .syntax unified
+ .text
+ .global x
+x:
+ mov r0, r1
+ cmp r0, #0
+ it ne
+ moveq r0, r1
+ bx lr
+ movgt r1, r2
Index: gas/testsuite/gas/arm/thumb2_it.d
===================================================================
RCS file: /cvs/src/src/gas/testsuite/gas/arm/thumb2_it.d,v
retrieving revision 1.2
diff -u -p -r1.2 thumb2_it.d
--- gas/testsuite/gas/arm/thumb2_it.d 15 Aug 2005 19:19:55 -0000 1.2
+++ gas/testsuite/gas/arm/thumb2_it.d 19 Jun 2009 19:35:05 -0000
@@ -1,62 +1,61 @@
# name: Mixed 16 and 32-bit Thumb conditional instructions
# as: -march=armv6kt2
# 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
Index: gas/testsuite/gas/arm/thumb2_it_auto.d
===================================================================
RCS file: gas/testsuite/gas/arm/thumb2_it_auto.d
diff -N gas/testsuite/gas/arm/thumb2_it_auto.d
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gas/testsuite/gas/arm/thumb2_it_auto.d 19 Jun 2009 19:35:05 -0000
@@ -0,0 +1,61 @@
+# name: Mixed 16 and 32-bit Thumb conditional instructions
+# as: -march=armv6kt2 -mimplicit-it=always
+# source: thumb2_it.s
+# objdump: -dr --prefix-addresses --show-raw-insn
+
+.*: +file format .*arm.*
+
+Disassembly of section .text:
+0+000 <[^>]+> bf05 ittet eq
+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 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 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 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 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 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 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 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
Index: gas/testsuite/gas/arm/thumb2_it_bad.d
===================================================================
RCS file: /cvs/src/src/gas/testsuite/gas/arm/thumb2_it_bad.d,v
retrieving revision 1.3
diff -u -p -r1.3 thumb2_it_bad.d
--- gas/testsuite/gas/arm/thumb2_it_bad.d 20 Apr 2006 12:39:51 -0000 1.3
+++ gas/testsuite/gas/arm/thumb2_it_bad.d 19 Jun 2009 19:35:05 -0000
@@ -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.
Index: gas/testsuite/gas/arm/thumb2_it_bad.l
===================================================================
RCS file: /cvs/src/src/gas/testsuite/gas/arm/thumb2_it_bad.l,v
retrieving revision 1.1
diff -u -p -r1.1 thumb2_it_bad.l
--- gas/testsuite/gas/arm/thumb2_it_bad.l 20 Mar 2006 15:38:02 -0000 1.1
+++ gas/testsuite/gas/arm/thumb2_it_bad.l 19 Jun 2009 19:35:05 -0000
@@ -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'
Index: gas/testsuite/gas/arm/thumb2_it_bad_auto.d
===================================================================
RCS file: gas/testsuite/gas/arm/thumb2_it_bad_auto.d
diff -N gas/testsuite/gas/arm/thumb2_it_bad_auto.d
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gas/testsuite/gas/arm/thumb2_it_bad_auto.d 19 Jun 2009 19:35:05 -0000
@@ -0,0 +1,4 @@
+#name: Invalid IT instructions
+#as: -mimplicit-it=always
+#source: thumb2_it_bad.s
+#error-output: thumb2_it_bad.l