]> granicus.if.org Git - clang/commitdiff
Warn when calling a non interrupt function from an interrupt on ARM
authorJonathan Roelofs <jonathan@codesourcery.com>
Wed, 18 Jan 2017 15:31:11 +0000 (15:31 +0000)
committerJonathan Roelofs <jonathan@codesourcery.com>
Wed, 18 Jan 2017 15:31:11 +0000 (15:31 +0000)
The idea for this originated from a really tricky bug: ISRs on ARM don't
automatically save off the VFP regs, so if say, memcpy gets interrupted and the
ISR itself calls memcpy, the regs are left clobbered when the ISR is done.

https://reviews.llvm.org/D28820

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@292375 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaExpr.cpp
test/Sema/arm-interrupt-attr.c

index 03789d59dd14233d62d8bcd40c1ea511d5e6e893..e0a5073483d9c3f3668a3a6d1e57b8569f159022 100644 (file)
@@ -259,6 +259,9 @@ def err_anyx86_interrupt_attribute : Error<
   "a pointer as the first parameter|a %2 type as the second parameter}1">;
 def err_anyx86_interrupt_called : Error<
   "interrupt service routine cannot be called directly">;
+def warn_arm_interrupt_calling_convention : Warning<
+   "call to function without interrupt attribute could clobber interruptee's VFP registers">,
+   InGroup<Extra>;
 def warn_mips_interrupt_attribute : Warning<
    "MIPS 'interrupt' attribute only applies to functions that have "
    "%select{no parameters|a 'void' return type}0">,
index 7b404f40a769d1fbdb5c89823cb9faa8c4564d29..7d72b7ede82d30c7ee333fe262c26f89e73e282a 100644 (file)
@@ -5395,6 +5395,15 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
     return ExprError();
   }
 
+  // Interrupt handlers don't save off the VFP regs automatically on ARM,
+  // so there's some risk when calling out to non-interrupt handler functions
+  // that the callee might not preserve them. This is easy to diagnose here,
+  // but can be very challenging to debug.
+  if (auto *Caller = getCurFunctionDecl())
+    if (Caller->hasAttr<ARMInterruptAttr>())
+      if (!FDecl->hasAttr<ARMInterruptAttr>())
+        Diag(Fn->getExprLoc(), diag::warn_arm_interrupt_calling_convention);
+
   // Promote the function operand.
   // We special-case function promotion here because we only allow promoting
   // builtin functions to function pointers in the callee of a call.
index b9684f0b46c1e983ddacfdd09eb2e3ba8b004944..cd67278d944e8bd8f3c88b4ecab76e91258d1a74 100644 (file)
@@ -17,3 +17,14 @@ __attribute__((interrupt("UNDEF"))) void foo7() {}
 __attribute__((interrupt)) void foo8() {}
 __attribute__((interrupt())) void foo9() {}
 __attribute__((interrupt(""))) void foo10() {}
+
+void callee1();
+__attribute__((interrupt("IRQ"))) void callee2();
+void caller1() {
+  callee1();
+  callee2();
+}
+__attribute__((interrupt("IRQ"))) void caller2() {
+  callee1(); // expected-warning {{call to function without interrupt attribute could clobber interruptee's VFP registers}}
+  callee2();
+}