Skip to content

Commit 7cc1234

Browse files
committed
[clang] All Clang Changes
This patch adds clang CodeGen option to emit callgraph section. The `-fcall-graph-section` Driver flag is introduced to control the `CallGraphSection` CodeGen option.
1 parent d392563 commit 7cc1234

File tree

13 files changed

+470
-8
lines changed

13 files changed

+470
-8
lines changed

clang/include/clang/Basic/CodeGenOptions.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ CODEGENOPT(EnableNoundefAttrs, 1, 0, Benign) ///< Enable emitting `noundef` attr
7272
CODEGENOPT(DebugPassManager, 1, 0, Benign) ///< Prints debug information for the new
7373
///< pass manager.
7474
CODEGENOPT(DisableRedZone , 1, 0, Benign) ///< Set when -mno-red-zone is enabled.
75+
CODEGENOPT(CallGraphSection, 1, 0, Benign) ///< Emit a call graph section into the
76+
///< object file.
7577
CODEGENOPT(EmitCallSiteInfo, 1, 0, Benign) ///< Emit call site info only in the case of
7678
///< '-g' + 'O>0' level.
7779
CODEGENOPT(IndirectTlsSegRefs, 1, 0, Benign) ///< Set when -mno-tls-direct-seg-refs

clang/include/clang/Driver/Options.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4512,6 +4512,12 @@ defm data_sections : BoolFOption<"data-sections",
45124512
PosFlag<SetTrue, [], [ClangOption, CC1Option],
45134513
"Place each data in its own section">,
45144514
NegFlag<SetFalse>>;
4515+
defm experimental_call_graph_section
4516+
: BoolFOption<"experimental-call-graph-section", CodeGenOpts<"CallGraphSection">,
4517+
DefaultFalse,
4518+
PosFlag<SetTrue, [], [ClangOption, CC1Option],
4519+
"Emit a call graph section">,
4520+
NegFlag<SetFalse>>;
45154521
defm stack_size_section : BoolFOption<"stack-size-section",
45164522
CodeGenOpts<"StackSizeSection">, DefaultFalse,
45174523
PosFlag<SetTrue, [], [ClangOption, CC1Option],

clang/lib/CodeGen/BackendUtil.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,7 @@ static bool initTargetOptions(const CompilerInstance &CI,
463463
Options.StackUsageOutput = CodeGenOpts.StackUsageOutput;
464464
Options.EmitAddrsig = CodeGenOpts.Addrsig;
465465
Options.ForceDwarfFrameSection = CodeGenOpts.ForceDwarfFrameSection;
466+
Options.EmitCallGraphSection = CodeGenOpts.CallGraphSection;
466467
Options.EmitCallSiteInfo = CodeGenOpts.EmitCallSiteInfo;
467468
Options.EnableAIXExtendedAltivecABI = LangOpts.EnableAIXExtendedAltivecABI;
468469
Options.XRayFunctionIndex = CodeGenOpts.XRayFunctionIndex;

clang/lib/CodeGen/CGCall.cpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5945,8 +5945,24 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
59455945
CI->getCalledFunction()->getName().starts_with("_Z4sqrt")) {
59465946
SetSqrtFPAccuracy(CI);
59475947
}
5948-
if (callOrInvoke)
5948+
if (callOrInvoke) {
59495949
*callOrInvoke = CI;
5950+
if (CGM.getCodeGenOpts().CallGraphSection) {
5951+
QualType CST;
5952+
if (TargetDecl && TargetDecl->getFunctionType())
5953+
CST = QualType(TargetDecl->getFunctionType(), 0);
5954+
else if (const auto *FPT =
5955+
Callee.getAbstractInfo().getCalleeFunctionProtoType())
5956+
CST = QualType(FPT, 0);
5957+
else
5958+
llvm_unreachable(
5959+
"Cannot find the callee type to generate callee_type metadata.");
5960+
5961+
// Set type identifier metadata of indirect calls for call graph section.
5962+
if (!CST.isNull())
5963+
CGM.createCalleeTypeMetadataForIcall(CST, *callOrInvoke);
5964+
}
5965+
}
59505966

59515967
// If this is within a function that has the guard(nocf) attribute and is an
59525968
// indirect call, add the "guard_nocf" attribute to this call to indicate that

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2836,8 +2836,9 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
28362836

28372837
// In the cross-dso CFI mode with canonical jump tables, we want !type
28382838
// attributes on definitions only.
2839-
if (CodeGenOpts.SanitizeCfiCrossDso &&
2840-
CodeGenOpts.SanitizeCfiCanonicalJumpTables) {
2839+
if ((CodeGenOpts.SanitizeCfiCrossDso &&
2840+
CodeGenOpts.SanitizeCfiCanonicalJumpTables) ||
2841+
CodeGenOpts.CallGraphSection) {
28412842
if (auto *FD = dyn_cast<FunctionDecl>(D)) {
28422843
// Skip available_externally functions. They won't be codegen'ed in the
28432844
// current module anyway.
@@ -3049,9 +3050,21 @@ static void setLinkageForGV(llvm::GlobalValue *GV, const NamedDecl *ND) {
30493050
GV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
30503051
}
30513052

3053+
static bool hasExistingGeneralizedTypeMD(llvm::Function *F) {
3054+
llvm::MDNode *MD = F->getMetadata(llvm::LLVMContext::MD_type);
3055+
return MD && MD->hasGeneralizedMDString();
3056+
}
3057+
30523058
void CodeGenModule::createFunctionTypeMetadataForIcall(const FunctionDecl *FD,
30533059
llvm::Function *F) {
3054-
// Only if we are checking indirect calls.
3060+
if (CodeGenOpts.CallGraphSection && !hasExistingGeneralizedTypeMD(F) &&
3061+
(!F->hasLocalLinkage() ||
3062+
F->getFunction().hasAddressTaken(nullptr, /*IgnoreCallbackUses=*/true,
3063+
/*IgnoreAssumeLikeCalls=*/true,
3064+
/*IgnoreLLVMUsed=*/false)))
3065+
F->addTypeMetadata(0, CreateMetadataIdentifierGeneralized(FD->getType()));
3066+
3067+
// Add additional metadata only if we are checking indirect calls with CFI.
30553068
if (!LangOpts.Sanitize.has(SanitizerKind::CFIICall))
30563069
return;
30573070

@@ -3064,17 +3077,34 @@ void CodeGenModule::createFunctionTypeMetadataForIcall(const FunctionDecl *FD,
30643077
/*GeneralizePointers=*/false);
30653078
llvm::Metadata *MD = CreateMetadataIdentifierForType(FnType);
30663079
F->addTypeMetadata(0, MD);
3067-
3068-
QualType GenPtrFnType = GeneralizeFunctionType(getContext(), FD->getType(),
3069-
/*GeneralizePointers=*/true);
3070-
F->addTypeMetadata(0, CreateMetadataIdentifierGeneralized(GenPtrFnType));
3080+
// Add the generalized identifier if not added already.
3081+
if (!hasExistingGeneralizedTypeMD(F)) {
3082+
QualType GenPtrFnType = GeneralizeFunctionType(getContext(), FD->getType(),
3083+
/*GeneralizePointers=*/true);
3084+
F->addTypeMetadata(0, CreateMetadataIdentifierGeneralized(GenPtrFnType));
3085+
}
30713086

30723087
// Emit a hash-based bit set entry for cross-DSO calls.
30733088
if (CodeGenOpts.SanitizeCfiCrossDso)
30743089
if (auto CrossDsoTypeId = CreateCrossDsoCfiTypeId(MD))
30753090
F->addTypeMetadata(0, llvm::ConstantAsMetadata::get(CrossDsoTypeId));
30763091
}
30773092

3093+
void CodeGenModule::createCalleeTypeMetadataForIcall(const QualType &QT,
3094+
llvm::CallBase *CB) {
3095+
// Only if needed for call graph section and only for indirect calls.
3096+
if (!CodeGenOpts.CallGraphSection || !CB->isIndirectCall())
3097+
return;
3098+
3099+
llvm::Metadata *TypeIdMD = CreateMetadataIdentifierGeneralized(QT);
3100+
llvm::MDTuple *TypeTuple = llvm::MDTuple::get(
3101+
getLLVMContext(), {llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
3102+
llvm::Type::getInt64Ty(getLLVMContext()), 0)),
3103+
TypeIdMD});
3104+
llvm::MDTuple *MDN = llvm::MDNode::get(getLLVMContext(), {TypeTuple});
3105+
CB->setMetadata(llvm::LLVMContext::MD_callee_type, MDN);
3106+
}
3107+
30783108
void CodeGenModule::setKCFIType(const FunctionDecl *FD, llvm::Function *F) {
30793109
llvm::LLVMContext &Ctx = F->getContext();
30803110
llvm::MDBuilder MDB(Ctx);

clang/lib/CodeGen/CodeGenModule.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1644,6 +1644,9 @@ class CodeGenModule : public CodeGenTypeCache {
16441644
void createFunctionTypeMetadataForIcall(const FunctionDecl *FD,
16451645
llvm::Function *F);
16461646

1647+
/// Create and attach type metadata to the given call.
1648+
void createCalleeTypeMetadataForIcall(const QualType &QT, llvm::CallBase *CB);
1649+
16471650
/// Set type metadata to the given function.
16481651
void setKCFIType(const FunctionDecl *FD, llvm::Function *F);
16491652

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6447,6 +6447,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
64476447
CmdArgs.push_back(A->getValue());
64486448
}
64496449

6450+
if (Args.hasFlag(options::OPT_fexperimental_call_graph_section,
6451+
options::OPT_fno_experimental_call_graph_section, false))
6452+
CmdArgs.push_back("-fexperimental-call-graph-section");
6453+
64506454
Args.addOptInFlag(CmdArgs, options::OPT_fstack_size_section,
64516455
options::OPT_fno_stack_size_section);
64526456

clang/lib/Driver/ToolChains/CommonArgs.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1272,6 +1272,11 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args,
12721272
CmdArgs.push_back(
12731273
Args.MakeArgString(Twine(PluginOptPrefix) + "-stack-size-section"));
12741274

1275+
if (Args.hasFlag(options::OPT_fexperimental_call_graph_section,
1276+
options::OPT_fno_experimental_call_graph_section, false))
1277+
CmdArgs.push_back(
1278+
Args.MakeArgString(Twine(PluginOptPrefix) + "-call-graph-section"));
1279+
12751280
// Setup statistics file output.
12761281
SmallString<128> StatsFile = getStatsFileName(Args, Output, *Input, D);
12771282
if (!StatsFile.empty())
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
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 -fexperimental-call-graph-section \
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 and template classes (check for indirect target metadata)
11+
12+
class Cls1 {};
13+
14+
// Cls2 is instantiated with T=Cls1 in foo(). Following checks are for this
15+
// instantiation.
16+
template <class T>
17+
class Cls2 {
18+
public:
19+
// FT: define {{.*}} void @_ZN4Cls2I4Cls1E2f1Ev({{.*}} !type [[F_TCLS2F1:![0-9]+]]
20+
void f1() {}
21+
22+
// FT: define {{.*}} void @_ZN4Cls2I4Cls1E2f2ES0_({{.*}} !type [[F_TCLS2F2:![0-9]+]]
23+
void f2(T a) {}
24+
25+
// FT: define {{.*}} void @_ZN4Cls2I4Cls1E2f3EPS0_({{.*}} !type [[F_TCLS2F3:![0-9]+]]
26+
void f3(T *a) {}
27+
28+
// FT: define {{.*}} void @_ZN4Cls2I4Cls1E2f4EPKS0_({{.*}} !type [[F_TCLS2F4:![0-9]+]]
29+
void f4(const T *a) {}
30+
31+
// FT: define {{.*}} void @_ZN4Cls2I4Cls1E2f5ERS0_({{.*}} !type [[F_TCLS2F5:![0-9]+]]
32+
void f5(T &a) {}
33+
34+
// FT: define {{.*}} void @_ZN4Cls2I4Cls1E2f6ERKS0_({{.*}} !type [[F_TCLS2F6:![0-9]+]]
35+
void f6(const T &a) {}
36+
37+
// Mixed type function pointer member
38+
T *(*fp)(T a, T *b, const T *c, T &d, const T &e);
39+
};
40+
41+
// FT-DAG: [[F_TCLS2F1]] = !{i64 0, !"_ZTSFvvE.generalized"}
42+
// FT-DAG: [[F_TCLS2F2]] = !{i64 0, !"_ZTSFv4Cls1E.generalized"}
43+
// FT-DAG: [[F_TCLS2F3]] = !{i64 0, !"_ZTSFvPvE.generalized"}
44+
// FT-DAG: [[F_TCLS2F4]] = !{i64 0, !"_ZTSFvPKvE.generalized"}
45+
// FT-DAG: [[F_TCLS2F5]] = !{i64 0, !"_ZTSFvR4Cls1E.generalized"}
46+
// FT-DAG: [[F_TCLS2F6]] = !{i64 0, !"_ZTSFvRK4Cls1E.generalized"}
47+
48+
////////////////////////////////////////////////////////////////////////////////
49+
// Callsites (check for indirect callsite operand bundles)
50+
51+
template <class T>
52+
T *T_func(T a, T *b, const T *c, T &d, const T &e) { return b; }
53+
54+
// CST-LABEL: define {{.*}} @_Z3foov
55+
void foo() {
56+
// Methods for Cls2<Cls1> is checked above within the template description.
57+
Cls2<Cls1> Obj;
58+
59+
Obj.fp = T_func<Cls1>;
60+
Cls1 Cls1Obj;
61+
62+
// CST: call noundef ptr %{{.*}}, !callee_type [[F_TFUNC_CLS1_CT:![0-9]+]]
63+
Obj.fp(Cls1Obj, &Cls1Obj, &Cls1Obj, Cls1Obj, Cls1Obj);
64+
65+
// Make indirect calls to Cls2's member methods
66+
auto fp_f1 = &Cls2<Cls1>::f1;
67+
auto fp_f2 = &Cls2<Cls1>::f2;
68+
auto fp_f3 = &Cls2<Cls1>::f3;
69+
auto fp_f4 = &Cls2<Cls1>::f4;
70+
auto fp_f5 = &Cls2<Cls1>::f5;
71+
auto fp_f6 = &Cls2<Cls1>::f6;
72+
73+
auto *Obj2Ptr = &Obj;
74+
75+
// CST: call void %{{.*}}, !callee_type [[F_TCLS2F1_CT:![0-9]+]]
76+
(Obj2Ptr->*fp_f1)();
77+
78+
// CST: call void %{{.*}}, !callee_type [[F_TCLS2F2_CT:![0-9]+]]
79+
(Obj2Ptr->*fp_f2)(Cls1Obj);
80+
81+
// CST: call void %{{.*}}, !callee_type [[F_TCLS2F3_CT:![0-9]+]]
82+
(Obj2Ptr->*fp_f3)(&Cls1Obj);
83+
84+
// CST: call void %{{.*}}, !callee_type [[F_TCLS2F4_CT:![0-9]+]]
85+
(Obj2Ptr->*fp_f4)(&Cls1Obj);
86+
87+
// CST: call void %{{.*}}, !callee_type [[F_TCLS2F5_CT:![0-9]+]]
88+
(Obj2Ptr->*fp_f5)(Cls1Obj);
89+
90+
// CST: call void %{{.*}}, !callee_type [[F_TCLS2F6_CT:![0-9]+]]
91+
(Obj2Ptr->*fp_f6)(Cls1Obj);
92+
}
93+
94+
// CST: define {{.*}} @_Z6T_funcI4Cls1EPT_S1_S2_PKS1_RS1_RS3_({{.*}} !type [[F_TFUNC_CLS1:![0-9]+]]
95+
// CST-DAG: [[F_TFUNC_CLS1_CT]] = !{[[F_TFUNC_CLS1:![0-9]+]]}
96+
// CST-DAG: [[F_TFUNC_CLS1]] = !{i64 0, !"_ZTSFPv4Cls1S_PKvRS0_RKS0_E.generalized"}
97+
98+
// CST-DAG: [[F_TCLS2F1_CT]] = !{[[F_TCLS2F1:![0-9]+]]}
99+
// CST-DAG: [[F_TCLS2F1]] = !{i64 0, !"_ZTSFvvE.generalized"}
100+
101+
// CST-DAG: [[F_TCLS2F2_CT]] = !{[[F_TCLS2F2:![0-9]+]]}
102+
// CST-DAG: [[F_TCLS2F2]] = !{i64 0, !"_ZTSFv4Cls1E.generalized"}
103+
104+
// CST-DAG: [[F_TCLS2F3_CT]] = !{[[F_TCLS2F3:![0-9]+]]}
105+
// CST-DAG: [[F_TCLS2F3]] = !{i64 0, !"_ZTSFvPvE.generalized"}
106+
107+
// CST-DAG: [[F_TCLS2F4_CT]] = !{[[F_TCLS2F4:![0-9]+]]}
108+
// CST-DAG: [[F_TCLS2F4]] = !{i64 0, !"_ZTSFvPKvE.generalized"}
109+
110+
// CST-DAG: [[F_TCLS2F5_CT]] = !{[[F_TCLS2F5:![0-9]+]]}
111+
// CST-DAG: [[F_TCLS2F5]] = !{i64 0, !"_ZTSFvR4Cls1E.generalized"}
112+
113+
// CST-DAG: [[F_TCLS2F6_CT]] = !{[[F_TCLS2F6:![0-9]+]]}
114+
// CST-DAG: [[F_TCLS2F6]] = !{i64 0, !"_ZTSFvRK4Cls1E.generalized"}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// Tests that we assign appropriate identifiers to indirect calls and targets
2+
// specifically for virtual methods.
3+
4+
// RUN: %clang_cc1 -triple x86_64-unknown-linux -fexperimental-call-graph-section \
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 Base {
13+
public:
14+
// FT-DAG: define {{.*}} @_ZN4Base2vfEPc({{.*}} !type [[F_TVF:![0-9]+]]
15+
virtual int vf(char *a) { return 0; };
16+
};
17+
18+
class Derived : public Base {
19+
public:
20+
// FT-DAG: define {{.*}} @_ZN7Derived2vfEPc({{.*}} !type [[F_TVF]]
21+
int vf(char *a) override { return 1; };
22+
};
23+
24+
// FT-DAG: [[F_TVF]] = !{i64 0, !"_ZTSFiPvE.generalized"}
25+
26+
////////////////////////////////////////////////////////////////////////////////
27+
// Callsites (check for indirect callsite operand bundles)
28+
29+
// CST-LABEL: define {{.*}} @_Z3foov
30+
void foo() {
31+
auto B = Base();
32+
auto D = Derived();
33+
34+
Base *Bptr = &B;
35+
Base *BptrToD = &D;
36+
Derived *Dptr = &D;
37+
38+
auto FpBaseVf = &Base::vf;
39+
auto FpDerivedVf = &Derived::vf;
40+
41+
// CST: call noundef i32 %{{.*}}, !callee_type [[F_TVF_CT:![0-9]+]]
42+
(Bptr->*FpBaseVf)(0);
43+
44+
// CST: call noundef i32 %{{.*}}, !callee_type [[F_TVF_CT:![0-9]+]]
45+
(BptrToD->*FpBaseVf)(0);
46+
47+
// CST: call noundef i32 %{{.*}}, !callee_type [[F_TVF_CT:![0-9]+]]
48+
(Dptr->*FpBaseVf)(0);
49+
50+
// CST: call noundef i32 %{{.*}}, !callee_type [[F_TVF_CT:![0-9]+]]
51+
(Dptr->*FpDerivedVf)(0);
52+
}
53+
54+
// CST-DAG: [[F_TVF_CT]] = !{[[F_TVF:![0-9]+]]}
55+
// CST-DAG: [[F_TVF]] = !{i64 0, !"_ZTSFiPvE.generalized"}

0 commit comments

Comments
 (0)