? ChangeLog.csl ? auto_it.patch Index: gas/config/tc-arm.c =================================================================== RCS file: /cvs/src/src/gas/config/tc-arm.c,v retrieving revision 1.384 diff -u -p -r1.384 tc-arm.c --- gas/config/tc-arm.c 5 May 2009 11:41:31 -0000 1.384 +++ gas/config/tc-arm.c 8 May 2009 01:20:10 -0000 @@ -265,6 +265,9 @@ static int thumb_mode = 0; tc_frag_data field of a frag. */ #define MODE_RECORDED (1 << 4) +/* Enables/disables automatic IT insn insertion mode. */ +static int do_automatic_it = 0; + /* If unified_syntax is true, we are processing the new unified ARM/Thumb syntax. Important differences from the old ARM mode: @@ -315,6 +318,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 +352,8 @@ struct arm_it int pc_rel; } reloc; + enum it_instruction_type it_insn_type; + struct { unsigned reg; @@ -674,6 +691,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 +715,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. */ @@ -715,9 +735,58 @@ typedef struct literal_pool literal_pool * list_of_pools = NULL; /* State variables for IT block handling. */ -static bfd_boolean current_it_mask = 0; -static int current_cc; - +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; +}; + +static struct current_it current_it; + +static inline int +current_it_compatible (int cond) +{ + return (cond & ~1) == (current_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 +6189,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) \ @@ -8482,6 +8551,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 +8563,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 +8817,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 +8905,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 +9060,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 +9083,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 +9140,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 +9168,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 +9180,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 +9206,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 +9260,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 +9306,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); + current_it.mask = (inst.instruction & 0xf) | 0x10; + current_it.cc = cond; /* If the condition is a negative condition, invert the mask. */ if ((cond & 0x1) == 0x0) @@ -9268,9 +9343,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 +9525,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 +9752,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 +9765,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 +9820,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 +9846,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 +9902,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 +10064,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 +10205,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 +10273,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 +10311,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 +10537,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 +10573,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 +10603,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 +10891,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 +14528,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 +14795,304 @@ 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 current_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) +{ + current_it.state = AUTOMATIC_IT_BLOCK; + current_it.mask = 0x18; + current_it.cc = cond; + current_it.block_length = 1; + current_it.insn = output_it_inst(cond, current_it.mask, NULL); +} + +/* Close an automatic IT block. + See comments in new_automatic_it_block (). */ +static void +close_automatic_it_block (void) +{ + current_it.mask = 0x10; + current_it.block_length = 0; +} + +/* Update the mask of the current automatically-generated IT + instruction. See comments in new_automatic_it_block (). */ +static void +current_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); + current_it.mask &= 0xf; + current_it.mask = SET_BIT_VALUE (current_it.mask, + resulting_bit, + (5 - current_it.block_length)); + current_it.mask = SET_BIT_VALUE (current_it.mask, + 1, + ((5 - current_it.block_length) - 1) ); + output_it_inst (current_it.cc, current_it.mask, current_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; + + current_it.state_handled = 0; +} + +/* IT state FSM handling function. */ +static int +handle_it_state (void) +{ + current_it.state_handled = 1; + + switch(current_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 (do_automatic_it) + { + /* 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: + current_it.state = MANUAL_IT_BLOCK; + current_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: + current_it.block_length++; + + if (current_it.block_length > 4 + || !current_it_compatible (inst.cond)) + { + close_automatic_it_block (); + if (inst.it_insn_type != IF_INSIDE_IT_LAST_INSN) + new_automatic_it_block (inst.cond); + } + else + { + current_it_add_mask (inst.cond); + } + + if (inst.it_insn_type == INSIDE_IT_LAST_INSN + || inst.it_insn_type == IF_INSIDE_IT_LAST_INSN) + close_automatic_it_block (); /* This can be called twice. */ + break; + + case NEUTRAL_IT_INSN: + current_it.block_length++; + + if (current_it.block_length > 4) + close_automatic_it_block (); + else + current_it_add_mask (current_it.cc & 1); + break; + + case IT_INSN: + close_automatic_it_block (); + current_it.state = MANUAL_IT_BLOCK; + break; + } + break; + + case MANUAL_IT_BLOCK: + { + /* Check conditional suffixes. */ + const int cond = current_it.cc ^ ((current_it.mask >> 4) & 1) ^ 1; + int is_last; + current_it.mask <<= 1; + current_it.mask &= 0x1f; + is_last = (current_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 (!current_it.state_handled) + handle_it_state (); + + is_last = (current_it.mask == 0x10); + if (is_last) + { + current_it.state = OUTSIDE_IT_BLOCK; + current_it.mask = 0; + } +} + +static void +force_automatic_it_block_close (void) +{ + if (current_it.state == AUTOMATIC_IT_BLOCK) + { + close_automatic_it_block (); + current_it.state = OUTSIDE_IT_BLOCK; + current_it.mask = 0; + } +} + +static int +in_it_block (void) +{ + if (!current_it.state_handled) + handle_it_state (); + + return current_it.state != OUTSIDE_IT_BLOCK; +} + void md_assemble (char *str) { @@ -14751,36 +15162,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)) { @@ -14876,6 +15270,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 @@ -20701,6 +21097,8 @@ struct arm_option_table arm_opts[] = {"mthumb", N_("assemble Thumb code"), &thumb_mode, 1, NULL}, {"mthumb-interwork", N_("support ARM/Thumb interworking"), &support_interwork, 1, NULL}, + {"mauto-it", N_("Enables/disables automatic IT insn insertion mode"), + &do_automatic_it, 1, NULL}, {"mapcs-32", N_("code uses 32-bit program counter"), &uses_apcs_26, 0, NULL}, {"mapcs-26", N_("code uses 26-bit program counter"), &uses_apcs_26, 1, NULL}, {"mapcs-float", N_("floating point args are in fp regs"), &uses_apcs_float, 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 8 May 2009 01:20:10 -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.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 8 May 2009 01:20:10 -0000 @@ -0,0 +1,81 @@ +#name: ARM IT automatic instruction generation +#as: -mthumb -march=armv7 -mauto-it +#objdump: -d --prefix-addresses --show-raw-insn +#skip: *-*-*coff *-*-pe *-*-wince *-*-*aout* *-*-netbsd *-*-riscix* + +.*: +file format .*arm.* + +Disassembly of section .text: +00000000
f000 f821 bl 00000046 +00000004 f000 f80c bl 00000020 +00000008 f000 f813 bl 00000032 +0000000c d142 bne.n 00000094 +0000000e bf18 it ne +00000010 4487 addne pc, r0 +00000012 bf18 it ne +00000014 e8d0 f001 tbbne \[r0, r1\] +00000018 bf08 it eq +0000001a e8d1 f010 tbheq \[r1, r0, lsl #1\] +0000001e bf0a itet eq +00000020 2002 moveq r0, #2 +00000022 2003 movne r0, #3 +00000024 2004 moveq r0, #4 +00000026 bf16 itet ne +00000028 2002 movne r0, #2 +0000002a 2003 moveq r0, #3 +0000002c 2004 movne r0, #4 +0000002e bf18 it ne +00000030 2001 movne r0, #1 +00000032 bf0c ite eq +00000034 2002 moveq r0, #2 +00000036 f8d1 f000 ldrne.w pc, \[r1\] +0000003a bf18 it ne +0000003c f000 f82a blne 00000094 +00000040 bfb8 it lt +00000042 f000 f828 bllt 00000096 +00000046 bf17 itett ne +00000048 202d movne r0, #45 +0000004a 2005 moveq r0, #5 +0000004c 2006 movne r0, #6 +0000004e 4487 addne pc, r0 +00000050 bf0d iteet eq +00000052 2007 moveq r0, #7 +00000054 2008 movne r0, #8 +00000056 2003 movne r0, #3 +00000058 2004 moveq r0, #4 +0000005a bf0b itete eq +0000005c 2005 moveq r0, #5 +0000005e 2006 movne r0, #6 +00000060 2007 moveq r0, #7 +00000062 2008 movne r0, #8 +00000064 bf0c ite eq +00000066 2005 moveq r0, #5 +00000068 2006 movne r0, #6 +0000006a 4687 mov pc, r0 +0000006c bf0b itete eq +0000006e 2007 moveq r0, #7 +00000070 2008 movne r0, #8 +00000072 2005 moveq r0, #5 +00000074 2006 movne r0, #6 +00000076 4487 add pc, r0 +00000078 bf0c ite eq +0000007a 2007 moveq r0, #7 +0000007c 2008 movne r0, #8 +0000007e bfcc ite gt +00000080 2009 movgt r0, #9 +00000082 200a movle r0, #10 +00000084 bf08 it eq +00000086 200b moveq r0, #11 +00000088 bfd8 it le +0000008a 200c movle r0, #12 +0000008c bf18 it ne +0000008e 200d movne r0, #13 +00000090 f7ff fffe bl 00000000 +00000094 bd10 pop {r4, pc} +00000096 f7ff fffe bl 00000000 +0000009a bfb8 it lt +0000009c 2000 movlt r0, #0 +0000009e 4348 muls r0, r1 +000000a0 bfb8 it lt +000000a2 2000 movlt r0, #0 +000000a4 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 8 May 2009 01:20:10 -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/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 8 May 2009 01:20:10 -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 8 May 2009 01:20:10 -0000 @@ -0,0 +1,61 @@ +# name: Mixed 16 and 32-bit Thumb conditional instructions +# as: -march=armv6kt2 -mauto-it +# 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 8 May 2009 01:20:10 -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 8 May 2009 01:20:10 -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 8 May 2009 01:20:10 -0000 @@ -0,0 +1,4 @@ +#name: Invalid IT instructions +#as: -mauto-it +#source: thumb2_it_bad.s +#error-output: thumb2_it_bad.l