mirror of https://github.com/microsoft/clang.git
[RISCV] Add support for interrupt attribute
Summary: Clang supports the GNU style ``__attribute__((interrupt))`` attribute on RISCV targets. Permissible values for this parameter are user, supervisor, and machine. If there is no parameter, then it defaults to machine. Reference: https://gcc.gnu.org/onlinedocs/gcc/RISC-V-Function-Attributes.html Based on initial patch by Zhaoshi Zheng. Reviewers: asb, aaron.ballman Reviewed By: asb, aaron.ballman Subscribers: rkruppe, the_o, aaron.ballman, MartinMosbeck, brucehoult, rbar, johnrusso, simoncook, sabuasal, niosHD, kito-cheng, shiva0217, zzheng, edward-jones, mgrang, rogfer01, cfe-commits Differential Revision: https://reviews.llvm.org/D48412 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@338045 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
95dc1a4cb7
commit
a37cc0790f
|
@ -308,6 +308,7 @@ def TargetAVR : TargetArch<["avr"]>;
|
|||
def TargetMips32 : TargetArch<["mips", "mipsel"]>;
|
||||
def TargetAnyMips : TargetArch<["mips", "mipsel", "mips64", "mips64el"]>;
|
||||
def TargetMSP430 : TargetArch<["msp430"]>;
|
||||
def TargetRISCV : TargetArch<["riscv32", "riscv64"]>;
|
||||
def TargetX86 : TargetArch<["x86"]>;
|
||||
def TargetAnyX86 : TargetArch<["x86", "x86_64"]>;
|
||||
def TargetWindows : TargetArch<["x86", "x86_64", "arm", "thumb", "aarch64"]> {
|
||||
|
@ -1374,6 +1375,17 @@ def NoMicroMips : InheritableAttr, TargetSpecificAttr<TargetMips32> {
|
|||
let Documentation = [MicroMipsDocs];
|
||||
}
|
||||
|
||||
def RISCVInterrupt : InheritableAttr, TargetSpecificAttr<TargetRISCV> {
|
||||
let Spellings = [GCC<"interrupt">];
|
||||
let Subjects = SubjectList<[Function]>;
|
||||
let Args = [EnumArgument<"Interrupt", "InterruptType",
|
||||
["user", "supervisor", "machine"],
|
||||
["user", "supervisor", "machine"],
|
||||
1>];
|
||||
let ParseKind = "Interrupt";
|
||||
let Documentation = [RISCVInterruptDocs];
|
||||
}
|
||||
|
||||
// This is not a TargetSpecificAttr so that is silently accepted and
|
||||
// ignored on other targets as encouraged by the OpenCL spec.
|
||||
//
|
||||
|
|
|
@ -1501,6 +1501,29 @@ as ``-mlong-calls`` and ``-mno-long-calls``.
|
|||
}];
|
||||
}
|
||||
|
||||
def RISCVInterruptDocs : Documentation {
|
||||
let Category = DocCatFunction;
|
||||
let Heading = "interrupt (RISCV)";
|
||||
let Content = [{
|
||||
Clang supports the GNU style ``__attribute__((interrupt))`` attribute on RISCV
|
||||
targets. 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 service routine.
|
||||
|
||||
Permissible values for this parameter are ``user``, ``supervisor``,
|
||||
and ``machine``. If there is no parameter, then it defaults to machine.
|
||||
|
||||
Repeated interrupt attribute on the same declaration will cause a warning
|
||||
to be emitted. In case of repeated declarations, the last one prevails.
|
||||
|
||||
Refer to:
|
||||
https://gcc.gnu.org/onlinedocs/gcc/RISC-V-Function-Attributes.html
|
||||
https://riscv.org/specifications/privileged-isa/
|
||||
The RISC-V Instruction Set Manual Volume II: Privileged Architecture
|
||||
Version 1.10.
|
||||
}];
|
||||
}
|
||||
|
||||
def AVRInterruptDocs : Documentation {
|
||||
let Category = DocCatFunction;
|
||||
let Heading = "interrupt (AVR)";
|
||||
|
|
|
@ -274,6 +274,14 @@ def warn_mips_interrupt_attribute : Warning<
|
|||
"MIPS 'interrupt' attribute only applies to functions that have "
|
||||
"%select{no parameters|a 'void' return type}0">,
|
||||
InGroup<IgnoredAttributes>;
|
||||
def warn_riscv_repeated_interrupt_attribute : Warning<
|
||||
"repeated RISC-V 'interrupt' attribute">, InGroup<IgnoredAttributes>;
|
||||
def note_riscv_repeated_interrupt_attribute : Note<
|
||||
"repeated RISC-V 'interrupt' attribute is here">;
|
||||
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_unused_parameter : Warning<"unused parameter %0">,
|
||||
InGroup<UnusedParameter>, DefaultIgnore;
|
||||
def warn_unused_variable : Warning<"unused variable %0">,
|
||||
|
@ -281,7 +289,7 @@ def warn_unused_variable : Warning<"unused variable %0">,
|
|||
def warn_unused_local_typedef : Warning<
|
||||
"unused %select{typedef|type alias}0 %1">,
|
||||
InGroup<UnusedLocalTypedef>, DefaultIgnore;
|
||||
def warn_unused_property_backing_ivar :
|
||||
def warn_unused_property_backing_ivar :
|
||||
Warning<"ivar %0 which backs the property is not "
|
||||
"referenced in this property's accessor">,
|
||||
InGroup<UnusedPropertyIvar>, DefaultIgnore;
|
||||
|
|
|
@ -8971,6 +8971,27 @@ class RISCVTargetCodeGenInfo : public TargetCodeGenInfo {
|
|||
public:
|
||||
RISCVTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, unsigned XLen)
|
||||
: TargetCodeGenInfo(new RISCVABIInfo(CGT, XLen)) {}
|
||||
|
||||
void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
|
||||
CodeGen::CodeGenModule &CGM) const override {
|
||||
const auto *FD = dyn_cast_or_null<FunctionDecl>(D);
|
||||
if (!FD) return;
|
||||
|
||||
const auto *Attr = FD->getAttr<RISCVInterruptAttr>();
|
||||
if (!Attr)
|
||||
return;
|
||||
|
||||
const char *Kind;
|
||||
switch (Attr->getInterrupt()) {
|
||||
case RISCVInterruptAttr::user: Kind = "user"; break;
|
||||
case RISCVInterruptAttr::supervisor: Kind = "supervisor"; break;
|
||||
case RISCVInterruptAttr::machine: Kind = "machine"; break;
|
||||
}
|
||||
|
||||
auto *Fn = cast<llvm::Function>(GV);
|
||||
|
||||
Fn->addFnAttr("interrupt", Kind);
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
|
|
|
@ -5372,6 +5372,64 @@ static void handleAVRSignalAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
|
|||
handleSimpleAttribute<AVRSignalAttr>(S, D, AL);
|
||||
}
|
||||
|
||||
|
||||
static void handleRISCVInterruptAttr(Sema &S, Decl *D,
|
||||
const ParsedAttr &AL) {
|
||||
// Warn about repeated attributes.
|
||||
if (const auto *A = D->getAttr<RISCVInterruptAttr>()) {
|
||||
S.Diag(AL.getRange().getBegin(),
|
||||
diag::warn_riscv_repeated_interrupt_attribute);
|
||||
S.Diag(A->getLocation(), diag::note_riscv_repeated_interrupt_attribute);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check the attribute argument. Argument is optional.
|
||||
if (!checkAttributeAtMostNumArgs(S, AL, 1))
|
||||
return;
|
||||
|
||||
StringRef Str;
|
||||
SourceLocation ArgLoc;
|
||||
|
||||
// 'machine'is the default interrupt mode.
|
||||
if (AL.getNumArgs() == 0)
|
||||
Str = "machine";
|
||||
else if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
|
||||
return;
|
||||
|
||||
// Semantic checks for a function with the 'interrupt' attribute:
|
||||
// - Must be a function.
|
||||
// - Must have no parameters.
|
||||
// - Must have the 'void' return type.
|
||||
// - The attribute itself must either have no argument or one of the
|
||||
// valid interrupt types, see [RISCVInterruptDocs].
|
||||
|
||||
if (D->getFunctionType() == nullptr) {
|
||||
S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
|
||||
<< "'interrupt'" << ExpectedFunction;
|
||||
return;
|
||||
}
|
||||
|
||||
if (hasFunctionProto(D) && getFunctionOrMethodNumParams(D) != 0) {
|
||||
S.Diag(D->getLocation(), diag::warn_riscv_interrupt_attribute) << 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!getFunctionOrMethodResultType(D)->isVoidType()) {
|
||||
S.Diag(D->getLocation(), diag::warn_riscv_interrupt_attribute) << 1;
|
||||
return;
|
||||
}
|
||||
|
||||
RISCVInterruptAttr::InterruptType Kind;
|
||||
if (!RISCVInterruptAttr::ConvertStrToInterruptType(Str, Kind)) {
|
||||
S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported)
|
||||
<< AL.getName() << Str << ArgLoc;
|
||||
return;
|
||||
}
|
||||
|
||||
D->addAttr(::new (S.Context) RISCVInterruptAttr(
|
||||
AL.getLoc(), S.Context, Kind, AL.getAttributeSpellingListIndex()));
|
||||
}
|
||||
|
||||
static void handleInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
|
||||
// Dispatch the interrupt attribute based on the current target.
|
||||
switch (S.Context.getTargetInfo().getTriple().getArch()) {
|
||||
|
@ -5389,6 +5447,10 @@ static void handleInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
|
|||
case llvm::Triple::avr:
|
||||
handleAVRInterruptAttr(S, D, AL);
|
||||
break;
|
||||
case llvm::Triple::riscv32:
|
||||
case llvm::Triple::riscv64:
|
||||
handleRISCVInterruptAttr(S, D, AL);
|
||||
break;
|
||||
default:
|
||||
handleARMInterruptAttr(S, D, AL);
|
||||
break;
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
// RUN: %clang_cc1 -triple riscv32-unknown-elf -emit-llvm -DCHECK_IR < %s| FileCheck %s
|
||||
// RUN: %clang_cc1 -triple riscv64-unknown-elf -emit-llvm -DCHECK_IR < %s| FileCheck %s
|
||||
// RUN: %clang_cc1 %s -triple riscv32-unknown-elf -verify -fsyntax-only
|
||||
// RUN: %clang_cc1 %s -triple riscv64-unknown-elf -verify -fsyntax-only
|
||||
|
||||
#if defined(CHECK_IR)
|
||||
// CHECK-LABEL: @foo_user() #0
|
||||
// CHECK: ret void
|
||||
__attribute__((interrupt("user"))) void foo_user(void) {}
|
||||
// CHECK-LABEL: @foo_supervisor() #1
|
||||
// CHECK: ret void
|
||||
__attribute__((interrupt("supervisor"))) void foo_supervisor(void) {}
|
||||
// CHECK-LABEL: @foo_machine() #2
|
||||
// CHECK: ret void
|
||||
__attribute__((interrupt("machine"))) void foo_machine(void) {}
|
||||
// CHECK-LABEL: @foo_default() #2
|
||||
// CHECK: ret void
|
||||
__attribute__((interrupt())) void foo_default(void) {}
|
||||
// CHECK-LABEL: @foo_default2() #2
|
||||
// CHECK: ret void
|
||||
__attribute__((interrupt())) void foo_default2(void) {}
|
||||
// CHECK: attributes #0
|
||||
// CHECK: "interrupt"="user"
|
||||
// CHECK: attributes #1
|
||||
// CHECK: "interrupt"="supervisor"
|
||||
// CHECK: attributes #2
|
||||
// CHECK: "interrupt"="machine"
|
||||
#else
|
||||
struct a { int b; };
|
||||
|
||||
struct a test __attribute__((interrupt)); // expected-warning {{'interrupt' attribute only applies to functions}}
|
||||
|
||||
__attribute__((interrupt("USER"))) void foo1(void) {} // expected-warning {{'interrupt' attribute argument not supported: USER}}
|
||||
|
||||
__attribute__((interrupt("user", 1))) void foo2(void) {} // expected-error {{'interrupt' attribute takes no more than 1 argument}}
|
||||
|
||||
__attribute__((interrupt)) int foo3(void) {return 0;} // expected-warning {{RISC-V 'interrupt' attribute only applies to functions that have a 'void' return type}}
|
||||
|
||||
__attribute__((interrupt())) void foo4();
|
||||
__attribute__((interrupt())) void foo4() {};
|
||||
|
||||
__attribute__((interrupt())) void foo5(int a) {} // expected-warning {{RISC-V 'interrupt' attribute only applies to functions that have no parameters}}
|
||||
|
||||
__attribute__((interrupt("user"), interrupt("supervisor"))) void foo6(void) {} // expected-warning {{repeated RISC-V 'interrupt' attribute}} \
|
||||
// expected-note {{repeated RISC-V 'interrupt' attribute is here}}
|
||||
|
||||
__attribute__((interrupt, interrupt)) void foo7(void) {} // expected-warning {{repeated RISC-V 'interrupt' attribute}} \
|
||||
// expected-note {{repeated RISC-V 'interrupt' attribute is here}}
|
||||
|
||||
__attribute__((interrupt(""))) void foo8(void) {} // expected-warning {{'interrupt' attribute argument not supported}}
|
||||
|
||||
__attribute__((interrupt("user"))) void foo9(void);
|
||||
__attribute__((interrupt("supervisor"))) void foo9(void);
|
||||
__attribute__((interrupt("machine"))) void foo9(void);
|
||||
|
||||
__attribute__((interrupt("user"))) void foo10(void) {}
|
||||
__attribute__((interrupt("supervisor"))) void foo11(void) {}
|
||||
__attribute__((interrupt("machine"))) void foo12(void) {}
|
||||
__attribute__((interrupt())) void foo13(void) {}
|
||||
__attribute__((interrupt)) void foo14(void) {}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
// RUN: %clang_cc1 -x c++ -triple riscv32-unknown-elf -emit-llvm -DCHECK_IR < %s | FileCheck %s
|
||||
// RUN: %clang_cc1 -x c++ -triple riscv64-unknown-elf -emit-llvm -DCHECK_IR < %s | FileCheck %s
|
||||
// RUN: %clang_cc1 %s -triple riscv32-unknown-elf -verify -fsyntax-only
|
||||
// RUN: %clang_cc1 %s -triple riscv64-unknown-elf -verify -fsyntax-only
|
||||
|
||||
#if defined(CHECK_IR)
|
||||
// CHECK-LABEL: @_Z11foo_defaultv() #0
|
||||
// CHECK: ret void
|
||||
[[gnu::interrupt]] void foo_default() {}
|
||||
// CHECK: attributes #0
|
||||
// CHECK: "interrupt"="machine"
|
||||
#else
|
||||
[[gnu::interrupt]] [[gnu::interrupt]] void foo1() {} // expected-warning {{repeated RISC-V 'interrupt' attribute}} \
|
||||
// expected-note {{repeated RISC-V 'interrupt' attribute is here}}
|
||||
[[gnu::interrupt]] void foo2() {}
|
||||
#endif
|
Loading…
Reference in New Issue