On Tue, May 10, 2016 at 1:02 PM, Sandra Loosemore <san...@codesourcery.com> wrote: > On 04/20/2016 07:42 AM, Koval, Julia wrote: >> >> diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi >> index a5a8b23..82de5bf 100644 >> --- a/gcc/doc/extend.texi >> +++ b/gcc/doc/extend.texi >> @@ -5263,6 +5263,83 @@ On x86-32 targets, the @code{stdcall} attribute >> causes the compiler to >> assume that the called function pops off the stack space used to >> pass arguments, unless it takes a variable number of arguments. >> >> +@item no_caller_saved_registers >> +@cindex @code{no_caller_saved_registers} function attribute, x86 >> +Use this attribute to indicate that the specified function has no >> +caller-saved registers. That is, all registers are callee-saved. >> +The compiler generates proper function entry and exit sequences to >> +save and restore any modified registers, except for the EFLAGS >> +register. If the compiler generates MPX, SSE, MMX or x87 instructions >> +in a function with @code{no_caller_saved_registers} attribute or >> +functions called from a function with @code{no_caller_saved_registers} >> +attribute may contain MPX, SSE, MMX or x87 instructions, the compiler >> +must save and restore the corresponding state. > > > I cannot parse the last sentence in this paragraph. How can the compiler > know whether called functions may contain those instructions? Plus, talking > about what the compiler must do seems too implementor-speaky for user > documentation. Maybe you mean something like "The compiler also saves and > restores state associated with MPX, SSE, MMX, and x87 instructions." ? > > I also think the documentation needs to give some hint about why a user > would want to put this attribute on a function. > >> + >> +@item interrupt >> +@cindex @code{interrupt} function attribute, x86 >> +Use this attribute to indicate that the specified function is an >> +interrupt handler. The compiler generates function >> +entry and exit sequences suitable for use in an interrupt handler when >> +this attribute is present. The @code{IRET} instruction, instead of the >> +@code{RET} instruction, is used to return from interrupt handlers. All >> +registers, except for the EFLAGS register which is restored by the >> +@code{IRET} instruction, are preserved by the compiler. If the >> +compiler generates MPX, SSE, MMX or x87 instructions in an interrupt >> +handler, or functions called from an interrupt handler may contain MPX, >> +SSE, MMX or x87 instructions, the compiler must save and restore the >> +corresponding state. > > > Similar problems here. > > From the further discussion that follows, it appears that you can use the > "interrupt" attribute on exception handlers as well, but the paragraph above > only mentions interrupt handlers. > >> + >> +Since the direction flag in the FLAGS register in interrupt handlers >> +is undetermined, cld instruction must be emitted in function prologue >> +if rep string instructions are used in interrupt handler or interrupt >> +handler isn't a leaf function. > > > Again, this sounds like implementor-speak, and there are grammatical errors > (noun/verb disagreement, missing articles). Do users of this attribute need > to know what instructions the compiler is emitting? We already say above > that it causes GCC to generate suitable entry and exit sequences. >
It was done on purpose since this document is also served as the spec for compiler implementers. Here is a patch to add -mgeneral-regs-only option to x86 backend. We can update spec for interrupt handle to recommend compiling interrupt handler with -mgeneral-regs-only option and add a note for compiler implementers. OK for trunk if there is no regression? -- H.J.
From d6f72979f077064c59ac83c8fe5e738ade732e96 Mon Sep 17 00:00:00 2001 From: "H.J. Lu" <hjl.to...@gmail.com> Date: Wed, 11 May 2016 09:49:33 -0700 Subject: [PATCH] Add -mgeneral-regs-only option X86 Linux kernel is compiled only with integer instructions. Currently, -mno-sse -mno-mmx -mno-sse2 -mno-3dnow -mno-avx -mno-80387 -mno-fp-ret-in-387 -mskip-rax-setup is used to compile kernel. If we add another non-integer feature, it has to be turned off. We can add a -mgeneral-regs-only option, similar to AArch64, to disable all non-integer features so that kernel doesn't need a long list and the same option will work for future compilers. It can also be used to compile interrupt handler. gcc/ PR target/70738 * common/config/i386/i386-common.c (OPTION_MASK_ISA_GENERAL_REGS_ONLY_UNSET): New. (ix86_handle_option): Disable MPX, MMX, SSE and x87 instructions for -mgeneral-regs-only. * config/i386/i386.c (ix86_option_override_internal): Don't enable x87 instructions if only the general registers are allowed. * config/i386/i386.opt: Add -mgeneral-regs-only. * doc/invoke.texi: Document -mgeneral-regs-only. gcc/testsuite/ PR target/70738 * gcc.target/i386/pr70738-1.c: Likewise. * gcc.target/i386/pr70738-2.c: Likewise. * gcc.target/i386/pr70738-3.c: Likewise. * gcc.target/i386/pr70738-4.c: Likewise. * gcc.target/i386/pr70738-5.c: Likewise. * gcc.target/i386/pr70738-6.c: Likewise. * gcc.target/i386/pr70738-7.c: Likewise. * gcc.target/i386/pr70738-8.c: Likewise. * gcc.target/i386/pr70738-9.c: Likewise. --- gcc/common/config/i386/i386-common.c | 20 ++++++++++++++++++++ gcc/config/i386/i386.c | 5 ++++- gcc/config/i386/i386.opt | 4 ++++ gcc/doc/invoke.texi | 8 +++++++- gcc/testsuite/gcc.target/i386/pr70738-1.c | 9 +++++++++ gcc/testsuite/gcc.target/i386/pr70738-2.c | 10 ++++++++++ gcc/testsuite/gcc.target/i386/pr70738-3.c | 11 +++++++++++ gcc/testsuite/gcc.target/i386/pr70738-4.c | 10 ++++++++++ gcc/testsuite/gcc.target/i386/pr70738-5.c | 16 ++++++++++++++++ gcc/testsuite/gcc.target/i386/pr70738-6.c | 10 ++++++++++ gcc/testsuite/gcc.target/i386/pr70738-7.c | 13 +++++++++++++ gcc/testsuite/gcc.target/i386/pr70738-8.c | 30 ++++++++++++++++++++++++++++++ gcc/testsuite/gcc.target/i386/pr70738-9.c | 23 +++++++++++++++++++++++ 13 files changed, 167 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/gcc.target/i386/pr70738-1.c create mode 100644 gcc/testsuite/gcc.target/i386/pr70738-2.c create mode 100644 gcc/testsuite/gcc.target/i386/pr70738-3.c create mode 100644 gcc/testsuite/gcc.target/i386/pr70738-4.c create mode 100644 gcc/testsuite/gcc.target/i386/pr70738-5.c create mode 100644 gcc/testsuite/gcc.target/i386/pr70738-6.c create mode 100644 gcc/testsuite/gcc.target/i386/pr70738-7.c create mode 100644 gcc/testsuite/gcc.target/i386/pr70738-8.c create mode 100644 gcc/testsuite/gcc.target/i386/pr70738-9.c diff --git a/gcc/common/config/i386/i386-common.c b/gcc/common/config/i386/i386-common.c index cc65c8c..b150c9e 100644 --- a/gcc/common/config/i386/i386-common.c +++ b/gcc/common/config/i386/i386-common.c @@ -223,6 +223,11 @@ along with GCC; see the file COPYING3. If not see #define OPTION_MASK_ISA_RDRND_UNSET OPTION_MASK_ISA_RDRND #define OPTION_MASK_ISA_F16C_UNSET OPTION_MASK_ISA_F16C +#define OPTION_MASK_ISA_GENERAL_REGS_ONLY_UNSET \ + (OPTION_MASK_ISA_MMX_UNSET \ + | OPTION_MASK_ISA_SSE_UNSET \ + | OPTION_MASK_ISA_MPX) + /* Implement TARGET_HANDLE_OPTION. */ bool @@ -236,6 +241,21 @@ ix86_handle_option (struct gcc_options *opts, switch (code) { + case OPT_mgeneral_regs_only: + if (value) + { + /* Disable MPX, MMX, SSE and x87 instructions if only the + general registers are allowed.. */ + opts->x_ix86_isa_flags + &= ~OPTION_MASK_ISA_GENERAL_REGS_ONLY_UNSET; + opts->x_ix86_isa_flags_explicit + |= OPTION_MASK_ISA_GENERAL_REGS_ONLY_UNSET; + opts->x_target_flags &= ~MASK_80387; + } + else + gcc_unreachable (); + return true; + case OPT_mmmx: if (value) { diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 9f62089..4d515d2 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -5331,7 +5331,10 @@ ix86_option_override_internal (bool main_args_p, && !(opts->x_ix86_isa_flags_explicit & OPTION_MASK_ISA_PKU)) opts->x_ix86_isa_flags |= OPTION_MASK_ISA_PKU; - if (!(opts_set->x_target_flags & MASK_80387)) + /* Don't enable x87 instructions if only the general registers + are allowed. */ + if (!(opts_set->x_target_flags & MASK_GENERAL_REGS_ONLY) + && !(opts_set->x_target_flags & MASK_80387)) { if (processor_alias_table[i].flags & PTA_NO_80387) opts->x_target_flags &= ~MASK_80387; diff --git a/gcc/config/i386/i386.opt b/gcc/config/i386/i386.opt index 36dd4bd..d12b29a 100644 --- a/gcc/config/i386/i386.opt +++ b/gcc/config/i386/i386.opt @@ -897,3 +897,7 @@ Enum(stack_protector_guard) String(global) Value(SSP_GLOBAL) mmitigate-rop Target Var(flag_mitigate_rop) Init(0) Attempt to avoid generating instruction sequences containing ret bytes. + +mgeneral-regs-only +Target Report RejectNegative Mask(GENERAL_REGS_ONLY) Save +Generate code which uses only the general registers. diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index a54a0af..bbb00fd 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -1171,7 +1171,7 @@ See RS/6000 and PowerPC Options. -msse2avx -mfentry -mrecord-mcount -mnop-mcount -m8bit-idiv @gol -mavx256-split-unaligned-load -mavx256-split-unaligned-store @gol -malign-data=@var{type} -mstack-protector-guard=@var{guard} @gol --mmitigate-rop} +-mmitigate-rop -mgeneral-regs-only} @emph{x86 Windows Options} @gccoptlist{-mconsole -mcygwin -mno-cygwin -mdll @gol @@ -24242,6 +24242,12 @@ opcodes, to mitigate against certain forms of attack. At the moment, this option is limited in what it can do and should not be relied on to provide serious protection. +@item -mgeneral-regs-only +@opindex mgeneral-regs-only +Generate code which uses only the general-purpose registers. This will +prevent the compiler from using floating-point, vector, mask and bound +registers, but will not impose any restrictions on the assembler. + @end table These @samp{-m} switches are supported in addition to the above diff --git a/gcc/testsuite/gcc.target/i386/pr70738-1.c b/gcc/testsuite/gcc.target/i386/pr70738-1.c new file mode 100644 index 0000000..19381c2 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr70738-1.c @@ -0,0 +1,9 @@ +/* { dg-do compile { target { ! ia32 } } } */ +/* { dg-options "-msse2 -mgeneral-regs-only" } */ + +typedef int int32x2_t __attribute__ ((__vector_size__ ((8)))); + +int32x2_t test (int32x2_t a, int32x2_t b) +{ /* { dg-error "SSE register return with SSE disabled" } */ + return a + b; +} diff --git a/gcc/testsuite/gcc.target/i386/pr70738-2.c b/gcc/testsuite/gcc.target/i386/pr70738-2.c new file mode 100644 index 0000000..8b90904 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr70738-2.c @@ -0,0 +1,10 @@ +/* { dg-do compile { target ia32 } } */ +/* { dg-options "-mmmx -mgeneral-regs-only" } */ + +typedef int int32x2_t __attribute__ ((__vector_size__ ((8)))); + +int32x2_t +test (int32x2_t a, int32x2_t b) /* { dg-warning "MMX vector argument without MMX enabled" } */ +{ /* { dg-warning "MMX vector return without MMX enabled" } */ + return a + b; +} diff --git a/gcc/testsuite/gcc.target/i386/pr70738-3.c b/gcc/testsuite/gcc.target/i386/pr70738-3.c new file mode 100644 index 0000000..1ac3adb --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr70738-3.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-msse2 -mgeneral-regs-only" } */ + +typedef int int32x4_t __attribute__ ((__vector_size__ ((16)))); +extern int32x4_t c; + +void +test (int32x4_t a, int32x4_t b) /* { dg-warning "SSE vector argument without SSE enabled" } */ +{ + c = a + b; +} diff --git a/gcc/testsuite/gcc.target/i386/pr70738-4.c b/gcc/testsuite/gcc.target/i386/pr70738-4.c new file mode 100644 index 0000000..c6d20f2 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr70738-4.c @@ -0,0 +1,10 @@ +/* { dg-do compile { target ia32 } } */ +/* { dg-options "-msse2 -mgeneral-regs-only" } */ + +typedef int int32x4_t __attribute__ ((__vector_size__ ((16)))); + +int32x4_t +test (int32x4_t a, int32x4_t b) /* { dg-warning "SSE vector argument without SSE enabled" } */ +{ /* { dg-warning "SSE vector return without SSE enabled" } */ + return a + b; +} diff --git a/gcc/testsuite/gcc.target/i386/pr70738-5.c b/gcc/testsuite/gcc.target/i386/pr70738-5.c new file mode 100644 index 0000000..8b43809 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr70738-5.c @@ -0,0 +1,16 @@ +/* { dg-do compile { target { ! ia32 } } } */ +/* { dg-options "-msse2 -mgeneral-regs-only" } */ + +#include <stdarg.h> + +typedef int int32x2_t __attribute__ ((__vector_size__ ((8)))); + +int +test (int i, ...) +{ + va_list argp; + va_start (argp, i); + int32x2_t x = (int32x2_t) {0, 1}; + x += va_arg (argp, int32x2_t); /* { dg-error "SSE register argument with SSE disabled" } */ + return x[0] + x[1]; +} diff --git a/gcc/testsuite/gcc.target/i386/pr70738-6.c b/gcc/testsuite/gcc.target/i386/pr70738-6.c new file mode 100644 index 0000000..3bccabb --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr70738-6.c @@ -0,0 +1,10 @@ +/* { dg-do compile { target { ! ia32 } } } */ +/* { dg-options "-msse2 -mgeneral-regs-only" } */ + +extern float a, b, c; + +void +foo (void) +{ + c = a * b; /* { dg-error "SSE register return with SSE disabled" } */ +} diff --git a/gcc/testsuite/gcc.target/i386/pr70738-7.c b/gcc/testsuite/gcc.target/i386/pr70738-7.c new file mode 100644 index 0000000..2e5b49f --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr70738-7.c @@ -0,0 +1,13 @@ +/* { dg-do compile { target ia32 } } */ +/* { dg-options "-msse2 -mgeneral-regs-only" } */ + +extern float a, b, c; + +void +foo (void) +{ + c = a * b; +} + +/* { dg-final { scan-assembler-not "mulss" } } */ +/* { dg-final { scan-assembler "call\[ \t\]__mulsf3" } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr70738-8.c b/gcc/testsuite/gcc.target/i386/pr70738-8.c new file mode 100644 index 0000000..0740460 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr70738-8.c @@ -0,0 +1,30 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -mgeneral-regs-only" } */ + +extern void abort (); + +int +dec (int a, int b) +{ + return a + b; +} + +int +cal (int a, int b) +{ + int sum1 = a * b; + int sum2 = a / b; + int sum = dec (sum1, sum2); + return a + b + sum + sum1 + sum2; +} + +int +main (int argc, char **argv) +{ + int ret = cal (2, 1); + + if (ret != 11) + abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/i386/pr70738-9.c b/gcc/testsuite/gcc.target/i386/pr70738-9.c new file mode 100644 index 0000000..c71f0b0 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr70738-9.c @@ -0,0 +1,23 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -mgeneral-regs-only" } */ + +extern void abort (); + +int +cal (int a, int b) +{ + int sum = a + b; + int sum1 = a * b; + return (a + b + sum + sum1); +} + +int +main (int argc, char **argv) +{ + int ret = cal (1, 2); + + if (ret != 8) + abort (); + + return 0; +} -- 2.5.5