Skip to content

Commit cc3d25b

Browse files
author
Melanie Blower
committed
[clang][patch] To solve PR26413, x86 interrupt routines may only call routines with no_saved_reg
Reviewed By: Aaron Ballman Differential Revision: https://reviews.llvm.org/D97764
1 parent b2bc0a3 commit cc3d25b

File tree

4 files changed

+39
-2
lines changed

4 files changed

+39
-2
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,9 @@ def err_anyx86_interrupt_attribute : Error<
293293
"a pointer as the first parameter|a %2 type as the second parameter}1">;
294294
def err_anyx86_interrupt_called : Error<
295295
"interrupt service routine cannot be called directly">;
296+
def err_anyx86_interrupt_regsave : Error<
297+
"interrupt service routine may only call a function"
298+
" with attribute 'no_caller_saved_registers'">;
296299
def warn_arm_interrupt_calling_convention : Warning<
297300
"call to function without interrupt attribute could clobber interruptee's VFP registers">,
298301
InGroup<Extra>;

clang/lib/Sema/SemaExpr.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6552,12 +6552,25 @@ ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
65526552
// so there's some risk when calling out to non-interrupt handler functions
65536553
// that the callee might not preserve them. This is easy to diagnose here,
65546554
// but can be very challenging to debug.
6555-
if (auto *Caller = getCurFunctionDecl())
6555+
// Likewise, X86 interrupt handlers may only call routines with attribute
6556+
// no_caller_saved_registers since there is no efficient way to
6557+
// save and restore the non-GPR state.
6558+
if (auto *Caller = getCurFunctionDecl()) {
65566559
if (Caller->hasAttr<ARMInterruptAttr>()) {
65576560
bool VFP = Context.getTargetInfo().hasFeature("vfp");
6558-
if (VFP && (!FDecl || !FDecl->hasAttr<ARMInterruptAttr>()))
6561+
if (VFP && (!FDecl || !FDecl->hasAttr<ARMInterruptAttr>())) {
65596562
Diag(Fn->getExprLoc(), diag::warn_arm_interrupt_calling_convention);
6563+
if (FDecl)
6564+
Diag(FDecl->getLocation(), diag::note_callee_decl) << FDecl;
6565+
}
6566+
}
6567+
if (Caller->hasAttr<AnyX86InterruptAttr>() &&
6568+
((!FDecl || !FDecl->hasAttr<AnyX86NoCallerSavedRegistersAttr>()))) {
6569+
Diag(Fn->getExprLoc(), diag::err_anyx86_interrupt_regsave);
6570+
if (FDecl)
6571+
Diag(FDecl->getLocation(), diag::note_callee_decl) << FDecl;
65606572
}
6573+
}
65616574

65626575
// Promote the function operand.
65636576
// We special-case function promotion here because we only allow promoting

clang/test/Sema/arm-interrupt-attr.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ __attribute__((interrupt)) void foo8() {}
1919
__attribute__((interrupt())) void foo9() {}
2020
__attribute__((interrupt(""))) void foo10() {}
2121

22+
#ifndef SOFT
23+
// expected-note@+2 {{'callee1' declared here}}
24+
#endif
2225
void callee1();
2326
__attribute__((interrupt("IRQ"))) void callee2();
2427
void caller1() {

clang/test/Sema/attr-x86-interrupt.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// RUN: %clang_cc1 -triple x86_64-pc-win32 -fsyntax-only -verify %s
44
// RUN: %clang_cc1 -triple i386-pc-win32 -fsyntax-only -verify %s
55
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnux32 -fsyntax-only -verify %s
6+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fsyntax-only -verify %s -DNOCALLERSAVE=1
67

78
struct a {
89
int b;
@@ -39,6 +40,23 @@ __attribute__((interrupt)) void foo6(float *a, int b) {}
3940
__attribute__((interrupt)) void foo7(int *a, unsigned b) {}
4041
__attribute__((interrupt)) void foo8(int *a) {}
4142

43+
#ifdef _LP64
44+
typedef unsigned long Arg2Type;
45+
#elif defined(__x86_64__)
46+
typedef unsigned long long Arg2Type;
47+
#else
48+
typedef unsigned int Arg2Type;
49+
#endif
50+
#ifndef NOCALLERSAVE
51+
__attribute__((no_caller_saved_registers))
52+
#else
53+
// expected-note@+3 {{'foo9' declared here}}
54+
// expected-error@+4 {{interrupt service routine may only call a function with attribute 'no_caller_saved_registers'}}
55+
#endif
56+
void foo9(int *a, Arg2Type b) {}
57+
__attribute__((interrupt)) void fooA(int *a, Arg2Type b) {
58+
foo9(a, b);
59+
}
4260
void g(void (*fp)(int *));
4361
int main(int argc, char **argv) {
4462
void *ptr = (void *)&foo7;

0 commit comments

Comments
 (0)