Skip to content

Commit 0cc12aa

Browse files
committed
[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).
1 parent 65da32c commit 0cc12aa

18 files changed

+486
-4
lines changed

clang/include/clang/AST/ASTContext.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1876,6 +1876,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
18761876
/// (struct/union/class/enum) decl.
18771877
QualType getTagDeclType(const TagDecl *Decl) const;
18781878

1879+
/// Return the type for "void *"
1880+
QualType getVoidPtrType() const { return VoidPtrTy; }
1881+
18791882
/// Return the unique type for "size_t" (C99 7.17), defined in
18801883
/// <stddef.h>.
18811884
///
@@ -1903,6 +1906,10 @@ class ASTContext : public RefCountedBase<ASTContext> {
19031906
/// defined in <stddef.h> as defined by the target.
19041907
QualType getWideCharType() const { return WideCharTy; }
19051908

1909+
/// Return the type of wide characters in C context, no matter whether it's C
1910+
/// or C++ being compiled.
1911+
QualType getWCharTypeInC() const;
1912+
19061913
/// Return the type of "signed wchar_t".
19071914
///
19081915
/// Used when in C++, as a GCC extension.

clang/include/clang/AST/Mangle.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,11 @@ class ItaniumMangleContext : public MangleContext {
212212

213213
virtual void mangleModuleInitializer(const Module *Module, raw_ostream &) = 0;
214214

215+
virtual void mangleForRISCVZicfilpFuncSigLabel(const FunctionType &FT,
216+
const bool IsCXXInstanceMethod,
217+
const bool IsCXXVirtualMethod,
218+
raw_ostream &) = 0;
219+
215220
// This has to live here, otherwise the CXXNameMangler won't have access to
216221
// it.
217222
virtual DiscriminatorOverrideTy getDiscriminatorOverride() const = 0;

clang/lib/AST/ASTContext.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6442,6 +6442,12 @@ CanQualType ASTContext::getUIntMaxType() const {
64426442
return getFromTargetType(Target->getUIntMaxType());
64436443
}
64446444

6445+
/// Return the type of wide characters in C context, no matter whether it's C
6446+
/// or C++ being compiled.
6447+
QualType ASTContext::getWCharTypeInC() const {
6448+
return getFromTargetType(Target->getWCharType());
6449+
}
6450+
64456451
/// getSignedWCharType - Return the type of "signed wchar_t".
64466452
/// Used when in C++, as a GCC extension.
64476453
QualType ASTContext::getSignedWCharType() const {

clang/lib/AST/ItaniumMangle.cpp

Lines changed: 136 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,14 @@ using namespace clang;
4343

4444
namespace {
4545

46+
static bool mayBeCovariant(const Type &Ty) {
47+
if (auto *const PT = Ty.getAs<PointerType>())
48+
return PT->getPointeeType()->isStructureOrClassType();
49+
if (auto *const RT = Ty.getAs<ReferenceType>())
50+
return RT->getPointeeType()->isStructureOrClassType();
51+
return false;
52+
}
53+
4654
static bool isLocalContainerContext(const DeclContext *DC) {
4755
return isa<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC) || isa<BlockDecl>(DC);
4856
}
@@ -136,6 +144,11 @@ class ItaniumMangleContextImpl : public ItaniumMangleContext {
136144

137145
void mangleModuleInitializer(const Module *Module, raw_ostream &) override;
138146

147+
void mangleForRISCVZicfilpFuncSigLabel(const FunctionType &,
148+
const bool IsCXXInstanceMethod,
149+
const bool IsCXXVirtualMethod,
150+
raw_ostream &) override;
151+
139152
bool getNextDiscriminator(const NamedDecl *ND, unsigned &disc) {
140153
// Lambda closure types are already numbered.
141154
if (isLambda(ND))
@@ -395,8 +408,10 @@ class CXXNameMangler {
395408
llvm::DenseMap<uintptr_t, unsigned> Substitutions;
396409
llvm::DenseMap<StringRef, unsigned> ModuleSubstitutions;
397410

411+
protected:
398412
ASTContext &getASTContext() const { return Context.getASTContext(); }
399413

414+
private:
400415
bool isCompatibleWith(LangOptions::ClangABI Ver) {
401416
return Context.getASTContext().getLangOpts().getClangABICompat() <= Ver;
402417
}
@@ -443,6 +458,8 @@ class CXXNameMangler {
443458
NullOut = true;
444459
}
445460

461+
virtual ~CXXNameMangler() = default;
462+
446463
struct WithTemplateDepthOffset { unsigned Offset; };
447464
CXXNameMangler(ItaniumMangleContextImpl &C, raw_ostream &Out,
448465
WithTemplateDepthOffset Offset)
@@ -559,9 +576,12 @@ class CXXNameMangler {
559576
StringRef Prefix = "");
560577
void mangleOperatorName(DeclarationName Name, unsigned Arity);
561578
void mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity);
579+
580+
protected:
562581
void mangleQualifiers(Qualifiers Quals, const DependentAddressSpaceType *DAST = nullptr);
563582
void mangleRefQualifier(RefQualifierKind RefQualifier);
564583

584+
private:
565585
void mangleObjCMethodName(const ObjCMethodDecl *MD);
566586

567587
// Declare manglers for every type class.
@@ -572,11 +592,24 @@ class CXXNameMangler {
572592

573593
void mangleType(const TagType*);
574594
void mangleType(TemplateName);
595+
596+
protected:
597+
// Use the `Impl` scheme instead of directly virtualizing `mangleType`s since
598+
// `mangleType`s are declared by tables
599+
virtual void mangleTypeImpl(const BuiltinType *T);
600+
virtual void mangleTypeImpl(const FunctionProtoType *T);
601+
virtual void mangleTypeImpl(const FunctionNoProtoType *T);
602+
603+
private:
575604
static StringRef getCallingConvQualifierName(CallingConv CC);
576605
void mangleExtParameterInfo(FunctionProtoType::ExtParameterInfo info);
577606
void mangleExtFunctionInfo(const FunctionType *T);
607+
608+
protected:
578609
void mangleBareFunctionType(const FunctionProtoType *T, bool MangleReturnType,
579610
const FunctionDecl *FD = nullptr);
611+
612+
private:
580613
void mangleNeonVectorType(const VectorType *T);
581614
void mangleNeonVectorType(const DependentVectorType *T);
582615
void mangleAArch64NeonVectorType(const VectorType *T);
@@ -3058,7 +3091,9 @@ void CXXNameMangler::mangleCXXRecordDecl(const CXXRecordDecl *Record) {
30583091
addSubstitution(Record);
30593092
}
30603093

3061-
void CXXNameMangler::mangleType(const BuiltinType *T) {
3094+
void CXXNameMangler::mangleType(const BuiltinType *T) { mangleTypeImpl(T); }
3095+
3096+
void CXXNameMangler::mangleTypeImpl(const BuiltinType *T) {
30623097
// <type> ::= <builtin-type>
30633098
// <builtin-type> ::= v # void
30643099
// ::= w # wchar_t
@@ -3563,10 +3598,14 @@ CXXNameMangler::mangleExtParameterInfo(FunctionProtoType::ExtParameterInfo PI) {
35633598
mangleVendorQualifier("noescape");
35643599
}
35653600

3601+
void CXXNameMangler::mangleType(const FunctionProtoType *T) {
3602+
return mangleTypeImpl(T);
3603+
}
3604+
35663605
// <type> ::= <function-type>
35673606
// <function-type> ::= [<CV-qualifiers>] F [Y]
35683607
// <bare-function-type> [<ref-qualifier>] E
3569-
void CXXNameMangler::mangleType(const FunctionProtoType *T) {
3608+
void CXXNameMangler::mangleTypeImpl(const FunctionProtoType *T) {
35703609
mangleExtFunctionInfo(T);
35713610

35723611
// Mangle CV-qualifiers, if present. These are 'this' qualifiers,
@@ -3604,6 +3643,10 @@ void CXXNameMangler::mangleType(const FunctionProtoType *T) {
36043643
}
36053644

36063645
void CXXNameMangler::mangleType(const FunctionNoProtoType *T) {
3646+
return mangleTypeImpl(T);
3647+
}
3648+
3649+
void CXXNameMangler::mangleTypeImpl(const FunctionNoProtoType *T) {
36073650
// Function types without prototypes can arise when mangling a function type
36083651
// within an overloadable function in C. We mangle these as the absence of any
36093652
// parameter types (not even an empty parameter list).
@@ -7074,6 +7117,86 @@ bool CXXNameMangler::shouldHaveAbiTags(ItaniumMangleContextImpl &C,
70747117
return TrackAbiTags.AbiTagsRoot.getUsedAbiTags().size();
70757118
}
70767119

7120+
namespace {
7121+
7122+
class RISCVZicfilpFuncSigLabelMangler : public CXXNameMangler {
7123+
bool IsTopLevelAndCXXVirtualMethod;
7124+
7125+
public:
7126+
RISCVZicfilpFuncSigLabelMangler(ItaniumMangleContextImpl &C, raw_ostream &Out,
7127+
const bool IsCXXVirtualMethod)
7128+
: CXXNameMangler(C, Out),
7129+
IsTopLevelAndCXXVirtualMethod(/*IsTopLevel=*/true &&
7130+
IsCXXVirtualMethod) {}
7131+
7132+
void mangleTypeImpl(const BuiltinType *T) override {
7133+
if (T->getKind() == BuiltinType::WChar_S ||
7134+
T->getKind() == BuiltinType::WChar_U) {
7135+
const Type *const OverrideT =
7136+
getASTContext().getWCharTypeInC().getTypePtr();
7137+
assert(isa<BuiltinType>(OverrideT) &&
7138+
"`wchar_t' in C is expected to be defined to a built-in type");
7139+
T = static_cast<const BuiltinType *>(OverrideT);
7140+
}
7141+
return CXXNameMangler::mangleTypeImpl(T);
7142+
}
7143+
7144+
// This <function-type> is the RISC-V psABI modified version
7145+
// <function-type> ::= [<CV-qualifiers>] [Dx] F <bare-function-type>
7146+
// [<ref-qualifier>] E
7147+
void mangleTypeImpl(const FunctionProtoType *T) override {
7148+
const bool WasTopLevelAndCXXVirtualMethod = IsTopLevelAndCXXVirtualMethod;
7149+
IsTopLevelAndCXXVirtualMethod = false; // Not top-level anymore
7150+
7151+
// Mangle CV-qualifiers, if present. These are 'this' qualifiers,
7152+
// e.g. "const" in "int (A::*)() const".
7153+
mangleQualifiers(T->getMethodQuals());
7154+
7155+
getStream() << 'F';
7156+
7157+
bool MangleReturnType = true;
7158+
if (const Type &RetT = *T->getReturnType().getTypePtr();
7159+
WasTopLevelAndCXXVirtualMethod && mayBeCovariant(RetT)) {
7160+
// Possible covariant types mangle dummy cv-unqualified `class v` as its
7161+
// class type
7162+
if (RetT.isPointerType())
7163+
getStream() << "P1v";
7164+
else if (RetT.isLValueReferenceType())
7165+
getStream() << "R1v";
7166+
else {
7167+
assert(RetT.isRValueReferenceType() &&
7168+
"Expect an r-value ref for covariant return type that is not a "
7169+
"pointer or an l-value ref");
7170+
getStream() << "O1v";
7171+
}
7172+
MangleReturnType = false;
7173+
}
7174+
mangleBareFunctionType(T, MangleReturnType);
7175+
7176+
// Mangle the ref-qualifier, if present.
7177+
mangleRefQualifier(T->getRefQualifier());
7178+
7179+
getStream() << 'E';
7180+
}
7181+
7182+
void mangleTypeImpl(const FunctionNoProtoType *T) override {
7183+
return CXXNameMangler::mangleTypeImpl(toFunctionProtoType(T));
7184+
}
7185+
7186+
private:
7187+
const FunctionProtoType *
7188+
toFunctionProtoType(const FunctionNoProtoType *const T) {
7189+
FunctionProtoType::ExtProtoInfo EPI;
7190+
EPI.ExtInfo = T->getExtInfo();
7191+
const Type *const NewT = getASTContext()
7192+
.getFunctionType(T->getReturnType(), {}, EPI)
7193+
.getTypePtr();
7194+
return static_cast<const FunctionProtoType *>(NewT);
7195+
}
7196+
}; // class RISCVZicfilpFuncSigLabelMangler
7197+
7198+
} // anonymous namespace
7199+
70777200
//
70787201

70797202
/// Mangles the name of the declaration D and emits that name to the given
@@ -7412,6 +7535,17 @@ void ItaniumMangleContextImpl::mangleModuleInitializer(const Module *M,
74127535
}
74137536
}
74147537

7538+
void ItaniumMangleContextImpl::mangleForRISCVZicfilpFuncSigLabel(
7539+
const FunctionType &FT, const bool IsCXXInstanceMethod,
7540+
const bool IsCXXVirtualMethod, raw_ostream &Out) {
7541+
if (IsCXXInstanceMethod)
7542+
// member methods uses a dummy class named `v` in place of real classes
7543+
Out << "M1v";
7544+
7545+
RISCVZicfilpFuncSigLabelMangler Mangler(*this, Out, IsCXXVirtualMethod);
7546+
Mangler.mangleType(QualType(&FT, 0));
7547+
}
7548+
74157549
ItaniumMangleContext *ItaniumMangleContext::create(ASTContext &Context,
74167550
DiagnosticsEngine &Diags,
74177551
bool IsAux) {

0 commit comments

Comments
 (0)