llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang-driver @llvm/pr-subscribers-clang Author: Sam Elliott (lenary) <details> <summary>Changes</summary> This Change adds support for two SiFive vendor attributes in clang: - "SiFive-CLIC-preemptible" - "SiFive-CLIC-stack-swap" These can be given together, and can be combined with "machine", but cannot be combined with any other interrupt attribute values. These are handled primarily in RISCVFrameLowering: - "SiFive-CLIC-stack-swap" entails swapping `sp` with `mscratchcsw` at function entry and exit, which holds the trap stack pointer. - "SiFive-CLIC-preemptible" entails saving `mcause` and `mepc` before re-enabling interrupts using `mstatus`. To save these, `s0` and `s1` are first spilled to the stack, and then the values are read into these registers. If these registers are used in the function, their values will be spilled a second time onto the stack with the generic callee-saved-register handling. At the end of the function interrupts are disabled again before `mepc` and `mcause` are restored. This Change also adds support for the following two experimental extensions, which only contain CSRs: - XSfsclic - for SiFive's CLIC Supervisor-Mode CSRs - XSfmclic - for SiFive's CLIC Machine-Mode CSRs The latter is needed for interrupt support. The CFI information for this implementation is not correct, but I'd prefer to correct this in a follow-up. While it's unlikely anyone wants to unwind through a handler, the CFI information is also used by debuggers so it would be good to get it right. --- Patch is 96.10 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/132481.diff 22 Files Affected: - (modified) clang/include/clang/Basic/Attr.td (+17-4) - (modified) clang/include/clang/Basic/AttrDocs.td (+13-2) - (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+3-1) - (modified) clang/lib/CodeGen/Targets/RISCV.cpp (+33-10) - (modified) clang/lib/Sema/SemaRISCV.cpp (+96-36) - (modified) clang/test/Driver/print-supported-extensions-riscv.c (+2) - (modified) clang/test/Sema/riscv-interrupt-attr-qci.c (+32-17) - (added) clang/test/Sema/riscv-interrupt-attr-sifive.c (+98) - (modified) clang/test/Sema/riscv-interrupt-attr.c (+31-15) - (modified) llvm/lib/CodeGen/PrologEpilogInserter.cpp (+28) - (modified) llvm/lib/Target/RISCV/RISCVFeatures.td (+8) - (modified) llvm/lib/Target/RISCV/RISCVFrameLowering.cpp (+160) - (modified) llvm/lib/Target/RISCV/RISCVISelLowering.cpp (+8-2) - (modified) llvm/lib/Target/RISCV/RISCVMachineFunctionInfo.cpp (+14-5) - (modified) llvm/lib/Target/RISCV/RISCVMachineFunctionInfo.h (+37-1) - (modified) llvm/lib/Target/RISCV/RISCVSystemOperands.td (+23) - (added) llvm/test/CodeGen/RISCV/sifive-interrupt-attr.ll (+1050) - (added) llvm/test/MC/RISCV/rvsfmclic-invalid.s (+20) - (added) llvm/test/MC/RISCV/rvsfmclic-valid.s (+46) - (added) llvm/test/MC/RISCV/rvsfsclic-invalid.s (+20) - (added) llvm/test/MC/RISCV/rvsfsclic-valid.s (+46) - (modified) llvm/unittests/TargetParser/RISCVISAInfoTest.cpp (+2) ``````````diff diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index b8cd3475bb88a..8f1f5baef24a2 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -2224,10 +2224,23 @@ def NoMicroMips : InheritableAttr, TargetSpecificAttr<TargetMips32> { def RISCVInterrupt : InheritableAttr, TargetSpecificAttr<TargetRISCV> { let Spellings = [GCC<"interrupt">]; let Subjects = SubjectList<[Function]>; - let Args = [EnumArgument<"Interrupt", "InterruptType", /*is_string=*/true, - ["supervisor", "machine", "qci-nest", "qci-nonest"], - ["supervisor", "machine", "qcinest", "qcinonest"], - 1>]; + let Args = [VariadicEnumArgument<"Interrupt", "InterruptType", /*is_string=*/true, + [ + "supervisor", + "machine", + "qci-nest", + "qci-nonest", + "SiFive-CLIC-preemptible", + "SiFive-CLIC-stack-swap", + ], + [ + "supervisor", + "machine", + "qcinest", + "qcinonest", + "SiFiveCLICPreemptible", + "SiFiveCLICStackSwap", + ]>]; let ParseKind = "Interrupt"; let Documentation = [RISCVInterruptDocs]; } diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 34e7ff9612859..552cb7f45a7d2 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -2863,8 +2863,9 @@ 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 ``supervisor``, ``machine``, -``qci-nest`` and ``qci-nonest``. If there is no parameter, then it defaults to +Permissible values for this parameter are ``machine``, ``supervisor``, +``qci-nest``, ``qci-nonest``, ``SiFive-CLIC-preemptible``, and +``SiFive-CLIC-stack-swap``. If there is no parameter, then it defaults to ``machine``. The ``qci-nest`` and ``qci-nonest`` values require Qualcomm's Xqciint extension @@ -2875,6 +2876,15 @@ restore interrupt state to the stack -- the ``qci-nest`` value will use begin the interrupt handler. Both of these will use ``qc.c.mileaveret`` to restore the state and return to the previous context. +The ``SiFive-CLIC-preemptible`` and ``SiFive-CLIC-stack-swap`` values are used +for machine-mode interrupts. For ``SiFive-CLIC-preemptible`` interrupts, the +values of ``mcause`` and ``mepc`` are saved onto the stack, and interrupts are +re-enabled. For ``SiFive-CLIC-stack-swap`` interrupts, the stack pointer is +swapped with ``mscratch`` before its first use and after its last use. + +The SiFive CLIC values may be combined with each other and with the ``machine`` +attribute value. Any other combination of different values is not allowed. + Repeated interrupt attribute on the same declaration will cause a warning to be emitted. In case of repeated declarations, the last one prevails. @@ -2884,6 +2894,7 @@ https://riscv.org/specifications/privileged-isa/ The RISC-V Instruction Set Manual Volume II: Privileged Architecture Version 1.10. https://github.com/quic/riscv-unified-db/releases/tag/Xqci-0.7 +https://sifive.cdn.prismic.io/sifive/d1984d2b-c9b9-4c91-8de0-d68a5e64fa0f_sifive-interrupt-cookbook-v1p2.pdf }]; } diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 1536a3b8c920a..0c587d8b677d5 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -12705,7 +12705,9 @@ def err_riscv_builtin_invalid_lmul : Error< def err_riscv_type_requires_extension : Error< "RISC-V type %0 requires the '%1' extension">; def err_riscv_attribute_interrupt_requires_extension : Error< - "RISC-V interrupt attribute '%0' requires extension '%1'">; + "RISC-V 'interrupt' attribute '%0' requires extension '%1'">; +def err_riscv_attribute_interrupt_invalid_combination : Error< + "RISC-V 'interrupt' attribute contains invalid combination of interrupt types">; def err_std_source_location_impl_not_found : Error< "'std::source_location::__impl' was not found; it must be defined before '__builtin_source_location' is called">; diff --git a/clang/lib/CodeGen/Targets/RISCV.cpp b/clang/lib/CodeGen/Targets/RISCV.cpp index 5aa10ba41f5ed..14d4cee7c61d3 100644 --- a/clang/lib/CodeGen/Targets/RISCV.cpp +++ b/clang/lib/CodeGen/Targets/RISCV.cpp @@ -829,16 +829,39 @@ class RISCVTargetCodeGenInfo : public TargetCodeGenInfo { if (!Attr) return; - const char *Kind; - switch (Attr->getInterrupt()) { - case RISCVInterruptAttr::supervisor: Kind = "supervisor"; break; - case RISCVInterruptAttr::machine: Kind = "machine"; break; - case RISCVInterruptAttr::qcinest: - Kind = "qci-nest"; - break; - case RISCVInterruptAttr::qcinonest: - Kind = "qci-nonest"; - break; + StringRef Kind = "machine"; + bool HasSiFiveCLICPreemptible = false; + bool HasSiFiveCLICStackSwap = false; + for (RISCVInterruptAttr::InterruptType type : Attr->interrupt()) { + switch (type) { + case RISCVInterruptAttr::machine: + // Do not update `Kind` because `Kind` is already "machine", or the + // kinds also contains SiFive types which need to be applied. + break; + case RISCVInterruptAttr::supervisor: + Kind = "supervisor"; + break; + case RISCVInterruptAttr::qcinest: + Kind = "qci-nest"; + break; + case RISCVInterruptAttr::qcinonest: + Kind = "qci-nonest"; + break; + // There are three different LLVM IR attribute values for SiFive CLIC + // interrupt kinds, one for each kind and one extra for their combination. + case RISCVInterruptAttr::SiFiveCLICPreemptible: { + HasSiFiveCLICPreemptible = true; + Kind = HasSiFiveCLICStackSwap ? "SiFive-CLIC-preemptible-stack-swap" + : "SiFive-CLIC-preemptible"; + break; + } + case RISCVInterruptAttr::SiFiveCLICStackSwap: { + HasSiFiveCLICStackSwap = true; + Kind = HasSiFiveCLICPreemptible ? "SiFive-CLIC-preemptible-stack-swap" + : "SiFive-CLIC-stack-swap"; + break; + } + } } Fn->addFnAttr("interrupt", Kind); diff --git a/clang/lib/Sema/SemaRISCV.cpp b/clang/lib/Sema/SemaRISCV.cpp index f23827d566610..25ff1e99498ec 100644 --- a/clang/lib/Sema/SemaRISCV.cpp +++ b/clang/lib/Sema/SemaRISCV.cpp @@ -13,6 +13,7 @@ #include "clang/Sema/SemaRISCV.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Attr.h" +#include "clang/AST/Attrs.inc" #include "clang/AST/Decl.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/TargetBuiltins.h" @@ -1453,25 +1454,14 @@ void SemaRISCV::handleInterruptAttr(Decl *D, const ParsedAttr &AL) { return; } - // Check the attribute argument. Argument is optional. - if (!AL.checkAtMostNumArgs(SemaRef, 1)) - return; - - StringRef Str; - SourceLocation ArgLoc; - - // 'machine'is the default interrupt mode. - if (AL.getNumArgs() == 0) - Str = "machine"; - else if (!SemaRef.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]. + // - The attribute itself must have at most 2 arguments + // - The attribute arguments must be string literals, and valid choices. + // - The attribute arguments must be a valid combination + // - The current target must support the right extensions for the combination. if (D->getFunctionType() == nullptr) { Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) @@ -1491,35 +1481,105 @@ void SemaRISCV::handleInterruptAttr(Decl *D, const ParsedAttr &AL) { return; } - RISCVInterruptAttr::InterruptType Kind; - if (!RISCVInterruptAttr::ConvertStrToInterruptType(Str, Kind)) { - Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) - << AL << Str << ArgLoc; + if (!AL.checkAtMostNumArgs(SemaRef, 2)) return; - } - switch (Kind) { - default: - break; - case RISCVInterruptAttr::InterruptType::qcinest: - case RISCVInterruptAttr::InterruptType::qcinonest: { - const TargetInfo &TI = getASTContext().getTargetInfo(); - llvm::StringMap<bool> FunctionFeatureMap; - getASTContext().getFunctionFeatureMap(FunctionFeatureMap, - dyn_cast<FunctionDecl>(D)); + bool HasSiFiveCLICType = false; + bool HasUnaryType = false; + + SmallSet<RISCVInterruptAttr::InterruptType, 2> Types; + for (unsigned ArgIndex = 0; ArgIndex < AL.getNumArgs(); ++ArgIndex) { + RISCVInterruptAttr::InterruptType Type; + StringRef TypeString; + SourceLocation Loc; - if (!TI.hasFeature("experimental-xqciint") && - !FunctionFeatureMap.lookup("experimental-xqciint")) { - Diag(AL.getLoc(), diag::err_riscv_attribute_interrupt_requires_extension) - << Str << "Xqciint"; + if (!SemaRef.checkStringLiteralArgumentAttr(AL, ArgIndex, TypeString, &Loc)) + return; + + if (!RISCVInterruptAttr::ConvertStrToInterruptType(TypeString, Type)) { + std::string TypeLiteral = ("\"" + TypeString + "\"").str(); + Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) + << AL << TypeLiteral << Loc; return; } - break; + + switch (Type) { + case RISCVInterruptAttr::machine: + // "machine" could be combined with the SiFive CLIC types, or could be + // just "machine". + break; + case RISCVInterruptAttr::SiFiveCLICPreemptible: + case RISCVInterruptAttr::SiFiveCLICStackSwap: + // SiFive-CLIC types can be combined with each other and "machine" + HasSiFiveCLICType = true; + break; + case RISCVInterruptAttr::supervisor: + case RISCVInterruptAttr::qcinest: + case RISCVInterruptAttr::qcinonest: + // "supervisor" and "qci-(no)nest" cannot be combined with any other types + HasUnaryType = true; + break; + } + + Types.insert(Type); + } + + if (HasUnaryType && Types.size() > 1) { + Diag(AL.getLoc(), diag::err_riscv_attribute_interrupt_invalid_combination); + return; } + + if (HasUnaryType && HasSiFiveCLICType) { + Diag(AL.getLoc(), diag::err_riscv_attribute_interrupt_invalid_combination); + return; + } + + // "machine" is the default, if nothing is specified. + if (AL.getNumArgs() == 0) + Types.insert(RISCVInterruptAttr::machine); + + const TargetInfo &TI = getASTContext().getTargetInfo(); + llvm::StringMap<bool> FunctionFeatureMap; + getASTContext().getFunctionFeatureMap(FunctionFeatureMap, + dyn_cast<FunctionDecl>(D)); + + auto HasFeature = [&](StringRef FeatureName) -> bool { + return TI.hasFeature(FeatureName) || FunctionFeatureMap.lookup(FeatureName); }; - D->addAttr(::new (getASTContext()) - RISCVInterruptAttr(getASTContext(), AL, Kind)); + for (RISCVInterruptAttr::InterruptType Type : Types) { + switch (Type) { + // The QCI interrupt types require Xqciint + case RISCVInterruptAttr::qcinest: + case RISCVInterruptAttr::qcinonest: { + if (!HasFeature("experimental-xqciint")) { + Diag(AL.getLoc(), + diag::err_riscv_attribute_interrupt_requires_extension) + << RISCVInterruptAttr::ConvertInterruptTypeToStr(Type) << "Xqciint"; + return; + } + } break; + // The SiFive CLIC interrupt types require Xsfmclic + case RISCVInterruptAttr::SiFiveCLICPreemptible: + case RISCVInterruptAttr::SiFiveCLICStackSwap: { + if (!HasFeature("experimental-xsfmclic")) { + Diag(AL.getLoc(), + diag::err_riscv_attribute_interrupt_requires_extension) + << RISCVInterruptAttr::ConvertInterruptTypeToStr(Type) + << "XSfmclic"; + return; + } + } break; + default: + break; + } + } + + SmallVector<RISCVInterruptAttr::InterruptType, 2> TypesVec(Types.begin(), + Types.end()); + + D->addAttr(::new (getASTContext()) RISCVInterruptAttr( + getASTContext(), AL, TypesVec.data(), TypesVec.size())); } bool SemaRISCV::isAliasValid(unsigned BuiltinID, StringRef AliasName) { diff --git a/clang/test/Driver/print-supported-extensions-riscv.c b/clang/test/Driver/print-supported-extensions-riscv.c index 35de2820ef84f..ca695221dee9d 100644 --- a/clang/test/Driver/print-supported-extensions-riscv.c +++ b/clang/test/Driver/print-supported-extensions-riscv.c @@ -213,6 +213,8 @@ // CHECK-NEXT: xqcisls 0.2 'Xqcisls' (Qualcomm uC Scaled Load Store Extension) // CHECK-NEXT: xrivosvisni 0.1 'XRivosVisni' (Rivos Vector Integer Small New) // CHECK-NEXT: xrivosvizip 0.1 'XRivosVizip' (Rivos Vector Register Zips) +// CHECK-NEXT: xsfmclic 0.1 'XSfmclic' (SiFive CLIC Machine-mode CSRs) +// CHECK-NEXT: xsfsclic 0.1 'XSfsclic' (SiFive CLIC Supervisor-mode CSRs) // CHECK-EMPTY: // CHECK-NEXT: Supported Profiles // CHECK-NEXT: rva20s64 diff --git a/clang/test/Sema/riscv-interrupt-attr-qci.c b/clang/test/Sema/riscv-interrupt-attr-qci.c index bdac4e154bb3c..e54c50c0e25bb 100644 --- a/clang/test/Sema/riscv-interrupt-attr-qci.c +++ b/clang/test/Sema/riscv-interrupt-attr-qci.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -triple riscv32-unknown-elf -target-feature +experimental-xqciint -emit-llvm -DCHECK_IR < %s| FileCheck %s +// RUN: %clang_cc1 -triple riscv32-unknown-elf -target-feature +experimental-xqciint -emit-llvm -DCHECK_IR < %s | FileCheck %s // RUN: %clang_cc1 %s -triple riscv32-unknown-elf -target-feature +experimental-xqciint -verify=enabled,both -fsyntax-only // RUN: %clang_cc1 %s -triple riscv32-unknown-elf -verify=disabled,both -fsyntax-only // RUN: %clang_cc1 %s -triple riscv32-unknown-elf -target-feature -experimental-xqciint -verify=disabled,both -fsyntax-only @@ -11,10 +11,20 @@ __attribute__((interrupt("qci-nest"))) void foo_nest_interrupt(void) {} -// CHECK-LABEL: @foo_nonnest_interrupt() #1 +// CHECK-LABEL: @foo_nest_nest_interrupt() #0 +// CHECK: ret void +__attribute__((interrupt("qci-nest", "qci-nest"))) +void foo_nest_nest_interrupt(void) {} + +// CHECK-LABEL: @foo_nonest_interrupt() #1 // CHECK: ret void __attribute__((interrupt("qci-nonest"))) -void foo_nonnest_interrupt(void) {} +void foo_nonest_interrupt(void) {} + +// CHECK-LABEL: @foo_nonest_nonest_interrupt() #1 +// CHECK: ret void +__attribute__((interrupt("qci-nonest", "qci-nonest"))) +void foo_nonest_nonest_interrupt(void) {} // CHECK: attributes #0 // CHECK: "interrupt"="qci-nest" @@ -22,18 +32,23 @@ void foo_nonnest_interrupt(void) {} // CHECK: "interrupt"="qci-nonest" #else // Test for QCI extension's interrupt attribute support -__attribute__((interrupt("qci-est"))) void foo_nest1(void) {} // both-warning {{'interrupt' attribute argument not supported: qci-est}} -__attribute__((interrupt("qci-noest"))) void foo_nonest1(void) {} // both-warning {{'interrupt' attribute argument not supported: qci-noest}} -__attribute__((interrupt(1))) void foo_nest2(void) {} // both-error {{expected string literal as argument of 'interrupt' attribute}} -__attribute__((interrupt("qci-nest", "qci-nonest"))) void foo1(void) {} // both-error {{'interrupt' attribute takes no more than 1 argument}} -__attribute__((interrupt("qci-nonest", "qci-nest"))) void foo2(void) {} // both-error {{'interrupt' attribute takes no more than 1 argument}} -__attribute__((interrupt("", "qci-nonest"))) void foo3(void) {} // both-error {{'interrupt' attribute takes no more than 1 argument}} -__attribute__((interrupt("", "qci-nest"))) void foo4(void) {} // both-error {{'interrupt' attribute takes no more than 1 argument}} -__attribute__((interrupt("qci-nonest", 1))) void foo5(void) {} // both-error {{'interrupt' attribute takes no more than 1 argument}} -__attribute__((interrupt("qci-nest", 1))) void foo6(void) {} // both-error {{'interrupt' attribute takes no more than 1 argument}} - -__attribute__((interrupt("qci-nest"))) void foo_nest(void) {} // disabled-error {{RISC-V interrupt attribute 'qci-nest' requires extension 'Xqciint'}} -__attribute__((interrupt("qci-nonest"))) void foo_nonest(void) {} // disabled-error {{RISC-V interrupt attribute 'qci-nonest' requires extension 'Xqciint'}} +__attribute__((interrupt(1))) void foo1(void) {} // both-error {{expected string literal as argument of 'interrupt' attribute}} +__attribute__((interrupt("qci-nonest", 1))) void foo_nonest2(void) {} // both-error {{expected string literal as argument of 'interrupt' attribute}} +__attribute__((interrupt("qci-nest", 1))) void foo_nest2(void) {} // both-error {{expected string literal as argument of 'interrupt' attribute}} +__attribute__((interrupt("qci-est"))) void foo_nest3(void) {} // both-warning {{'interrupt' attribute argument not supported: "qci-est"}} +__attribute__((interrupt("qci-noest"))) void foo_nonest3(void) {} // both-warning {{'interrupt' attribute argument not supported: "qci-noest"}} +__attribute__((interrupt("", "qci-nonest"))) void foo_nonest4(void) {} // both-warning {{'interrupt' attribute argument not supported: ""}} +__attribute__((interrupt("", "qci-nest"))) void foo_nest4(void) {} // both-warning {{'interrupt' attribute argument not supported: ""}} + +__attribute__((interrupt("qci-nonest", "qci-nest"))) void foo_nonest5(void) {} // both-error {{RISC-V 'interrupt' attribute contains invalid combination of interrupt types}} +__attribute__((interrupt("qci-nest", "qci-nonest"))) void foo_nest5(void) {} // both-error {{RISC-V 'interrupt' attribute contains invalid combination of interrupt types}} + +__attribute__((interrupt("qci-nest"))) void foo_nest(void) {} // disabled-error {{RISC-V 'interrupt' attribute 'qci-nest' requires extension 'Xqciint'}} +__attribute__((interrupt("qci-nonest"))) void foo_nonest(void) {} // disabled-error {{RISC-V 'interrupt' attribute 'qci-nonest' requires extension 'Xqciint'}} + +__attribute__((interrupt("qci-nest", "qci-nest"))) void foo_nest_nest(void) {} // disabled-error {{RISC-V 'interrupt' attribute 'qci-nest' requires extension 'Xqciint'}} +__attribute__((interrupt("qci-nonest", "qci-nonest"))) void foo_nonest_nonest(void) {} // disabled-error {{RISC-V 'interrupt' attribute 'qci-nonest' requires extension 'Xqciint'}} + // This tests the errors for the qci interrupts when using // `__attribute__((target(...)))` - but they fail on RV64, because you cannot @@ -44,8 +59,8 @@ __attribute__((target("arch=+xqciint"))) __attribute__((interrupt("qci-nonest")) // The attribute order is important, the interrupt attribute must come after the // target attribute -__attribute__((interrupt("qci-nest"))) __attribute__((target("arch=+xqciint"))) void foo_nest_xqciint2(void) {} // disabled-error {{RISC-V interrupt attribute 'qci-nest' requires extension 'Xqciint'}} -__attribute__((interrupt("qci-nonest"))) __attribute__((target("arch=+xqciint"))) void foo_nonest_xqciint2(void) {} // disabled-error {{RISC-V interrupt attribute 'qci-nonest' requires extension 'Xqciint'}} +__attribute__((interrupt("qci-nest"))) __attribute__((target("arch=+xqciint"))) void foo_nest_xqciint2(void) {} // disabled-error {{RISC-V 'interrupt' attribute 'qci-nest' requires extension 'Xqciint'}} +__attribute__((interrupt("qci-nonest"))) __attribute__((target("arch=+xqciint"))) void foo_nonest_xqciint2(void) {} // disabled-error {{RISC-V 'interrupt' attribute 'qci-nonest' requires extension 'Xqciint'}} #endif #endif diff... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/132481 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits