=================================================================== Index: gas/config/tc-arm.c --- gas/config/tc-arm.c (revision 57) +++ gas/config/tc-arm.c (revision 58) @@ -3806,8 +3806,7 @@ OP_oI255c, /* curly-brace enclosed, 0 .. 255 */ OP_oRL, /* Thumb low register */ - OP_oRL_EXi, /* Thumb low register or expression */ - OP_oRR_EXi, /* ARM register or expression */ + OP_oRR, /* ARM register */ OP_oSHll, /* LSL immediate */ OP_oSHar, /* ASR immediate */ @@ -3824,9 +3823,10 @@ static int parse_operands (char *str, const char *pattern) { - int i; - int val; - unsigned const char *p = pattern; + unsigned const char *upat = pattern; + char *backtrack_pos = 0; + const char *backtrack_error = 0; + int i, val, backtrack_index = 0; #define po_char_or_fail(chr) do { \ if (skip_past_char (&str, chr) == FAIL) \ @@ -3838,7 +3838,7 @@ if (val == FAIL) \ { \ inst.error = _(reg_expected_msgs[regtype]); \ - return FAIL; \ + goto failure; \ } \ inst.operands[i].reg = val; \ inst.operands[i].isreg = 1; \ @@ -3855,25 +3855,38 @@ #define po_imm_or_fail(min, max, popt) do { \ if (immediate_required_here (&str, &val, min, max, popt) == FAIL) \ - return FAIL; \ + goto failure; \ inst.operands[i].imm = val; \ } while (0) +#define po_misc_or_fail(expr) do { \ + if (expr) \ + goto failure; \ +} while (0) + skip_whitespace (str); - /* Check for a no-operand instruction, or an instruction with only - optional operands given none, and bypass the loop if so. */ - if (*p == OP_stop || (*p >= OP_FIRST_OPTIONAL && *str == 0)) - goto done; - - for (i = 0; ; i++) + for (i = 0; upat[i] != OP_stop; i++) { - switch (*p) + if (upat[i] >= OP_FIRST_OPTIONAL) { + /* Remember where we are in case we need to backtrack. */ + assert (!backtrack_pos); + backtrack_pos = str; + backtrack_error = inst.error; + backtrack_index = i; + } + + if (i > 0) + po_char_or_fail (','); + + switch (upat[i]) + { /* Registers */ case OP_RRnpc: case OP_oRL: case OP_RL: + case OP_oRR: case OP_RR: po_reg_or_fail (REG_TYPE_RN); break; case OP_RCP: po_reg_or_fail (REG_TYPE_CP); break; case OP_RCN: po_reg_or_fail (REG_TYPE_CN); break; @@ -3951,25 +3964,25 @@ /* Expressions */ case OP_EXPi: EXPi: - if (my_get_expression (&inst.reloc.exp, &str, GE_OPT_PREFIX)) - return FAIL; + po_misc_or_fail (my_get_expression (&inst.reloc.exp, &str, + GE_OPT_PREFIX)); break; case OP_EXP: EXP: - if (my_get_expression (&inst.reloc.exp, &str, GE_NO_PREFIX)) - return FAIL; + po_misc_or_fail (my_get_expression (&inst.reloc.exp, &str, + GE_NO_PREFIX)); break; case OP_EXPr: EXPr: - if (my_get_expression (&inst.reloc.exp, &str, GE_NO_PREFIX)) - return FAIL; + po_misc_or_fail (my_get_expression (&inst.reloc.exp, &str, + GE_NO_PREFIX)); if (inst.reloc.exp.X_op == O_symbol) { val = parse_reloc (&str); if (val == -1) { inst.error = _("unrecognized relocation suffix"); - return FAIL; + goto failure; } else if (val != BFD_RELOC_UNUSED) { @@ -3982,8 +3995,6 @@ /* Register or expression */ case OP_RR_EX: po_reg_or_goto (REG_TYPE_RN, EXP); break; case OP_RR_EXr: po_reg_or_goto (REG_TYPE_RN, EXPr); break; - case OP_oRL_EXi: - case OP_oRR_EXi: case OP_RL_EXi: case OP_RR_EXi: po_reg_or_goto (REG_TYPE_RN, EXPi); break; @@ -3991,21 +4002,18 @@ case OP_RRnpc_I0: po_reg_or_goto (REG_TYPE_RN, I0); break; I0: po_imm_or_fail (0, 0, FALSE); break; - - case OP_RF_IF: + case OP_RF_IF: po_reg_or_goto (REG_TYPE_FN, IF); break; + IF: if (!is_immediate_prefix (*str)) - po_reg_or_fail (REG_TYPE_FN); - else - { - str++; - val = fpa_immediate (&str); - if (val == FAIL) - return FAIL; - /* FPA immediates are encoded as registers 8-15. - fpa_immediate has already applied the offset. */ - inst.operands[i].reg = val; - inst.operands[i].isreg = 1; - } + goto bad_args; + str++; + val = fpa_immediate (&str); + if (val == FAIL) + goto failure; + /* FPA immediates are encoded as registers 8-15. + fpa_immediate has already applied the offset. */ + inst.operands[i].reg = val; + inst.operands[i].isreg = 1; break; /* Two kinds of register */ @@ -4015,7 +4023,7 @@ if (rege->type != REG_TYPE_MMXWR && rege->type != REG_TYPE_MMXWC) { inst.error = _("iWMMXt data or control register expected"); - return FAIL; + goto failure; } inst.operands[i].reg = rege->number; inst.operands[i].isreg = (rege->type == REG_TYPE_MMXWR); @@ -4048,38 +4056,33 @@ /* Addressing modes */ case OP_ADDR: - if (parse_address (&str, i)) - return FAIL; + po_misc_or_fail (parse_address (&str, i)); break; case OP_SH: - if (parse_shifter_operand (&str, i)) - return FAIL; + po_misc_or_fail (parse_shifter_operand (&str, i)); break; case OP_oSHll: - if (parse_shift (&str, i, SHIFT_LSL_IMMEDIATE)) - return FAIL; + po_misc_or_fail (parse_shift (&str, i, SHIFT_LSL_IMMEDIATE)); break; case OP_oSHar: - if (parse_shift (&str, i, SHIFT_ASR_IMMEDIATE)) - return FAIL; + po_misc_or_fail (parse_shift (&str, i, SHIFT_ASR_IMMEDIATE)); break; case OP_oSHllar: - if (parse_shift (&str, i, SHIFT_LSL_OR_ASR_IMMEDIATE)) - return FAIL; + po_misc_or_fail (parse_shift (&str, i, SHIFT_LSL_OR_ASR_IMMEDIATE)); break; default: - as_fatal ("unhandled operand code %03o", *p); + as_fatal ("unhandled operand code %d", upat[i]); } /* Various value-based sanity checks and shared operations. We do not signal immediate failures for the register constraints; this allows a syntax error to take precedence. */ - switch (*p) + switch (upat[i]) { case OP_RRnpc: case OP_RRnpcb: @@ -4092,7 +4095,6 @@ case OP_oRL: case OP_RL: case OP_RLw: - case OP_oRL_EXi: case OP_RL_EXi: if (inst.operands[i].isreg && inst.operands[i].reg > 7) inst.error = BAD_HIREG; @@ -4106,7 +4108,7 @@ case OP_VRSLST: case OP_VRDLST: if (val == FAIL) - return FAIL; + goto failure; inst.operands[i].imm = val; break; @@ -4116,40 +4118,35 @@ /* If we get here, this operand was successfully parsed. */ inst.operands[i].present = 1; + continue; - if (*++p == OP_stop) - break; + bad_args: + inst.error = BAD_ARGS; - /* If this is an optional argument, and we have no further - operands, stop. */ - if (*p >= OP_FIRST_OPTIONAL && *str == '\0') - break; + failure: + if (!backtrack_pos) + return FAIL; - if (skip_past_comma (&str) == FAIL) - goto bad_args; + /* Try again, skipping the optional argument at backtrack_pos. */ + str = backtrack_pos; + inst.error = backtrack_error; + inst.operands[backtrack_index].present = 0; + i = backtrack_index; + backtrack_pos = 0; } - done: /* Check that we have parsed all the arguments. */ if (*str != '\0' && !inst.error) inst.error = _("garbage following instruction"); return inst.error ? FAIL : SUCCESS; +} - bad_args: - inst.error = BAD_ARGS; - return FAIL; - #undef po_char_or_fail #undef po_reg_or_fail #undef po_reg_or_goto #undef po_imm_or_fail -} -#undef OP_ -#undef OP__ -#undef OP___ - /* Operand validation functions. */ /* Set inst.error to BAD_OVERLAP and return FAIL if any of the @@ -5062,38 +5059,20 @@ int subtract = !!(inst.instruction & 0x8000); Rd = inst.operands[0].reg; - if (inst.operands[2].present) - { - /* If there were three operands, operand 1 must be a register. */ - if (!inst.operands[1].isreg) - { - inst.error = BAD_ARGS; - return; - } + Rs = (inst.operands[1].present + ? inst.operands[1].reg /* Rd, Rs, foo */ + : inst.operands[0].reg); /* Rd, foo -> Rd, Rd, foo */ - Rs = inst.operands[1].reg; - if (!inst.operands[2].isreg) /* Rd, Rs, #imm */ - { - inst.instruction |= (Rd << 4) | Rs; - inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD; - return; - } - else /* Rd, Rs, Rn */ - Rn = inst.operands[2].reg; - } - else if (!inst.operands[1].isreg) /* Rd, #imm -> Rd, Rd, #imm */ + if (!inst.operands[2].isreg) /* Rd, Rs, #imm */ { - inst.instruction |= (Rd << 4) | Rd; + inst.instruction |= (Rd << 4) | Rs; inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD; return; } - else /* Rd, Rs -> Rd, Rd, Rs */ - { - Rs = inst.operands[0].reg; - Rn = inst.operands[1].reg; - } - /* We now have Rd and Rs, and Rn set to registers. */ + Rn = inst.operands[2].reg; + + /* We now have Rd, Rs, and Rn set to registers. */ if (Rd > 7 || Rs > 7 || Rn > 7) { if (Rs != Rd) @@ -5151,16 +5130,14 @@ static void do_t_arit3 (void) { - if (inst.operands[2].present) + if (inst.operands[1].present + && inst.operands[0].reg != inst.operands[1].reg) { - if (inst.operands[0].reg != inst.operands[1].reg) - { - inst.error = _("dest and source1 must be the same register"); - return; - } - inst.operands[1].reg = inst.operands[2].reg; + inst.error = _("dest and source1 must be the same register"); + return; } - do_t_arit (); + inst.instruction |= inst.operands[0].reg; + inst.instruction |= inst.operands[2].reg << 3; } /* ARM V5 Thumb BLX (argument parse) @@ -5424,38 +5401,21 @@ static void do_t_shift (void) { - int Rs; + unsigned int Rs = (inst.operands[1].present + ? inst.operands[1].reg + : inst.operands[0].reg); - if (inst.operands[2].present) + if (inst.operands[2].isreg) /* Rd, {Rs,} Rn */ { - /* If there were three operands, operand 1 must be a register. */ - if (!inst.operands[1].isreg) + if (inst.operands[0].reg != Rs) { - inst.error = BAD_ARGS; + inst.error = _("source1 and dest must be same register"); return; } - else if (inst.operands[2].isreg) /* Rd, Rs, Rn */ - { - if (inst.operands[0].reg != inst.operands[1].reg) - { - inst.error = _("source1 and dest must be same register"); - return; - } - inst.instruction |= inst.operands[0].reg; - inst.instruction |= inst.operands[2].reg << 3; - return; - } - else /* Rd, Rs, imm */ - Rs = inst.operands[1].reg; - } - else if (inst.operands[1].isreg) /* Rd, Rs -> Rd, Rd, Rs */ - { inst.instruction |= inst.operands[0].reg; inst.instruction |= inst.operands[2].reg << 3; return; } - else /* Rd, imm -> Rd, Rd, imm */ - Rs = inst.operands[0].reg; /* If we get here, we are doing a shift by an immediate. inst.operands[0].reg and Rs are the registers, and inst.reloc is the immediate. */ @@ -7621,10 +7581,10 @@ static const struct asm_opcode tinsns[] = { #define THUMB_VARIANT ARM_EXT_V4T /* Thumb v1 (ARMv4T). */ - TI(adc, 4140, 3, (RL, RL, oRL), t_arit3), - TI(add, 0000, 3, (RR, RR_EXi, oRR_EXi), t_add_sub), - TI(and, 4000, 3, (RL, RL, oRL), t_arit3), - TI(asr, 4100, 3, (RL, RL_EXi, oRL_EXi), t_shift), + TI(adc, 4140, 3, (RL, oRL, RL), t_arit3), + TI(add, 0000, 3, (RR, oRR, RR_EXi), t_add_sub), + TI(and, 4000, 3, (RL, oRL, RL), t_arit3), + TI(asr, 4100, 3, (RL, oRL, RL_EXi), t_shift), TI(b, e7fe, 1, (EXP), t_branch12), TI(beq, d0fe, 1, (EXP), t_branch9), TI(bne, d1fe, 1, (EXP), t_branch9), @@ -7644,12 +7604,12 @@ TI(bgt, dcfe, 1, (EXP), t_branch9), TI(ble, ddfe, 1, (EXP), t_branch9), TI(bal, defe, 1, (EXP), t_branch9), - TI(bic, 4380, 3, (RL, RL, oRL), t_arit3), + TI(bic, 4380, 3, (RL, oRL, RL), t_arit3), TI(bl, f7fffffe, 1, (EXP), t_branch23), TI(bx, 4700, 1, (RR), t_bx), TI(cmn, 42c0, 2, (RL, RL), t_arit), TI(cmp, 4280, 2, (RR, RR_EXi), t_mov_cmp), - TI(eor, 4040, 3, (RL, RL, oRL), t_arit3), + TI(eor, 4040, 3, (RL, oRL, RL), t_arit3), TI(ldmia, c800, 2, (RLw, REGLST), t_ldmstm), TI(ldr, 5800, 2, (RL, ADDR), t_ldst), TI(ldrb, 5c00, 2, (RL, ADDR), t_ldst), @@ -7658,23 +7618,23 @@ TI(ldrsh, 5e00, 2, (RL, ADDR), t_lds), TI(ldsb, 5600, 2, (RL, ADDR), t_lds), TI(ldsh, 5e00, 2, (RL, ADDR), t_lds), - TI(lsl, 4080, 3, (RL, RL_EXi, oRL_EXi), t_shift), - TI(lsr, 40c0, 3, (RL, RL_EXi, oRL_EXi), t_shift), + TI(lsl, 4080, 3, (RL, oRL, RL_EXi), t_shift), + TI(lsr, 40c0, 3, (RL, oRL, RL_EXi), t_shift), TI(mov, 4600, 2, (RR, RR_EXi), t_mov_cmp), - TI(mul, 4340, 3, (RL, RL, oRL), t_arit3), + TI(mul, 4340, 3, (RL, oRL, RL), t_arit3), TI(mvn, 43c0, 2, (RL, RL), t_arit), TI(neg, 4240, 2, (RL, RL), t_arit), - TI(orr, 4300, 3, (RL, RL, oRL), t_arit3), + TI(orr, 4300, 3, (RL, oRL, RL), t_arit3), TI(pop, bc00, 1, (REGLST), t_push_pop), TI(push, b400, 1, (REGLST), t_push_pop), - TI(ror, 41c0, 3, (RL, RL, oRL), t_arit3), - TI(sbc, 4180, 3, (RL, RL, oRL), t_arit3), + TI(ror, 41c0, 3, (RL, oRL, RL), t_arit3), + TI(sbc, 4180, 3, (RL, oRL, RL), t_arit3), TI(stmia, c000, 2, (RLw, REGLST), t_ldmstm), TI(str, 5000, 2, (RL, ADDR), t_ldst), TI(strb, 5400, 2, (RL, ADDR), t_ldst), TI(strh, 5200, 2, (RL, ADDR), t_ldst), TI(swi, df00, 1, (EXP), t_swi), - TI(sub, 8000, 3, (RR, RR_EXi, oRR_EXi), t_add_sub), + TI(sub, 8000, 3, (RR, oRR, RR_EXi), t_add_sub), TI(tst, 4200, 2, (RL, RL), t_arit), /* Pseudo ops: */ TI(adr, 000f, 2, (RL, EXP), t_adr),