This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
PATCH: PR target/70738: Add -mgeneral-regs-only option
- From: "H.J. Lu" <hjl dot tools at gmail dot com>
- To: Sandra Loosemore <sandra at codesourcery dot com>
- Cc: "Koval, Julia" <julia dot koval at intel dot com>, "gcc-patches at gcc dot gnu dot org" <gcc-patches at gcc dot gnu dot org>, "Lu, Hongjiu" <hongjiu dot lu at intel dot com>, "vaalfreja at gmail dot com" <vaalfreja at gmail dot com>, "ubizjak at gmail dot com" <ubizjak at gmail dot com>, "law at redhat dot com" <law at redhat dot com>, "Zamyatin, Igor" <igor dot zamyatin at intel dot com>
- Date: Wed, 11 May 2016 10:02:04 -0700
- Subject: PATCH: PR target/70738: Add -mgeneral-regs-only option
- Authentication-results: sourceware.org; auth=none
On Tue, May 10, 2016 at 1:02 PM, Sandra Loosemore
<sandra@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.tools@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