forked from OSchip/llvm-project
[MSP430] Improve support of 'interrupt' attribute
* Accept as an argument constants in range 0..63 (aligned with TI headers and linker scripts provided with TI GCC toolchain). * Emit function attribute 'interrupt'='xx' instead of aliases (used in the backend to create a section for particular interrupt vector). * Add more diagnostics. Patch by Kristina Bessonova! Differential Revision: https://reviews.llvm.org/D56663 llvm-svn: 351344
This commit is contained in:
parent
b6cee6ceb6
commit
383e827121
|
@ -274,6 +274,10 @@ def warn_riscv_interrupt_attribute : Warning<
|
|||
"RISC-V 'interrupt' attribute only applies to functions that have "
|
||||
"%select{no parameters|a 'void' return type}0">,
|
||||
InGroup<IgnoredAttributes>;
|
||||
def warn_msp430_interrupt_attribute : Warning<
|
||||
"MSP430 'interrupt' attribute only applies to functions that have "
|
||||
"%select{no parameters|a 'void' return type}0">,
|
||||
InGroup<IgnoredAttributes>;
|
||||
def warn_unused_parameter : Warning<"unused parameter %0">,
|
||||
InGroup<UnusedParameter>, DefaultIgnore;
|
||||
def warn_unused_variable : Warning<"unused variable %0">,
|
||||
|
|
|
@ -6774,21 +6774,19 @@ void MSP430TargetCodeGenInfo::setTargetAttributes(
|
|||
if (GV->isDeclaration())
|
||||
return;
|
||||
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) {
|
||||
if (const MSP430InterruptAttr *attr = FD->getAttr<MSP430InterruptAttr>()) {
|
||||
// Handle 'interrupt' attribute:
|
||||
llvm::Function *F = cast<llvm::Function>(GV);
|
||||
const auto *InterruptAttr = FD->getAttr<MSP430InterruptAttr>();
|
||||
if (!InterruptAttr)
|
||||
return;
|
||||
|
||||
// Step 1: Set ISR calling convention.
|
||||
F->setCallingConv(llvm::CallingConv::MSP430_INTR);
|
||||
// Handle 'interrupt' attribute:
|
||||
llvm::Function *F = cast<llvm::Function>(GV);
|
||||
|
||||
// Step 2: Add attributes goodness.
|
||||
F->addFnAttr(llvm::Attribute::NoInline);
|
||||
// Step 1: Set ISR calling convention.
|
||||
F->setCallingConv(llvm::CallingConv::MSP430_INTR);
|
||||
|
||||
// Step 3: Emit ISR vector alias.
|
||||
unsigned Num = attr->getNumber() / 2;
|
||||
llvm::GlobalAlias::create(llvm::Function::ExternalLinkage,
|
||||
"__isr_" + Twine(Num), F);
|
||||
}
|
||||
// Step 2: Add attributes goodness.
|
||||
F->addFnAttr(llvm::Attribute::NoInline);
|
||||
F->addFnAttr("interrupt", llvm::utostr(InterruptAttr->getNumber()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5377,6 +5377,27 @@ static void handleARMInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
|
|||
}
|
||||
|
||||
static void handleMSP430InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
|
||||
// MSP430 'interrupt' attribute is applied to
|
||||
// a function with no parameters and void return type.
|
||||
if (!isFunctionOrMethod(D)) {
|
||||
S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
|
||||
<< "'interrupt'" << ExpectedFunctionOrMethod;
|
||||
return;
|
||||
}
|
||||
|
||||
if (hasFunctionProto(D) && getFunctionOrMethodNumParams(D) != 0) {
|
||||
S.Diag(D->getLocation(), diag::warn_msp430_interrupt_attribute)
|
||||
<< 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!getFunctionOrMethodResultType(D)->isVoidType()) {
|
||||
S.Diag(D->getLocation(), diag::warn_msp430_interrupt_attribute)
|
||||
<< 1;
|
||||
return;
|
||||
}
|
||||
|
||||
// The attribute takes one integer argument.
|
||||
if (!checkAttributeNumArgs(S, AL, 1))
|
||||
return;
|
||||
|
||||
|
@ -5386,8 +5407,6 @@ static void handleMSP430InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
|
|||
return;
|
||||
}
|
||||
|
||||
// FIXME: Check for decl - it should be void ()(void).
|
||||
|
||||
Expr *NumParamsExpr = static_cast<Expr *>(AL.getArgAsExpr(0));
|
||||
llvm::APSInt NumParams(32);
|
||||
if (!NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context)) {
|
||||
|
@ -5396,9 +5415,9 @@ static void handleMSP430InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
|
|||
<< NumParamsExpr->getSourceRange();
|
||||
return;
|
||||
}
|
||||
|
||||
// The argument should be in range 0..63.
|
||||
unsigned Num = NumParams.getLimitedValue(255);
|
||||
if ((Num & 1) || Num > 30) {
|
||||
if (Num > 63) {
|
||||
S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds)
|
||||
<< AL << (int)NumParams.getSExtValue()
|
||||
<< NumParamsExpr->getSourceRange();
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
// RUN: %clang_cc1 -triple msp430-unknown-unknown -emit-llvm < %s| FileCheck %s
|
||||
|
||||
__attribute__((interrupt(1))) void foo(void) {}
|
||||
// CHECK: @llvm.used
|
||||
// CHECK-SAME: @foo
|
||||
|
||||
// CHECK: define msp430_intrcc void @foo() #0
|
||||
// CHECK: attributes #0
|
||||
// CHECK-SAME: noinline
|
||||
// CHECK-SAME: "interrupt"="1"
|
|
@ -1,6 +1,13 @@
|
|||
// RUN: %clang_cc1 -triple msp430-unknown-unknown -fsyntax-only -verify %s
|
||||
|
||||
int i;
|
||||
void f(void) __attribute__((interrupt(i))); /* expected-error {{'interrupt' attribute requires an integer constant}} */
|
||||
__attribute__((interrupt(1))) int t; // expected-warning {{'interrupt' attribute only applies to functions}}
|
||||
|
||||
void f2(void) __attribute__((interrupt(12)));
|
||||
int i;
|
||||
__attribute__((interrupt(i))) void f(void); // expected-error {{'interrupt' attribute requires an integer constant}}
|
||||
__attribute__((interrupt(1, 2))) void f2(void); // expected-error {{'interrupt' attribute takes one argument}}
|
||||
__attribute__((interrupt(1))) int f3(void); // expected-warning {{MSP430 'interrupt' attribute only applies to functions that have a 'void' return type}}
|
||||
__attribute__((interrupt(1))) void f4(int a); // expected-warning {{MSP430 'interrupt' attribute only applies to functions that have no parameters}}
|
||||
__attribute__((interrupt(64))) void f5(void); // expected-error {{'interrupt' attribute parameter 64 is out of bounds}}
|
||||
|
||||
__attribute__((interrupt(0))) void f6(void);
|
||||
__attribute__((interrupt(63))) void f7(void);
|
||||
|
|
Loading…
Reference in New Issue