diff options
author | Andreas Krebbel <Andreas.Krebbel@de.ibm.com> | 2011-04-14 11:11:33 +0000 |
---|---|---|
committer | Andreas Krebbel <Andreas.Krebbel@de.ibm.com> | 2011-04-14 11:11:33 +0000 |
commit | 902cc293a01e649f45869d567e957cc303e44b96 (patch) | |
tree | 84ae13cbc8b8ffa3e56f6e4682d8f44ba6a7a872 /gas/config | |
parent | ba770c9cff8f08be74bf4b5028d060229086e9c4 (diff) | |
download | gdb-902cc293a01e649f45869d567e957cc303e44b96.zip gdb-902cc293a01e649f45869d567e957cc303e44b96.tar.gz gdb-902cc293a01e649f45869d567e957cc303e44b96.tar.bz2 |
2011-04-14 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-14 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.
Diffstat (limited to 'gas/config')
-rw-r--r-- | gas/config/tc-s390.c | 198 |
1 files changed, 148 insertions, 50 deletions
diff --git a/gas/config/tc-s390.c b/gas/config/tc-s390.c index 37c0e4d..8fc66d8 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) { |