https://github.com/mylai-mtk updated 
https://github.com/llvm/llvm-project/pull/111661

>From b3a7b9f4bd6d65f837b3cc9e4a0e0bd6fdede6ab Mon Sep 17 00:00:00 2001
From: Ming-Yi Lai <ming-yi....@mediatek.com>
Date: Fri, 31 May 2024 17:03:04 +0800
Subject: [PATCH] [clang][RISCV] Emit RISCV function-signature-based CFI label
 in llvm::Function metadata

---
 clang/include/clang/AST/ASTContext.h          |   7 +
 clang/include/clang/AST/Mangle.h              |   5 +
 clang/lib/AST/ASTContext.cpp                  |   6 +
 clang/lib/AST/ItaniumMangle.cpp               | 138 +++++++++++++++++-
 clang/lib/CodeGen/CodeGenModule.cpp           | 124 ++++++++++++++++
 clang/lib/CodeGen/CodeGenModule.h             |  17 +++
 .../mangle-class-covariant-virtual-method.cpp |  39 +++++
 .../mangle-class-destructor.cpp               |  19 +++
 ...angle-class-incovariant-virtual-method.cpp |  20 +++
 .../zicfilp-func-sig/mangle-class-method.cpp  |  21 +++
 .../mangle-class-static-method.cpp            |  23 +++
 .../mangle-func-empty-param-list.c            |  17 +++
 .../mangle-func-empty-param-list.cpp          |  17 +++
 .../mangle-ignore-exception-spec.cpp          |  17 +++
 .../RISCV/zicfilp-func-sig/mangle-main.cpp    |  41 ++++++
 .../RISCV/zicfilp-func-sig/mangle-wchar-t.cpp |  14 ++
 llvm/include/llvm/Support/RISCVISAUtils.h     |   6 +-
 llvm/lib/Support/RISCVISAUtils.cpp            |  22 ++-
 llvm/unittests/Support/CMakeLists.txt         |   1 +
 llvm/unittests/Support/RISCVISAUtils.cpp      |  23 +++
 20 files changed, 573 insertions(+), 4 deletions(-)
 create mode 100644 
clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-class-covariant-virtual-method.cpp
 create mode 100644 
clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-class-destructor.cpp
 create mode 100644 
clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-class-incovariant-virtual-method.cpp
 create mode 100644 
clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-class-method.cpp
 create mode 100644 
clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-class-static-method.cpp
 create mode 100644 
clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-func-empty-param-list.c
 create mode 100644 
clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-func-empty-param-list.cpp
 create mode 100644 
clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-ignore-exception-spec.cpp
 create mode 100644 clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-main.cpp
 create mode 100644 clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-wchar-t.cpp
 create mode 100644 llvm/unittests/Support/RISCVISAUtils.cpp

diff --git a/clang/include/clang/AST/ASTContext.h 
b/clang/include/clang/AST/ASTContext.h
index 1fdc488a76507..2349f3eab3950 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -1952,6 +1952,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
   /// (struct/union/class/enum) decl.
   QualType getTagDeclType(const TagDecl *Decl) const;
 
+  /// Return the type for "void *"
+  QualType getVoidPtrType() const { return VoidPtrTy; }
+
   /// Return the unique type for "size_t" (C99 7.17), defined in
   /// <stddef.h>.
   ///
@@ -1979,6 +1982,10 @@ class ASTContext : public RefCountedBase<ASTContext> {
   /// defined in <stddef.h> as defined by the target.
   QualType getWideCharType() const { return WideCharTy; }
 
+  /// Return the type of wide characters in C context, no matter whether it's C
+  /// or C++ being compiled.
+  QualType getWCharTypeInC() const;
+
   /// Return the type of "signed wchar_t".
   ///
   /// Used when in C++, as a GCC extension.
diff --git a/clang/include/clang/AST/Mangle.h b/clang/include/clang/AST/Mangle.h
index ca72dcfd4483d..579df6d6bfbb7 100644
--- a/clang/include/clang/AST/Mangle.h
+++ b/clang/include/clang/AST/Mangle.h
@@ -215,6 +215,11 @@ class ItaniumMangleContext : public MangleContext {
 
   virtual void mangleModuleInitializer(const Module *Module, raw_ostream &) = 
0;
 
+  virtual void mangleForRISCVZicfilpFuncSigLabel(const FunctionType &FT,
+                                                 const bool 
IsCXXInstanceMethod,
+                                                 const bool IsCXXVirtualMethod,
+                                                 raw_ostream &) = 0;
+
   // This has to live here, otherwise the CXXNameMangler won't have access to
   // it.
   virtual DiscriminatorOverrideTy getDiscriminatorOverride() const = 0;
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index b5417fcf20ddd..a3e1a09157265 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -6712,6 +6712,12 @@ CanQualType ASTContext::getUIntMaxType() const {
   return getFromTargetType(Target->getUIntMaxType());
 }
 
+/// Return the type of wide characters in C context, no matter whether it's C
+/// or C++ being compiled.
+QualType ASTContext::getWCharTypeInC() const {
+  return getFromTargetType(Target->getWCharType());
+}
+
 /// getSignedWCharType - Return the type of "signed wchar_t".
 /// Used when in C++, as a GCC extension.
 QualType ASTContext::getSignedWCharType() const {
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 33a8728728574..b22bc5e50ee9b 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -41,6 +41,14 @@ using namespace clang;
 
 namespace {
 
+static bool mayBeCovariant(const Type &Ty) {
+  if (auto *const PT = Ty.getAs<PointerType>())
+    return PT->getPointeeType()->isStructureOrClassType();
+  if (auto *const RT = Ty.getAs<ReferenceType>())
+    return RT->getPointeeType()->isStructureOrClassType();
+  return false;
+}
+
 static bool isLocalContainerContext(const DeclContext *DC) {
   return isa<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC) || 
isa<BlockDecl>(DC);
 }
@@ -134,6 +142,11 @@ class ItaniumMangleContextImpl : public 
ItaniumMangleContext {
 
   void mangleModuleInitializer(const Module *Module, raw_ostream &) override;
 
+  void mangleForRISCVZicfilpFuncSigLabel(const FunctionType &,
+                                         const bool IsCXXInstanceMethod,
+                                         const bool IsCXXVirtualMethod,
+                                         raw_ostream &) override;
+
   bool getNextDiscriminator(const NamedDecl *ND, unsigned &disc) {
     // Lambda closure types are already numbered.
     if (isLambda(ND))
@@ -386,8 +399,10 @@ class CXXNameMangler {
   llvm::DenseMap<uintptr_t, unsigned> Substitutions;
   llvm::DenseMap<StringRef, unsigned> ModuleSubstitutions;
 
+protected:
   ASTContext &getASTContext() const { return Context.getASTContext(); }
 
+private:
   bool isCompatibleWith(LangOptions::ClangABI Ver) {
     return Context.getASTContext().getLangOpts().getClangABICompat() <= Ver;
   }
@@ -434,6 +449,8 @@ class CXXNameMangler {
     NullOut = true;
   }
 
+  virtual ~CXXNameMangler() = default;
+
   struct WithTemplateDepthOffset { unsigned Offset; };
   CXXNameMangler(ItaniumMangleContextImpl &C, raw_ostream &Out,
                  WithTemplateDepthOffset Offset)
@@ -552,9 +569,12 @@ class CXXNameMangler {
                                       StringRef Prefix = "");
   void mangleOperatorName(DeclarationName Name, unsigned Arity);
   void mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity);
+
+protected:
   void mangleQualifiers(Qualifiers Quals, const DependentAddressSpaceType 
*DAST = nullptr);
   void mangleRefQualifier(RefQualifierKind RefQualifier);
 
+private:
   void mangleObjCMethodName(const ObjCMethodDecl *MD);
 
   // Declare manglers for every type class.
@@ -565,12 +585,25 @@ class CXXNameMangler {
 
   void mangleType(const TagType*);
   void mangleType(TemplateName);
+
+protected:
+  // Use the `Impl` scheme instead of directly virtualizing `mangleType`s since
+  // `mangleType`s are declared by tables
+  virtual void mangleTypeImpl(const BuiltinType *T);
+  virtual void mangleTypeImpl(const FunctionProtoType *T);
+  virtual void mangleTypeImpl(const FunctionNoProtoType *T);
+
+private:
   static StringRef getCallingConvQualifierName(CallingConv CC);
   void mangleExtParameterInfo(FunctionProtoType::ExtParameterInfo info);
   void mangleExtFunctionInfo(const FunctionType *T);
   void mangleSMEAttrs(unsigned SMEAttrs);
+
+protected:
   void mangleBareFunctionType(const FunctionProtoType *T, bool 
MangleReturnType,
                               const FunctionDecl *FD = nullptr);
+
+private:
   void mangleNeonVectorType(const VectorType *T);
   void mangleNeonVectorType(const DependentVectorType *T);
   void mangleAArch64NeonVectorType(const VectorType *T);
@@ -3111,7 +3144,9 @@ void CXXNameMangler::mangleCXXRecordDecl(const 
CXXRecordDecl *Record) {
   addSubstitution(Record);
 }
 
-void CXXNameMangler::mangleType(const BuiltinType *T) {
+void CXXNameMangler::mangleType(const BuiltinType *T) { mangleTypeImpl(T); }
+
+void CXXNameMangler::mangleTypeImpl(const BuiltinType *T) {
   //  <type>         ::= <builtin-type>
   //  <builtin-type> ::= v  # void
   //                 ::= w  # wchar_t
@@ -3694,10 +3729,14 @@ 
CXXNameMangler::mangleExtParameterInfo(FunctionProtoType::ExtParameterInfo PI) {
     mangleVendorQualifier("noescape");
 }
 
+void CXXNameMangler::mangleType(const FunctionProtoType *T) {
+  return mangleTypeImpl(T);
+}
+
 // <type>          ::= <function-type>
 // <function-type> ::= [<CV-qualifiers>] F [Y]
 //                      <bare-function-type> [<ref-qualifier>] E
-void CXXNameMangler::mangleType(const FunctionProtoType *T) {
+void CXXNameMangler::mangleTypeImpl(const FunctionProtoType *T) {
   unsigned SMEAttrs = T->getAArch64SMEAttributes();
 
   if (SMEAttrs)
@@ -3742,6 +3781,10 @@ void CXXNameMangler::mangleType(const FunctionProtoType 
*T) {
 }
 
 void CXXNameMangler::mangleType(const FunctionNoProtoType *T) {
+  return mangleTypeImpl(T);
+}
+
+void CXXNameMangler::mangleTypeImpl(const FunctionNoProtoType *T) {
   // Function types without prototypes can arise when mangling a function type
   // within an overloadable function in C. We mangle these as the absence of 
any
   // parameter types (not even an empty parameter list).
@@ -7233,6 +7276,86 @@ bool 
CXXNameMangler::shouldHaveAbiTags(ItaniumMangleContextImpl &C,
   return TrackAbiTags.AbiTagsRoot.getUsedAbiTags().size();
 }
 
+namespace {
+
+class RISCVZicfilpFuncSigLabelMangler : public CXXNameMangler {
+  bool IsTopLevelAndCXXVirtualMethod;
+
+public:
+  RISCVZicfilpFuncSigLabelMangler(ItaniumMangleContextImpl &C, raw_ostream 
&Out,
+                                  const bool IsCXXVirtualMethod)
+      : CXXNameMangler(C, Out),
+        IsTopLevelAndCXXVirtualMethod(/*IsTopLevel=*/true &&
+                                      IsCXXVirtualMethod) {}
+
+  void mangleTypeImpl(const BuiltinType *T) override {
+    if (T->getKind() == BuiltinType::WChar_S ||
+        T->getKind() == BuiltinType::WChar_U) {
+      const Type *const OverrideT =
+          getASTContext().getWCharTypeInC().getTypePtr();
+      assert(isa<BuiltinType>(OverrideT) &&
+             "`wchar_t' in C is expected to be defined to a built-in type");
+      T = static_cast<const BuiltinType *>(OverrideT);
+    }
+    return CXXNameMangler::mangleTypeImpl(T);
+  }
+
+  // This <function-type> is the RISC-V psABI modified version
+  // <function-type> ::= [<CV-qualifiers>] [Dx] F <bare-function-type>
+  //                     [<ref-qualifier>] E
+  void mangleTypeImpl(const FunctionProtoType *T) override {
+    const bool WasTopLevelAndCXXVirtualMethod = IsTopLevelAndCXXVirtualMethod;
+    IsTopLevelAndCXXVirtualMethod = false; // Not top-level anymore
+
+    // Mangle CV-qualifiers, if present.  These are 'this' qualifiers,
+    // e.g. "const" in "int (A::*)() const".
+    mangleQualifiers(T->getMethodQuals());
+
+    getStream() << 'F';
+
+    bool MangleReturnType = true;
+    if (const Type &RetT = *T->getReturnType().getTypePtr();
+        WasTopLevelAndCXXVirtualMethod && mayBeCovariant(RetT)) {
+      // Possible covariant types mangle dummy cv-unqualified `class v` as its
+      // class type
+      if (RetT.isPointerType())
+        getStream() << "P1v";
+      else if (RetT.isLValueReferenceType())
+        getStream() << "R1v";
+      else {
+        assert(RetT.isRValueReferenceType() &&
+               "Expect an r-value ref for covariant return type that is not a "
+               "pointer or an l-value ref");
+        getStream() << "O1v";
+      }
+      MangleReturnType = false;
+    }
+    mangleBareFunctionType(T, MangleReturnType);
+
+    // Mangle the ref-qualifier, if present.
+    mangleRefQualifier(T->getRefQualifier());
+
+    getStream() << 'E';
+  }
+
+  void mangleTypeImpl(const FunctionNoProtoType *T) override {
+    return CXXNameMangler::mangleTypeImpl(toFunctionProtoType(T));
+  }
+
+private:
+  const FunctionProtoType *
+  toFunctionProtoType(const FunctionNoProtoType *const T) {
+    FunctionProtoType::ExtProtoInfo EPI;
+    EPI.ExtInfo = T->getExtInfo();
+    const Type *const NewT = getASTContext()
+                                 .getFunctionType(T->getReturnType(), {}, EPI)
+                                 .getTypePtr();
+    return static_cast<const FunctionProtoType *>(NewT);
+  }
+}; // class RISCVZicfilpFuncSigLabelMangler
+
+} // anonymous namespace
+
 //
 
 /// Mangles the name of the declaration D and emits that name to the given
@@ -7571,6 +7694,17 @@ void 
ItaniumMangleContextImpl::mangleModuleInitializer(const Module *M,
   }
 }
 
+void ItaniumMangleContextImpl::mangleForRISCVZicfilpFuncSigLabel(
+    const FunctionType &FT, const bool IsCXXInstanceMethod,
+    const bool IsCXXVirtualMethod, raw_ostream &Out) {
+  if (IsCXXInstanceMethod)
+    // member methods uses a dummy class named `v` in place of real classes
+    Out << "M1v";
+
+  RISCVZicfilpFuncSigLabelMangler Mangler(*this, Out, IsCXXVirtualMethod);
+  Mangler.mangleType(QualType(&FT, 0));
+}
+
 ItaniumMangleContext *ItaniumMangleContext::create(ASTContext &Context,
                                                    DiagnosticsEngine &Diags,
                                                    bool IsAux) {
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp 
b/clang/lib/CodeGen/CodeGenModule.cpp
index 16e010adbeb5f..cbe69fd91eee4 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -66,6 +66,7 @@
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/ConvertUTF.h"
 #include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/RISCVISAUtils.h"
 #include "llvm/Support/TimeProfiler.h"
 #include "llvm/Support/xxhash.h"
 #include "llvm/TargetParser/RISCVISAInfo.h"
@@ -453,6 +454,18 @@ CodeGenModule::CodeGenModule(ASTContext &C,
   if (Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86)
     getModule().addModuleFlag(llvm::Module::Error, "NumRegisterParameters",
                               CodeGenOpts.NumRegisterParameters);
+
+  if (CodeGenOpts.CFProtectionBranch &&
+      getTarget().checkCFProtectionBranchSupported(getDiags())) {
+    auto Scheme = CodeGenOpts.getCFBranchLabelScheme();
+    if (getTarget().checkCFBranchLabelSchemeSupported(Scheme, getDiags())) {
+      if (Scheme == CFBranchLabelSchemeKind::Default)
+        Scheme = getTarget().getDefaultCFBranchLabelScheme();
+
+      UseRISCVZicfilpFuncSigCFI =
+          (Scheme == CFBranchLabelSchemeKind::FuncSig && 
getTriple().isRISCV());
+    }
+  }
 }
 
 CodeGenModule::~CodeGenModule() {}
@@ -914,6 +927,8 @@ void CodeGenModule::Release() {
   }
   if (LangOpts.Sanitize.has(SanitizerKind::KCFI))
     finalizeKCFITypes();
+  if (UseRISCVZicfilpFuncSigCFI)
+    finalizeRISCVZicfilpFuncSigLabels();
   emitAtAvailableLinkGuard();
   if (Context.getTargetInfo().getTriple().isWasm())
     EmitMainVoidAlias();
@@ -2894,6 +2909,27 @@ void 
CodeGenModule::createFunctionTypeMetadataForIcall(const FunctionDecl *FD,
       F->addTypeMetadata(0, llvm::ConstantAsMetadata::get(CrossDsoTypeId));
 }
 
+std::string CodeGenModule::calcRISCVZicfilpFuncSig(
+    const FunctionType &FT, const bool IsMain, const bool IsCXXInstanceMethod,
+    const bool IsCXXVirtualMethod, const bool IsCXXDestructor) {
+  if (IsMain)
+    // All main functions use `int main(int, char**)` for label calculation
+    // according to psABI spec
+    return "FiiPPcE";
+
+  if (IsCXXDestructor)
+    // All destructors use `void (void*)` for label calculation according to 
the
+    // psABI spec
+    return "FvPvE";
+
+  std::string OutName;
+  llvm::raw_string_ostream Out(OutName);
+  MangleContext &MC = getCXXABI().getMangleContext();
+  cast<ItaniumMangleContext>(MC).mangleForRISCVZicfilpFuncSigLabel(
+      FT, IsCXXInstanceMethod, IsCXXVirtualMethod, Out);
+  return OutName;
+}
+
 void CodeGenModule::setKCFIType(const FunctionDecl *FD, llvm::Function *F) {
   llvm::LLVMContext &Ctx = F->getContext();
   llvm::MDBuilder MDB(Ctx);
@@ -2902,6 +2938,35 @@ void CodeGenModule::setKCFIType(const FunctionDecl *FD, 
llvm::Function *F) {
                      Ctx, 
MDB.createConstant(CreateKCFITypeId(FD->getType()))));
 }
 
+void CodeGenModule::setRISCVZicfilpFuncSigLabel(const FunctionDecl &FD,
+                                                llvm::Function *F) {
+  llvm::LLVMContext &Ctx = F->getContext();
+  llvm::MDBuilder MDB(Ctx);
+
+  bool IsCXXInstanceMethod = false;
+  bool IsCXXVirtualMethod = false;
+  if (const auto *const MD = dyn_cast<CXXMethodDecl>(&FD)) {
+    IsCXXInstanceMethod = MD->isInstance();
+    IsCXXVirtualMethod = MD->isVirtual();
+  }
+  bool IsMain;
+  if (const IdentifierInfo *const ID = FD.getIdentifier())
+    IsMain = ID->isStr("main");
+  else
+    IsMain = false;
+  const std::string FuncSig = calcRISCVZicfilpFuncSig(
+      *FD.getFunctionType(), IsMain, IsCXXInstanceMethod, IsCXXVirtualMethod,
+      isa<CXXDestructorDecl>(FD));
+  F->setMetadata("riscv_lpad_func_sig",
+                 llvm::MDNode::get(Ctx, MDB.createString(FuncSig)));
+
+  const uint32_t Label = llvm::RISCVISAUtils::zicfilpFuncSigHash(FuncSig);
+  F->setMetadata(
+      "riscv_lpad_label",
+      llvm::MDNode::get(
+          Ctx, MDB.createConstant(llvm::ConstantInt::get(Int32Ty, Label))));
+}
+
 static bool allowKCFIIdentifier(StringRef Name) {
   // KCFI type identifier constants are only necessary for external assembly
   // functions, which means it's safe to skip unusual names. Subset of
@@ -2942,6 +3007,62 @@ void CodeGenModule::finalizeKCFITypes() {
   }
 }
 
+void CodeGenModule::finalizeRISCVZicfilpFuncSigLabels() {
+  llvm::Module &M = getModule();
+  for (llvm::Function &F : M.functions())
+    finalizeRISCVZicfilpFuncSigLabel(F);
+}
+
+void CodeGenModule::finalizeRISCVZicfilpFuncSigLabel(llvm::Function &F) {
+  const unsigned FuncSigMDKindID =
+      F.getContext().getMDKindID("riscv_lpad_func_sig");
+  const unsigned LabelMDKindID = 
F.getContext().getMDKindID("riscv_lpad_label");
+  if (!F.hasAddressTaken() && F.hasLocalLinkage()) {
+    F.eraseMetadata(FuncSigMDKindID);
+    F.eraseMetadata(LabelMDKindID);
+    return;
+  }
+
+  if (F.getMetadata(FuncSigMDKindID)) {
+    assert(F.getMetadata(LabelMDKindID) &&
+           "riscv_lpad_label should had been set when setting "
+           "riscv_lpad_func_sig");
+    return;
+  }
+
+  if (GlobalDecl GD; lookupRepresentativeDecl(F.getName(), GD)) {
+    setRISCVZicfilpFuncSigLabel(*cast<FunctionDecl>(GD.getDecl()), &F);
+    return;
+  }
+
+  // If F is a declaration, and we cannot find a non-zero lpad value for it
+  // (since the C/C++ declaration cannot be found), we should refrain from
+  // adding an explicit 0-valued riscv_lpad_label to avoid emitting a 0-valued
+  // referencing lpad value in the .riscv.lpadinfo section, since it's illegal
+  // to have a 0-valued referencing lpad value as they are assumed to be
+  // generated from C/C++ references with known signature (and thus a non-zero
+  // lpad value can be obtained)
+  if (F.isDeclaration())
+    return;
+
+  // If function has a body and requires an lpad insn, but does not specify the
+  // label in riscv_lpad_label metadata and we cannot generate it from C/C++
+  // declaration (since the C/C++ declaration cannot be found), we use a
+  // permissive 0 as the label. This results in a 0-valued definitive lpad 
label
+  // in the .riscv.lpadinfo section, which can be overridden by other non-zero
+  // lpad labels if there's one at the static link stage. If there's no 
non-zero
+  // lpad label at the static link stage, the resulting executable would have 
to
+  // use this permissive 0 as the final lpad label, which is not ideal but is
+  // the best we can provide.
+  assert(!F.getMetadata(LabelMDKindID));
+  llvm::LLVMContext &Ctx = F.getContext();
+  llvm::MDBuilder MDB(Ctx);
+  F.setMetadata(
+      LabelMDKindID,
+      llvm::MDNode::get(
+          Ctx, MDB.createConstant(llvm::ConstantInt::get(Int32Ty, 0))));
+}
+
 void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F,
                                           bool IsIncompleteFunction,
                                           bool IsThunk) {
@@ -3026,6 +3147,9 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, 
llvm::Function *F,
   if (LangOpts.Sanitize.has(SanitizerKind::KCFI))
     setKCFIType(FD, F);
 
+  if (UseRISCVZicfilpFuncSigCFI)
+    setRISCVZicfilpFuncSigLabel(*FD, F);
+
   if (getLangOpts().OpenMP && FD->hasAttr<OMPDeclareSimdDeclAttr>())
     getOpenMPRuntime().emitDeclareSimdFunction(FD, F);
 
diff --git a/clang/lib/CodeGen/CodeGenModule.h 
b/clang/lib/CodeGen/CodeGenModule.h
index 1db5c3bc4e4ef..1d0567d45b689 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -1639,9 +1639,24 @@ class CodeGenModule : public CodeGenTypeCache {
   /// Set type metadata to the given function.
   void setKCFIType(const FunctionDecl *FD, llvm::Function *F);
 
+  /// Set RISC-V Zicfilp func-sig CFI label in metadata of the given function.
+  void setRISCVZicfilpFuncSigLabel(const FunctionDecl &FD, llvm::Function *F);
+
   /// Emit KCFI type identifier constants and remove unused identifiers.
   void finalizeKCFITypes();
 
+  /// Fixup RISCV Zicfilp func-sig CFI labels
+  void finalizeRISCVZicfilpFuncSigLabels();
+
+  /// Fixup RISCV Zicfilp func-sig CFI label for llvm::Function
+  void finalizeRISCVZicfilpFuncSigLabel(llvm::Function &F);
+
+  /// Calculate function signature based on RISC-V Zicfilp func-sig scheme
+  std::string calcRISCVZicfilpFuncSig(const FunctionType &FT, const bool 
IsMain,
+                                      const bool IsCXXInstanceMethod,
+                                      const bool IsCXXVirtualMethod,
+                                      const bool IsCXXDestructor);
+
   /// Whether this function's return type has no side effects, and thus may
   /// be trivially discarded if it is unused.
   bool MayDropFunctionReturn(const ASTContext &Context,
@@ -1810,6 +1825,8 @@ class CodeGenModule : public CodeGenTypeCache {
     return !getLangOpts().CPlusPlus;
   }
 
+  bool UseRISCVZicfilpFuncSigCFI;
+
 private:
   bool shouldDropDLLAttribute(const Decl *D, const llvm::GlobalValue *GV) 
const;
 
diff --git 
a/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-class-covariant-virtual-method.cpp
 
b/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-class-covariant-virtual-method.cpp
new file mode 100644
index 0000000000000..f7260ac131b62
--- /dev/null
+++ 
b/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-class-covariant-virtual-method.cpp
@@ -0,0 +1,39 @@
+// REQUIRES: riscv-registered-target
+// RUN: %clang_cc1 -triple riscv64 -target-cpu generic-rv64 -target-feature \
+// RUN:  +experimental-zicfilp -fcf-protection=branch \
+// RUN:  -mcf-branch-label-scheme=func-sig -emit-llvm -o - -x c++ %s \
+// RUN:  | FileCheck %s --check-prefixes=PTR,LREF,RREF
+
+class Class {
+public:
+  // test - virtual methods with return type that can possibly be covariant
+  //        mangle return class as `class v`
+  // PTR-LABEL: define{{.*}} @_ZN5Class35virtualMethodWithCovariantPtrReturnEv
+  // PTR-SAME: ({{.*}}){{.* !riscv_lpad_func_sig}} [[SIG_MD_PTR:![0-9]+]]
+  // PTR-SAME: {{.* !riscv_lpad_label}} [[LB_MD_PTR:![0-9]+]] {{.*}}{
+  //
+  virtual Class *virtualMethodWithCovariantPtrReturn() { return this; }
+
+  // LREF-LABEL: define{{.*}} 
@_ZN5Class36virtualMethodWithCovariantLRefReturnEv
+  // LREF-SAME: ({{.*}}){{.* !riscv_lpad_func_sig}} [[SIG_MD_LREF:![0-9]+]]
+  // LREF-SAME: {{.* !riscv_lpad_label}} [[LB_MD_LREF:![0-9]+]] {{.*}}{
+  //
+  virtual Class &virtualMethodWithCovariantLRefReturn() { return *this; }
+
+  // RREF-LABEL: define{{.*}} 
@_ZN5Class36virtualMethodWithCovariantRRefReturnEv
+  // RREF-SAME: ({{.*}}){{.* !riscv_lpad_func_sig}} [[SIG_MD_RREF:![0-9]+]]
+  // RREF-SAME: {{.* !riscv_lpad_label}} [[LB_MD_RREF:![0-9]+]] {{.*}}{
+  //
+  virtual Class &&virtualMethodWithCovariantRRefReturn() {
+    return static_cast<Class&&>(*this);
+  }
+};
+
+// PTR-DAG: [[SIG_MD_PTR]] = !{!"M1vFP1vvE"}
+// PTR-DAG: [[LB_MD_PTR]] = !{i32 996333}
+// LREF-DAG: [[SIG_MD_LREF]] = !{!"M1vFR1vvE"}
+// LREF-DAG: [[LB_MD_LREF]] = !{i32 918198}
+// RREF-DAG: [[SIG_MD_RREF]] = !{!"M1vFO1vvE"}
+// RREF-DAG: [[LB_MD_RREF]] = !{i32 86168}
+
+void use() { Class C; }
diff --git 
a/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-class-destructor.cpp 
b/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-class-destructor.cpp
new file mode 100644
index 0000000000000..92d390506c509
--- /dev/null
+++ b/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-class-destructor.cpp
@@ -0,0 +1,19 @@
+// REQUIRES: riscv-registered-target
+// RUN: %clang_cc1 -triple riscv64 -target-cpu generic-rv64 -target-feature \
+// RUN:  +experimental-zicfilp -fcf-protection=branch \
+// RUN:  -mcf-branch-label-scheme=func-sig -emit-llvm -o - -x c++ %s \
+// RUN:  | FileCheck %s
+
+class Class {
+public:
+  // test - destructors should use `void (*)(void*)`
+  // CHECK-LABEL: define{{.*}} @_ZN5ClassD1Ev({{.*}})
+  // CHECK-SAME: {{.* !riscv_lpad_func_sig}} [[SIG_MD:![0-9]+]]
+  // CHECK-SAME: {{.* !riscv_lpad_label}} [[LB_MD:![0-9]+]] {{.*}}{
+  // CHECK-DAG: [[SIG_MD]] = !{!"FvPvE"}
+  // CHECK-DAG: [[LB_MD]] = !{i32 408002}
+  //
+  ~Class() {}
+};
+
+void use() { Class C; }
diff --git 
a/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-class-incovariant-virtual-method.cpp
 
b/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-class-incovariant-virtual-method.cpp
new file mode 100644
index 0000000000000..33b9175208073
--- /dev/null
+++ 
b/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-class-incovariant-virtual-method.cpp
@@ -0,0 +1,20 @@
+// REQUIRES: riscv-registered-target
+// RUN: %clang_cc1 -triple riscv64 -target-cpu generic-rv64 -target-feature \
+// RUN:  +experimental-zicfilp -fcf-protection=branch \
+// RUN:  -mcf-branch-label-scheme=func-sig -emit-llvm -o - -x c++ %s \
+// RUN:  | FileCheck %s
+
+class Class {
+public:
+  // test - virtual methods with return type that cannot be covariant mangle
+  //        return type as it is declared
+  // CHECK-LABEL: define{{.*}} @_ZN5Class34virtualMethodWithIncovariantReturnEv
+  // CHECK-SAME: ({{.*}}){{.* !riscv_lpad_func_sig}} [[SIG_MD:![0-9]+]]
+  // CHECK-SAME: {{.* !riscv_lpad_label}} [[LB_MD:![0-9]+]] {{.*}}{
+  // CHECK-DAG: [[SIG_MD]] = !{!"M1vFivE"}
+  // CHECK-DAG: [[LB_MD]] = !{i32 910118}
+  //
+  virtual int virtualMethodWithIncovariantReturn() { return 0; }
+};
+
+void use() { Class C; }
diff --git a/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-class-method.cpp 
b/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-class-method.cpp
new file mode 100644
index 0000000000000..62e18ccba236d
--- /dev/null
+++ b/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-class-method.cpp
@@ -0,0 +1,21 @@
+// REQUIRES: riscv-registered-target
+// RUN: %clang_cc1 -triple riscv64 -target-cpu generic-rv64 -target-feature \
+// RUN:  +experimental-zicfilp -fcf-protection=branch \
+// RUN:  -mcf-branch-label-scheme=func-sig -emit-llvm -o - -x c++ %s \
+// RUN:  | FileCheck %s
+
+class Class {
+public:
+  // test - C++ member functions should use "pointer-to-member-type" mangling
+  //        rule, with `<class type>` being `1v` instead of the real class
+  //        (i.e. use a dummy class named `v`)
+  // CHECK-LABEL: define{{.*}} @_ZN5Class14instanceMethodEv({{.*}})
+  // CHECK-SAME: {{.* !riscv_lpad_func_sig}} [[SIG_MD:![0-9]+]]
+  // CHECK-SAME: {{.* !riscv_lpad_label}} [[LB_MD:![0-9]+]] {{.*}}{
+  // CHECK-DAG: [[SIG_MD]] = !{!"M1vFvvE"}
+  // CHECK-DAG: [[LB_MD]] = !{i32 974748}
+  //
+  void instanceMethod() {}
+};
+
+void use(Class &C) { C.instanceMethod(); }
diff --git 
a/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-class-static-method.cpp 
b/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-class-static-method.cpp
new file mode 100644
index 0000000000000..c6cc44a460868
--- /dev/null
+++ b/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-class-static-method.cpp
@@ -0,0 +1,23 @@
+// REQUIRES: riscv-registered-target
+// RUN: %clang_cc1 -triple riscv64 -target-cpu generic-rv64 -target-feature \
+// RUN:  +experimental-zicfilp -fcf-protection=branch \
+// RUN:  -mcf-branch-label-scheme=func-sig -emit-llvm -o - -x c++ %s \
+// RUN:  | FileCheck %s
+
+// CHECK-LABEL: define{{.*}} @_Z13nonMemberFuncv()
+// CHECK-SAME: {{.* !riscv_lpad_func_sig}} [[SIG_MD:![0-9]+]]
+// CHECK-SAME: {{.* !riscv_lpad_label}} [[LB_MD:![0-9]+]] {{.*}}{
+//
+void nonMemberFunc() {}
+
+class Class {
+public:
+  // test - static methods are mangled as non-member function
+  // CHECK-LABEL: define{{.*}} @_ZN5Class12staticMethodEv()
+  // CHECK-SAME: {{.* !riscv_lpad_func_sig}} [[SIG_MD]]
+  // CHECK-SAME: {{.* !riscv_lpad_label}} [[LB_MD]] {{.*}}{
+  //
+  static void staticMethod() {}
+};
+
+void use() { Class::staticMethod(); }
diff --git 
a/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-func-empty-param-list.c 
b/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-func-empty-param-list.c
new file mode 100644
index 0000000000000..c2ece35e86b2e
--- /dev/null
+++ b/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-func-empty-param-list.c
@@ -0,0 +1,17 @@
+// REQUIRES: riscv-registered-target
+// RUN: %clang_cc1 -triple riscv64 -target-cpu generic-rv64 -target-feature \
+// RUN:  +experimental-zicfilp -fcf-protection=branch \
+// RUN:  -mcf-branch-label-scheme=func-sig -emit-llvm -o - -x c %s \
+// RUN:  | FileCheck %s
+
+// test - functions with an empty parameter list are treated as `void 
(*)(void)`
+// CHECK-LABEL: define{{.*}} @funcWithEmptyParameterList()
+// CHECK-SAME: {{.* !riscv_lpad_func_sig}} [[SIG_MD:![0-9]+]]
+// CHECK-SAME: {{.* !riscv_lpad_label}} [[LB_MD:![0-9]+]] {{.*}}{
+//
+void funcWithEmptyParameterList() {}
+// CHECK-LABEL: define{{.*}} @funcWithVoidParameterList()
+// CHECK-SAME: {{.* !riscv_lpad_func_sig}} [[SIG_MD]]
+// CHECK-SAME: {{.* !riscv_lpad_label}} [[LB_MD]] {{.*}}{
+//
+void funcWithVoidParameterList(void) {}
diff --git 
a/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-func-empty-param-list.cpp 
b/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-func-empty-param-list.cpp
new file mode 100644
index 0000000000000..80a2222549cce
--- /dev/null
+++ b/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-func-empty-param-list.cpp
@@ -0,0 +1,17 @@
+// REQUIRES: riscv-registered-target
+// RUN: %clang_cc1 -triple riscv64 -target-cpu generic-rv64 -target-feature \
+// RUN:  +experimental-zicfilp -fcf-protection=branch \
+// RUN:  -mcf-branch-label-scheme=func-sig -emit-llvm -o - -x c++ %s \
+// RUN:  | FileCheck %s
+
+// test - functions with an empty parameter list are treated as `void 
(*)(void)`
+// CHECK-LABEL: define{{.*}} @_Z26funcWithEmptyParameterListv()
+// CHECK-SAME: {{.* !riscv_lpad_func_sig}} [[SIG_MD:![0-9]+]]
+// CHECK-SAME: {{.* !riscv_lpad_label}} [[LB_MD:![0-9]+]] {{.*}}{
+//
+void funcWithEmptyParameterList() {}
+// CHECK-LABEL: define{{.*}} @_Z25funcWithVoidParameterListv()
+// CHECK-SAME: {{.* !riscv_lpad_func_sig}} [[SIG_MD]]
+// CHECK-SAME: {{.* !riscv_lpad_label}} [[LB_MD]] {{.*}}{
+//
+void funcWithVoidParameterList(void) {}
diff --git 
a/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-ignore-exception-spec.cpp 
b/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-ignore-exception-spec.cpp
new file mode 100644
index 0000000000000..4de989eb31757
--- /dev/null
+++ b/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-ignore-exception-spec.cpp
@@ -0,0 +1,17 @@
+// REQUIRES: riscv-registered-target
+// RUN: %clang_cc1 -triple riscv64 -target-cpu generic-rv64 -target-feature \
+// RUN:  +experimental-zicfilp -fcf-protection=branch \
+// RUN:  -mcf-branch-label-scheme=func-sig -fcxx-exceptions -fexceptions \
+// RUN:  -emit-llvm -o - -x c++ %s | FileCheck %s
+
+// test - `<exception-spec>` should be ignored
+// CHECK-LABEL: define{{.*}} @_Z9funcThrowv()
+// CHECK-SAME: {{.* !riscv_lpad_func_sig}} [[SIG_MD:![0-9]+]]
+// CHECK-SAME: {{.* !riscv_lpad_label}} [[LB_MD:![0-9]+]] {{.*}}{
+///
+void funcThrow() { throw 0; }
+// CHECK-LABEL: define{{.*}} @_Z12funcNoExceptv()
+// CHECK-SAME: {{.* !riscv_lpad_func_sig}} [[SIG_MD]]
+// CHECK-SAME: {{.* !riscv_lpad_label}} [[LB_MD]] {{.*}}{
+//
+void funcNoExcept() noexcept {}
diff --git a/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-main.cpp 
b/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-main.cpp
new file mode 100644
index 0000000000000..724312807b2b5
--- /dev/null
+++ b/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-main.cpp
@@ -0,0 +1,41 @@
+// REQUIRES: riscv-registered-target
+// RUN: %clang_cc1 -DNO_PARAM -triple riscv64 -target-cpu generic-rv64 \
+// RUN:  -target-feature +experimental-zicfilp -fcf-protection=branch \
+// RUN:  -mcf-branch-label-scheme=func-sig -emit-llvm -o - -x c++ %s \
+// RUN:  | FileCheck %s
+// RUN: %clang_cc1 -DONE_PARAM -triple riscv64 -target-cpu generic-rv64 \
+// RUN:  -target-feature +experimental-zicfilp -fcf-protection=branch \
+// RUN:  -mcf-branch-label-scheme=func-sig -emit-llvm -o - -x c++ %s \
+// RUN:  | FileCheck %s
+// RUN: %clang_cc1 -DTWO_PARAMS -triple riscv64 -target-cpu generic-rv64 \
+// RUN:  -target-feature +experimental-zicfilp -fcf-protection=branch \
+// RUN:  -mcf-branch-label-scheme=func-sig -emit-llvm -o - -x c++ %s \
+// RUN:  | FileCheck %s
+// RUN: %clang_cc1 -DTWO_PARAMS -triple riscv64 -target-cpu generic-rv64 \
+// RUN:  -target-feature +experimental-zicfilp -fcf-protection=branch \
+// RUN:  -mcf-branch-label-scheme=func-sig -emit-llvm -o - -x c++ %s \
+// RUN:  | FileCheck %s
+
+// test - main functions should use `int (*)(int, char**)`
+// CHECK-LABEL: define{{.*}} @main({{.*}})
+// CHECK-SAME: {{.* !riscv_lpad_func_sig}} [[SIG_MD:![0-9]+]]
+// CHECK-SAME: {{.* !riscv_lpad_label}} [[LB_MD:![0-9]+]] {{.*}}{
+// CHECK-DAG: [[SIG_MD]] = !{!"FiiPPcE"}
+// CHECK-DAG: [[LB_MD]] = !{i32 853561}
+//
+
+#ifdef NO_PARAM
+int main() { return 0; }
+#endif
+
+#ifdef ONE_PARAM
+int main(int argc) { return argc; }
+#endif
+
+#ifdef TWO_PARAMS
+int main(int argc, char **argv) { return argc; }
+#endif
+
+#ifdef THREE_PARAMS
+int main(int argc, char **argv, char **envp) { return argc; }
+#endif
diff --git a/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-wchar-t.cpp 
b/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-wchar-t.cpp
new file mode 100644
index 0000000000000..4d19d482d6b5d
--- /dev/null
+++ b/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-wchar-t.cpp
@@ -0,0 +1,14 @@
+// REQUIRES: riscv-registered-target
+// RUN: %clang_cc1 -triple riscv64 -target-cpu generic-rv64 -target-feature \
+// RUN:  +experimental-zicfilp -fcf-protection=branch \
+// RUN:  -mcf-branch-label-scheme=func-sig -emit-llvm -o - -x c++ %s \
+// RUN:  | FileCheck %s
+
+// test - `wchar_t` in C++ should be mangled to `wchar_t` in C
+// CHECK-LABEL: define{{.*}} @_Z14funcWithWCharTw({{.*}})
+// CHECK-SAME: {{.* !riscv_lpad_func_sig}} [[SIG_MD:![0-9]+]]
+// CHECK-SAME: {{.* !riscv_lpad_label}} [[LB_MD:![0-9]+]] {{.*}}{
+// CHECK-DAG: [[SIG_MD]] = !{!"FviE"}
+// CHECK-DAG: [[LB_MD]] = !{i32 374765}
+//
+void funcWithWCharT(wchar_t) {}
diff --git a/llvm/include/llvm/Support/RISCVISAUtils.h 
b/llvm/include/llvm/Support/RISCVISAUtils.h
index 165bb08d66431..7f0d5b8aac70a 100644
--- a/llvm/include/llvm/Support/RISCVISAUtils.h
+++ b/llvm/include/llvm/Support/RISCVISAUtils.h
@@ -6,7 +6,7 @@
 //
 
//===----------------------------------------------------------------------===//
 //
-// Utilities shared by TableGen and RISCVISAInfo.
+// Utilities shared by TableGen, RISCVISAInfo and other RISC-V specifics.
 //
 
//===----------------------------------------------------------------------===//
 
@@ -43,6 +43,10 @@ struct ExtensionComparator {
 typedef std::map<std::string, ExtensionVersion, ExtensionComparator>
     OrderedExtensionMap;
 
+/// Obtain a 20-bit integer from a (function-signature) string using the method
+/// defined in the psABI for Zicfilp func-sig CFI scheme
+uint32_t zicfilpFuncSigHash(const StringRef FuncSig);
+
 } // namespace RISCVISAUtils
 
 } // namespace llvm
diff --git a/llvm/lib/Support/RISCVISAUtils.cpp 
b/llvm/lib/Support/RISCVISAUtils.cpp
index d6b002e66e7ab..ff8bd101505eb 100644
--- a/llvm/lib/Support/RISCVISAUtils.cpp
+++ b/llvm/lib/Support/RISCVISAUtils.cpp
@@ -6,12 +6,13 @@
 //
 
//===----------------------------------------------------------------------===//
 //
-// Utilities shared by TableGen and RISCVISAInfo.
+// Utilities shared by TableGen, RISCVISAInfo and other RISC-V specifics.
 //
 
//===----------------------------------------------------------------------===//
 
 #include "llvm/Support/RISCVISAUtils.h"
 #include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/MD5.h"
 #include <cassert>
 
 using namespace llvm;
@@ -90,3 +91,22 @@ bool llvm::RISCVISAUtils::compareExtension(const std::string 
&LHS,
   // If the rank is same, it must be sorted by lexicographic order.
   return LHS < RHS;
 }
+
+uint32_t llvm::RISCVISAUtils::zicfilpFuncSigHash(const StringRef FuncSig) {
+  const llvm::MD5::MD5Result MD5Result =
+      llvm::MD5::hash({(const uint8_t *)FuncSig.data(), FuncSig.size()});
+
+  uint64_t MD5High = MD5Result.high();
+  uint64_t MD5Low = MD5Result.low();
+  while (MD5High || MD5Low) {
+    const uint32_t Low20Bits = MD5Low & 0xFFFFFULL;
+    if (Low20Bits)
+      return Low20Bits;
+
+    // Logical right shift MD5 result by 20 bits
+    MD5Low = (MD5High & 0xFFFFF) << 44 | MD5Low >> 20;
+    MD5High >>= 20;
+  }
+
+  return llvm::MD5Hash("RISC-V") & 0xFFFFFULL;
+}
diff --git a/llvm/unittests/Support/CMakeLists.txt 
b/llvm/unittests/Support/CMakeLists.txt
index d048e871fd0fb..48a5fe424ddeb 100644
--- a/llvm/unittests/Support/CMakeLists.txt
+++ b/llvm/unittests/Support/CMakeLists.txt
@@ -78,6 +78,7 @@ add_llvm_unittest(SupportTests
   ReverseIterationTest.cpp
   ReplaceFileTest.cpp
   RISCVAttributeParserTest.cpp
+  RISCVISAUtils.cpp
   ScaledNumberTest.cpp
   ScopedPrinterTest.cpp
   SHA256.cpp
diff --git a/llvm/unittests/Support/RISCVISAUtils.cpp 
b/llvm/unittests/Support/RISCVISAUtils.cpp
new file mode 100644
index 0000000000000..6f5619ac67731
--- /dev/null
+++ b/llvm/unittests/Support/RISCVISAUtils.cpp
@@ -0,0 +1,23 @@
+//===- LLvm/unittest/Support/RISCVISAUtils.cpp - RISCVISAUtils tests 
------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/RISCVISAUtils.h"
+#include "gtest/gtest.h"
+
+using namespace llvm::RISCVISAUtils;
+
+TEST(ZicfilpFuncSigHash, testCommonCase) {
+  // A common representitive case is the signature of the main function
+  EXPECT_EQ(zicfilpFuncSigHash("FiiPPcE"), 853561U);
+}
+
+// The lowest 20 bits of a MD5 hash should be discarded if they're all zeros
+TEST(ZicfilpFuncSigHash, testDiscardAllZeroLabels) {
+  // as_number(md5('20412333')) = 0x7a13472ff22eb53e31f6a76027000000
+  EXPECT_EQ(zicfilpFuncSigHash("20412333"), 0x60270U);
+}

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to