llvm-project/clang/test/Sema/attr-x86-interrupt.c
Antonio Abbatangelo fa1dc06a1b [clang][X86] Update excessive register save diagnostic to more closely follow the interrupt attribute spec
The original diagnostic does not cover all cases according to my reading
of the spec.

For the interrupt attribute, the spec indicates that if the compiler
does not support saving SSE, MMX, or x87 then the function should
be compiled with '-mgeneral-regs-only' (GCC requires this).
Alternatively, calling functions with the `no_caller_saved_registers`
attribute will not clobber state and can be done without disabling
these features.

The warning as implemented in upstream only detects the latter case but
does not consider that disabling the above features also solves the issue
of these register saves being undesirable due to inefficiency.

For the no_caller_saved_registers attribute, the interrupt spec also
indicates that in the absence of saving SSE, MMX and x87 state, these
functions should be compiled with '-mgeneral-regs-only' (also required
by GCC). It does not make any statements about calling other functions
with the attribute, but by extension the result is the same as with the
interrupt attribute (in clang, at least).

This patch handles the remaining cases by adjusting the diagnostic to:

1. Not be shown if the function is compiled without the SSE, MMX or x87
   features enabled (i.e. with '-mgeneral-regs-only')
2. Also be shown for functions with the 'no_caller_saved_registers'
   attribute
3. In addition to advising that the function should only call functions
   with the `no_caller_saved_registers` attribute, the text also suggests
   compiling with `-mgeneral-regs-only` as an alternative.

The interrupt spec is available at https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=5ed3cc7b66af4758f7849ed6f65f4365be8223be
and was taken from the issue that resulted in this diagnostic being
added (#26787)

Reviewed By: pengfei

Differential Revision: https://reviews.llvm.org/D159068
2023-08-30 11:52:04 +08:00

57 lines
3.4 KiB
C

// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fsyntax-only -verify %s
// RUN: %clang_cc1 -triple i386-unknown-linux-gnu -fsyntax-only -verify %s
// RUN: %clang_cc1 -triple x86_64-pc-win32 -fsyntax-only -verify %s
// RUN: %clang_cc1 -triple i386-pc-win32 -fsyntax-only -verify %s
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnux32 -fsyntax-only -verify %s
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fsyntax-only -verify %s -DNOCALLERSAVE=1
struct a {
int b;
};
struct a test __attribute__((interrupt)); // expected-warning {{'interrupt' attribute only applies to non-K&R-style functions}}
__attribute__((interrupt)) int foo1(void) { return 0; } // expected-error-re {{{{(x86|x86-64)}} 'interrupt' attribute only applies to functions that have a 'void' return type}}
__attribute__((interrupt)) void foo2(void) {} // expected-error-re {{{{(x86|x86-64)}} 'interrupt' attribute only applies to functions that have only a pointer parameter optionally followed by an integer parameter}}
__attribute__((interrupt)) void foo3(void *a, unsigned b, int c) {} // expected-error-re {{{{(x86|x86-64)}} 'interrupt' attribute only applies to functions that have only a pointer parameter optionally followed by an integer parameter}}
__attribute__((interrupt)) void foo4(int a) {} // expected-error-re {{{{(x86|x86-64)}} 'interrupt' attribute only applies to functions that have a pointer as the first parameter}}
#ifdef _LP64
// expected-error-re@+6 {{{{(x86|x86-64)}} 'interrupt' attribute only applies to functions that have a 'unsigned long' type as the second parameter}}
#elif defined(__x86_64__)
// expected-error-re@+4 {{{{(x86|x86-64)}} 'interrupt' attribute only applies to functions that have a 'unsigned long long' type as the second parameter}}
#else
// expected-error-re@+2 {{{{(x86|x86-64)}} 'interrupt' attribute only applies to functions that have a 'unsigned int' type as the second parameter}}
#endif
__attribute__((interrupt)) void foo5(void *a, float b) {}
#ifdef _LP64
// expected-error-re@+6 {{{{(x86|x86-64)}} 'interrupt' attribute only applies to functions that have a 'unsigned long' type as the second parameter}}
#elif defined(__x86_64__)
// expected-error-re@+4 {{{{(x86|x86-64)}} 'interrupt' attribute only applies to functions that have a 'unsigned long long' type as the second parameter}}
#else
// expected-error-re@+2 {{{{(x86|x86-64)}} 'interrupt' attribute only applies to functions that have a 'unsigned int' type as the second parameter}}
#endif
__attribute__((interrupt)) void foo6(float *a, int b) {}
#ifdef _LP64
// expected-error-re@+4 {{{{(x86|x86-64)}} 'interrupt' attribute only applies to functions that have a 'unsigned long' type as the second parameter}}
#elif defined(__x86_64__)
// expected-error-re@+2 {{{{(x86|x86-64)}} 'interrupt' attribute only applies to functions that have a 'unsigned long long' type as the second parameter}}
#endif
__attribute__((interrupt)) void foo7(int *a, unsigned b) {}
__attribute__((interrupt)) void foo8(int *a) {}
void g(void (*fp)(int *));
int main(int argc, char **argv) {
void *ptr = (void *)&foo7;
g(foo8);
(void)ptr;
#ifndef __x86_64__
// expected-error@+2 {{interrupt service routine cannot be called directly}}
#endif
foo7((int *)argv, argc);
foo8((int *)argv); // expected-error {{interrupt service routine cannot be called directly}}
return 0;
}