-
Notifications
You must be signed in to change notification settings - Fork 13.6k
[clang][RISCV][Zicfilp] Emit RISCV function-signature-based CFI label in llvm::Function metadata #111661
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
[clang][RISCV][Zicfilp] Emit RISCV function-signature-based CFI label in llvm::Function metadata #111661
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is pretty broken if you actually have code using pre-C23 semantics. If you don't want to think about it, just require that everyone use C23, and you won't see any FunctionNoProtoType. Otherwise, you need to actually do something reasonable, like using the type of the call arguments. |
||
} | ||
}; // 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) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even if you're restricting yourself to C23, C type compatibility rules are complicated... this probably rejects some valid code. Like, C allows the following:
See also #96992.