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] S/390: Support the .machine pseudo


Hi,

the attached patch implements the .machine pseudo op from the Power
back-end for S/390.  Using .machine it is possible to switch to a
different CPU level in the asm listing.  In order to be able to
restore the previous state it is possible to push the current CPU
level setting to a stack.

This is particularly useful for code which uses instructions from
higher CPU levels wrapped into a runtime check.  Using .machine it is
possible to prevent AS from issuing errors for these instructions.
Usually this has been circumvented by converting these instructions to
.insn directives what makes the code unnecessarily hard to read.

I've simply copied over the code from Power and did only some minor
modifications.

No testsuite regressions.

I'll apply the patch tomorrow in case no veto arrives until then.

Bye,

-Andreas-


2011-04-13  Andreas Krebbel  <Andreas.Krebbel@de.ibm.com>

	* config/tc-s390.c (s390_machine): New prototype.
	(md_pseudo_table): New pseudo-op .machine.
	(s390_opcode_hash): Initialize to NULL.
	(s390_parse_cpu): New function.
	(md_parse_option): Use s390_parse_cpu.
	(s390_setup_opcodes): New function.
	(md_begin): Use s390_setup_opcodes.
	(s390_machine): New hook handling the new .machine pseudo.

	* doc/c-s390.texi: Document the new pseudo op .machine.


2011-04-13  Andreas Krebbel  <Andreas.Krebbel@de.ibm.com>

	* gas/s390/zarch-machine.s: New testcase.
	* gas/s390/zarch-machine.d: New testcase output.
	* gas/s390/s390.exp: Execute the new testcase.


Index: gas/config/tc-s390.c
===================================================================
--- gas/config/tc-s390.c.orig
+++ gas/config/tc-s390.c
@@ -85,6 +85,7 @@ static void s390_elf_cons (int);
 static void s390_bss (int);
 static void s390_insn (int);
 static void s390_literals (int);
+static void s390_machine (int);
 
 const pseudo_typeS md_pseudo_table[] =
 {
@@ -99,6 +100,7 @@ const pseudo_typeS md_pseudo_table[] =
   { "quad",     s390_elf_cons,  8 },
   { "ltorg",    s390_literals,  0 },
   { "string",   stringer,       8 + 1 },
+  { "machine",  s390_machine,   0 },
   { NULL,	NULL,		0 }
 };
 
@@ -293,7 +295,7 @@ register_name (expressionS *expressionP)
 static struct hash_control *s390_opformat_hash;
 
 /* Opcode hash table.  */
-static struct hash_control *s390_opcode_hash;
+static struct hash_control *s390_opcode_hash = NULL;
 
 /* Flags to set in the elf header */
 static flagword s390_flags = 0;
@@ -350,6 +352,35 @@ s390_target_format (void)
   return s390_arch_size == 64 ? "elf64-s390" : "elf32-s390";
 }
 
+/* Map a CPU string as given with -march= or .machine to the
+   respective enum s390_opcode_cpu_val value.  0xffffffff is returned
+   in case of an error.  */
+
+static int
+s390_parse_cpu (char *arg)
+{
+  if (strcmp (arg, "g5") == 0)
+    return S390_OPCODE_G5;
+  else if (strcmp (arg, "g6") == 0)
+    return S390_OPCODE_G6;
+  else if (strcmp (arg, "z900") == 0)
+    return S390_OPCODE_Z900;
+  else if (strcmp (arg, "z990") == 0)
+    return S390_OPCODE_Z990;
+  else if (strcmp (arg, "z9-109") == 0)
+    return S390_OPCODE_Z9_109;
+  else if (strcmp (arg, "z9-ec") == 0)
+    return S390_OPCODE_Z9_EC;
+  else if (strcmp (arg, "z10") == 0)
+    return S390_OPCODE_Z10;
+  else if (strcmp (arg, "z196") == 0)
+    return S390_OPCODE_Z196;
+  else if (strcmp (arg, "all") == 0)
+    return S390_OPCODE_MAXCPU - 1;
+  else
+    return ~(unsigned int)0;
+}
+
 int
 md_parse_option (int c, char *arg)
 {
@@ -382,25 +413,9 @@ md_parse_option (int c, char *arg)
 
       else if (arg != NULL && strncmp (arg, "arch=", 5) == 0)
 	{
-	  if (strcmp (arg + 5, "g5") == 0)
-	    current_cpu = S390_OPCODE_G5;
-	  else if (strcmp (arg + 5, "g6") == 0)
-	    current_cpu = S390_OPCODE_G6;
-	  else if (strcmp (arg + 5, "z900") == 0)
-	    current_cpu = S390_OPCODE_Z900;
-	  else if (strcmp (arg + 5, "z990") == 0)
-	    current_cpu = S390_OPCODE_Z990;
-	  else if (strcmp (arg + 5, "z9-109") == 0)
-	    current_cpu = S390_OPCODE_Z9_109;
-	  else if (strcmp (arg + 5, "z9-ec") == 0)
-	    current_cpu = S390_OPCODE_Z9_EC;
-	  else if (strcmp (arg + 5, "z10") == 0)
-	    current_cpu = S390_OPCODE_Z10;
-	  else if (strcmp (arg + 5, "z196") == 0)
-	    current_cpu = S390_OPCODE_Z196;
-	  else if (strcmp (arg + 5, "all") == 0)
-	    current_cpu = S390_OPCODE_MAXCPU - 1;
-	  else
+	  current_cpu = s390_parse_cpu (arg + 5);
+
+	  if (current_cpu == ~(unsigned int)0)
 	    {
 	      as_bad (_("invalid switch -m%s"), arg);
 	      return 0;
@@ -456,42 +471,20 @@ md_show_usage (FILE *stream)
         -Qy, -Qn          ignored\n"));
 }
 
-/* This function is called when the assembler starts up.  It is called
-   after the options have been parsed and the output file has been
-   opened.  */
+/* Generate the hash table mapping mnemonics to struct s390_opcode.
+   This table is built at startup and whenever the CPU level is
+   changed using .machine.  */
 
-void
-md_begin (void)
+static void
+s390_setup_opcodes (void)
 {
   register const struct s390_opcode *op;
   const struct s390_opcode *op_end;
   bfd_boolean dup_insn = FALSE;
   const char *retval;
 
-  /* Give a warning if the combination -m64-bit and -Aesa is used.  */
-  if (s390_arch_size == 64 && current_cpu < S390_OPCODE_Z900)
-    as_warn (_("The 64 bit file format is used without esame instructions."));
-
-  s390_cie_data_alignment = -s390_arch_size / 8;
-
-  /* Set the ELF flags if desired.  */
-  if (s390_flags)
-    bfd_set_private_flags (stdoutput, s390_flags);
-
-  /* Insert the opcode formats into a hash table.  */
-  s390_opformat_hash = hash_new ();
-
-  op_end = s390_opformats + s390_num_opformats;
-  for (op = s390_opformats; op < op_end; op++)
-    {
-      retval = hash_insert (s390_opformat_hash, op->name, (void *) op);
-      if (retval != (const char *) NULL)
-	{
-	  as_bad (_("Internal assembler error for instruction format %s"),
-		  op->name);
-	  dup_insn = TRUE;
-	}
-    }
+  if (s390_opcode_hash != NULL)
+    hash_die (s390_opcode_hash);
 
   /* Insert the opcodes into a hash table.  */
   s390_opcode_hash = hash_new ();
@@ -523,11 +516,50 @@ md_begin (void)
 
   if (dup_insn)
     abort ();
+}
+
+/* This function is called when the assembler starts up.  It is called
+   after the options have been parsed and the output file has been
+   opened.  */
+
+void
+md_begin (void)
+{
+  register const struct s390_opcode *op;
+  const struct s390_opcode *op_end;
+  bfd_boolean dup_insn = FALSE;
+  const char *retval;
+
+  /* Give a warning if the combination -m64-bit and -Aesa is used.  */
+  if (s390_arch_size == 64 && current_cpu < S390_OPCODE_Z900)
+    as_warn (_("The 64 bit file format is used without esame instructions."));
+
+  s390_cie_data_alignment = -s390_arch_size / 8;
+
+  /* Set the ELF flags if desired.  */
+  if (s390_flags)
+    bfd_set_private_flags (stdoutput, s390_flags);
+
+  /* Insert the opcode formats into a hash table.  */
+  s390_opformat_hash = hash_new ();
+
+  op_end = s390_opformats + s390_num_opformats;
+  for (op = s390_opformats; op < op_end; op++)
+    {
+      retval = hash_insert (s390_opformat_hash, op->name, (void *) op);
+      if (retval != (const char *) NULL)
+	{
+	  as_bad (_("Internal assembler error for instruction format %s"),
+		  op->name);
+	  dup_insn = TRUE;
+	}
+    }
+
+  s390_setup_opcodes ();
 
   record_alignment (text_section, 2);
   record_alignment (data_section, 2);
   record_alignment (bss_section, 2);
-
 }
 
 /* Called after all assembly has been done.  */
@@ -1755,6 +1787,72 @@ s390_literals (int ignore ATTRIBUTE_UNUS
   lpe_count = 0;
 }
 
+/* The .machine pseudo op allows to switch to a different CPU level in
+   the asm listing.  The current CPU setting can be stored on a stack
+   with .machine push and restored with .machined pop.  */
+
+static void
+s390_machine (int ignore ATTRIBUTE_UNUSED)
+{
+  char *cpu_string;
+#define MAX_HISTORY 100
+  static unsigned int *cpu_history;
+  static int curr_hist;
+
+  SKIP_WHITESPACE ();
+
+  if (*input_line_pointer == '"')
+    {
+      int len;
+      cpu_string = demand_copy_C_string (&len);
+    }
+  else
+    {
+      char c;
+      cpu_string = input_line_pointer;
+      c = get_symbol_end ();
+      cpu_string = xstrdup (cpu_string);
+      *input_line_pointer = c;
+    }
+
+  if (cpu_string != NULL)
+    {
+      unsigned int old_cpu = current_cpu;
+      unsigned int new_cpu;
+      char *p;
+
+      for (p = cpu_string; *p != 0; p++)
+	*p = TOLOWER (*p);
+
+      if (strcmp (cpu_string, "push") == 0)
+	{
+	  if (cpu_history == NULL)
+	    cpu_history = xmalloc (MAX_HISTORY * sizeof (*cpu_history));
+
+	  if (curr_hist >= MAX_HISTORY)
+	    as_bad (_(".machine stack overflow"));
+	  else
+	    cpu_history[curr_hist++] = current_cpu;
+	}
+      else if (strcmp (cpu_string, "pop") == 0)
+	{
+	  if (curr_hist <= 0)
+	    as_bad (_(".machine stack underflow"));
+	  else
+	    current_cpu = cpu_history[--curr_hist];
+	}
+      else if ((new_cpu = s390_parse_cpu (cpu_string)) != ~(unsigned int)0)
+	current_cpu = new_cpu;
+      else
+	as_bad (_("invalid machine `%s'"), cpu_string);
+
+      if (current_cpu != old_cpu)
+	s390_setup_opcodes ();
+    }
+
+  demand_empty_rest_of_line ();
+}
+
 char *
 md_atof (int type, char *litp, int *sizep)
 {
Index: gas/doc/c-s390.texi
===================================================================
--- gas/doc/c-s390.texi.orig
+++ gas/doc/c-s390.texi
@@ -862,6 +862,14 @@ ELF extension documentation @samp{ELF Ha
 @item .ltorg
 This directive causes the current contents of the literal pool to be
 dumped to the current location (@ref{s390 Literal Pool Entries}).
+
+@cindex @code{.machine} directive, s390
+@item .machine string
+This directive allows you to change the machine for which code is
+generated.  @code{string} may be any of the @code{-march=} selection options
+(without the -march=) enclosed in double quotes, @code{push}, or
+@code{pop}.  @code{.machine push} saves the currently selected
+cpu, which may be restored with @code{.machine pop}.
 @end table
 
 @node s390 Floating Point
Index: gas/testsuite/gas/s390/zarch-machine.d
===================================================================
--- /dev/null
+++ gas/testsuite/gas/s390/zarch-machine.d
@@ -0,0 +1,12 @@
+#name: s390x machine
+#objdump: -dr
+
+.*: +file format .*
+
+Disassembly of section .text:
+
+.* <foo>:
+.*:	e3 95 af ff 00 08 [ 	]*ag	%r9,4095\(%r5,%r10\)
+.*:	eb d6 65 b3 01 6a [ 	]*asi	5555\(%r6\),-42
+.*:	e3 95 af ff 00 18 [ 	]*agf	%r9,4095\(%r5,%r10\)
+.*:	07 07 [ 	]*nopr	%r7
Index: gas/testsuite/gas/s390/zarch-machine.s
===================================================================
--- /dev/null
+++ gas/testsuite/gas/s390/zarch-machine.s
@@ -0,0 +1,8 @@
+.text
+foo:
+	ag	%r9,4095(%r5,%r10)
+.machine push
+.machine z10
+	asi	5555(%r6),-42
+.machine pop
+	agf	%r9,4095(%r5,%r10)
Index: gas/testsuite/gas/s390/s390.exp
===================================================================
--- gas/testsuite/gas/s390/s390.exp.orig
+++ gas/testsuite/gas/s390/s390.exp
@@ -27,4 +27,5 @@ if [expr [istarget "s390-*-*"] ||  [ista
     run_dump_test "zarch-z196" "{as -m64} {as -march=z196}"
     run_dump_test "zarch-reloc" "{as -m64}"
     run_dump_test "zarch-operands" "{as -m64} {as -march=z9-109}"
+    run_dump_test "zarch-machine" "{as -m64} {as -march=z900}"
 }


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