1313#include " clang/Sema/SemaRISCV.h"
1414#include " clang/AST/ASTContext.h"
1515#include " clang/AST/Attr.h"
16+ #include " clang/AST/Attrs.inc"
1617#include " clang/AST/Decl.h"
1718#include " clang/Basic/Builtins.h"
1819#include " clang/Basic/TargetBuiltins.h"
@@ -1453,25 +1454,14 @@ void SemaRISCV::handleInterruptAttr(Decl *D, const ParsedAttr &AL) {
14531454 return ;
14541455 }
14551456
1456- // Check the attribute argument. Argument is optional.
1457- if (!AL.checkAtMostNumArgs (SemaRef, 1 ))
1458- return ;
1459-
1460- StringRef Str;
1461- SourceLocation ArgLoc;
1462-
1463- // 'machine'is the default interrupt mode.
1464- if (AL.getNumArgs () == 0 )
1465- Str = " machine" ;
1466- else if (!SemaRef.checkStringLiteralArgumentAttr (AL, 0 , Str, &ArgLoc))
1467- return ;
1468-
14691457 // Semantic checks for a function with the 'interrupt' attribute:
14701458 // - Must be a function.
14711459 // - Must have no parameters.
14721460 // - Must have the 'void' return type.
1473- // - The attribute itself must either have no argument or one of the
1474- // valid interrupt types, see [RISCVInterruptDocs].
1461+ // - The attribute itself must have at most 2 arguments
1462+ // - The attribute arguments must be string literals, and valid choices.
1463+ // - The attribute arguments must be a valid combination
1464+ // - The current target must support the right extensions for the combination.
14751465
14761466 if (D->getFunctionType () == nullptr ) {
14771467 Diag (D->getLocation (), diag::warn_attribute_wrong_decl_type)
@@ -1491,35 +1481,105 @@ void SemaRISCV::handleInterruptAttr(Decl *D, const ParsedAttr &AL) {
14911481 return ;
14921482 }
14931483
1494- RISCVInterruptAttr::InterruptType Kind;
1495- if (!RISCVInterruptAttr::ConvertStrToInterruptType (Str, Kind)) {
1496- Diag (AL.getLoc (), diag::warn_attribute_type_not_supported)
1497- << AL << Str << ArgLoc;
1484+ if (!AL.checkAtMostNumArgs (SemaRef, 2 ))
14981485 return ;
1499- }
15001486
1501- switch (Kind) {
1502- default :
1503- break ;
1504- case RISCVInterruptAttr::InterruptType::qcinest:
1505- case RISCVInterruptAttr::InterruptType::qcinonest: {
1506- const TargetInfo &TI = getASTContext ().getTargetInfo ();
1507- llvm::StringMap<bool > FunctionFeatureMap;
1508- getASTContext ().getFunctionFeatureMap (FunctionFeatureMap,
1509- dyn_cast<FunctionDecl>(D));
1487+ bool HasSiFiveCLICType = false ;
1488+ bool HasUnaryType = false ;
1489+
1490+ SmallSet<RISCVInterruptAttr::InterruptType, 2 > Types;
1491+ for (unsigned ArgIndex = 0 ; ArgIndex < AL.getNumArgs (); ++ArgIndex) {
1492+ RISCVInterruptAttr::InterruptType Type;
1493+ StringRef TypeString;
1494+ SourceLocation Loc;
15101495
1511- if (!TI.hasFeature (" experimental-xqciint" ) &&
1512- !FunctionFeatureMap.lookup (" experimental-xqciint" )) {
1513- Diag (AL.getLoc (), diag::err_riscv_attribute_interrupt_requires_extension)
1514- << Str << " Xqciint" ;
1496+ if (!SemaRef.checkStringLiteralArgumentAttr (AL, ArgIndex, TypeString, &Loc))
1497+ return ;
1498+
1499+ if (!RISCVInterruptAttr::ConvertStrToInterruptType (TypeString, Type)) {
1500+ std::string TypeLiteral = (" \" " + TypeString + " \" " ).str ();
1501+ Diag (AL.getLoc (), diag::warn_attribute_type_not_supported)
1502+ << AL << TypeLiteral << Loc;
15151503 return ;
15161504 }
1517- break ;
1505+
1506+ switch (Type) {
1507+ case RISCVInterruptAttr::machine:
1508+ // "machine" could be combined with the SiFive CLIC types, or could be
1509+ // just "machine".
1510+ break ;
1511+ case RISCVInterruptAttr::SiFiveCLICPreemptible:
1512+ case RISCVInterruptAttr::SiFiveCLICStackSwap:
1513+ // SiFive-CLIC types can be combined with each other and "machine"
1514+ HasSiFiveCLICType = true ;
1515+ break ;
1516+ case RISCVInterruptAttr::supervisor:
1517+ case RISCVInterruptAttr::qcinest:
1518+ case RISCVInterruptAttr::qcinonest:
1519+ // "supervisor" and "qci-(no)nest" cannot be combined with any other types
1520+ HasUnaryType = true ;
1521+ break ;
1522+ }
1523+
1524+ Types.insert (Type);
1525+ }
1526+
1527+ if (HasUnaryType && Types.size () > 1 ) {
1528+ Diag (AL.getLoc (), diag::err_riscv_attribute_interrupt_invalid_combination);
1529+ return ;
15181530 }
1531+
1532+ if (HasUnaryType && HasSiFiveCLICType) {
1533+ Diag (AL.getLoc (), diag::err_riscv_attribute_interrupt_invalid_combination);
1534+ return ;
1535+ }
1536+
1537+ // "machine" is the default, if nothing is specified.
1538+ if (AL.getNumArgs () == 0 )
1539+ Types.insert (RISCVInterruptAttr::machine);
1540+
1541+ const TargetInfo &TI = getASTContext ().getTargetInfo ();
1542+ llvm::StringMap<bool > FunctionFeatureMap;
1543+ getASTContext ().getFunctionFeatureMap (FunctionFeatureMap,
1544+ dyn_cast<FunctionDecl>(D));
1545+
1546+ auto HasFeature = [&](StringRef FeatureName) -> bool {
1547+ return TI.hasFeature (FeatureName) || FunctionFeatureMap.lookup (FeatureName);
15191548 };
15201549
1521- D->addAttr (::new (getASTContext ())
1522- RISCVInterruptAttr (getASTContext (), AL, Kind));
1550+ for (RISCVInterruptAttr::InterruptType Type : Types) {
1551+ switch (Type) {
1552+ // The QCI interrupt types require Xqciint
1553+ case RISCVInterruptAttr::qcinest:
1554+ case RISCVInterruptAttr::qcinonest: {
1555+ if (!HasFeature (" experimental-xqciint" )) {
1556+ Diag (AL.getLoc (),
1557+ diag::err_riscv_attribute_interrupt_requires_extension)
1558+ << RISCVInterruptAttr::ConvertInterruptTypeToStr (Type) << " Xqciint" ;
1559+ return ;
1560+ }
1561+ } break ;
1562+ // The SiFive CLIC interrupt types require Xsfmclic
1563+ case RISCVInterruptAttr::SiFiveCLICPreemptible:
1564+ case RISCVInterruptAttr::SiFiveCLICStackSwap: {
1565+ if (!HasFeature (" experimental-xsfmclic" )) {
1566+ Diag (AL.getLoc (),
1567+ diag::err_riscv_attribute_interrupt_requires_extension)
1568+ << RISCVInterruptAttr::ConvertInterruptTypeToStr (Type)
1569+ << " XSfmclic" ;
1570+ return ;
1571+ }
1572+ } break ;
1573+ default :
1574+ break ;
1575+ }
1576+ }
1577+
1578+ SmallVector<RISCVInterruptAttr::InterruptType, 2 > TypesVec (Types.begin (),
1579+ Types.end ());
1580+
1581+ D->addAttr (::new (getASTContext ()) RISCVInterruptAttr (
1582+ getASTContext (), AL, TypesVec.data (), TypesVec.size ()));
15231583}
15241584
15251585bool SemaRISCV::isAliasValid (unsigned BuiltinID, StringRef AliasName) {
0 commit comments