From 902cc293a01e649f45869d567e957cc303e44b96 Mon Sep 17 00:00:00 2001 From: Andreas Krebbel Date: Thu, 14 Apr 2011 11:11:33 +0000 Subject: [PATCH] 2011-04-14 Andreas Krebbel * 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-14 Andreas Krebbel * gas/s390/zarch-machine.s: New testcase. * gas/s390/zarch-machine.d: New testcase output. * gas/s390/s390.exp: Execute the new testcase. --- gas/ChangeLog | 13 ++ gas/config/tc-s390.c | 198 ++++++++++++++++++------- gas/doc/c-s390.texi | 11 ++ gas/testsuite/ChangeLog | 6 + gas/testsuite/gas/s390/s390.exp | 1 + gas/testsuite/gas/s390/zarch-machine.d | 12 ++ gas/testsuite/gas/s390/zarch-machine.s | 8 + 7 files changed, 199 insertions(+), 50 deletions(-) create mode 100644 gas/testsuite/gas/s390/zarch-machine.d create mode 100644 gas/testsuite/gas/s390/zarch-machine.s diff --git a/gas/ChangeLog b/gas/ChangeLog index 65bb3410e96..2c7f2f68bf7 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,16 @@ +2011-04-14 Andreas Krebbel + + * 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-12 H.J. Lu * config/tc-i386.c (i386_mach): Start error message with lower diff --git a/gas/config/tc-s390.c b/gas/config/tc-s390.c index 37c0e4d18cf..8fc66d8ebf8 100644 --- a/gas/config/tc-s390.c +++ b/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 unsigned 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 -1; +} + 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)-1) { 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_UNUSED) 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)-1) + 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) { diff --git a/gas/doc/c-s390.texi b/gas/doc/c-s390.texi index 0d629f9ae5b..79713277ca4 100644 --- a/gas/doc/c-s390.texi +++ b/gas/doc/c-s390.texi @@ -862,6 +862,17 @@ ELF extension documentation @samp{ELF Handling For Thread-Local Storage}. @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=), @code{push}, or @code{pop}. +@code{.machine push} saves the currently selected cpu, which may be +restored with @code{.machine pop}. Be aware that the cpu string has +to be put into double quotes in case it contains characters not +appropriate for identifiers. So you have to write @code{"z9-109"} +instead of just @code{z9-109}. @end table @node s390 Floating Point diff --git a/gas/testsuite/ChangeLog b/gas/testsuite/ChangeLog index 16abb0043d4..d3492aa87cc 100644 --- a/gas/testsuite/ChangeLog +++ b/gas/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2011-04-14 Andreas Krebbel + + * gas/s390/zarch-machine.s: New testcase. + * gas/s390/zarch-machine.d: New testcase output. + * gas/s390/s390.exp: Execute the new testcase. + 2011-04-13 Nick Clifton * gas/v850/v850e1.s: Add a insn using reg+offset addressing. diff --git a/gas/testsuite/gas/s390/s390.exp b/gas/testsuite/gas/s390/s390.exp index ec9805de5b0..dad828a0f26 100644 --- a/gas/testsuite/gas/s390/s390.exp +++ b/gas/testsuite/gas/s390/s390.exp @@ -27,4 +27,5 @@ if [expr [istarget "s390-*-*"] || [istarget "s390x-*-*"]] then { 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}" } diff --git a/gas/testsuite/gas/s390/zarch-machine.d b/gas/testsuite/gas/s390/zarch-machine.d new file mode 100644 index 00000000000..96a202dfb9d --- /dev/null +++ b/gas/testsuite/gas/s390/zarch-machine.d @@ -0,0 +1,12 @@ +#name: s390x machine +#objdump: -dr + +.*: +file format .* + +Disassembly of section .text: + +.* : +.*: 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 diff --git a/gas/testsuite/gas/s390/zarch-machine.s b/gas/testsuite/gas/s390/zarch-machine.s new file mode 100644 index 00000000000..f40a18c2220 --- /dev/null +++ b/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) -- 2.30.2