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, GAS] Fix single-reg LDM/STM to LDR/STR translation.


Hi,

The attached patch fixes the translation of single-register LDM/STM. For
instruction like:
        STMIA sp, {r1}
this patch chooses to encode this as 
        STR r1, [sp, #0]
which can fit into a 16-bit thumb encoding. This is in line with what
the ARM ARM has to say about choosing encodings for STM:

"Encoding T2 does not support a list containing only one register. If an
STM instruction with just one register <Rt> in the list is assembled to
Thumb and encoding T1 is not available, it is assembled to the
equivalent STR<c><q> <Rt>,[<Rn>]{,#4} instruction"

For LDM/STM with single-register list that can't fit into 16-bit
encoding after translation to STR/LDR, 32-bit encoding is used. Care
also has been taken to record UNPREDICTABLE errors where necessary. 

Tested with arm-none-eabi. OK?

--
Tejas Belagod
ARM.

Changelog:

gas/

2010-09-17  Tejas Belagod  <tejas.belagod@arm.com>

	* config/tc-arm.c (do_t_ldmstm): Add logic to handle
	single-register list for ldm/stm.

gas/testsuite

2010-09-17  Tejas Belagod  <tejas.belagod@arm.com>

	* gas/arm/thumb2_ldmstm.d: Change single-register stmia to use 
	16-bit str encoding instead of str.w. Likewise for ldmia.
	* gas/arm/thumb2_ldmstm.s: Change stmia comment. Add tests for
	T1 ldmia-to-ldr.
diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c
index f1ffe9c..285affe 100644
--- a/gas/config/tc-arm.c
+++ b/gas/config/tc-arm.c
@@ -9941,30 +9941,68 @@ do_t_ldmstm (void)
 	{
 	  mask = 1 << inst.operands[0].reg;
 
-	  if (inst.operands[0].reg <= 7
-	      && (inst.instruction == T_MNEM_stmia
-		  ? inst.operands[0].writeback
-		  : (inst.operands[0].writeback
-		     == !(inst.operands[1].imm & mask))))
+	  if (inst.operands[0].reg <= 7)
 	    {
 	      if (inst.instruction == T_MNEM_stmia
-		  && (inst.operands[1].imm & mask)
-		  && (inst.operands[1].imm & (mask - 1)))
-		as_warn (_("value stored for r%d is UNKNOWN"),
-			 inst.operands[0].reg);
+		  ? inst.operands[0].writeback
+		  : (inst.operands[0].writeback
+		     == !(inst.operands[1].imm & mask)))
+	        {
+		  if (inst.instruction == T_MNEM_stmia
+		      && (inst.operands[1].imm & mask)
+		      && (inst.operands[1].imm & (mask - 1)))
+		    as_warn (_("value stored for r%d is UNKNOWN"),
+			     inst.operands[0].reg);
 
-	      inst.instruction = THUMB_OP16 (inst.instruction);
-	      inst.instruction |= inst.operands[0].reg << 8;
-	      inst.instruction |= inst.operands[1].imm;
-	      narrow = TRUE;
+		  inst.instruction = THUMB_OP16 (inst.instruction);
+		  inst.instruction |= inst.operands[0].reg << 8;
+		  inst.instruction |= inst.operands[1].imm;
+		  narrow = TRUE;
+		}
+	      else if ((inst.operands[1].imm & (inst.operands[1].imm-1)) == 0)
+		{
+		  /* This means 1 register in reg list one of 3 situations:
+		     1. Instruction is stmia, but without writeback.
+		     2. lmdia without writeback, but with Rn not in
+		        reglist.
+		     3. ldmia with writeback, but with Rn in reglist.
+		     Case 3 is UNPREDICTABLE behaviour, so we handle
+		     case 1 and 2 which can be converted into a 16-bit
+		     str or ldr. The SP cases are handled below.  */
+		  unsigned long opcode;
+		  /* First, record an error for Case 3.  */
+		  if (inst.operands[1].imm & mask
+		      && inst.operands[0].writeback)
+    		    inst.error = 
+			_("having the base register in the register list when "
+			  "using write back is UNPREDICTABLE");
+		    
+		  opcode = (inst.instruction == T_MNEM_stmia ? T_MNEM_str 
+							     : T_MNEM_ldr);
+		  inst.instruction = THUMB_OP16 (opcode);
+		  inst.instruction |= inst.operands[0].reg << 3;
+		  inst.instruction |= (ffs (inst.operands[1].imm)-1);
+		  narrow = TRUE;
+		}
 	    }
-	  else if (inst.operands[0] .reg == REG_SP
-		   && inst.operands[0].writeback)
+	  else if (inst.operands[0] .reg == REG_SP)
 	    {
-	      inst.instruction = THUMB_OP16 (inst.instruction == T_MNEM_stmia
-					     ? T_MNEM_push : T_MNEM_pop);
-	      inst.instruction |= inst.operands[1].imm;
-	      narrow = TRUE;
+	      if (inst.operands[0].writeback)
+		{
+		  inst.instruction = 
+			THUMB_OP16 (inst.instruction == T_MNEM_stmia
+			            ? T_MNEM_push : T_MNEM_pop);
+		  inst.instruction |= inst.operands[1].imm;
+	          narrow = TRUE;
+		}
+	      else if ((inst.operands[1].imm & (inst.operands[1].imm-1)) == 0)
+		{
+		  inst.instruction = 
+			THUMB_OP16 (inst.instruction == T_MNEM_stmia
+			            ? T_MNEM_str_sp : T_MNEM_ldr_sp);
+		  inst.instruction |= ((ffs (inst.operands[1].imm)-1) << 8);
+	          narrow = TRUE;
+		}
 	    }
 	}
 
diff --git a/gas/testsuite/gas/arm/thumb2_ldmstm.d b/gas/testsuite/gas/arm/thumb2_ldmstm.d
index 50d3ee6..f89bf16 100644
--- a/gas/testsuite/gas/arm/thumb2_ldmstm.d
+++ b/gas/testsuite/gas/arm/thumb2_ldmstm.d
@@ -48,6 +48,12 @@ Disassembly of section .text:
 0[0-9a-f]+ <[^>]+> f858 9b04 	ldr.w	r9, \[r8\], #4
 0[0-9a-f]+ <[^>]+> f8d8 9000 	ldr.w	r9, \[r8\]
 0[0-9a-f]+ <[^>]+> f840 1b04 	str.w	r1, \[r0\], #4
-0[0-9a-f]+ <[^>]+> f8c0 1000 	str.w	r1, \[r0\]
+0[0-9a-f]+ <[^>]+> 6001      	str	r1, \[r0, #0\]
+0[0-9a-f]+ <[^>]+> 680a      	ldr	r2, \[r1, #0\]
+0[0-9a-f]+ <[^>]+> 6807      	ldr	r7, \[r0, #0\]
+0[0-9a-f]+ <[^>]+> 9700      	str	r7, \[sp, #0\]
+0[0-9a-f]+ <[^>]+> 9000      	str	r0, \[sp, #0\]
+0[0-9a-f]+ <[^>]+> 9f00      	ldr	r7, \[sp, #0\]
+0[0-9a-f]+ <[^>]+> 9800      	ldr	r0, \[sp, #0\]
 0[0-9a-f]+ <[^>]+> f848 9b04 	str.w	r9, \[r8\], #4
 0[0-9a-f]+ <[^>]+> f8c8 9000 	str.w	r9, \[r8\]
diff --git a/gas/testsuite/gas/arm/thumb2_ldmstm.s b/gas/testsuite/gas/arm/thumb2_ldmstm.s
index 6cbcc17..ab7701c 100644
--- a/gas/testsuite/gas/arm/thumb2_ldmstm.s
+++ b/gas/testsuite/gas/arm/thumb2_ldmstm.s
@@ -52,6 +52,12 @@ ldmstm:
 	ldmia r8!, {r9}		@ ldr.w r9, [r8], #4
         ldmia r8, {r9}		@ ldr.w r9, [r8]
 	stmia.w r0!, {r1}	@ str.w r1, [r0], #4
-	stmia r0, {r1}		@ str.w r1, [r0]
+	stmia r0, {r1}		@ T1 str r1, [r0]
+	ldmia r1, {r2}		@ T1 ldr r2, [r1]
+	ldmia r0, {r7}		@ T1 ldr r7, [r0]
+	stmia sp, {r7}		@ T1 str r7, [sp]
+	stmia sp, {r0}		@ T1 str r0, [sp]
+	ldmia sp, {r7}		@ T1 ldr r7, [sp]
+	ldmia sp, {r0}		@ T1 ldr r0, [sp]
 	stmia r8!, {r9}		@ str.w r9, [r8], #4
 	stmia r8, {r9}		@ str.w r9, [r8]

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