r257867 - [X86] Support 'interrupt' attribute for x86

Alexey Bataev via cfe-commits cfe-commits at lists.llvm.org
Thu Jan 14 20:06:31 PST 2016


Author: abataev
Date: Thu Jan 14 22:06:31 2016
New Revision: 257867

URL: http://llvm.org/viewvc/llvm-project?rev=257867&view=rev
Log:
[X86] Support 'interrupt' attribute for x86
This attribute may be attached to a function definition and instructs the backend to generate appropriate function entry/exit code so that
it can be used directly as an interrupt handler.
The IRET instruction, instead of the RET instruction, is used to return from interrupt or exception handlers. All registers, except for the EFLAGS register which is restored by the IRET instruction, are preserved by the compiler.
Any interruptible-without-stack-switch code must be compiled with -mno-red-zone since interrupt handlers can and will, because of the hardware design, touch
the red zone.

interrupt handler must be declared with a mandatory pointer argument:
struct interrupt_frame;

__attribute__ ((interrupt))
void f (struct interrupt_frame *frame) {
    ...
}
and user must properly define the structure the pointer pointing to.

exception handler: 

The exception handler is very similar to the interrupt handler with a different mandatory function signature:
#ifdef __x86_64__
typedef unsigned long long int uword_t;
#else
typedef unsigned int uword_t;
#endif

struct interrupt_frame;

__attribute__ ((interrupt))
void f (struct interrupt_frame *frame, uword_t error_code) {
    ...
}
and compiler pops the error code off stack before the IRET instruction.

The exception handler should only be used for exceptions which push an error code and all other exceptions must use the interrupt handler.
The system will crash if the wrong handler is used.
Differential Revision: http://reviews.llvm.org/D15709

Added:
    cfe/trunk/test/CodeGen/attr-x86-interrupt.c
    cfe/trunk/test/CodeGenCXX/attr-x86-interrupt.cpp
    cfe/trunk/test/Sema/attr-x86-interrupt.c
    cfe/trunk/test/SemaCXX/attr-x86-interrupt.cpp
Modified:
    cfe/trunk/include/clang/Basic/Attr.td
    cfe/trunk/include/clang/Basic/AttrDocs.td
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/CodeGen/TargetInfo.cpp
    cfe/trunk/lib/Sema/SemaDeclAttr.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp

Modified: cfe/trunk/include/clang/Basic/Attr.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=257867&r1=257866&r2=257867&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Attr.td (original)
+++ cfe/trunk/include/clang/Basic/Attr.td Thu Jan 14 22:06:31 2016
@@ -252,6 +252,7 @@ def TargetARM : TargetArch<["arm", "thum
 def TargetMips : TargetArch<["mips", "mipsel"]>;
 def TargetMSP430 : TargetArch<["msp430"]>;
 def TargetX86 : TargetArch<["x86"]>;
+def TargetAnyX86 : TargetArch<["x86", "x86_64"]>;
 def TargetWindows : TargetArch<["x86", "x86_64", "arm", "thumb"]> {
   let OSes = ["Win32"];
 }
@@ -426,8 +427,8 @@ def Annotate : InheritableParamAttr {
 }
 
 def ARMInterrupt : InheritableAttr, TargetSpecificAttr<TargetARM> {
-  // NOTE: If you add any additional spellings, MSP430Interrupt's and
-  // MipsInterrupt's spellings must match.
+  // NOTE: If you add any additional spellings, MSP430Interrupt's,
+  // MipsInterrupt's and AnyX86Interrupt's spellings must match.
   let Spellings = [GNU<"interrupt">];
   let Args = [EnumArgument<"Interrupt", "InterruptType",
                            ["IRQ", "FIQ", "SWI", "ABORT", "UNDEF", ""],
@@ -845,8 +846,8 @@ def MSABI : InheritableAttr {
 }
 
 def MSP430Interrupt : InheritableAttr, TargetSpecificAttr<TargetMSP430> {
-  // NOTE: If you add any additional spellings, ARMInterrupt's and
-  // MipsInterrupt's spellings must match.
+  // NOTE: If you add any additional spellings, ARMInterrupt's, MipsInterrupt's
+  // and AnyX86Interrupt's spellings must match.
   let Spellings = [GNU<"interrupt">];
   let Args = [UnsignedArgument<"Number">];
   let ParseKind = "Interrupt";
@@ -861,8 +862,8 @@ def Mips16 : InheritableAttr, TargetSpec
 }
 
 def MipsInterrupt : InheritableAttr, TargetSpecificAttr<TargetMips> {
-  // NOTE: If you add any additional spellings, ARMInterrupt's and
-  // MSP430Interrupt's spellings must match.
+  // NOTE: If you add any additional spellings, ARMInterrupt's,
+  // MSP430Interrupt's and AnyX86Interrupt's spellings must match.
   let Spellings = [GNU<"interrupt">];
   let Subjects = SubjectList<[Function]>;
   let Args = [EnumArgument<"Interrupt", "InterruptType",
@@ -1527,6 +1528,16 @@ def WeakRef : InheritableAttr {
   let Documentation = [Undocumented];
 }
 
+def AnyX86Interrupt : InheritableAttr, TargetSpecificAttr<TargetAnyX86> {
+  // NOTE: If you add any additional spellings, ARMInterrupt's,
+  // MSP430Interrupt's and MipsInterrupt's spellings must match.
+  let Spellings = [GNU<"interrupt">];
+  let Subjects = SubjectList<[HasFunctionProto]>;
+  let ParseKind = "Interrupt";
+  let HasCustomParsing = 1;
+  let Documentation = [AnyX86InterruptDocs];
+}
+
 def X86ForceAlignArgPointer : InheritableAttr, TargetSpecificAttr<TargetX86> {
   let Spellings = [GNU<"force_align_arg_pointer">];
   // Technically, this appertains to a FunctionDecl, but the target-specific

Modified: cfe/trunk/include/clang/Basic/AttrDocs.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/AttrDocs.td?rev=257867&r1=257866&r2=257867&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/AttrDocs.td (original)
+++ cfe/trunk/include/clang/Basic/AttrDocs.td Thu Jan 14 22:06:31 2016
@@ -1859,3 +1859,56 @@ Marking virtual functions as ``disable_t
 
   }];
 }
+
+def AnyX86InterruptDocs : Documentation {
+  let Category = DocCatFunction;
+  let Content = [{
+Clang supports the GNU style ``__attribute__((interrupt))`` attribute on
+x86/x86-64 targets.The compiler generates function entry and exit sequences
+suitable for use in an interrupt handler when this attribute is present.
+The 'IRET' instruction, instead of the 'RET' instruction, is used to return
+from interrupt or exception handlers.  All registers, except for the EFLAGS
+register which is restored by the 'IRET' instruction, are preserved by the
+compiler.
+
+Any interruptible-without-stack-switch code must be compiled with
+-mno-red-zone since interrupt handlers can and will, because of the
+hardware design, touch the red zone.
+
+1. interrupt handler must be declared with a mandatory pointer argument:
+
+  .. code-block:: c
+
+    struct interrupt_frame
+    {
+      uword_t ip;
+      uword_t cs;
+      uword_t flags;
+      uword_t sp;
+      uword_t ss;
+    };
+
+    __attribute__ ((interrupt))
+    void f (struct interrupt_frame *frame) {
+      ...
+    }
+
+2. exception handler:
+
+  The exception handler is very similar to the interrupt handler with
+  a different mandatory function signature:
+
+  .. code-block:: c
+
+    __attribute__ ((interrupt))
+    void f (struct interrupt_frame *frame, uword_t error_code) {
+      ...
+    }
+
+  and compiler pops 'ERROR_CODE' off stack before the 'IRET' instruction.
+
+  The exception handler should only be used for exceptions which push an
+  error code and all other exceptions must use the interrupt handler.
+  The system will crash if the wrong handler is used.
+  }];
+}

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=257867&r1=257866&r2=257867&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Jan 14 22:06:31 2016
@@ -254,6 +254,13 @@ def err_bad_variable_name : Error<
 def err_bad_parameter_name : Error<
   "%0 cannot be the name of a parameter">;
 def err_parameter_name_omitted : Error<"parameter name omitted">;
+def err_anyx86_interrupt_attribute : Error<
+  "%select{x86|x86-64}0 'interrupt' attribute only applies to functions that "
+  "have %select{a 'void' return type|"
+  "only a pointer parameter optionally followed by an integer parameter|"
+  "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_mips_interrupt_attribute : Warning<
    "MIPS 'interrupt' attribute only applies to functions that have "
    "%select{no parameters|a 'void' return type}0">,

Modified: cfe/trunk/lib/CodeGen/TargetInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/TargetInfo.cpp?rev=257867&r1=257866&r2=257867&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/TargetInfo.cpp (original)
+++ cfe/trunk/lib/CodeGen/TargetInfo.cpp Thu Jan 14 22:06:31 2016
@@ -1609,6 +1609,10 @@ void X86_32TargetCodeGenInfo::setTargetA
                                               llvm::AttributeSet::FunctionIndex,
                                               B));
     }
+    if (FD->hasAttr<AnyX86InterruptAttr>()) {
+      llvm::Function *Fn = cast<llvm::Function>(GV);
+      Fn->setCallingConv(llvm::CallingConv::X86_INTR);
+    }
   }
 }
 
@@ -1914,6 +1918,16 @@ public:
             ('T' << 24);
     return llvm::ConstantInt::get(CGM.Int32Ty, Sig);
   }
+
+  void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
+                           CodeGen::CodeGenModule &CGM) const override {
+    if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) {
+      if (FD->hasAttr<AnyX86InterruptAttr>()) {
+        llvm::Function *Fn = cast<llvm::Function>(GV);
+        Fn->setCallingConv(llvm::CallingConv::X86_INTR);
+      }
+    }
+  }
 };
 
 class PS4TargetCodeGenInfo : public X86_64TargetCodeGenInfo {
@@ -2031,6 +2045,13 @@ void WinX86_64TargetCodeGenInfo::setTarg
                                             CodeGen::CodeGenModule &CGM) const {
   TargetCodeGenInfo::setTargetAttributes(D, GV, CGM);
 
+  if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) {
+    if (FD->hasAttr<AnyX86InterruptAttr>()) {
+      llvm::Function *Fn = cast<llvm::Function>(GV);
+      Fn->setCallingConv(llvm::CallingConv::X86_INTR);
+    }
+  }
+
   addStackProbeSizeTargetAttribute(D, GV, CGM);
 }
 }

Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=257867&r1=257866&r2=257867&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Thu Jan 14 22:06:31 2016
@@ -4570,17 +4570,90 @@ static void handleMipsInterruptAttr(Sema
       Attr.getLoc(), S.Context, Kind, Attr.getAttributeSpellingListIndex()));
 }
 
+static void handleAnyX86InterruptAttr(Sema &S, Decl *D,
+                                      const AttributeList &Attr) {
+  // Semantic checks for a function with the 'interrupt' attribute.
+  // a) Must be a function.
+  // b) Must have the 'void' return type.
+  // c) Must take 1 or 2 arguments.
+  // d) The 1st argument must be a pointer.
+  // e) The 2nd argument (if any) must be an unsigned integer.
+  if (!isFunctionOrMethod(D) || !hasFunctionProto(D) || isInstanceMethod(D) ||
+      CXXMethodDecl::isStaticOverloadedOperator(
+          cast<NamedDecl>(D)->getDeclName().getCXXOverloadedOperator())) {
+    S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+        << Attr.getName() << ExpectedFunctionWithProtoType;
+    return;
+  }
+  // Interrupt handler must have void return type.
+  if (!getFunctionOrMethodResultType(D)->isVoidType()) {
+    S.Diag(getFunctionOrMethodResultSourceRange(D).getBegin(),
+           diag::err_anyx86_interrupt_attribute)
+        << (S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86
+                ? 0
+                : 1)
+        << 0;
+    return;
+  }
+  // Interrupt handler must have 1 or 2 parameters.
+  unsigned NumParams = getFunctionOrMethodNumParams(D);
+  if (NumParams < 1 || NumParams > 2) {
+    S.Diag(D->getLocStart(), diag::err_anyx86_interrupt_attribute)
+        << (S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86
+                ? 0
+                : 1)
+        << 1;
+    return;
+  }
+  // The first argument must be a pointer.
+  if (!getFunctionOrMethodParamType(D, 0)->isPointerType()) {
+    S.Diag(getFunctionOrMethodParamRange(D, 0).getBegin(),
+           diag::err_anyx86_interrupt_attribute)
+        << (S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86
+                ? 0
+                : 1)
+        << 2;
+    return;
+  }
+  // The second argument, if present, must be an unsigned integer.
+  unsigned TypeSize =
+      S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86_64
+          ? 64
+          : 32;
+  if (NumParams == 2 &&
+      (!getFunctionOrMethodParamType(D, 1)->isUnsignedIntegerType() ||
+       S.Context.getTypeSize(getFunctionOrMethodParamType(D, 1)) != TypeSize)) {
+    S.Diag(getFunctionOrMethodParamRange(D, 1).getBegin(),
+           diag::err_anyx86_interrupt_attribute)
+        << (S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86
+                ? 0
+                : 1)
+        << 3 << S.Context.getIntTypeForBitwidth(TypeSize, /*Signed=*/false);
+    return;
+  }
+  D->addAttr(::new (S.Context) AnyX86InterruptAttr(
+      Attr.getLoc(), S.Context, Attr.getAttributeSpellingListIndex()));
+  D->addAttr(UsedAttr::CreateImplicit(S.Context));
+}
+
 static void handleInterruptAttr(Sema &S, Decl *D, const AttributeList &Attr) {
   // Dispatch the interrupt attribute based on the current target.
-  if (S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::msp430)
+  switch (S.Context.getTargetInfo().getTriple().getArch()) {
+  case llvm::Triple::msp430:
     handleMSP430InterruptAttr(S, D, Attr);
-  else if (S.Context.getTargetInfo().getTriple().getArch() ==
-               llvm::Triple::mipsel ||
-           S.Context.getTargetInfo().getTriple().getArch() ==
-               llvm::Triple::mips)
+    break;
+  case llvm::Triple::mipsel:
+  case llvm::Triple::mips:
     handleMipsInterruptAttr(S, D, Attr);
-  else
+    break;
+  case llvm::Triple::x86:
+  case llvm::Triple::x86_64:
+    handleAnyX86InterruptAttr(S, D, Attr);
+    break;
+  default:
     handleARMInterruptAttr(S, D, Attr);
+    break;
+  }
 }
 
 static void handleAMDGPUNumVGPRAttr(Sema &S, Decl *D,

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=257867&r1=257866&r2=257867&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Thu Jan 14 22:06:31 2016
@@ -5053,6 +5053,12 @@ Sema::BuildResolvedCallExpr(Expr *Fn, Na
   FunctionDecl *FDecl = dyn_cast_or_null<FunctionDecl>(NDecl);
   unsigned BuiltinID = (FDecl ? FDecl->getBuiltinID() : 0);
 
+  // Functions with 'interrupt' attribute cannot be called directly.
+  if (FDecl && FDecl->hasAttr<AnyX86InterruptAttr>()) {
+    Diag(Fn->getExprLoc(), diag::err_anyx86_interrupt_called);
+    return ExprError();
+  }
+
   // 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.

Added: cfe/trunk/test/CodeGen/attr-x86-interrupt.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/attr-x86-interrupt.c?rev=257867&view=auto
==============================================================================
--- cfe/trunk/test/CodeGen/attr-x86-interrupt.c (added)
+++ cfe/trunk/test/CodeGen/attr-x86-interrupt.c Thu Jan 14 22:06:31 2016
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefix=X86_64_LINUX
+// RUN: %clang_cc1 -triple i386-unknown-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefix=X86_LINUX
+// RUN: %clang_cc1 -triple x86_64-pc-win32 %s -emit-llvm -o - | FileCheck %s --check-prefix=X86_64_WIN
+// RUN: %clang_cc1 -triple i386-pc-win32 %s -emit-llvm -o - | FileCheck %s --check-prefix=X86_WIN
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnux32 %s -emit-llvm -o - | FileCheck %s --check-prefix=X86_64_LINUX
+
+#ifdef __x86_64__
+typedef __UINT64_TYPE__ uword;
+#else
+typedef __UINT32_TYPE__ uword;
+#endif
+
+__attribute__((interrupt)) void foo7(int *a, uword b) {}
+__attribute__((interrupt)) void foo8(int *a) {}
+// X86_64_LINUX: @llvm.used = appending global [2 x i8*] [i8* bitcast (void (i32*, i64)* @foo7 to i8*), i8* bitcast (void (i32*)* @foo8 to i8*)], section "llvm.metadata"
+// X86_64_LINUX: define x86_intrcc void @foo7(i32* %{{.+}}, i64 %{{.+}})
+// X86_64_LINUX: define x86_intrcc void @foo8(i32* %{{.+}})
+// X86_LINUX: @llvm.used = appending global [2 x i8*] [i8* bitcast (void (i32*, i32)* @foo7 to i8*), i8* bitcast (void (i32*)* @foo8 to i8*)], section "llvm.metadata"
+// X86_LINUX: define x86_intrcc void @foo7(i32* %{{.+}}, i32 %{{.+}})
+// X86_LINUX: define x86_intrcc void @foo8(i32* %{{.+}})
+// X86_64_WIN: @llvm.used = appending global [2 x i8*] [i8* bitcast (void (i32*, i64)* @foo7 to i8*), i8* bitcast (void (i32*)* @foo8 to i8*)], section "llvm.metadata"
+// X86_64_WIN: define x86_intrcc void @foo7(i32* %{{.+}}, i64 %{{.+}})
+// X86_64_WIN: define x86_intrcc void @foo8(i32* %{{.+}})
+// X86_WIN: @llvm.used = appending global [2 x i8*] [i8* bitcast (void (i32*, i32)* @foo7 to i8*), i8* bitcast (void (i32*)* @foo8 to i8*)], section "llvm.metadata"
+// X86_WIN: define x86_intrcc void @foo7(i32* %{{.+}}, i32 %{{.+}})
+// X86_WIN: define x86_intrcc void @foo8(i32* %{{.+}})

Added: cfe/trunk/test/CodeGenCXX/attr-x86-interrupt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/attr-x86-interrupt.cpp?rev=257867&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/attr-x86-interrupt.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/attr-x86-interrupt.cpp Thu Jan 14 22:06:31 2016
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefix=X86_64_LINUX
+// RUN: %clang_cc1 -triple i386-unknown-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefix=X86_LINUX
+// RUN: %clang_cc1 -triple x86_64-pc-win32 %s -emit-llvm -o - | FileCheck %s --check-prefix=X86_64_WIN
+// RUN: %clang_cc1 -triple i386-pc-win32 %s -emit-llvm -o - | FileCheck %s --check-prefix=X86_WIN
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnux32 %s -emit-llvm -o - | FileCheck %s --check-prefix=X86_64_LINUX
+
+#ifdef __x86_64__
+typedef __UINT64_TYPE__ uword;
+#else
+typedef __UINT32_TYPE__ uword;
+#endif
+
+__attribute__((interrupt)) void foo7(int *a, uword b) {}
+namespace S {
+__attribute__((interrupt)) void foo8(int *a) {}
+}
+struct St {
+static void foo9(int *a) __attribute__((interrupt)) {}
+};
+// X86_64_LINUX: @llvm.used = appending global [3 x i8*] [i8* bitcast (void (i32*, i64)* @{{.*}}foo7{{.*}} to i8*), i8* bitcast (void (i32*)* @{{.*}}foo8{{.*}} to i8*), i8* bitcast (void (i32*)* @{{.*}}foo9{{.*}} to i8*)], section "llvm.metadata"
+// X86_64_LINUX: define x86_intrcc void @{{.*}}foo7{{.*}}(i32* %{{.+}}, i64 %{{.+}})
+// X86_64_LINUX: define x86_intrcc void @{{.*}}foo8{{.*}}(i32* %{{.+}})
+// X86_64_LINUX: define linkonce_odr x86_intrcc void @{{.*}}foo9{{.*}}(i32* %{{.+}})
+// X86_LINUX: @llvm.used = appending global [3 x i8*] [i8* bitcast (void (i32*, i32)* @{{.*}}foo7{{.*}} to i8*), i8* bitcast (void (i32*)* @{{.*}}foo8{{.*}} to i8*), i8* bitcast (void (i32*)* @{{.*}}foo9{{.*}} to i8*)], section "llvm.metadata"
+// X86_LINUX: define x86_intrcc void @{{.*}}foo7{{.*}}(i32* %{{.+}}, i32 %{{.+}})
+// X86_LINUX: define x86_intrcc void @{{.*}}foo8{{.*}}(i32* %{{.+}})
+// X86_LINUX: define linkonce_odr x86_intrcc void @{{.*}}foo9{{.*}}(i32* %{{.+}})
+// X86_64_WIN: @llvm.used = appending global [3 x i8*] [i8* bitcast (void (i32*, i64)* @{{.*}}foo7{{.*}} to i8*), i8* bitcast (void (i32*)* @{{.*}}foo8{{.*}} to i8*), i8* bitcast (void (i32*)* @{{.*}}foo9{{.*}} to i8*)], section "llvm.metadata"
+// X86_64_WIN: define x86_intrcc void @{{.*}}foo7{{.*}}(i32* %{{.+}}, i64 %{{.+}})
+// X86_64_WIN: define x86_intrcc void @{{.*}}foo8{{.*}}(i32* %{{.+}})
+// X86_64_WIN: define linkonce_odr x86_intrcc void @{{.*}}foo9{{.*}}(i32* %{{.+}})
+// X86_WIN: @llvm.used = appending global [3 x i8*] [i8* bitcast (void (i32*, i32)* @{{.*}}foo7{{.*}} to i8*), i8* bitcast (void (i32*)* @{{.*}}foo8{{.*}} to i8*), i8* bitcast (void (i32*)* @{{.*}}foo9{{.*}} to i8*)], section "llvm.metadata"
+// X86_WIN: define x86_intrcc void @{{.*}}foo7{{.*}}(i32* %{{.+}}, i32 %{{.+}})
+// X86_WIN: define x86_intrcc void @{{.*}}foo8{{.*}}(i32* %{{.+}})
+// X86_WIN: define linkonce_odr x86_intrcc void @{{.*}}foo9{{.*}}(i32* %{{.+}})

Added: cfe/trunk/test/Sema/attr-x86-interrupt.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/attr-x86-interrupt.c?rev=257867&view=auto
==============================================================================
--- cfe/trunk/test/Sema/attr-x86-interrupt.c (added)
+++ cfe/trunk/test/Sema/attr-x86-interrupt.c Thu Jan 14 22:06:31 2016
@@ -0,0 +1,55 @@
+// 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
+
+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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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;
+}
+

Added: cfe/trunk/test/SemaCXX/attr-x86-interrupt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/attr-x86-interrupt.cpp?rev=257867&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/attr-x86-interrupt.cpp (added)
+++ cfe/trunk/test/SemaCXX/attr-x86-interrupt.cpp Thu Jan 14 22:06:31 2016
@@ -0,0 +1,72 @@
+// 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
+
+struct a {
+  int b;
+  static void foo(int *a) __attribute__((interrupt)) {}
+  void *operator new(__SIZE_TYPE__) throw() __attribute__((interrupt)) { return 0; } // expected-warning {{'interrupt' attribute only applies to non-K&R-style functions}}
+};
+
+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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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) {}
+template<typename T>
+__attribute__((interrupt)) void foo9(T *a) {}
+
+template <typename T>
+void bar(T *a) {
+  foo9(a); // expected-error {{interrupt service routine cannot be called directly}}
+}
+
+template <typename Fn>
+void bar1(Fn F) {
+  F(0);
+}
+__attribute__((interrupt)) void foo(int *) {}
+
+void g(void (*fp)(int *));
+int main(int argc, char **argv) {
+  void *ptr = (void *)&foo7;
+  g(foo8);
+  (void)ptr;
+  a::foo(ptr); // expected-error {{interrupt service routine cannot be called directly}}
+  bar1(foo);
+#ifndef __x86_64__
+  // expected-error at +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}}
+  bar(argv); // expected-note {{in instantiation of function template specialization 'bar<char *>' requested here}}
+  return 0;
+}
+




More information about the cfe-commits mailing list