[3/4] s390: Treat addressing operand sequence as one in disassembler

Message ID 20241127102630.92800-4-jremus@linux.ibm.com
State New
Headers
Series s390: Correct handling of optional operands in (dis)assembler |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_binutils_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_binutils_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_binutils_check--master-aarch64 success Test passed
linaro-tcwg-bot/tcwg_binutils_check--master-arm success Test passed

Commit Message

Jens Remus Nov. 27, 2024, 10:26 a.m. UTC
  Reuse logic introduced with the preceding commit in the assembler to
treat addressing operand sequences D(X,B), D(B), and D(L,B) as one
with regards to optional last operands (i.e. optparm and optparm2).

With this "nop" now disassembles into "nop" instead of "nop 0".

opcodes/
	* s390-dis.c (operand_count): New helper to count the remaining
	operands, treating D(X,B), D(B), and D(L,B) as one.
	(skip_optargs_p): New helper to test whether remaining operands
	 are optional.
	(skip_optargs_zero_p): New helper to test whether remaining
	operands are optional and their values are zero.
	(s390_print_insn_with_opcode): Use skip_optargs_zero_p to skip
	optional last operands with a value of zero.

gas/testsuite/
	* gas/s390/zarch-optargs.d (nop): Adjust test case accordingly.

Signed-off-by: Jens Remus <jremus@linux.ibm.com>
---
 gas/testsuite/gas/s390/zarch-optargs.d |  2 +-
 opcodes/s390-dis.c                     | 84 ++++++++++++++++++++------
 2 files changed, 67 insertions(+), 19 deletions(-)
  

Patch

diff --git a/gas/testsuite/gas/s390/zarch-optargs.d b/gas/testsuite/gas/s390/zarch-optargs.d
index 919acbbac367..9af471ee908d 100644
--- a/gas/testsuite/gas/s390/zarch-optargs.d
+++ b/gas/testsuite/gas/s390/zarch-optargs.d
@@ -10,7 +10,7 @@  Disassembly of section .text:
 .*:	07 00 [	 ]*nopr
 .*:	07 01 [	 ]*nopr	%r1
 # nop [D1(X1,B1)]
-.*:	47 00 00 00 [	 ]*nop	0
+.*:	47 00 00 00 [	 ]*nop
 .*:	47 00 0f ff [	 ]*nop	4095
 .*:	47 00 2f ff [	 ]*nop	4095\(%r2\)
 .*:	47 01 0f ff [	 ]*nop	4095\(%r1,0\)
diff --git a/opcodes/s390-dis.c b/opcodes/s390-dis.c
index 1a23afc8f402..8e7b9838f81e 100644
--- a/opcodes/s390-dis.c
+++ b/opcodes/s390-dis.c
@@ -180,6 +180,69 @@  s390_extract_operand (const bfd_byte *insn,
   return ret;
 }
 
+/* Return remaining operand count.  */
+
+static unsigned int
+operand_count (const unsigned char *opindex_ptr)
+{
+  unsigned int count = 0;
+
+  for (; *opindex_ptr != 0; opindex_ptr++)
+    {
+      /* Count D(X,B), D(B), and D(L,B) as one operand.  Assuming correct
+	 instruction operand definitions simply do not count D, X, and L.  */
+      if (!(s390_operands[*opindex_ptr].flags & (S390_OPERAND_DISP
+						| S390_OPERAND_INDEX
+						| S390_OPERAND_LENGTH)))
+	count++;
+    }
+
+  return count;
+}
+
+/* Return true if all remaining instruction operands are optional.  */
+
+static bool
+skip_optargs_p (unsigned int opcode_flags, const unsigned char *opindex_ptr)
+{
+  if ((opcode_flags & (S390_INSTR_FLAG_OPTPARM | S390_INSTR_FLAG_OPTPARM2)))
+    {
+      unsigned int opcount = operand_count (opindex_ptr);
+
+      if (opcount == 1)
+	return true;
+
+      if ((opcode_flags & S390_INSTR_FLAG_OPTPARM2) && opcount == 2)
+	return true;
+    }
+
+  return false;
+}
+
+/* Return true if all remaining instruction operands are optional
+   and their values are zero.  */
+
+static bool
+skip_optargs_zero_p (const bfd_byte *buffer, unsigned int opcode_flags,
+		     const unsigned char *opindex_ptr)
+{
+  /* Test if remaining operands are optional.  */
+  if (!skip_optargs_p (opcode_flags, opindex_ptr))
+    return false;
+
+  /* Test if remaining operand values are zero.  */
+  for (; *opindex_ptr != 0; opindex_ptr++)
+    {
+      const struct s390_operand *operand = &s390_operands[*opindex_ptr];
+      union operand_value value = s390_extract_operand (buffer, operand);
+
+      if (value.u != 0)
+	return false;
+    }
+
+  return true;
+}
+
 /* Print the S390 instruction in BUFFER, assuming that it matches the
    given OPCODE.  */
 
@@ -220,24 +283,9 @@  s390_print_insn_with_opcode (bfd_vma memaddr,
 	 handled separately, as they may not be omitted unconditionally.  */
       if (!(operand->flags & (S390_OPERAND_BASE
 			      | S390_OPERAND_INDEX
-			      | S390_OPERAND_LENGTH)))
-	{
-	  if ((opcode->flags & (S390_INSTR_FLAG_OPTPARM | S390_INSTR_FLAG_OPTPARM2))
-	      && val.u == 0
-	      && opindex[1] == 0)
-	    break;
-
-	  if ((opcode->flags & S390_INSTR_FLAG_OPTPARM2)
-	      && val.u == 0
-	      && opindex[1] != 0 && opindex[2] == 0)
-	    {
-	      union operand_value next_op_val =
-		s390_extract_operand (buffer, s390_operands + opindex[1]);
-
-	      if (next_op_val.u == 0)
-		break;
-	    }
-	}
+			      | S390_OPERAND_LENGTH))
+	  && skip_optargs_zero_p (buffer, opcode->flags, opindex))
+	break;
 
       if (flags & S390_OPERAND_GPR)
 	{