From: Jan Beulich Date: Wed, 6 Jul 2022 07:22:47 +0000 (+0200) Subject: x86: introduce a state stack for .arch X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=f68697e82319687871943f949078ed334f188211;p=binutils-gdb.git x86: introduce a state stack for .arch When using just slightly non-trivial combinations of .arch, it can be quite useful to be able to go back to prior state without needing to re-invoke perhaps many earlier directives and without needing to invoke perhaps many "negative" ones. Like some other architectures allow saving (pushing) and restoring (popping) present/prior state. For now require the same .code to be in effect for ".arch pop" that was in effect for the corresponding ".arch push". Also change the global "no_cond_jump_promotion" to be bool, to match the new struct field. --- diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c index c11f0529141..d915b15a6b2 100644 --- a/gas/config/tc-i386.c +++ b/gas/config/tc-i386.c @@ -788,7 +788,7 @@ i386_cpu_flags cpu_arch_isa_flags; /* If set, conditional jumps are not automatically promoted to handle larger than a byte offset. */ -static unsigned int no_cond_jump_promotion = 0; +static bool no_cond_jump_promotion = false; /* Encode SSE instructions with VEX prefix. */ static unsigned int sse2avx; @@ -2660,6 +2660,20 @@ extend_cpu_sub_arch_name (const char *name) static void set_cpu_arch (int dummy ATTRIBUTE_UNUSED) { + typedef struct arch_stack_entry + { + const struct arch_stack_entry *prev; + const char *name; + char *sub_name; + i386_cpu_flags flags; + i386_cpu_flags isa_flags; + enum processor_type isa; + enum flag_code flag_code; + char stackop_size; + bool no_cond_jump_promotion; + } arch_stack_entry; + static const arch_stack_entry *arch_stack_top; + SKIP_WHITESPACE (); if (!is_end_of_line[(unsigned char) *input_line_pointer]) @@ -2703,6 +2717,67 @@ set_cpu_arch (int dummy ATTRIBUTE_UNUSED) j = ARRAY_SIZE (cpu_arch) + 1; } } + else if (strcmp (string, "push") == 0) + { + arch_stack_entry *top = XNEW (arch_stack_entry); + + top->name = cpu_arch_name; + if (cpu_sub_arch_name) + top->sub_name = xstrdup (cpu_sub_arch_name); + else + top->sub_name = NULL; + top->flags = cpu_arch_flags; + top->isa = cpu_arch_isa; + top->isa_flags = cpu_arch_isa_flags; + top->flag_code = flag_code; + top->stackop_size = stackop_size; + top->no_cond_jump_promotion = no_cond_jump_promotion; + + top->prev = arch_stack_top; + arch_stack_top = top; + + (void) restore_line_pointer (e); + demand_empty_rest_of_line (); + return; + } + else if (strcmp (string, "pop") == 0) + { + const arch_stack_entry *top = arch_stack_top; + + if (!top) + as_bad (_(".arch stack is empty")); + else if (top->flag_code != flag_code + || top->stackop_size != stackop_size) + { + static const unsigned int bits[] = { + [CODE_16BIT] = 16, + [CODE_32BIT] = 32, + [CODE_64BIT] = 64, + }; + + as_bad (_("this `.arch pop' requires `.code%u%s' to be in effect"), + bits[top->flag_code], + top->stackop_size == LONG_MNEM_SUFFIX ? "gcc" : ""); + } + else + { + arch_stack_top = top->prev; + + cpu_arch_name = top->name; + free (cpu_sub_arch_name); + cpu_sub_arch_name = top->sub_name; + cpu_arch_flags = top->flags; + cpu_arch_isa = top->isa; + cpu_arch_isa_flags = top->isa_flags; + no_cond_jump_promotion = top->no_cond_jump_promotion; + + XDELETE (top); + } + + (void) restore_line_pointer (e); + demand_empty_rest_of_line (); + return; + } for (; j < ARRAY_SIZE (cpu_arch); j++) { @@ -13660,6 +13735,10 @@ show_arch (FILE *stream, int ext, int check) { p = output_message (stream, p, message, start, &left, STRING_COMMA_LEN ("default")); + p = output_message (stream, p, message, start, &left, + STRING_COMMA_LEN ("push")); + p = output_message (stream, p, message, start, &left, + STRING_COMMA_LEN ("pop")); } for (j = 0; j < ARRAY_SIZE (cpu_arch); j++) diff --git a/gas/doc/c-i386.texi b/gas/doc/c-i386.texi index 95fd8ec9dc9..c4a39670146 100644 --- a/gas/doc/c-i386.texi +++ b/gas/doc/c-i386.texi @@ -1504,7 +1504,7 @@ directive enables a warning when gas detects an instruction that is not supported on the CPU specified. The choices for @var{cpu_type} are: @multitable @columnfractions .20 .20 .20 .20 -@item @samp{default} +@item @samp{default} @tab @samp{push} @tab @samp{pop} @item @samp{i8086} @tab @samp{i186} @tab @samp{i286} @tab @samp{i386} @item @samp{i486} @tab @samp{i586} @tab @samp{i686} @tab @samp{pentium} @item @samp{pentiumpro} @tab @samp{pentiumii} @tab @samp{pentiumiii} @tab @samp{pentium4} diff --git a/gas/testsuite/gas/i386/arch-stk.l b/gas/testsuite/gas/i386/arch-stk.l new file mode 100644 index 00000000000..4b774cc6dd7 --- /dev/null +++ b/gas/testsuite/gas/i386/arch-stk.l @@ -0,0 +1,43 @@ +.*: Assembler messages: +.*:3: Error:.*`cmovl'.* +.*:10: Error:.*`cmovg'.* +.*:17: Error:.*`cmovz'.* +.*:21: Error:.*`\.arch pop'.*`\.code32'.* +.*:28: Error:.*`\.arch pop'.*`\.code16gcc'.* +.*:32: Error:.*\.arch.*empty.* +GAS LISTING .* + + +[ ]*[0-9]*[ ]+\.text +[ ]*[0-9]*[ ]+start: +[ ]*[0-9]*[ ]+cmovl %eax, %ecx +[ ]*[0-9]*[ ]* +[ ]*[0-9]*[ ]+\.arch push +[ ]*[0-9]*[ ]+\.arch default +[ ]*[0-9]*[ ]+\?\?\?\? 0F4DC8[ ]+cmovnl %eax, %ecx +[ ]*[0-9]*[ ]* +[ ]*[0-9]*[ ]+\.arch pop +[ ]*[0-9]*[ ]+cmovg %eax, %ecx +[ ]*[0-9]*[ ]* +[ ]*[0-9]*[ ]+\.arch push +[ ]*[0-9]*[ ]+\.arch \.cmov +[ ]*[0-9]*[ ]+\?\?\?\? 0F4EC8[ ]+cmovng %eax, %ecx +[ ]*[0-9]*[ ]* +[ ]*[0-9]*[ ]+\.arch pop +[ ]*[0-9]*[ ]+cmovz %eax, %ecx +[ ]*[0-9]*[ ]* +[ ]*[0-9]*[ ]+\.arch push +[ ]*[0-9]*[ ]+\.code16 +[ ]*[0-9]*[ ]+\.arch pop +[ ]*[0-9]*[ ]+\.code32 +[ ]*[0-9]*[ ]+\.arch pop +[ ]*[0-9]*[ ]* +[ ]*[0-9]*[ ]+\.code16gcc +[ ]*[0-9]*[ ]+\.arch push +[ ]*[0-9]*[ ]+\.code32 +[ ]*[0-9]*[ ]+\.arch pop +[ ]*[0-9]*[ ]+\.code16gcc +[ ]*[0-9]*[ ]+\.arch pop +[ ]*[0-9]*[ ]* +[ ]*[0-9]*[ ]+\.arch pop +#pass diff --git a/gas/testsuite/gas/i386/arch-stk.s b/gas/testsuite/gas/i386/arch-stk.s new file mode 100644 index 00000000000..3e7286dac31 --- /dev/null +++ b/gas/testsuite/gas/i386/arch-stk.s @@ -0,0 +1,34 @@ + .text +start: + cmovl %eax, %ecx + + .arch push + .arch default + cmovnl %eax, %ecx + + .arch pop + cmovg %eax, %ecx + + .arch push + .arch .cmov + cmovng %eax, %ecx + + .arch pop + cmovz %eax, %ecx + + .arch push + .code16 + .arch pop + .code32 + .arch pop + + .code16gcc + .arch push + .code32 + .arch pop + .code16gcc + .arch pop + + .arch pop + + .end diff --git a/gas/testsuite/gas/i386/i386.exp b/gas/testsuite/gas/i386/i386.exp index de4eb1cfba5..c7822c4c9ba 100644 --- a/gas/testsuite/gas/i386/i386.exp +++ b/gas/testsuite/gas/i386/i386.exp @@ -206,6 +206,7 @@ if [gas_32_check] then { run_dump_test "arch-13" run_dump_test "arch-14" run_list_test "arch-dflt" "-march=generic32 -al" + run_list_test "arch-stk" "-march=generic32 -al" run_dump_test "8087" run_dump_test "287" run_dump_test "387"