diff options
author | Paul Brook <paul@codesourcery.com> | 2006-02-02 13:34:17 +0000 |
---|---|---|
committer | Paul Brook <paul@codesourcery.com> | 2006-02-02 13:34:17 +0000 |
commit | ef8d22e63b889bff1ac315e95eb33b78c7ea8949 (patch) | |
tree | 04d69759355a82501c3ac39d2442de0084c0cbec /gas/config | |
parent | 59f6d9d6f82ccc6c306740f7eedb613fe0f281a3 (diff) | |
download | gdb-ef8d22e63b889bff1ac315e95eb33b78c7ea8949.zip gdb-ef8d22e63b889bff1ac315e95eb33b78c7ea8949.tar.gz gdb-ef8d22e63b889bff1ac315e95eb33b78c7ea8949.tar.bz2 |
2005-02-02 Paul Brook <paul@codesourcery.com>
gas/
* config/tc-arm.c (T2_OPCODE_MASK, T2_DATA_OP_SHIFT, T2_OPCODE_AND,
T2_OPCODE_BIC, T2_OPCODE_ORR, T2_OPCODE_ORN, T2_OPCODE_EOR,
T2_OPCODE_ADD, T2_OPCODE_ADC, T2_OPCODE_SBC, T2_OPCODE_SUB,
T2_OPCODE_RSB): Define.
(thumb32_negate_data_op): New function.
(md_apply_fix): Use it.
gas/testsuite/
* gas/arm/thumb2_invert.d: New test.
* gas/arm/thumb2_invert.s: New test.
Diffstat (limited to 'gas/config')
-rw-r--r-- | gas/config/tc-arm.c | 96 |
1 files changed, 95 insertions, 1 deletions
diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c index dc315c0..8cf49ea 100644 --- a/gas/config/tc-arm.c +++ b/gas/config/tc-arm.c @@ -460,6 +460,9 @@ struct asm_opcode #define DATA_OP_SHIFT 21 +#define T2_OPCODE_MASK 0xfe1fffff +#define T2_DATA_OP_SHIFT 21 + /* Codes to distinguish the arithmetic instructions. */ #define OPCODE_AND 0 #define OPCODE_EOR 1 @@ -478,6 +481,17 @@ struct asm_opcode #define OPCODE_BIC 14 #define OPCODE_MVN 15 +#define T2_OPCODE_AND 0 +#define T2_OPCODE_BIC 1 +#define T2_OPCODE_ORR 2 +#define T2_OPCODE_ORN 3 +#define T2_OPCODE_EOR 4 +#define T2_OPCODE_ADD 8 +#define T2_OPCODE_ADC 10 +#define T2_OPCODE_SBC 11 +#define T2_OPCODE_SUB 13 +#define T2_OPCODE_RSB 14 + #define T_OPCODE_MUL 0x4340 #define T_OPCODE_TST 0x4200 #define T_OPCODE_CMN 0x42c0 @@ -11113,6 +11127,82 @@ negate_data_op (unsigned long * instruction, return value; } +/* Like negate_data_op, but for Thumb-2. */ + +static unsigned int +thumb32_negate_data_op (offsetT *instruction, offsetT value) +{ + int op, new_inst; + int rd; + offsetT negated, inverted; + + negated = encode_thumb32_immediate (-value); + inverted = encode_thumb32_immediate (~value); + + rd = (*instruction >> 8) & 0xf; + op = (*instruction >> T2_DATA_OP_SHIFT) & 0xf; + switch (op) + { + /* ADD <-> SUB. Includes CMP <-> CMN. */ + case T2_OPCODE_SUB: + new_inst = T2_OPCODE_ADD; + value = negated; + break; + + case T2_OPCODE_ADD: + new_inst = T2_OPCODE_SUB; + value = negated; + break; + + /* ORR <-> ORN. Includes MOV <-> MVN. */ + case T2_OPCODE_ORR: + new_inst = T2_OPCODE_ORN; + value = inverted; + break; + + case T2_OPCODE_ORN: + new_inst = T2_OPCODE_ORR; + value = inverted; + break; + + /* AND <-> BIC. TST has no inverted equivalent. */ + case T2_OPCODE_AND: + new_inst = T2_OPCODE_BIC; + if (rd == 15) + value = FAIL; + else + value = inverted; + break; + + case T2_OPCODE_BIC: + new_inst = T2_OPCODE_AND; + value = inverted; + break; + + /* ADC <-> SBC */ + case T2_OPCODE_ADC: + new_inst = T2_OPCODE_SBC; + value = inverted; + break; + + case T2_OPCODE_SBC: + new_inst = T2_OPCODE_ADC; + value = inverted; + break; + + /* We cannot do anything. */ + default: + return FAIL; + } + + if (value == FAIL) + return FAIL; + + *instruction &= T2_OPCODE_MASK; + *instruction |= new_inst << T2_DATA_OP_SHIFT; + return value; +} + /* Read a 32-bit thumb instruction from buf. */ static unsigned long get_thumb32_insn (char * buf) @@ -11465,7 +11555,11 @@ md_apply_fix (fixS * fixP, /* FUTURE: Implement analogue of negate_data_op for T32. */ if (fixP->fx_r_type == BFD_RELOC_ARM_T32_IMMEDIATE) - newimm = encode_thumb32_immediate (value); + { + newimm = encode_thumb32_immediate (value); + if (newimm == (unsigned int) FAIL) + newimm = thumb32_negate_data_op (&newval, value); + } else { /* 12 bit immediate for addw/subw. */ |