Skip to content

Commit eb0584d

Browse files
necipfazilPrabhuk
authored andcommitted
[CallSiteInfo][CallGraphSection] Extract and propagate indirect call type ids
Extract numeric type ids for indirect calls, and carry them to the back-end with CallSiteInfo. The numeric type ids will be used at the back-end to emit the call graph section. Original RFC: https://lists.llvm.org/pipermail/llvm-dev/2021-June/151044.html Updated RFC: https://lists.llvm.org/pipermail/llvm-dev/2021-July/151739.html Reviewed By: morehouse Differential Revision: https://reviews.llvm.org/D107111?id=362891 Pull Request: llvm#87575
1 parent 2b6eec5 commit eb0584d

12 files changed

+331
-2
lines changed

llvm/include/llvm/CodeGen/MachineFunction.h

+34
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@
2727
#include "llvm/CodeGen/MachineBasicBlock.h"
2828
#include "llvm/CodeGen/MachineInstr.h"
2929
#include "llvm/CodeGen/MachineMemOperand.h"
30+
#include "llvm/IR/Constants.h"
3031
#include "llvm/IR/EHPersonalities.h"
32+
#include "llvm/IR/Instructions.h"
3133
#include "llvm/Support/Allocator.h"
3234
#include "llvm/Support/ArrayRecycler.h"
3335
#include "llvm/Support/AtomicOrdering.h"
@@ -488,6 +490,38 @@ class LLVM_EXTERNAL_VISIBILITY MachineFunction {
488490

489491
/// Callee type id.
490492
ConstantInt *TypeId = nullptr;
493+
494+
CallSiteInfo() {}
495+
496+
/// Extracts the numeric type id from the CallBase's type operand bundle,
497+
/// and sets TypeId. This is used as type id for the indirect call in the
498+
/// call graph section.
499+
CallSiteInfo(const CallBase &CB) {
500+
// Call graph section needs numeric type id only for indirect calls.
501+
if (!CB.isIndirectCall())
502+
return;
503+
504+
auto Opt = CB.getOperandBundle(LLVMContext::OB_type);
505+
if (!Opt.has_value()) {
506+
errs() << "warning: cannot find indirect call type operand bundle for "
507+
"call graph section\n";
508+
return;
509+
}
510+
511+
// Get generalized type id string
512+
auto OB = Opt.value();
513+
assert(OB.Inputs.size() == 1 && "invalid input size");
514+
auto *OBVal = OB.Inputs.front().get();
515+
auto *TypeIdMD = cast<MetadataAsValue>(OBVal)->getMetadata();
516+
auto *TypeIdStr = cast<MDString>(TypeIdMD);
517+
assert(TypeIdStr->getString().endswith(".generalized") &&
518+
"invalid type identifier");
519+
520+
// Compute numeric type id from generalized type id string
521+
uint64_t TypeIdVal = llvm::MD5Hash(TypeIdStr->getString());
522+
IntegerType *Int64Ty = Type::getInt64Ty(CB.getContext());
523+
TypeId = llvm::ConstantInt::get(Int64Ty, TypeIdVal, /*IsSigned=*/false);
524+
}
491525
};
492526

493527
private:

llvm/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -888,7 +888,8 @@ EmitSchedule(MachineBasicBlock::iterator &InsertPos) {
888888
}
889889

890890
if (MI->isCandidateForCallSiteEntry() &&
891-
DAG->getTarget().Options.EmitCallSiteInfo) {
891+
(DAG->getTarget().Options.EmitCallSiteInfo ||
892+
DAG->getTarget().Options.EmitCallGraphSection)) {
892893
MF.addCallSiteInfo(MI, DAG->getCallSiteInfo(Node));
893894
}
894895

llvm/lib/Target/AArch64/AArch64ISelLowering.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -7811,6 +7811,7 @@ AArch64TargetLowering::LowerCall(CallLoweringInfo &CLI,
78117811
bool &IsTailCall = CLI.IsTailCall;
78127812
CallingConv::ID &CallConv = CLI.CallConv;
78137813
bool IsVarArg = CLI.IsVarArg;
7814+
const auto *CB = CLI.CB;
78147815

78157816
MachineFunction &MF = DAG.getMachineFunction();
78167817
MachineFunction::CallSiteInfo CSInfo;
@@ -7850,6 +7851,10 @@ AArch64TargetLowering::LowerCall(CallLoweringInfo &CLI,
78507851
*DAG.getContext());
78517852
RetCCInfo.AnalyzeCallResult(Ins, RetCC);
78527853

7854+
// Set type id for call site info.
7855+
if (MF.getTarget().Options.EmitCallGraphSection && CB && CB->isIndirectCall())
7856+
CSInfo = MachineFunction::CallSiteInfo(*CB);
7857+
78537858
// Check callee args/returns for SVE registers and set calling convention
78547859
// accordingly.
78557860
if (CallConv == CallingConv::C || CallConv == CallingConv::Fast) {

llvm/lib/Target/ARM/ARMISelLowering.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -2359,6 +2359,7 @@ ARMTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
23592359
CallingConv::ID CallConv = CLI.CallConv;
23602360
bool doesNotRet = CLI.DoesNotReturn;
23612361
bool isVarArg = CLI.IsVarArg;
2362+
const auto *CB = CLI.CB;
23622363

23632364
MachineFunction &MF = DAG.getMachineFunction();
23642365
ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
@@ -2375,6 +2376,10 @@ ARMTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
23752376
!Subtarget->noBTIAtReturnTwice())
23762377
GuardWithBTI = AFI->branchTargetEnforcement();
23772378

2379+
// Set type id for call site info.
2380+
if (MF.getTarget().Options.EmitCallGraphSection && CB && CB->isIndirectCall())
2381+
CSInfo = MachineFunction::CallSiteInfo(*CB);
2382+
23782383
// Determine whether this is a non-secure function call.
23792384
if (CLI.CB && CLI.CB->getAttributes().hasFnAttr("cmse_nonsecure_call"))
23802385
isCmseNSCall = true;

llvm/lib/Target/Mips/MipsISelLowering.cpp

+5-1
Original file line numberDiff line numberDiff line change
@@ -3185,6 +3185,7 @@ MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
31853185
bool &IsTailCall = CLI.IsTailCall;
31863186
CallingConv::ID CallConv = CLI.CallConv;
31873187
bool IsVarArg = CLI.IsVarArg;
3188+
const auto *CB = CLI.CB;
31883189

31893190
MachineFunction &MF = DAG.getMachineFunction();
31903191
MachineFrameInfo &MFI = MF.getFrameInfo();
@@ -3242,8 +3243,11 @@ MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
32423243
// Get a count of how many bytes are to be pushed on the stack.
32433244
unsigned StackSize = CCInfo.getStackSize();
32443245

3245-
// Call site info for function parameters tracking.
3246+
// Call site info for function parameters tracking and call base type info.
32463247
MachineFunction::CallSiteInfo CSInfo;
3248+
// Set type id for call site info.
3249+
if (MF.getTarget().Options.EmitCallGraphSection && CB && CB->isIndirectCall())
3250+
CSInfo = MachineFunction::CallSiteInfo(*CB);
32473251

32483252
// Check if it's really possible to do a tail call. Restrict it to functions
32493253
// that are part of this compilation unit.

llvm/lib/Target/X86/X86FastISel.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -3630,6 +3630,12 @@ bool X86FastISel::fastLowerCall(CallLoweringInfo &CLI) {
36303630
CLI.NumResultRegs = RVLocs.size();
36313631
CLI.Call = MIB;
36323632

3633+
// Add call site info for call graph section.
3634+
if (TM.Options.EmitCallGraphSection && CB && CB->isIndirectCall()) {
3635+
MachineFunction::CallSiteInfo CSInfo(*CB);
3636+
MF->addCallSiteInfo(CLI.Call, std::move(CSInfo));
3637+
}
3638+
36333639
return true;
36343640
}
36353641

@@ -4025,6 +4031,8 @@ bool X86FastISel::tryToFoldLoadIntoMI(MachineInstr *MI, unsigned OpNo,
40254031
MO.setReg(IndexReg);
40264032
}
40274033

4034+
if (MI->isCall())
4035+
FuncInfo.MF->moveCallSiteInfo(MI, Result);
40284036
Result->addMemOperand(*FuncInfo.MF, createMachineMemOperandFor(LI));
40294037
Result->cloneInstrSymbols(*FuncInfo.MF, *MI);
40304038
MachineBasicBlock::iterator I(MI);

llvm/lib/Target/X86/X86ISelLoweringCall.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -2021,6 +2021,10 @@ X86TargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
20212021
if (CallConv == CallingConv::X86_INTR)
20222022
report_fatal_error("X86 interrupts may not be called directly");
20232023

2024+
// Set type id for call site info.
2025+
if (MF.getTarget().Options.EmitCallGraphSection && CB && CB->isIndirectCall())
2026+
CSInfo = MachineFunction::CallSiteInfo(*CB);
2027+
20242028
bool IsMustTail = CLI.CB && CLI.CB->isMustTailCall();
20252029
if (Subtarget.isPICStyleGOT() && !IsGuaranteeTCO && !IsMustTail) {
20262030
// If we are using a GOT, disable tail calls to external symbols with
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
; Tests that call site type ids can be extracted and set from type operand
2+
; bundles.
3+
4+
; Verify the exact typeId value to ensure it is not garbage but the value
5+
; computed as the type id from the type operand bundle.
6+
; RUN: llc --call-graph-section -mtriple aarch64-linux-gnu %s -stop-before=finalize-isel -o - | FileCheck %s
7+
8+
; ModuleID = 'test.c'
9+
source_filename = "test.c"
10+
target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
11+
target triple = "aarch64-unknown-linux-gnu"
12+
13+
define dso_local void @foo(i8 signext %a) !type !3 {
14+
entry:
15+
ret void
16+
}
17+
18+
; CHECK: name: main
19+
define dso_local i32 @main() !type !4 {
20+
entry:
21+
%retval = alloca i32, align 4
22+
%fp = alloca void (i8)*, align 8
23+
store i32 0, i32* %retval, align 4
24+
store void (i8)* @foo, void (i8)** %fp, align 8
25+
%0 = load void (i8)*, void (i8)** %fp, align 8
26+
; CHECK: callSites:
27+
; CHECK-NEXT: - { bb: {{.*}}, offset: {{.*}}, fwdArgRegs: [], typeId:
28+
; CHECK-NEXT: 7854600665770582568 }
29+
call void %0(i8 signext 97) [ "type"(metadata !"_ZTSFvcE.generalized") ]
30+
ret i32 0
31+
}
32+
33+
!llvm.module.flags = !{!0, !1, !2}
34+
35+
!0 = !{i32 1, !"wchar_size", i32 4}
36+
!1 = !{i32 7, !"uwtable", i32 1}
37+
!2 = !{i32 7, !"frame-pointer", i32 2}
38+
!3 = !{i64 0, !"_ZTSFvcE.generalized"}
39+
!4 = !{i64 0, !"_ZTSFiE.generalized"}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
; Tests that call site type ids can be extracted and set from type operand
2+
; bundles.
3+
4+
; Verify the exact typeId value to ensure it is not garbage but the value
5+
; computed as the type id from the type operand bundle.
6+
; RUN: llc --call-graph-section -mtriple arm-linux-gnu %s -stop-before=finalize-isel -o - | FileCheck %s
7+
8+
; ModuleID = 'test.c'
9+
source_filename = "test.c"
10+
target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
11+
target triple = "armv4t-unknown-linux-gnu"
12+
13+
define dso_local void @foo(i8 signext %a) !type !3 {
14+
entry:
15+
ret void
16+
}
17+
18+
; CHECK: name: main
19+
define dso_local i32 @main() !type !4 {
20+
entry:
21+
%retval = alloca i32, align 4
22+
%fp = alloca void (i8)*, align 8
23+
store i32 0, i32* %retval, align 4
24+
store void (i8)* @foo, void (i8)** %fp, align 8
25+
%0 = load void (i8)*, void (i8)** %fp, align 8
26+
; CHECK: callSites:
27+
; CHECK-NEXT: - { bb: {{.*}}, offset: {{.*}}, fwdArgRegs: [], typeId:
28+
; CHECK-NEXT: 7854600665770582568 }
29+
call void %0(i8 signext 97) [ "type"(metadata !"_ZTSFvcE.generalized") ]
30+
ret i32 0
31+
}
32+
33+
!llvm.module.flags = !{!0, !1, !2}
34+
35+
!0 = !{i32 1, !"wchar_size", i32 4}
36+
!1 = !{i32 7, !"uwtable", i32 1}
37+
!2 = !{i32 7, !"frame-pointer", i32 2}
38+
!3 = !{i64 0, !"_ZTSFvcE.generalized"}
39+
!4 = !{i64 0, !"_ZTSFiE.generalized"}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
; Test MIR printer and parser for type id field in call site info. Test that
2+
; it works well with/without --emit-call-site-info.
3+
4+
; Multiplex --call-graph-section and -emit-call-site-info as both utilize
5+
; CallSiteInfo and callSites.
6+
7+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
8+
;; Test printer and parser with --call-graph-section only.
9+
10+
; Test printer.
11+
; Verify that fwdArgRegs is not set, typeId is set.
12+
; Verify the exact typeId value to ensure it is not garbage but the value
13+
; computed as the type id from the type operand bundle.
14+
; RUN: llc --call-graph-section %s -stop-before=finalize-isel -o %t1.mir
15+
; RUN: cat %t1.mir | FileCheck %s --check-prefix=PRINTER_CGS
16+
; PRINTER_CGS: name: main
17+
; PRINTER_CGS: callSites:
18+
; PRINTER_CGS-NEXT: - { bb: {{.*}}, offset: {{.*}}, fwdArgRegs: [], typeId:
19+
; PRINTER_CGS-NEXT: 7854600665770582568 }
20+
21+
22+
; Test parser.
23+
; Verify that we get the same result.
24+
; RUN: llc --call-graph-section %t1.mir -run-pass=finalize-isel -o - \
25+
; RUN: | FileCheck %s --check-prefix=PARSER_CGS
26+
; PARSER_CGS: name: main
27+
; PARSER_CGS: callSites:
28+
; PARSER_CGS-NEXT: - { bb: {{.*}}, offset: {{.*}}, fwdArgRegs: [], typeId:
29+
; PARSER_CGS-NEXT: 7854600665770582568 }
30+
31+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
32+
;; Test printer and parser with -emit-call-site-info only.
33+
34+
; Test printer.
35+
; Verify that fwdArgRegs is set, typeId is not set.
36+
; RUN: llc -emit-call-site-info %s -stop-before=finalize-isel -o %t2.mir
37+
; RUN: cat %t2.mir | FileCheck %s --check-prefix=PRINTER_CSI
38+
; PRINTER_CSI: name: main
39+
; PRINTER_CSI: callSites:
40+
; PRINTER_CSI-NEXT: - { bb: {{.*}}, offset: {{.*}}, fwdArgRegs:
41+
; PRINTER_CSI-NEXT: { arg: 0, reg: '$edi' }
42+
; PRINTER_CSI-NOT: typeId:
43+
44+
45+
; Test parser.
46+
; Verify that we get the same result.
47+
; RUN: llc -emit-call-site-info %t2.mir -run-pass=finalize-isel -o - \
48+
; RUN: | FileCheck %s --check-prefix=PARSER_CSI
49+
; PARSER_CSI: name: main
50+
; PARSER_CSI: callSites:
51+
; PARSER_CSI-NEXT: - { bb: {{.*}}, offset: {{.*}}, fwdArgRegs:
52+
; PARSER_CSI-NEXT: { arg: 0, reg: '$edi' }
53+
; PARSER_CSI-NOT: typeId:
54+
55+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
56+
;; Test printer and parser with both -emit-call-site-info and --call-graph-section.
57+
58+
; Test printer.
59+
; Verify both fwdArgRegs and typeId are set.
60+
; Verify the exact typeId value to ensure it is not garbage but the value
61+
; computed as the type id from the type operand bundle.
62+
; RUN: llc --call-graph-section -emit-call-site-info %s -stop-before=finalize-isel -o %t2.mir
63+
; RUN: cat %t2.mir | FileCheck %s --check-prefix=PRINTER_CGS_CSI
64+
; PRINTER_CGS_CSI: name: main
65+
; PRINTER_CGS_CSI: callSites:
66+
; PRINTER_CGS_CSI-NEXT: - { bb: {{.*}}, offset: {{.*}}, fwdArgRegs:
67+
; PRINTER_CGS_CSI-NEXT: { arg: 0, reg: '$edi' }, typeId:
68+
; PRINTER_CGS_CSI-NEXT: 7854600665770582568 }
69+
70+
71+
; Test parser.
72+
; Verify that we get the same result.
73+
; RUN: llc --call-graph-section -emit-call-site-info %t2.mir -run-pass=finalize-isel -o - \
74+
; RUN: | FileCheck %s --check-prefix=PARSER_CGS_CSI
75+
; PARSER_CGS_CSI: name: main
76+
; PARSER_CGS_CSI: callSites:
77+
; PARSER_CGS_CSI-NEXT: - { bb: {{.*}}, offset: {{.*}}, fwdArgRegs:
78+
; PARSER_CGS_CSI-NEXT: { arg: 0, reg: '$edi' }, typeId:
79+
; PARSER_CGS_CSI-NEXT: 7854600665770582568 }
80+
81+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
82+
83+
; ModuleID = 'test.c'
84+
source_filename = "test.c"
85+
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
86+
target triple = "x86_64-unknown-linux-gnu"
87+
88+
; Function Attrs: noinline nounwind optnone uwtable
89+
define dso_local void @foo(i8 signext %a) !type !3 {
90+
entry:
91+
ret void
92+
}
93+
94+
; Function Attrs: noinline nounwind optnone uwtable
95+
define dso_local i32 @main() !type !4 {
96+
entry:
97+
%retval = alloca i32, align 4
98+
%fp = alloca void (i8)*, align 8
99+
store i32 0, i32* %retval, align 4
100+
store void (i8)* @foo, void (i8)** %fp, align 8
101+
%0 = load void (i8)*, void (i8)** %fp, align 8
102+
call void %0(i8 signext 97) [ "type"(metadata !"_ZTSFvcE.generalized") ]
103+
ret i32 0
104+
}
105+
106+
!llvm.module.flags = !{!0, !1, !2}
107+
108+
!0 = !{i32 1, !"wchar_size", i32 4}
109+
!1 = !{i32 7, !"uwtable", i32 1}
110+
!2 = !{i32 7, !"frame-pointer", i32 2}
111+
!3 = !{i64 0, !"_ZTSFvcE.generalized"}
112+
!4 = !{i64 0, !"_ZTSFiE.generalized"}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
; Tests that call site type ids can be extracted and set from type operand
2+
; bundles.
3+
4+
; Verify the exact typeId value to ensure it is not garbage but the value
5+
; computed as the type id from the type operand bundle.
6+
; RUN: llc --call-graph-section -mtriple=mips-linux-gnu %s -stop-before=finalize-isel -o - | FileCheck %s
7+
8+
; ModuleID = 'test.c'
9+
source_filename = "test.c"
10+
target datalayout = "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64"
11+
target triple = "mips-unknown-linux-gnu"
12+
13+
define dso_local void @foo(i8 signext %a) !type !3 {
14+
entry:
15+
ret void
16+
}
17+
18+
; CHECK: name: main
19+
define dso_local i32 @main() !type !4 {
20+
entry:
21+
%retval = alloca i32, align 4
22+
%fp = alloca void (i8)*, align 8
23+
store i32 0, i32* %retval, align 4
24+
store void (i8)* @foo, void (i8)** %fp, align 8
25+
%0 = load void (i8)*, void (i8)** %fp, align 8
26+
; CHECK: callSites:
27+
; CHECK-NEXT: - { bb: {{.*}}, offset: {{.*}}, fwdArgRegs: [], typeId:
28+
; CHECK-NEXT: 7854600665770582568 }
29+
call void %0(i8 signext 97) [ "type"(metadata !"_ZTSFvcE.generalized") ]
30+
ret i32 0
31+
}
32+
33+
!llvm.module.flags = !{!0, !1, !2}
34+
35+
!0 = !{i32 1, !"wchar_size", i32 4}
36+
!1 = !{i32 7, !"uwtable", i32 1}
37+
!2 = !{i32 7, !"frame-pointer", i32 2}
38+
!3 = !{i64 0, !"_ZTSFvcE.generalized"}
39+
!4 = !{i64 0, !"_ZTSFiE.generalized"}

0 commit comments

Comments
 (0)