mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-26 04:36:07 +00:00

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
57 lines
3.4 KiB
C
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;
|
|
}
|
|
|