This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]