From ef8d22e63b889bff1ac315e95eb33b78c7ea8949 Mon Sep 17 00:00:00 2001 From: Paul Brook Date: Thu, 2 Feb 2006 13:34:17 +0000 Subject: [PATCH] 2005-02-02 Paul Brook 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. --- gas/ChangeLog | 9 +++ gas/config/tc-arm.c | 96 ++++++++++++++++++++++++++- gas/testsuite/ChangeLog | 5 ++ gas/testsuite/gas/arm/thumb2_invert.d | 16 +++++ gas/testsuite/gas/arm/thumb2_invert.s | 14 ++++ 5 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 gas/testsuite/gas/arm/thumb2_invert.d create mode 100644 gas/testsuite/gas/arm/thumb2_invert.s diff --git a/gas/ChangeLog b/gas/ChangeLog index 77d896ed526..e35956eb815 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,12 @@ +2005-02-02 Paul Brook + + * 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. + 2006-01-31 Bob Wilson * config/xtensa-istack.h (TInsn): Remove record_fix and sub_symbol diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c index dc315c058ee..8cf49ea7990 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. */ diff --git a/gas/testsuite/ChangeLog b/gas/testsuite/ChangeLog index f2e907f26c5..99cb99428be 100644 --- a/gas/testsuite/ChangeLog +++ b/gas/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2005-02-02 Paul Brook + + * gas/arm/thumb2_invert.d: New test. + * gas/arm/thumb2_invert.s: New test. + 2006-01-31 Paul Brook * gas/testsuite/gas/arm/iwmmxt-bad.s: Add check for bad register name. diff --git a/gas/testsuite/gas/arm/thumb2_invert.d b/gas/testsuite/gas/arm/thumb2_invert.d new file mode 100644 index 00000000000..3880e5bb5fc --- /dev/null +++ b/gas/testsuite/gas/arm/thumb2_invert.d @@ -0,0 +1,16 @@ +# as: -march=armv6kt2 +# objdump: -dr --prefix-addresses --show-raw-insn + +.*: +file format .*arm.* + +Disassembly of section .text: +0+000 <[^>]+> f517 0f80 cmn.w r7, #4194304 ; 0x400000 +0+004 <[^>]+> f5b8 0f80 cmp.w r8, #4194304 ; 0x400000 +0+008 <[^>]+> f5a4 0980 sub.w r9, r4, #4194304 ; 0x400000 +0+00c <[^>]+> f506 0380 add.w r3, r6, #4194304 ; 0x400000 +0+010 <[^>]+> f160 4500 sbc.w r5, r0, #2147483648 ; 0x80000000 +0+014 <[^>]+> f147 4400 adc.w r4, r7, #2147483648 ; 0x80000000 +0+018 <[^>]+> f022 4600 bic.w r6, r2, #2147483648 ; 0x80000000 +0+01c <[^>]+> f002 4800 and.w r8, r2, #2147483648 ; 0x80000000 +0+020 <[^>]+> f06f 4300 mvn.w r3, #2147483648 ; 0x80000000 +0+024 <[^>]+> f04f 4100 mov.w r1, #2147483648 ; 0x80000000 diff --git a/gas/testsuite/gas/arm/thumb2_invert.s b/gas/testsuite/gas/arm/thumb2_invert.s new file mode 100644 index 00000000000..38ebcdda4cb --- /dev/null +++ b/gas/testsuite/gas/arm/thumb2_invert.s @@ -0,0 +1,14 @@ + .text + .thumb + .syntax unified +thumb2_invert: + cmp r7, #0xffc00000 + cmn r8, #0xffc00000 + add r9, r4, #0xffc00000 + sub r3, r6, #0xffc00000 + adc r5, r0, #0x7fffffff + sbc r4, r7, #0x7fffffff + and r6, r2, #0x7fffffff + bic r8, r2, #0x7fffffff + mov r3, 0x7fffffff + mvn r1, 0x7fffffff -- 2.30.2