[PATCH] : SH Assembler generates incorrect opcode for PCMP instructions

Nick Clifton nickc@cambridge.redhat.com
Thu Jan 31 13:55:00 GMT 2002


Hi Arati,

> The SH assembler generates incorrect opcodes for the parallel PCMP 
> instruction.  Basically, its last nibble is a copy of the previous
> instruction's second nibble when working in Big Endian format.
> 
> For example,
> test.s
> 	movs.w @-R5, A0
>       PCMP X0,Y0
> 
> generates opcodes
> 	f5 70
> 	f8 00 84 05
> 
>  instead of
> 	f8 00 84 00
> 
> The following patch corrects this. I have also verified that it does
> not cause any side effect on other DSP instructions.

>  	  if (field_b)
>  	    as_bad (_("multiple parallel processing specifications"));
>  	  field_b = ((opcode->nibbles[2] << 12) + (opcode->nibbles[3] <<
> 8)
> -		     + (reg_x << 6) + (reg_y << 4) + reg_n);
> +		     + (reg_x << 6) + (reg_y << 4) );
> +
> +	  if (strcmp (opcode->name, "pcmp") != 0)
> +	  	 field_b += reg_n;
>  	  break;
>  	case PDC:
>  	  if (cond)

Your patch does work, but I do not like the way it makes a special
case out of the opcode's name.  In fact I think that it may not be
just the PCMP instruction that has this problem, since a perusal of
the sh-opc.h file indicates that the PABS and PRND instructions may
also have similar difficulties.

Please could you try the patch below, which I believe provides a more
generic fix for the problem, and which also adds some tests to the SH
gas testsuite to make sure that the problem does not arise again in
the future.

Cheers
        Nick

gas/ChangeLog
2002-01-31  Nick Clifton  <nickc@cambridge.redhat.com>

	* config/tc-sh.c (opcode_has_arg): New function.
        (assemble_ppi): For case PPI3 only insert those registers
        which are specified in the opcode's arg array.

gas/testsuite/ChangeLog
2002-01-31  Nick Clifton  <nickc@cambridge.redhat.com>

	* gas/sh/dsp.s: Add tests of a few DSP instructions.
        * gas/sh/dsp.d: Add expected disassembly.

Index: gas/config/tc-sh.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-sh.c,v
retrieving revision 1.53
diff -c -3 -p -w -r1.53 tc-sh.c
*** tc-sh.c	2002/01/30 18:25:30	1.53
--- tc-sh.c	2002/01/31 21:38:50
***************
*** 29,34 ****
--- 29,35 ----
  #include "opcodes/sh-opc.h"
  #include "safe-ctype.h"
  #include "struc-symbol.h"
+ #include "libiberty.h"
  
  #ifdef OBJ_ELF
  #include "elf/sh.h"
*************** static void build_relax PARAMS ((sh_opco
*** 72,77 ****
--- 73,79 ----
  static char *insert_loop_bounds PARAMS ((char *, sh_operand_info *));
  static unsigned int build_Mytes
    PARAMS ((sh_opcode_info *, sh_operand_info *));
+ static boolean opcode_has_arg PARAMS ((sh_opcode_info *, sh_arg_type));
  
  #ifdef OBJ_ELF
  static void sh_elf_cons PARAMS ((int));
*************** find_cooked_opcode (str_p)
*** 1679,1684 ****
--- 1681,1702 ----
    return (sh_opcode_info *) hash_find (opcode_hash_control, name);
  }
  
+ /* Returns true if OPCODE has an arg of type ARG.  */
+ 
+ static boolean
+ opcode_has_arg (opcode, arg)
+      sh_opcode_info * opcode;
+      sh_arg_type arg;
+ {
+   unsigned int i;
+ 
+   for (i = 0; i < ARRAY_SIZE (opcode->arg); i++)
+     if (opcode->arg[i] == arg)
+       return true;
+ 
+   return false;
+ }
+ 
  /* Assemble a parallel processing insn.  */
  #define DDT_BASE 0xf000 /* Base value for double data transfer insns */
  
*************** assemble_ppi (op_end, opcode)
*** 1791,1798 ****
  	case PPI3:
  	  if (field_b)
  	    as_bad (_("multiple parallel processing specifications"));
! 	  field_b = ((opcode->nibbles[2] << 12) + (opcode->nibbles[3] << 8)
! 		     + (reg_x << 6) + (reg_y << 4) + reg_n);
  	  break;
  	case PDC:
  	  if (cond)
--- 1809,1824 ----
  	case PPI3:
  	  if (field_b)
  	    as_bad (_("multiple parallel processing specifications"));
!  	  field_b = ((opcode->nibbles[2] << 12) + (opcode->nibbles[3] << 8));
! 
! 	  if (opcode_has_arg (opcode, DSP_REG_X))
! 	    field_b |= (reg_x << 6);
! 
! 	  if (opcode_has_arg (opcode, DSP_REG_Y))
! 	    field_b |= (reg_y << 4);
!       
! 	  if (opcode_has_arg (opcode, DSP_REG_N))
! 	    field_b |= reg_n;
  	  break;
  	case PDC:
  	  if (cond)

Index: gas/testsuite/gas/sh/dsp.s
===================================================================
RCS file: /cvs/src/src/gas/testsuite/gas/sh/dsp.s,v
retrieving revision 1.1
diff -c -3 -p -w -r1.1 dsp.s
*** dsp.s	2001/10/09 12:25:52	1.1
--- dsp.s	2002/01/31 21:38:50
***************
*** 1,4 ****
! #	Test file for ARM/GAS -- basic instructions
  
  	.text
  	.align
--- 1,4 ----
! #	Test file for SH DSP assembler instructions.
  
  	.text
  	.align
*************** dsp_tests:
*** 22,24 ****
--- 22,36 ----
  	movs.l m0, @r3+
  	movs.l m1, @r2+r8
  
+ 	# The following tests reproduce a bug discovered in the toolchain
+ 	# The symptom was that insns encoded with the PPI3 attribute would
+ 	# always have three registers encoded into their bitfields, even if
+ 	# they did not actually accept three registers.  The "third" register
+ 	# would come from whatever value was used for the previous instruction.
+ 	movs.w @-R5, A0
+ 	pcmp   X0, Y0
+ 	psubc  X1, Y1, A1
+ 	pabs   X0, A0
+ 	pabs   Y0, A1
+ 	prnd   X1, M0
+ 	prnd   Y1, A1G

Index: gas/testsuite/gas/sh/dsp.d
===================================================================
RCS file: /cvs/src/src/gas/testsuite/gas/sh/dsp.d,v
retrieving revision 1.2
diff -c -3 -p -w -r1.2 dsp.d
*** dsp.d	2002/01/15 12:27:53	1.2
--- dsp.d	2002/01/31 21:38:50
*************** Disassembly of section .text:
*** 22,24 ****
--- 22,31 ----
  0+01a <[^>]*> f4 b7 [ 	]*movs.l	y1,@r4
  0+01c <[^>]*> f7 cb [ 	]*movs.l	m0,@r3\+
  0+01e <[^>]*> f6 ef [ 	]*movs.l	m1,@r2\+r8
+ 0+020 <[^>]*> f5 70 [ 	]*movs.w	@-r5,a0
+ 0+022 <[^>]*> f8 00 84 00 [ 	]*pcmp	x0,y0
+ 0+026 <[^>]*> f8 00 a0 55 [ 	]*psubc	x1,y1,a1
+ 0+02a <[^>]*> f8 00 88 07 [ 	]*pabs	x0,a0
+ 0+02e <[^>]*> f8 00 a8 05 [ 	]*pabs	y0,a1
+ 0+032 <[^>]*> f8 00 98 4c [ 	]*prnd	x1,m0
+ 0+036 <[^>]*> f8 00 b8 1d [ 	]*prnd	y1,a1g



More information about the Binutils mailing list