[clang] [RISCV][clang] Support XSfmm ABI attributes (PR #206260)

via cfe-commits cfe-commits at lists.llvm.org
Sat Jun 27 08:55:46 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Brandon Wu (4vtomat)

<details>
<summary>Changes</summary>

This patch introduces a new attribute keyword to describe the architecture state for RISC-V, currently this is used by XSfmm matrix state, detail usage is described in SiFive documentation: https://www.sifive.com/document-file/xsfmm-matrix-extensions-specification

We add five new function type attributes:
  1. __riscv_in("xsfmm"): function reads from matrix state
  2. __riscv_out("xsfmm"): function writes to matrix state
  3. __riscv_inout("xsfmm"): function reads and writes matrix state
  4. __riscv_preserves("xsfmm"): function doesn't read or write state
  5. __riscv_new("xsfmm"): function initiates new matrix state

TODO: Support __xsfmm_preserves statement attribute. We should allow non user-defined functions that are xsfmm unaware and is proved to not reading or writing the state, e.g. libc, libm, etc. One of the approach is providing statement attribute, e.g. __xsfmm_preserves printf("hello\n");, to make sema checking recognize and be aware of this call.

---

Patch is 33.80 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/206260.diff


10 Files Affected:

- (modified) clang/include/clang/AST/TypeBase.h (+95-7) 
- (modified) clang/include/clang/Basic/Attr.td (+35) 
- (modified) clang/include/clang/Basic/AttrDocs.td (+67) 
- (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+9) 
- (modified) clang/lib/AST/ASTContext.cpp (+4-2) 
- (modified) clang/lib/AST/Type.cpp (+18) 
- (modified) clang/lib/AST/TypePrinter.cpp (+5) 
- (modified) clang/lib/Sema/SemaChecking.cpp (+100) 
- (modified) clang/lib/Sema/SemaType.cpp (+102) 
- (added) clang/test/Sema/sifive-xsfmm-func-attr.c (+142) 


``````````diff
diff --git a/clang/include/clang/AST/TypeBase.h b/clang/include/clang/AST/TypeBase.h
index c9658775f0470..9654bdf34a196 100644
--- a/clang/include/clang/AST/TypeBase.h
+++ b/clang/include/clang/AST/TypeBase.h
@@ -4816,14 +4816,17 @@ class FunctionType : public Type {
     LLVM_PREFERRED_TYPE(bool)
     unsigned HasArmTypeAttributes : 1;
 
+    LLVM_PREFERRED_TYPE(bool)
+    unsigned HasRISCVTypeAttributes : 1;
+
     LLVM_PREFERRED_TYPE(bool)
     unsigned EffectsHaveConditions : 1;
     unsigned NumFunctionEffects : 4;
 
     FunctionTypeExtraBitfields()
         : NumExceptionType(0), HasExtraAttributeInfo(false),
-          HasArmTypeAttributes(false), EffectsHaveConditions(false),
-          NumFunctionEffects(0) {}
+          HasArmTypeAttributes(false), HasRISCVTypeAttributes(false),
+          EffectsHaveConditions(false), NumFunctionEffects(0) {}
   };
 
   /// A holder for extra information from attributes which aren't part of an
@@ -4869,6 +4872,46 @@ class FunctionType : public Type {
     ARM_InOut = 4,
   };
 
+  /// RISC-V type attributes for states.
+  enum RISCVTypeAttributes : uint8_t {
+    RISCVNormalFunction = 0,
+
+    // Describes the value of the xsfmm tile state using RISCVStateValue.
+    // Each tile gets 3 bits to store its state.
+    RISCVXsfmmShift = 0,
+    RISCVXsfmmMask = 0b111 << RISCVXsfmmShift,
+
+    // Currently using 3 bits for xsfmm
+    RISCVAttributeMask = 0b111
+  };
+
+  enum RISCVStateValue : unsigned {
+    RISCVNone = 0,
+    RISCVIn = 1,
+    RISCVOut = 2,
+    RISCVInOut = 3,
+    RISCVPreserves = 4,
+    RISCVNew = 5,
+  };
+
+  static const char *ToRISCVStateString(RISCVStateValue St) {
+    switch (St) {
+    case RISCVNone:
+      return "none";
+    case RISCVIn:
+      return "__riscv_in";
+    case RISCVOut:
+      return "__riscv_out";
+    case RISCVInOut:
+      return "__riscv_inout";
+    case RISCVPreserves:
+      return "__riscv_preserves";
+    case RISCVNew:
+      return "__riscv_new";
+    }
+    llvm_unreachable("Invalid RISCV state value");
+  }
+
   static ArmStateValue getArmZAState(unsigned AttrBits) {
     return static_cast<ArmStateValue>((AttrBits & SME_ZAMask) >> SME_ZAShift);
   }
@@ -4877,6 +4920,11 @@ class FunctionType : public Type {
     return static_cast<ArmStateValue>((AttrBits & SME_ZT0Mask) >> SME_ZT0Shift);
   }
 
+  static RISCVStateValue getRISCVXsfmmState(unsigned AttrBits) {
+    return static_cast<RISCVStateValue>((AttrBits & RISCVXsfmmMask) >>
+                                        RISCVXsfmmShift);
+  }
+
   /// A holder for Arm type attributes as described in the Arm C/C++
   /// Language extensions which are not particularly common to all
   /// types and therefore accounted separately from FunctionTypeBitfields.
@@ -4889,6 +4937,13 @@ class FunctionType : public Type {
     FunctionTypeArmAttributes() : AArch64SMEAttributes(SME_NormalFunction) {}
   };
 
+  struct alignas(void *) FunctionTypeRISCVAttributes {
+    LLVM_PREFERRED_TYPE(RISCVTypeAttributes)
+    unsigned RISCVAttributes : 3;
+
+    FunctionTypeRISCVAttributes() : RISCVAttributes(RISCVNormalFunction) {}
+  };
+
 protected:
   FunctionType(TypeClass tc, QualType res, QualType Canonical,
                TypeDependence Dependence, ExtInfo Info)
@@ -5366,9 +5421,11 @@ class FunctionProtoType final
           FunctionProtoType, QualType, SourceLocation,
           FunctionType::FunctionTypeExtraBitfields,
           FunctionType::FunctionTypeExtraAttributeInfo,
-          FunctionType::FunctionTypeArmAttributes, FunctionType::ExceptionType,
-          Expr *, FunctionDecl *, FunctionType::ExtParameterInfo, Qualifiers,
-          FunctionEffect, EffectConditionExpr> {
+          FunctionType::FunctionTypeArmAttributes,
+          FunctionType::FunctionTypeRISCVAttributes,
+          FunctionType::ExceptionType, Expr *, FunctionDecl *,
+          FunctionType::ExtParameterInfo, Qualifiers, FunctionEffect,
+          EffectConditionExpr> {
   friend class ASTContext; // ASTContext creates these.
   friend TrailingObjects;
 
@@ -5471,14 +5528,18 @@ class FunctionProtoType final
     unsigned CFIUncheckedCallee : 1;
     LLVM_PREFERRED_TYPE(AArch64SMETypeAttributes)
     unsigned AArch64SMEAttributes : 9;
+    LLVM_PREFERRED_TYPE(RISCVTypeAttributes)
+    unsigned RISCVAttributes : 3;
 
     ExtProtoInfo()
         : Variadic(false), HasTrailingReturn(false), CFIUncheckedCallee(false),
-          AArch64SMEAttributes(SME_NormalFunction) {}
+          AArch64SMEAttributes(SME_NormalFunction),
+          RISCVAttributes(RISCVNormalFunction) {}
 
     ExtProtoInfo(CallingConv CC)
         : ExtInfo(CC), Variadic(false), HasTrailingReturn(false),
-          CFIUncheckedCallee(false), AArch64SMEAttributes(SME_NormalFunction) {}
+          CFIUncheckedCallee(false), AArch64SMEAttributes(SME_NormalFunction),
+          RISCVAttributes(RISCVNormalFunction) {}
 
     ExtProtoInfo withExceptionSpec(const ExceptionSpecInfo &ESI) {
       ExtProtoInfo Result(*this);
@@ -5495,6 +5556,7 @@ class FunctionProtoType final
     bool requiresFunctionProtoTypeExtraBitfields() const {
       return ExceptionSpec.Type == EST_Dynamic ||
              requiresFunctionProtoTypeArmAttributes() ||
+             requiresFunctionProtoTypeRISCVAttributes() ||
              requiresFunctionProtoTypeExtraAttributeInfo() ||
              !FunctionEffects.empty();
     }
@@ -5513,6 +5575,14 @@ class FunctionProtoType final
       else
         AArch64SMEAttributes &= ~Kind;
     }
+
+    bool requiresFunctionProtoTypeRISCVAttributes() const {
+      return RISCVAttributes != RISCVNormalFunction;
+    }
+
+    void setRISCVAttribute(RISCVTypeAttributes Kind) {
+      RISCVAttributes |= Kind;
+    }
   };
 
 private:
@@ -5528,6 +5598,11 @@ class FunctionProtoType final
     return hasArmTypeAttributes();
   }
 
+  unsigned
+  numTrailingObjects(OverloadToken<FunctionTypeRISCVAttributes>) const {
+    return hasRISCVTypeAttributes();
+  }
+
   unsigned numTrailingObjects(OverloadToken<FunctionTypeExtraBitfields>) const {
     return hasExtraBitfields();
   }
@@ -5641,6 +5716,12 @@ class FunctionProtoType final
                ->HasArmTypeAttributes;
   }
 
+  bool hasRISCVTypeAttributes() const {
+    return FunctionTypeBits.HasExtraBitfields &&
+           getTrailingObjects<FunctionTypeExtraBitfields>()
+               ->HasRISCVTypeAttributes;
+  }
+
   bool hasExtQualifiers() const {
     return FunctionTypeBits.HasExtQuals;
   }
@@ -5670,6 +5751,7 @@ class FunctionProtoType final
     EPI.ExtParameterInfos = getExtParameterInfosOrNull();
     EPI.ExtraAttributeInfo = getExtraAttributeInfo();
     EPI.AArch64SMEAttributes = getAArch64SMEAttributes();
+    EPI.RISCVAttributes = getRISCVAttributes();
     EPI.FunctionEffects = getFunctionEffects();
     return EPI;
   }
@@ -5872,6 +5954,12 @@ class FunctionProtoType final
         ->AArch64SMEAttributes;
   }
 
+  unsigned getRISCVAttributes() const {
+    if (!hasRISCVTypeAttributes())
+      return RISCVNormalFunction;
+    return getTrailingObjects<FunctionTypeRISCVAttributes>()->RISCVAttributes;
+  }
+
   ExtParameterInfo getExtParameterInfo(unsigned I) const {
     assert(I < getNumParams() && "parameter index out of range");
     if (hasExtParameterInfos())
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index a222092cd42cf..9e78094640b33 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -3583,6 +3583,41 @@ def RISCVVLSCC: DeclOrTypeAttr, TargetSpecificAttr<TargetRISCV> {
  let Documentation = [RISCVVLSCCDocs];
 }
 
+def RISCVIn : TypeAttr, TargetSpecificAttr<TargetRISCV> {
+  let Spellings = [RegularKeyword<"__riscv_in">];
+  let Args = [VariadicStringArgument<"InArgs">];
+  let Subjects = SubjectList<[HasFunctionProto], ErrorDiag>;
+  let Documentation = [RISCVInDocs];
+}
+
+def RISCVOut : TypeAttr, TargetSpecificAttr<TargetRISCV> {
+  let Spellings = [RegularKeyword<"__riscv_out">];
+  let Args = [VariadicStringArgument<"OutArgs">];
+  let Subjects = SubjectList<[HasFunctionProto], ErrorDiag>;
+  let Documentation = [RISCVOutDocs];
+}
+
+def RISCVInOut : TypeAttr, TargetSpecificAttr<TargetRISCV> {
+  let Spellings = [RegularKeyword<"__riscv_inout">];
+  let Args = [VariadicStringArgument<"InOutArgs">];
+  let Subjects = SubjectList<[HasFunctionProto], ErrorDiag>;
+  let Documentation = [RISCVInOutDocs];
+}
+
+def RISCVPreserves : TypeAttr, TargetSpecificAttr<TargetRISCV> {
+  let Spellings = [RegularKeyword<"__riscv_preserves">];
+  let Args = [VariadicStringArgument<"PreserveArgs">];
+  let Subjects = SubjectList<[HasFunctionProto], ErrorDiag>;
+  let Documentation = [RISCVPreservesDocs];
+}
+
+def RISCVNew : TypeAttr, TargetSpecificAttr<TargetRISCV> {
+  let Spellings = [RegularKeyword<"__riscv_new">];
+  let Args = [VariadicStringArgument<"NewArgs">];
+  let Subjects = SubjectList<[HasFunctionProto], ErrorDiag>;
+  let Documentation = [RISCVNewDocs];
+}
+
 def Target : InheritableAttr {
   let Spellings = [GCC<"target">];
   let Args = [StringArgument<"featuresStr">];
diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index 04362de2d5be2..c86891c3c5cea 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -6787,6 +6787,73 @@ the ABI. This variant aims to pass fixed-length vectors via vector registers,
 if possible, rather than through general-purpose registers.}];
 }
 
+def RISCVInDocs : Documentation {
+  let Category = DocCatFunction;
+  let Heading = "__riscv_in";
+  let Content = [{
+The ``__riscv_in(S)`` attribute indicates that a function reads from state S.
+This attribute is usually used in RISC-V matrix extensions to specify that the
+function will read from a matrix state passed as arguments.
+This helps compiler checks to prevent common programming errors that could lead
+to undefined behavior, data corruption, or incorrect computation results when
+working with matrix operations.
+  }];
+}
+
+def RISCVOutDocs : Documentation {
+  let Category = DocCatFunction;
+  let Heading = "__riscv_out";
+  let Content = [{
+The ``__riscv_out(S)`` attribute indicates that a function writes to state S.
+This attribute is usually used in RISC-V matrix extensions to specify that the
+function will write to a matrix state passed as arguments.
+This helps compiler checks to prevent common programming errors that could lead
+to undefined behavior, data corruption, or incorrect computation results when
+working with matrix operations.
+  }];
+}
+
+def RISCVInOutDocs : Documentation {
+  let Category = DocCatFunction;
+  let Heading = "__riscv_inout";
+  let Content = [{
+The ``__riscv_inout(S)`` attribute indicates that a function reads from and
+writes to state S.
+This attribute is usually used in RISC-V matrix extensions to specify that the
+function will read from and write to a matrix state passed as arguments.
+This helps compiler checks to prevent common programming errors that could lead
+to undefined behavior, data corruption, or incorrect computation results when
+working with matrix operations.
+  }];
+}
+
+def RISCVPreservesDocs : Documentation {
+  let Category = DocCatFunction;
+  let Heading = "__riscv_preserves";
+  let Content = [{
+The ``__riscv_preserves(S)`` attribute indicates that a function neither reads
+from nor writes to state S.
+This attribute is usually used in RISC-V matrix extensions to specify that the
+function will not read from or write to a matrix state passed as arguments.
+This helps compiler checks to prevent common programming errors that could lead
+to undefined behavior, data corruption, or incorrect computation results when
+working with matrix operations.
+  }];
+}
+
+def RISCVNewDocs : Documentation {
+  let Category = DocCatFunction;
+  let Heading = "__riscv_new";
+  let Content = [{
+The ``__riscv_new(S)`` attribute indicates that a function initiates a new state.
+This attribute is usually used in RISC-V matrix extensions to specify that the
+function will initiate a new matrix state passed as arguments.
+This helps compiler checks to prevent common programming errors that could lead
+to undefined behavior, data corruption, or incorrect computation results when
+working with matrix operations.
+  }];
+}
+
 def PreferredNameDocs : Documentation {
   let Category = DocCatDecl;
   let Content = [{
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index f7fba8df1e4d7..42a55dcdf0128 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -13619,6 +13619,15 @@ def err_riscv_attribute_interrupt_requires_extension : Error<
 def err_riscv_attribute_interrupt_invalid_combination : Error<
   "RISC-V 'interrupt' attribute contains invalid combination of interrupt types">;
 def err_riscv_builtin_invalid_twiden : Error<"RISC-V XSfmm twiden must be 1, 2 or 4">;
+// RISC-V errors
+def err_riscv_call_invalid_features : Error<
+  "call to an attributed function requires %0">;
+def err_missing_riscv_state : Error<"missing state for %0">;
+def err_unknown_riscv_state : Error<"unknown state '%0'">;
+def err_conflicting_attributes_riscv_state : Error<
+  "conflicting attribute. Description: %0">;
+def err_mutually_exclusive_attributes_riscv_state : Error<
+  "mutually exclusive attributes for state '%0'">;
 
 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/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index abf0cd5e18c2b..c02b43c947072 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -5161,12 +5161,14 @@ QualType ASTContext::getFunctionTypeInternal(
   size_t Size = FunctionProtoType::totalSizeToAlloc<
       QualType, SourceLocation, FunctionType::FunctionTypeExtraBitfields,
       FunctionType::FunctionTypeExtraAttributeInfo,
-      FunctionType::FunctionTypeArmAttributes, FunctionType::ExceptionType,
+      FunctionType::FunctionTypeArmAttributes,
+      FunctionType::FunctionTypeRISCVAttributes, FunctionType::ExceptionType,
       Expr *, FunctionDecl *, FunctionProtoType::ExtParameterInfo, Qualifiers,
       FunctionEffect, EffectConditionExpr>(
       NumArgs, EPI.Variadic, EPI.requiresFunctionProtoTypeExtraBitfields(),
       EPI.requiresFunctionProtoTypeExtraAttributeInfo(),
-      EPI.requiresFunctionProtoTypeArmAttributes(), ESH.NumExceptionType,
+      EPI.requiresFunctionProtoTypeArmAttributes(),
+      EPI.requiresFunctionProtoTypeRISCVAttributes(), ESH.NumExceptionType,
       ESH.NumExprPtr, ESH.NumFunctionDeclPtr,
       EPI.ExtParameterInfos ? NumArgs : 0,
       EPI.TypeQuals.hasNonFastQualifiers() ? 1 : 0, EPI.FunctionEffects.size(),
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index b7bef40ca89f3..f704f748f7055 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -3819,6 +3819,15 @@ FunctionProtoType::FunctionProtoType(QualType result, ArrayRef<QualType> params,
     ExtraBits.HasArmTypeAttributes = true;
   }
 
+  if (epi.requiresFunctionProtoTypeRISCVAttributes()) {
+    auto &RISCVTypeAttrs = *getTrailingObjects<FunctionTypeRISCVAttributes>();
+    RISCVTypeAttrs = FunctionTypeRISCVAttributes();
+
+    // Also set the bit in FunctionTypeExtraBitfields
+    auto &ExtraBits = *getTrailingObjects<FunctionTypeExtraBitfields>();
+    ExtraBits.HasRISCVTypeAttributes = true;
+  }
+
   // Fill in the trailing argument array.
   auto *argSlot = getTrailingObjects<QualType>();
   for (unsigned i = 0; i != getNumParams(); ++i) {
@@ -3835,6 +3844,14 @@ FunctionProtoType::FunctionProtoType(QualType result, ArrayRef<QualType> params,
     ArmTypeAttrs.AArch64SMEAttributes = epi.AArch64SMEAttributes;
   }
 
+  // Propagate the RISC-V state attributes.
+  if (epi.RISCVAttributes != RISCVNormalFunction) {
+    auto &RISCVTypeAttrs = *getTrailingObjects<FunctionTypeRISCVAttributes>();
+    assert(epi.RISCVAttributes <= RISCVAttributeMask &&
+           "Not enough bits to encode RISC-V attributes");
+    RISCVTypeAttrs.RISCVAttributes = epi.RISCVAttributes;
+  }
+
   // Fill in the exception type array if present.
   if (getExceptionSpecType() == EST_Dynamic) {
     auto &ExtraBits = *getTrailingObjects<FunctionTypeExtraBitfields>();
@@ -4071,6 +4088,7 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
   ID.AddInteger((EffectCount << 3) | (HasConds << 2) |
                 (epi.AArch64SMEAttributes << 1) | epi.HasTrailingReturn);
   ID.AddInteger(epi.CFIUncheckedCallee);
+  ID.AddInteger(epi.RISCVAttributes);
 
   for (unsigned Idx = 0; Idx != EffectCount; ++Idx) {
     ID.AddInteger(epi.FunctionEffects.Effects[Idx].toOpaqueInt32());
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index e8fbffb9f954d..04d990d028694 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -2060,6 +2060,11 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
   case attr::ArmOut:
   case attr::ArmInOut:
   case attr::ArmPreserves:
+  case attr::RISCVIn:
+  case attr::RISCVOut:
+  case attr::RISCVInOut:
+  case attr::RISCVPreserves:
+  case attr::RISCVNew:
   case attr::NonBlocking:
   case attr::NonAllocating:
   case attr::Blocking:
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index ec4a9037f5c23..13a15f4bb0b83 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -4536,6 +4536,106 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
         Diag(Loc, diag::note_sme_use_preserves_za);
       }
     }
+
+    // Check if there's any conflicting call for every state, it should not be
+    // any conflict if caller and callee are in different state.
+
+    if (CallerFD &&
+        (!FD || !FD->getBuiltinID() ||
+         Context.BuiltinInfo.isLibFunction(FD->getBuiltinID()) ||
+         Context.BuiltinInfo.isPredefinedLibFunction(FD->getBuiltinID()))) {
+      QualType CallerType = CallerFD->getType();
+      if (!CallerType.isNull()) {
+        if (const auto *FPT = CallerType->getAs<FunctionProtoType>()) {
+          FunctionProtoType::ExtProtoInfo CallerExtInfo =
+              FPT->getExtProtoInfo();
+          llvm::StringMap<bool> CallerFeatureMap;
+          if (CallerExtInfo.RISCVAttributes & FunctionType::RISCVAttributeMask)
+            Context.getFunctionFeatureMap(CallerFeatureMap, CallerFD);
+          // tuple(CallerAttr, CalleeAttr, required feature)
+          const std::tuple<FunctionType::RISCVStateValue,
+                           FunctionType::RISCVStateValue, StringRef>
+              RISCVStateInfo[] = {
+                  {FunctionType::getRISCVXsfmmState(
+                       CallerExtInfo.RISCVAttributes),
+                   FunctionType::getRISCVXsfmmState(ExtInfo.RISCVAttributes),
+                   "xsfmmbase"}};
+          for (auto [CallerAttr, CalleeAttr, RequiredFeature] :
+               RISCVStateInfo) {
+            // If both caller and callee are not attributed, then we're fine.
+            if (CallerAttr == FunctionType::RISCVNone &&
+                CalleeAttr == FunctionType::RISCVNone)
+              continue;
+
+            if (!Context.getTargetInfo().hasFeature(RequiredFeature) &&
+                !CallerFeatureMap.lookup(RequiredFeature)) {
+              // check if corresponding attributes are enabled.
+              Diag(Loc, diag::err_riscv_call_invalid_features)
+                  << RequiredFeature;
+              continue;
+            }
+
+            switch (CallerAttr) {
+            case FunctionType::RISCVNone:
+              if (CalleeAttr != FunctionType::RISCVNew) {
+                // Check limitation:
+                // 1. Only __riscv_new function can be called in non-attributed
+                // function.
+                Diag(Loc, diag::err_conflicting_attributes_riscv_state)
+                    << "Only __riscv_new function can be called in "
+                       "non-attributed function.";
+              }
+              break;
+            case FunctionType::RISCVIn:
+              if (CalleeAttr != FunctionType::RISCVIn &&
+                  CalleeAttr != FunctionType::RISCVPreserves) {
+                // 2. Function with __riscv_in can only call __ris...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/206260


More information about the cfe-commits mailing list