diff options
author | Alexey Bataev <a.bataev@hotmail.com> | 2016-01-15 04:06:31 +0000 |
---|---|---|
committer | Alexey Bataev <a.bataev@hotmail.com> | 2016-01-15 04:06:31 +0000 |
commit | d51e9933b6aaa6d99efe871bf6a73c0484e317b9 (patch) | |
tree | 5ed18426dde4cd81281ed6ea4a00cc1942059cc6 /clang/lib/Sema/SemaDeclAttr.cpp | |
parent | bd3a772e9ff81e32c308d05670dc35438e5f93c4 (diff) | |
download | bcm5719-llvm-d51e9933b6aaa6d99efe871bf6a73c0484e317b9.tar.gz bcm5719-llvm-d51e9933b6aaa6d99efe871bf6a73c0484e317b9.zip |
[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
llvm-svn: 257867
Diffstat (limited to 'clang/lib/Sema/SemaDeclAttr.cpp')
-rw-r--r-- | clang/lib/Sema/SemaDeclAttr.cpp | 85 |
1 files changed, 79 insertions, 6 deletions
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index f94c822b90f..dcd7fd1ec48 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -4570,17 +4570,90 @@ static void handleMipsInterruptAttr(Sema &S, Decl *D, 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, |