[clang] [llvm] [clang][RISCV] Emit RISCV function-signature-based CFI label in llvm::Function metadata (PR #111661)
Ming-Yi Lai via cfe-commits
cfe-commits at lists.llvm.org
Fri May 23 01:03:32 PDT 2025
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.lai at 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);
+}
More information about the cfe-commits
mailing list