This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[patch] Arm Thumb-2 immediate operand inversion


The attached patch implements inversion of Thumb-2 immediate operands.
eg. turn "add reg, reg, #const" into "sub reg, reg, #-const" if only the 
latter is a legal instruction. We already do this conversion for Arm 
instructions, just not for Thumb-2.

Tested with cross to arm-none-eabi.
Ok?

Paul

2005-02-01  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.
Index: gas/config/tc-arm.c
===================================================================
RCS file: /var/cvsroot/src-cvs/src/gas/config/tc-arm.c,v
retrieving revision 1.238
diff -u -p -r1.238 tc-arm.c
--- gas/config/tc-arm.c	31 Jan 2006 16:19:41 -0000	1.238
+++ gas/config/tc-arm.c	1 Feb 2006 18:36:33 -0000
@@ -460,6 +461,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 +482,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 +11128,82 @@ negate_data_op (unsigned long * instruct
   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 +11556,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.  */
Index: gas/testsuite/gas/arm/thumb2_invert.d
===================================================================
RCS file: gas/testsuite/gas/arm/thumb2_invert.d
diff -N gas/testsuite/gas/arm/thumb2_invert.d
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gas/testsuite/gas/arm/thumb2_invert.d	1 Feb 2006 18:29:43 -0000
@@ -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
Index: gas/testsuite/gas/arm/thumb2_invert.s
===================================================================
RCS file: gas/testsuite/gas/arm/thumb2_invert.s
diff -N gas/testsuite/gas/arm/thumb2_invert.s
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gas/testsuite/gas/arm/thumb2_invert.s	1 Feb 2006 18:29:45 -0000
@@ -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

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]