https://github.com/mylai-mtk updated https://github.com/llvm/llvm-project/pull/111661
>From 9041af3df59b6f6f2f6c2ff335cc697dfd41ac73 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 This patch emits the RISC-V Zicfilp func-sig CFI label in the metadata of generated `llvm::Function`s. It introduces CodeGenModule::calcRISCVZicfilpFuncSigLabel(), which calculates a CFI label used in the RISC-V Zicfilp func-sig CFI scheme for a given function type/declaration. The scheme, according to psABI, encodes the label based on function signature, and the rules are modified from the Itanium C++ ABI mangling rule to allow functions (callees) that are called indirectly to have the expected label as indicated by the function pointer type seen at the call site (caller). --- 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 | 137 +++++++++++++++++- clang/lib/CodeGen/CodeGenModule.cpp | 84 +++++++++++ clang/lib/CodeGen/CodeGenModule.h | 19 +++ .../mangle-class-covariant-virtual-method.cpp | 33 +++++ .../mangle-class-destructor.cpp | 17 +++ ...angle-class-incovariant-virtual-method.cpp | 18 +++ .../zicfilp-func-sig/mangle-class-method.cpp | 18 +++ .../mangle-class-static-method.cpp | 21 +++ .../mangle-func-empty-param-list.c | 15 ++ .../mangle-func-empty-param-list.cpp | 15 ++ .../mangle-ignore-exception-spec.cpp | 15 ++ .../RISCV/zicfilp-func-sig/mangle-main.cpp | 39 +++++ .../RISCV/zicfilp-func-sig/mangle-wchar-t.cpp | 12 ++ llvm/include/llvm/Support/RISCVISAUtils.h | 6 +- llvm/lib/Support/RISCVISAUtils.cpp | 22 ++- 18 files changed, 485 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 diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index a4d36f2eacd5d1..4812e0bac2cfc3 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -1876,6 +1876,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>. /// @@ -1903,6 +1906,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 d5f6c0f6cc67df..16cbd802177ba4 100644 --- a/clang/include/clang/AST/Mangle.h +++ b/clang/include/clang/AST/Mangle.h @@ -212,6 +212,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 034fbbe0bc7829..ce8688a489cb43 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -6442,6 +6442,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 777cdca1a0c0d7..9eff94b0844092 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -43,6 +43,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); } @@ -136,6 +144,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)) @@ -395,8 +408,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; } @@ -443,6 +458,8 @@ class CXXNameMangler { NullOut = true; } + virtual ~CXXNameMangler() = default; + struct WithTemplateDepthOffset { unsigned Offset; }; CXXNameMangler(ItaniumMangleContextImpl &C, raw_ostream &Out, WithTemplateDepthOffset Offset) @@ -559,9 +576,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. @@ -572,11 +592,24 @@ 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); + +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); @@ -3058,7 +3091,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 @@ -3563,10 +3598,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) { mangleExtFunctionInfo(T); // Mangle CV-qualifiers, if present. These are 'this' qualifiers, @@ -3604,6 +3643,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). @@ -7074,6 +7117,85 @@ 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 { + // 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(); + IsTopLevelAndCXXVirtualMethod && 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"; + } + + IsTopLevelAndCXXVirtualMethod = false; // Not top-level anymore + 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 @@ -7412,6 +7534,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 5ba098144a74e7..3042bc2c105de4 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -69,6 +69,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() {} @@ -912,6 +925,8 @@ void CodeGenModule::Release() { } if (LangOpts.Sanitize.has(SanitizerKind::KCFI)) finalizeKCFITypes(); + if (UseRISCVZicfilpFuncSigCFI) + finalizeRISCVZicfilpFuncSigLabels(); emitAtAvailableLinkGuard(); if (Context.getTargetInfo().getTriple().isWasm()) EmitMainVoidAlias(); @@ -2829,6 +2844,39 @@ void CodeGenModule::CreateFunctionTypeMetadataForIcall(const FunctionDecl *FD, F->addTypeMetadata(0, llvm::ConstantAsMetadata::get(CrossDsoTypeId)); } +uint32_t +CodeGenModule::calcRISCVZicfilpFuncSigLabel(const FunctionType &FT, + const bool IsCXXInstanceMethod, + const bool IsCXXVirtualMethod) { + std::string OutName; + llvm::raw_string_ostream Out(OutName); + MangleContext &MC = getCXXABI().getMangleContext(); + cast<ItaniumMangleContext>(MC).mangleForRISCVZicfilpFuncSigLabel( + FT, IsCXXInstanceMethod, IsCXXVirtualMethod, Out); + return llvm::RISCVISAUtils::zicfilpFuncSigHash(OutName); +} + +uint32_t CodeGenModule::calcRISCVZicfilpFuncSigLabel(const FunctionDecl &FD) { + if (FD.isMain()) + // All main functions use `int main(int, char**)` for label calculation + // according to psABI spec. This value is the pre-calculated label. + return 0xd0639; + + if (isa<CXXDestructorDecl>(FD)) + // All destructors use `void (void*)` for label calculation according to the + // psABI spec. This value is the pre-calculated label. + return 0x639c2; + + bool IsCXXInstanceMethod = false; + bool IsCXXVirtualMethod = false; + if (const auto *const MD = dyn_cast<CXXMethodDecl>(&FD)) { + IsCXXInstanceMethod = MD->isInstance(); + IsCXXVirtualMethod = MD->isVirtual(); + } + return calcRISCVZicfilpFuncSigLabel(*FD.getFunctionType(), + IsCXXInstanceMethod, IsCXXVirtualMethod); +} + void CodeGenModule::setKCFIType(const FunctionDecl *FD, llvm::Function *F) { llvm::LLVMContext &Ctx = F->getContext(); llvm::MDBuilder MDB(Ctx); @@ -2837,6 +2885,16 @@ 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); + F->setMetadata( + "riscv_lpad_label", + llvm::MDNode::get(Ctx, MDB.createConstant(llvm::ConstantInt::get( + Int32Ty, calcRISCVZicfilpFuncSigLabel(*FD))))); +} + 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 @@ -2877,6 +2935,29 @@ 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 MDKindID = F.getContext().getMDKindID("riscv_lpad_label"); + if (!F.hasAddressTaken() && F.hasLocalLinkage()) { + F.eraseMetadata(MDKindID); + return; + } + + const llvm::MDNode *MD = F.getMetadata(MDKindID); + if (!MD) { + GlobalDecl GD; + if (!lookupRepresentativeDecl(F.getName(), GD)) + return; + + setRISCVZicfilpFuncSigLabel(cast<FunctionDecl>(GD.getDecl()), &F); + } +} + void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F, bool IsIncompleteFunction, bool IsThunk) { @@ -2962,6 +3043,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 c58bb88035ca8a..a24c92dd2ba546 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -1556,9 +1556,26 @@ 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 RISC-V Zicfilp func-sig scheme CFI label + uint32_t calcRISCVZicfilpFuncSigLabel(const FunctionType &FT, + const bool IsCXXInstanceMethod, + const bool IsCXXVirtualMethod); + + /// Calculate RISC-V Zicfilp func-sig scheme CFI label + uint32_t calcRISCVZicfilpFuncSigLabel(const FunctionDecl &FD); + /// 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, @@ -1676,6 +1693,8 @@ class CodeGenModule : public CodeGenTypeCache { MustTailCallUndefinedGlobals.insert(Global); } + 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 00000000000000..f536acbf867b85 --- /dev/null +++ b/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-class-covariant-virtual-method.cpp @@ -0,0 +1,33 @@ +// 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_label}} [[MD_PTR:![0-9]+]] {{.*}}{ + // + virtual Class *virtualMethodWithCovariantPtrReturn() { return this; } + + // LREF-LABEL: define{{.*}} @_ZN5Class36virtualMethodWithCovariantLRefReturnEv + // LREF-SAME: ({{.*}}){{.* !riscv_lpad_label}} [[MD_LREF:![0-9]+]] {{.*}}{ + // + virtual Class &virtualMethodWithCovariantLRefReturn() { return *this; } + + // RREF-LABEL: define{{.*}} @_ZN5Class36virtualMethodWithCovariantRRefReturnEv + // RREF-SAME: ({{.*}}){{.* !riscv_lpad_label}} [[MD_RREF:![0-9]+]] {{.*}}{ + // + virtual Class &&virtualMethodWithCovariantRRefReturn() { + return static_cast<Class&&>(*this); + } +}; + +// PTR-DAG: [[MD_PTR]] = !{i32 996333} +// LREF-DAG: [[MD_LREF]] = !{i32 918198} +// RREF-DAG: [[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 00000000000000..196bb69c2f61ac --- /dev/null +++ b/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-class-destructor.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 + +class Class { +public: + // test - destructors should use `void (*)(void*)` + // CHECK-LABEL: define{{.*}} @_ZN5ClassD1Ev({{.*}}) + // CHECK-SAME: {{.* !riscv_lpad_label}} [[MD:![0-9]+]] {{.*}}{ + // CHECK: [[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 00000000000000..9ff4a83046fb72 --- /dev/null +++ b/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-class-incovariant-virtual-method.cpp @@ -0,0 +1,18 @@ +// 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_label}} [[MD:![0-9]+]] {{.*}}{ + // CHECK: [[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 00000000000000..8e335b838b5df1 --- /dev/null +++ b/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-class-method.cpp @@ -0,0 +1,18 @@ +// 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" types, with + // `<class type>` being `1v` (i.e. using a dummy class named `v`) + // CHECK-LABEL: define{{.*}} @_ZN5Class14instanceMethodEv({{.*}}) + // CHECK-SAME: {{.* !riscv_lpad_label}} [[MD:![0-9]+]] {{.*}}{ + // CHECK: [[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 00000000000000..d1bf9914e84a9b --- /dev/null +++ b/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-class-static-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 + +// CHECK-LABEL: define{{.*}} @_Z13nonMemberFuncv() +// CHECK-SAME: {{.* !riscv_lpad_label}} [[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_label}} [[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 00000000000000..3a122acb600493 --- /dev/null +++ b/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-func-empty-param-list.c @@ -0,0 +1,15 @@ +// 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_label}} [[MD:![0-9]+]] {{.*}}{ +// +void funcWithEmptyParameterList() {} +// CHECK-LABEL: define{{.*}} @funcWithVoidParameterList() +// CHECK-SAME: {{.* !riscv_lpad_label}} [[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 00000000000000..561889057f2d5b --- /dev/null +++ b/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-func-empty-param-list.cpp @@ -0,0 +1,15 @@ +// 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_label}} [[MD:![0-9]+]] {{.*}}{ +// +void funcWithEmptyParameterList() {} +// CHECK-LABEL: define{{.*}} @_Z25funcWithVoidParameterListv() +// CHECK-SAME: {{.* !riscv_lpad_label}} [[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 00000000000000..921fcfbb9c08de --- /dev/null +++ b/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-ignore-exception-spec.cpp @@ -0,0 +1,15 @@ +// 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_label}} [[MD:![0-9]+]] {{.*}}{ +/// +void funcThrow() { throw 0; } +// CHECK-LABEL: define{{.*}} @_Z12funcNoExceptv() +// CHECK-SAME: {{.* !riscv_lpad_label}} [[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 00000000000000..1a8cc4b5723c67 --- /dev/null +++ b/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-main.cpp @@ -0,0 +1,39 @@ +// 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_label}} [[MD:![0-9]+]] {{.*}}{ +// CHECK: [[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 00000000000000..14de1b7bbfdda9 --- /dev/null +++ b/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-wchar-t.cpp @@ -0,0 +1,12 @@ +// 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_label}} [[MD:![0-9]+]] {{.*}}{ +// CHECK: [[MD]] = !{i32 374765} +// +void funcWithWCharT(wchar_t) {} diff --git a/llvm/include/llvm/Support/RISCVISAUtils.h b/llvm/include/llvm/Support/RISCVISAUtils.h index 77f8c3e45f1ab5..b569184fddff0a 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. // //===----------------------------------------------------------------------===// @@ -42,6 +42,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 d6b002e66e7ab2..386fb157ecdee4 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; +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits