Skip to content

Commit 08d0dc1

Browse files
committed
[𝘀𝗽𝗿] initial version
Created using spr 1.3.6-beta.1
2 parents 581f755 + c59725c commit 08d0dc1

File tree

15 files changed

+456
-17
lines changed

15 files changed

+456
-17
lines changed

clang/lib/CodeGen/CGCall.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "clang/AST/Decl.h"
2626
#include "clang/AST/DeclCXX.h"
2727
#include "clang/AST/DeclObjC.h"
28+
#include "clang/AST/Type.h"
2829
#include "clang/Basic/CodeGenOptions.h"
2930
#include "clang/Basic/TargetInfo.h"
3031
#include "clang/CodeGen/CGFunctionInfo.h"
@@ -5077,6 +5078,11 @@ static unsigned getMaxVectorWidth(const llvm::Type *Ty) {
50775078
return MaxVectorWidth;
50785079
}
50795080

5081+
static bool isCXXDeclType(const FunctionDecl *FD) {
5082+
return isa<CXXConstructorDecl>(FD) || isa<CXXMethodDecl>(FD) ||
5083+
isa<CXXDestructorDecl>(FD);
5084+
}
5085+
50805086
RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
50815087
const CGCallee &Callee,
50825088
ReturnValueSlot ReturnValue,
@@ -5765,6 +5771,38 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
57655771
AllocAlignAttrEmitter AllocAlignAttrEmitter(*this, TargetDecl, CallArgs);
57665772
Attrs = AllocAlignAttrEmitter.TryEmitAsCallSiteAttribute(Attrs);
57675773

5774+
if (CGM.getCodeGenOpts().CallGraphSection) {
5775+
// Create operand bundle only for indirect calls, not for all
5776+
if (callOrInvoke && *callOrInvoke && (*callOrInvoke)->isIndirectCall()) {
5777+
5778+
assert((TargetDecl && TargetDecl->getFunctionType() ||
5779+
Callee.getAbstractInfo().getCalleeFunctionProtoType()) &&
5780+
"cannot find callsite type");
5781+
5782+
QualType CST;
5783+
if (TargetDecl && TargetDecl->getFunctionType())
5784+
CST = QualType(TargetDecl->getFunctionType(), 0);
5785+
else if (const auto *FPT =
5786+
Callee.getAbstractInfo().getCalleeFunctionProtoType())
5787+
CST = QualType(FPT, 0);
5788+
5789+
if (!CST.isNull()) {
5790+
auto *TypeIdMD = CGM.CreateMetadataIdentifierGeneralized(CST);
5791+
auto *TypeIdMDVal =
5792+
llvm::MetadataAsValue::get(getLLVMContext(), TypeIdMD);
5793+
BundleList.emplace_back("type", TypeIdMDVal);
5794+
}
5795+
5796+
// Set type identifier metadata of indirect calls for call graph section.
5797+
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(TargetDecl)) {
5798+
// Type id metadata is set only for C/C++ contexts.
5799+
if (isCXXDeclType(FD)) {
5800+
CGM.CreateFunctionTypeMetadataForIcall(FD->getType(), *callOrInvoke);
5801+
}
5802+
}
5803+
}
5804+
}
5805+
57685806
// Emit the actual call/invoke instruction.
57695807
llvm::CallBase *CI;
57705808
if (!InvokeDest) {

clang/lib/CodeGen/CGExpr.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6173,6 +6173,12 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType,
61736173
if (CallOrInvoke)
61746174
*CallOrInvoke = LocalCallOrInvoke;
61756175

6176+
// Set type identifier metadata of indirect calls for call graph section.
6177+
if (CGM.getCodeGenOpts().CallGraphSection && LocalCallOrInvoke &&
6178+
LocalCallOrInvoke->isIndirectCall())
6179+
CGM.CreateFunctionTypeMetadataForIcall(QualType(FnType, 0),
6180+
LocalCallOrInvoke);
6181+
61766182
return Call;
61776183
}
61786184

clang/lib/CodeGen/CGObjCMac.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2214,9 +2214,8 @@ CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF,
22142214

22152215
llvm::CallBase *CallSite;
22162216
CGCallee Callee = CGCallee::forDirect(BitcastFn);
2217-
RValue rvalue = CGF.EmitCall(MSI.CallInfo, Callee, Return, ActualArgs,
2218-
&CallSite);
2219-
2217+
RValue rvalue =
2218+
CGF.EmitCall(MSI.CallInfo, Callee, Return, ActualArgs, &CallSite);
22202219
// Mark the call as noreturn if the method is marked noreturn and the
22212220
// receiver cannot be null.
22222221
if (Method && Method->hasAttr<NoReturnAttr>() && !ReceiverCanBeNull) {

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2622,8 +2622,9 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
26222622

26232623
// In the cross-dso CFI mode with canonical jump tables, we want !type
26242624
// attributes on definitions only.
2625-
if (CodeGenOpts.SanitizeCfiCrossDso &&
2626-
CodeGenOpts.SanitizeCfiCanonicalJumpTables) {
2625+
if ((CodeGenOpts.SanitizeCfiCrossDso &&
2626+
CodeGenOpts.SanitizeCfiCanonicalJumpTables) ||
2627+
CodeGenOpts.CallGraphSection) {
26272628
if (auto *FD = dyn_cast<FunctionDecl>(D)) {
26282629
// Skip available_externally functions. They won't be codegen'ed in the
26292630
// current module anyway.
@@ -2813,7 +2814,17 @@ static void setLinkageForGV(llvm::GlobalValue *GV, const NamedDecl *ND) {
28132814

28142815
void CodeGenModule::CreateFunctionTypeMetadataForIcall(const FunctionDecl *FD,
28152816
llvm::Function *F) {
2816-
// Only if we are checking indirect calls.
2817+
bool EmittedMDIdGeneralized = false;
2818+
if (CodeGenOpts.CallGraphSection &&
2819+
(!F->hasLocalLinkage() ||
2820+
F->getFunction().hasAddressTaken(nullptr, /*IgnoreCallbackUses=*/true,
2821+
/*IgnoreAssumeLikeCalls=*/true,
2822+
/*IgnoreLLVMUsed=*/false))) {
2823+
F->addTypeMetadata(0, CreateMetadataIdentifierGeneralized(FD->getType()));
2824+
EmittedMDIdGeneralized = true;
2825+
}
2826+
2827+
// Add additional metadata only if we are checking indirect calls with CFI.
28172828
if (!LangOpts.Sanitize.has(SanitizerKind::CFIICall))
28182829
return;
28192830

@@ -2824,14 +2835,27 @@ void CodeGenModule::CreateFunctionTypeMetadataForIcall(const FunctionDecl *FD,
28242835

28252836
llvm::Metadata *MD = CreateMetadataIdentifierForType(FD->getType());
28262837
F->addTypeMetadata(0, MD);
2827-
F->addTypeMetadata(0, CreateMetadataIdentifierGeneralized(FD->getType()));
2838+
// Add the generalized identifier if not added already.
2839+
if (!EmittedMDIdGeneralized)
2840+
F->addTypeMetadata(0, CreateMetadataIdentifierGeneralized(FD->getType()));
28282841

28292842
// Emit a hash-based bit set entry for cross-DSO calls.
28302843
if (CodeGenOpts.SanitizeCfiCrossDso)
28312844
if (auto CrossDsoTypeId = CreateCrossDsoCfiTypeId(MD))
28322845
F->addTypeMetadata(0, llvm::ConstantAsMetadata::get(CrossDsoTypeId));
28332846
}
28342847

2848+
void CodeGenModule::CreateFunctionTypeMetadataForIcall(const QualType &QT,
2849+
llvm::CallBase *CB) {
2850+
// Only if needed for call graph section and only for indirect calls.
2851+
if (!CodeGenOpts.CallGraphSection || !CB || !CB->isIndirectCall())
2852+
return;
2853+
2854+
auto *MD = CreateMetadataIdentifierGeneralized(QT);
2855+
auto *MDN = llvm::MDNode::get(getLLVMContext(), MD);
2856+
CB->setMetadata(llvm::LLVMContext::MD_type, MDN);
2857+
}
2858+
28352859
void CodeGenModule::setKCFIType(const FunctionDecl *FD, llvm::Function *F) {
28362860
llvm::LLVMContext &Ctx = F->getContext();
28372861
llvm::MDBuilder MDB(Ctx);
@@ -2959,7 +2983,8 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F,
29592983
// are non-canonical then we need type metadata in order to produce the local
29602984
// jump table.
29612985
if (!CodeGenOpts.SanitizeCfiCrossDso ||
2962-
!CodeGenOpts.SanitizeCfiCanonicalJumpTables)
2986+
!CodeGenOpts.SanitizeCfiCanonicalJumpTables ||
2987+
CodeGenOpts.CallGraphSection)
29632988
CreateFunctionTypeMetadataForIcall(FD, F);
29642989

29652990
if (LangOpts.Sanitize.has(SanitizerKind::KCFI))

clang/lib/CodeGen/CodeGenModule.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1572,6 +1572,10 @@ class CodeGenModule : public CodeGenTypeCache {
15721572
void CreateFunctionTypeMetadataForIcall(const FunctionDecl *FD,
15731573
llvm::Function *F);
15741574

1575+
/// Create and attach type metadata to the given call.
1576+
void CreateFunctionTypeMetadataForIcall(const QualType &QT,
1577+
llvm::CallBase *CB);
1578+
15751579
/// Set type metadata to the given function.
15761580
void setKCFIType(const FunctionDecl *FD, llvm::Function *F);
15771581

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
// Tests that we assign appropriate identifiers to indirect calls and targets
2+
// specifically for C++ class and instance methods.
3+
4+
// RUN: %clang_cc1 -triple x86_64-unknown-linux -fcall-graph-section -S \
5+
// RUN: -emit-llvm -o %t %s
6+
// RUN: FileCheck --check-prefix=FT %s < %t
7+
// RUN: FileCheck --check-prefix=CST %s < %t
8+
9+
////////////////////////////////////////////////////////////////////////////////
10+
// Class definitions (check for indirect target metadata)
11+
12+
class Cls1 {
13+
public:
14+
// FT-DAG: define {{.*}} ptr @_ZN4Cls18receiverEPcPf({{.*}} !type [[F_TCLS1RECEIVER:![0-9]+]]
15+
static int *receiver(char *a, float *b) { return 0; }
16+
};
17+
18+
class Cls2 {
19+
public:
20+
int *(*fp)(char *, float *);
21+
22+
// FT-DAG: define {{.*}} i32 @_ZN4Cls22f1Ecfd({{.*}} !type [[F_TCLS2F1:![0-9]+]]
23+
int f1(char a, float b, double c) { return 0; }
24+
25+
// FT-DAG: define {{.*}} ptr @_ZN4Cls22f2EPcPfPd({{.*}} !type [[F_TCLS2F2:![0-9]+]]
26+
int *f2(char *a, float *b, double *c) { return 0; }
27+
28+
// FT-DAG: define {{.*}} void @_ZN4Cls22f3E4Cls1({{.*}} !type [[F_TCLS2F3F4:![0-9]+]]
29+
void f3(Cls1 a) {}
30+
31+
// FT-DAG: define {{.*}} void @_ZN4Cls22f4E4Cls1({{.*}} !type [[F_TCLS2F3F4]]
32+
void f4(const Cls1 a) {}
33+
34+
// FT-DAG: define {{.*}} void @_ZN4Cls22f5EP4Cls1({{.*}} !type [[F_TCLS2F5:![0-9]+]]
35+
void f5(Cls1 *a) {}
36+
37+
// FT-DAG: define {{.*}} void @_ZN4Cls22f6EPK4Cls1({{.*}} !type [[F_TCLS2F6:![0-9]+]]
38+
void f6(const Cls1 *a) {}
39+
40+
// FT-DAG: define {{.*}} void @_ZN4Cls22f7ER4Cls1({{.*}} !type [[F_TCLS2F7:![0-9]+]]
41+
void f7(Cls1 &a) {}
42+
43+
// FT-DAG: define {{.*}} void @_ZN4Cls22f8ERK4Cls1({{.*}} !type [[F_TCLS2F8:![0-9]+]]
44+
void f8(const Cls1 &a) {}
45+
46+
// FT-DAG: define {{.*}} void @_ZNK4Cls22f9Ev({{.*}} !type [[F_TCLS2F9:![0-9]+]]
47+
void f9() const {}
48+
};
49+
50+
// FT-DAG: [[F_TCLS1RECEIVER]] = !{i64 0, !"_ZTSFPvS_S_E.generalized"}
51+
// FT-DAG: [[F_TCLS2F2]] = !{i64 0, !"_ZTSFPvS_S_S_E.generalized"}
52+
// FT-DAG: [[F_TCLS2F1]] = !{i64 0, !"_ZTSFicfdE.generalized"}
53+
// FT-DAG: [[F_TCLS2F3F4]] = !{i64 0, !"_ZTSFv4Cls1E.generalized"}
54+
// FT-DAG: [[F_TCLS2F5]] = !{i64 0, !"_ZTSFvPvE.generalized"}
55+
// FT-DAG: [[F_TCLS2F6]] = !{i64 0, !"_ZTSFvPKvE.generalized"}
56+
// FT-DAG: [[F_TCLS2F7]] = !{i64 0, !"_ZTSFvR4Cls1E.generalized"}
57+
// FT-DAG: [[F_TCLS2F8]] = !{i64 0, !"_ZTSFvRK4Cls1E.generalized"}
58+
// FT-DAG: [[F_TCLS2F9]] = !{i64 0, !"_ZTSKFvvE.generalized"}
59+
60+
////////////////////////////////////////////////////////////////////////////////
61+
// Callsites (check for indirect callsite operand bundles)
62+
63+
// CST-LABEL: define {{.*}} @_Z3foov
64+
void foo() {
65+
Cls2 ObjCls2;
66+
ObjCls2.fp = &Cls1::receiver;
67+
68+
// CST: call noundef ptr %{{.*}} [ "type"(metadata !"_ZTSFPvS_S_E.generalized") ]
69+
ObjCls2.fp(0, 0);
70+
71+
auto fp_f1 = &Cls2::f1;
72+
auto fp_f2 = &Cls2::f2;
73+
auto fp_f3 = &Cls2::f3;
74+
auto fp_f4 = &Cls2::f4;
75+
auto fp_f5 = &Cls2::f5;
76+
auto fp_f6 = &Cls2::f6;
77+
auto fp_f7 = &Cls2::f7;
78+
auto fp_f8 = &Cls2::f8;
79+
auto fp_f9 = &Cls2::f9;
80+
81+
Cls2 *ObjCls2Ptr = &ObjCls2;
82+
Cls1 Cls1Param;
83+
84+
// CST: call noundef i32 %{{.*}} [ "type"(metadata !"_ZTSFicfdE.generalized") ]
85+
(ObjCls2Ptr->*fp_f1)(0, 0, 0);
86+
87+
// CST: call noundef ptr %{{.*}} [ "type"(metadata !"_ZTSFPvS_S_S_E.generalized") ]
88+
(ObjCls2Ptr->*fp_f2)(0, 0, 0);
89+
90+
// CST: call void %{{.*}} [ "type"(metadata !"_ZTSFv4Cls1E.generalized") ]
91+
(ObjCls2Ptr->*fp_f3)(Cls1Param);
92+
93+
// CST: call void %{{.*}} [ "type"(metadata !"_ZTSFv4Cls1E.generalized") ]
94+
(ObjCls2Ptr->*fp_f4)(Cls1Param);
95+
96+
// CST: call void %{{.*}} [ "type"(metadata !"_ZTSFvPvE.generalized") ]
97+
(ObjCls2Ptr->*fp_f5)(&Cls1Param);
98+
99+
// CST: call void %{{.*}} [ "type"(metadata !"_ZTSFvPKvE.generalized") ]
100+
(ObjCls2Ptr->*fp_f6)(&Cls1Param);
101+
102+
// CST: call void %{{.*}} [ "type"(metadata !"_ZTSFvR4Cls1E.generalized") ]
103+
(ObjCls2Ptr->*fp_f7)(Cls1Param);
104+
105+
// CST: call void %{{.*}} [ "type"(metadata !"_ZTSFvRK4Cls1E.generalized") ]
106+
(ObjCls2Ptr->*fp_f8)(Cls1Param);
107+
108+
// CST: call void %{{.*}} [ "type"(metadata !"_ZTSKFvvE.generalized") ]
109+
(ObjCls2Ptr->*fp_f9)();
110+
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// Tests that we assign appropriate identifiers to indirect calls and targets
2+
// specifically for C++ templates.
3+
4+
// RUN: %clang_cc1 -triple x86_64-unknown-linux -fcall-graph-section -S \
5+
// RUN: -emit-llvm -o %t %s
6+
// RUN: FileCheck --check-prefix=FT %s < %t
7+
// RUN: FileCheck --check-prefix=CST %s < %t
8+
// RUN: FileCheck --check-prefix=CHECK %s < %t
9+
10+
////////////////////////////////////////////////////////////////////////////////
11+
// Class definitions and template classes (check for indirect target metadata)
12+
13+
class Cls1 {};
14+
15+
// Cls2 is instantiated with T=Cls1 in foo(). Following checks are for this
16+
// instantiation.
17+
template <class T>
18+
class Cls2 {
19+
public:
20+
// FT: define {{.*}} void @_ZN4Cls2I4Cls1E2f1Ev({{.*}} !type [[F_TCLS2F1:![0-9]+]]
21+
void f1() {}
22+
23+
// FT: define {{.*}} void @_ZN4Cls2I4Cls1E2f2ES0_({{.*}} !type [[F_TCLS2F2:![0-9]+]]
24+
void f2(T a) {}
25+
26+
// FT: define {{.*}} void @_ZN4Cls2I4Cls1E2f3EPS0_({{.*}} !type [[F_TCLS2F3:![0-9]+]]
27+
void f3(T *a) {}
28+
29+
// FT: define {{.*}} void @_ZN4Cls2I4Cls1E2f4EPKS0_({{.*}} !type [[F_TCLS2F4:![0-9]+]]
30+
void f4(const T *a) {}
31+
32+
// FT: define {{.*}} void @_ZN4Cls2I4Cls1E2f5ERS0_({{.*}} !type [[F_TCLS2F5:![0-9]+]]
33+
void f5(T &a) {}
34+
35+
// FT: define {{.*}} void @_ZN4Cls2I4Cls1E2f6ERKS0_({{.*}} !type [[F_TCLS2F6:![0-9]+]]
36+
void f6(const T &a) {}
37+
38+
// Mixed type function pointer member
39+
T *(*fp)(T a, T *b, const T *c, T &d, const T &e);
40+
};
41+
42+
// FT-DAG: [[F_TCLS2F1]] = !{i64 0, !"_ZTSFvvE.generalized"}
43+
// FT-DAG: [[F_TCLS2F2]] = !{i64 0, !"_ZTSFv4Cls1E.generalized"}
44+
// FT-DAG: [[F_TCLS2F3]] = !{i64 0, !"_ZTSFvPvE.generalized"}
45+
// FT-DAG: [[F_TCLS2F4]] = !{i64 0, !"_ZTSFvPKvE.generalized"}
46+
// FT-DAG: [[F_TCLS2F5]] = !{i64 0, !"_ZTSFvR4Cls1E.generalized"}
47+
// FT-DAG: [[F_TCLS2F6]] = !{i64 0, !"_ZTSFvRK4Cls1E.generalized"}
48+
49+
////////////////////////////////////////////////////////////////////////////////
50+
// Callsites (check for indirect callsite operand bundles)
51+
52+
template <class T>
53+
T *T_func(T a, T *b, const T *c, T &d, const T &e) { return b; }
54+
55+
// CST-LABEL: define {{.*}} @_Z3foov
56+
void foo() {
57+
// Methods for Cls2<Cls1> is checked above within the template description.
58+
Cls2<Cls1> Obj;
59+
60+
// CHECK-DAG: define {{.*}} @_Z6T_funcI4Cls1EPT_S1_S2_PKS1_RS1_RS3_({{.*}} !type [[F_TFUNC_CLS1:![0-9]+]]
61+
// CHECK-DAG: [[F_TFUNC_CLS1]] = !{i64 0, !"_ZTSFPv4Cls1S_PKvRS0_RKS0_E.generalized"}
62+
Obj.fp = T_func<Cls1>;
63+
Cls1 Cls1Obj;
64+
65+
// CST: call noundef ptr %{{.*}} [ "type"(metadata !"_ZTSFPv4Cls1S_PKvRS0_RKS0_E.generalized") ]
66+
Obj.fp(Cls1Obj, &Cls1Obj, &Cls1Obj, Cls1Obj, Cls1Obj);
67+
68+
// Make indirect calls to Cls2's member methods
69+
auto fp_f1 = &Cls2<Cls1>::f1;
70+
auto fp_f2 = &Cls2<Cls1>::f2;
71+
auto fp_f3 = &Cls2<Cls1>::f3;
72+
auto fp_f4 = &Cls2<Cls1>::f4;
73+
auto fp_f5 = &Cls2<Cls1>::f5;
74+
auto fp_f6 = &Cls2<Cls1>::f6;
75+
76+
auto *Obj2Ptr = &Obj;
77+
78+
// CST: call void %{{.*}} [ "type"(metadata !"_ZTSFvvE.generalized") ]
79+
(Obj2Ptr->*fp_f1)();
80+
81+
// CST: call void %{{.*}} [ "type"(metadata !"_ZTSFv4Cls1E.generalized") ]
82+
(Obj2Ptr->*fp_f2)(Cls1Obj);
83+
84+
// CST: call void %{{.*}} [ "type"(metadata !"_ZTSFvPvE.generalized") ]
85+
(Obj2Ptr->*fp_f3)(&Cls1Obj);
86+
87+
// CST: call void %{{.*}} [ "type"(metadata !"_ZTSFvPKvE.generalized") ]
88+
(Obj2Ptr->*fp_f4)(&Cls1Obj);
89+
90+
// CST: call void %{{.*}} [ "type"(metadata !"_ZTSFvR4Cls1E.generalized") ]
91+
(Obj2Ptr->*fp_f5)(Cls1Obj);
92+
93+
// CST: call void %{{.*}} [ "type"(metadata !"_ZTSFvRK4Cls1E.generalized") ]
94+
(Obj2Ptr->*fp_f6)(Cls1Obj);
95+
}

0 commit comments

Comments
 (0)