This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[PATCH 2] New option for automatically generating IT instructions and enhancing validations
- From: Daniel Gutson <dgutson at codesourcery dot com>
- To: binutils at sourceware dot org, Richard Earnshaw <rearnsha at arm dot com>
- Date: Tue, 09 Jun 2009 18:38:10 -0300
- Subject: [PATCH 2] New option for automatically generating IT instructions and enhancing validations
Hi,
this is the last version of the patch for the automatic IT instructions generation.
With this patch, the assembler allows use of conditional Thumb-2 instructions without requiring explicit IT instructions.
The patch adds the -mimplicit-it command-line option.
This option controls the behavior of the assembler when conditional instructions are not enclosed in IT blocks.
There are four possible behaviors.
If -mimplicit-it=never is specified, such constructs cause a warning in ARM code and an error in Thumb-2 code.
If -mimplicit-it=always is specified, such constructs are accepted in both ARM and Thumb-2 code; the IT instruction is added implicitly.
If -mimplicit-it=arm is specified, such constructs are accepted in ARM code and cause an error in Thumb-2 code.
If -mimplicit-it=thumb is specified, such constructs cause a warning in ARM code and are accepted in Thumb-2 code.
If you omit this option, the behavior is equivalent to -mimplicit-it=arm.
I tested this by running the gas testsuite, plus the test cases I added.
Please note that I don't have write access, so please commit this for me if accepted.
Thanks,
Daniel.
------------
gas/
* config/tc-arm.c (implicit_it_mode): New enum.
(implicit_it_mode): New global.
(it_instruction_type): New enum.
(arm_parse_it_mode): New function.
(arm_long_opts): New option added.
(arm_it): New field.
(it_state): New enum.
(now_it): New macro.
(check_it_blocks_finished): New function.
(insns[]): Use the IT Thumb opcodes for ARM too.
(arm_cleanup): Call check_it_blocks_finished.
(now_it_compatible): New function.
(conditional_insn): New function.
(set_it_insn_type): New macro.
(set_it_insn_type_last): New macro.
(do_it): Call automatic IT machinery functions.
(do_t_add_sub): Likewise
(do_t_arit3): Likewise.
(do_t_arit3c): Likewise.
(do_t_blx): Likewise.
(do_t_branch): Likewise.
(do_t_bkpt): Likewise.
(do_t_branch23): Likewise.
(do_t_bx): Likewise.
(do_t_bxj): Likewise.
(do_t_cps): Likewise.
(do_t_cpsi): Likewise.
(do_t_cbz): Likewise.
(do_t_it): Likewise.
(encode_thumb2_ldmstm): Likewise.
(do_t_ldst): Likewise.
(do_t_mov_cmp): Likewise.
(do_t_mvn_tst): Likewise.
(do_t_mul): Likewise.
(do_t_neg): Likewise.
(do_t_setend): Likewise.
(do_t_shift): Likewise.
(do_t_tb): Likewise.
(output_it_inst): New function.
(new_automatic_it_block): New function.
(close_automatic_it_block): New function.
(now_it_add_mask): New function.
(it_fsm_pre_encode): New function.
(handle_it_state): New function.
(it_fsm_post_encode): New function.
(force_automatic_it_block_close): New function.
(in_it_block): New function.
(md_assemble): Call automatic IT block machinery functions.
(arm_frob_label): Likewise.
(arm_opts): New element.
* config/tc-arm.h (it_state): New enum.
(current_it): New struct.
(arm_segment_info_type): New member added.
* doc/c-arm.texi: New option -mimplicit-it documented.
gas/testsuite/
* gas/arm/arm-it-auto.d: New test.
* gas/arm/arm-it-auto.s: New file.
* gas/arm/arm-it-auto-2.d: New test case.
* gas/arm/arm-it-auto-2.s: New file.
* gas/arm/arm-it-auto-3.d: New test case.
* gas/arm/arm-it-auto-3.s: New file.
* gas/arm/arm-it-bad.d: New test case.
* gas/arm/arm-it-bad.l: New file.
* gas/arm/arm-it-bad.s: New file.
* gas/arm/arm-it-bad-2.d: New test case.
* gas/arm/arm-it-bad-2.l: New file.
* gas/arm/arm-it-bad-2.s: New file.
* gas/arm/arm-it-bad-3.d: New test case.
* gas/arm/arm-it-bad-3.l: New file.
* gas/arm/arm-it-bad-3.s: New file.
* gas/arm/thumb2_it_auto.d: New test.
* gas/arm/thumb2_it_bad.l: Error message updated.
* gas/arm/thumb2_it_bad_auto.d: New test.
* gas/arm/thumb2_it.d: Comment added.
* gas/arm/thumb2_it_bad.d: Comment added.
Index: gas/config/tc-arm.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-arm.c,v
retrieving revision 1.385
diff -u -p -r1.385 tc-arm.c
--- gas/config/tc-arm.c 13 May 2009 16:44:56 -0000 1.385
+++ gas/config/tc-arm.c 9 Jun 2009 21:11:00 -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,41 @@ 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;
-
+#define now_it seg_info (now_seg)->tc_segment_info_data.current_it
+
+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 +6178,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 +7018,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 +8549,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 +8561,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 +8815,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 +8903,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 +9058,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 +9081,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 +9138,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 +9166,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 +9178,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 +9204,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 +9258,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 +9304,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 +9341,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 +9523,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 +9750,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 +9763,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 +9818,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 +9844,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 +9900,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 +10062,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 +10203,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 +10271,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 +10309,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 +10535,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 +10571,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 +10601,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)
@@ -10800,7 +10889,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"));
@@ -14437,6 +14526,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
{
@@ -14682,6 +14793,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)
{
@@ -14751,36 +15172,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 ();
- /* Clear current_it_mask at the end of an IT block. */
- if (current_it_mask == 0x10)
- current_it_mask = 0;
+ opcode->tencode ();
+
+ it_fsm_post_encode ();
+ }
if (!(inst.error || inst.relax))
{
@@ -14839,7 +15243,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)
@@ -14857,6 +15265,20 @@ md_assemble (char *str)
output_inst (str);
}
+static void
+check_it_blocks_finished (void)
+{
+ 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);
+ }
+}
+
/* Various frobbings of labels and their addresses. */
void
@@ -14876,6 +15298,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
@@ -15830,24 +16254,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),
@@ -20258,15 +20684,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. */
@@ -21276,6 +21701,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>"),
@@ -21290,6 +21738,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 9 Jun 2009 21:11:00 -0000
@@ -235,10 +235,26 @@ enum mstate
void mapping_state (enum mstate);
+/* 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;
+};
+
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 9 Jun 2009 21:11:00 -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 9 Jun 2009 21:11:00 -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 9 Jun 2009 21:11:00 -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 9 Jun 2009 21:11:00 -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 9 Jun 2009 21:11:00 -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 9 Jun 2009 21:11:00 -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 9 Jun 2009 21:11:00 -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 9 Jun 2009 21:11:00 -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 9 Jun 2009 21:11:00 -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 9 Jun 2009 21:11:00 -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 9 Jun 2009 21:11:00 -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 9 Jun 2009 21:11:00 -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 9 Jun 2009 21:11:00 -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 9 Jun 2009 21:11:00 -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 9 Jun 2009 21:11:00 -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 9 Jun 2009 21:11:00 -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 9 Jun 2009 21:11:00 -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 9 Jun 2009 21:11:00 -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 9 Jun 2009 21:11:00 -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 9 Jun 2009 21:11:00 -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 9 Jun 2009 21:11:00 -0000
@@ -0,0 +1,4 @@
+#name: Invalid IT instructions
+#as: -mimplicit-it=always
+#source: thumb2_it_bad.s
+#error-output: thumb2_it_bad.l