Skip to content

Commit faab664

Browse files
committed
Add a pass for basic block tracing.
This pass is a crucial part of the Software Tracer implementation. Software Tracer will allow us to execute tracing on platforms that are not supported by the Hardware Tracer and compare performance between both. The pass iterates over module basic blocks and injects externally linked function yk_trace_basicblock call instruction into the beginning of each block.
1 parent 6ad2989 commit faab664

File tree

7 files changed

+181
-1
lines changed

7 files changed

+181
-1
lines changed

llvm/include/llvm/InitializePasses.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ void initializeWinEHPreparePass(PassRegistry&);
342342
void initializeWriteBitcodePassPass(PassRegistry&);
343343
void initializeXRayInstrumentationPass(PassRegistry&);
344344
void initializeYkSplitBlocksAfterCallsPass(PassRegistry&);
345-
345+
void initializeYkBasicBlockTracerPass(PassRegistry&);
346346
} // end namespace llvm
347347

348348
#endif // LLVM_INITIALIZEPASSES_H
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#ifndef LLVM_TRANSFORMS_YK_HELLOWORLD_H
2+
#define LLVM_TRANSFORMS_YK_HELLOWORLD_H
3+
4+
#include "llvm/Pass.h"
5+
6+
// The name of the trace function
7+
#define YK_TRACE_FUNCTION "yk_trace_basicblock"
8+
9+
namespace llvm {
10+
ModulePass *createYkBasicBlockTracerPass();
11+
} // namespace llvm
12+
13+
#endif

llvm/lib/CodeGen/CodeGen.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,4 +151,5 @@ void llvm::initializeCodeGen(PassRegistry &Registry) {
151151
initializeWinEHPreparePass(Registry);
152152
initializeXRayInstrumentationPass(Registry);
153153
initializeYkSplitBlocksAfterCallsPass(Registry);
154+
initializeYkBasicBlockTracerPass(Registry);
154155
}

llvm/lib/CodeGen/TargetPassConfig.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
#include "llvm/Transforms/Yk/SplitBlocksAfterCalls.h"
5656
#include "llvm/Transforms/Yk/Stackmaps.h"
5757
#include "llvm/Transforms/Yk/NoCallsInEntryBlocks.h"
58+
#include "llvm/Transforms/Yk/BasicBlockTracer.h"
5859
#include <cassert>
5960
#include <optional>
6061
#include <string>
@@ -292,6 +293,11 @@ static cl::opt<bool>
292293
YkSplitBlocksAfterCalls("yk-split-blocks-after-calls", cl::init(false), cl::NotHidden,
293294
cl::desc("Split blocks after function calls."));
294295

296+
static cl::opt<bool>
297+
YkBasicBlockTracer("yk-basicblock-tracer", cl::init(false), cl::NotHidden,
298+
cl::desc("Enables YK Software Tracer capability"));
299+
300+
295301
/// Allow standard passes to be disabled by command line options. This supports
296302
/// simple binary flags that either suppress the pass or do nothing.
297303
/// i.e. -disable-mypass=false has no effect.
@@ -1181,6 +1187,10 @@ bool TargetPassConfig::addISelPasses() {
11811187
addPass(createYkStackmapsPass());
11821188
}
11831189

1190+
if (YkBasicBlockTracer) {
1191+
addPass(createYkBasicBlockTracerPass());
1192+
}
1193+
11841194
addISelPrepare();
11851195
return addCoreISelPasses();
11861196
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#include "llvm/Transforms/Yk/BasicBlockTracer.h"
2+
#include "llvm/IR/BasicBlock.h"
3+
#include "llvm/IR/Function.h"
4+
#include "llvm/IR/IRBuilder.h"
5+
#include "llvm/IR/Instruction.h"
6+
#include "llvm/IR/Instructions.h"
7+
#include "llvm/IR/LLVMContext.h"
8+
#include "llvm/IR/Module.h"
9+
#include "llvm/InitializePasses.h"
10+
#include "llvm/Pass.h"
11+
12+
#define DEBUG_TYPE "yk-basicblock-tracer-pass"
13+
14+
using namespace llvm;
15+
16+
namespace llvm {
17+
void initializeYkBasicBlockTracerPass(PassRegistry &);
18+
} // namespace llvm
19+
20+
namespace {
21+
struct YkBasicBlockTracer : public ModulePass {
22+
static char ID;
23+
24+
YkBasicBlockTracer() : ModulePass(ID) {
25+
initializeYkBasicBlockTracerPass(*PassRegistry::getPassRegistry());
26+
}
27+
28+
bool runOnModule(Module &M) override {
29+
LLVMContext &Context = M.getContext();
30+
// Create externally linked function declaration:
31+
// void yk_trace_basicblock(int functionIndex, int blockIndex)
32+
Type *ReturnType = Type::getVoidTy(Context);
33+
Type *FunctionIndexArgType = Type::getInt32Ty(Context);
34+
Type *BlockIndexArgType = Type::getInt32Ty(Context);
35+
36+
FunctionType *FType = FunctionType::get(
37+
ReturnType, {FunctionIndexArgType, BlockIndexArgType}, false);
38+
Function *TraceFunc = Function::Create(
39+
FType, GlobalVariable::ExternalLinkage, YK_TRACE_FUNCTION, M);
40+
41+
IRBuilder<> builder(Context);
42+
uint32_t FunctionIndex = 0;
43+
for (auto &F : M) {
44+
uint32_t BlockIndex = 0;
45+
for (auto &BB : F) {
46+
builder.SetInsertPoint(&*BB.getFirstInsertionPt());
47+
builder.CreateCall(TraceFunc, {builder.getInt32(FunctionIndex),
48+
builder.getInt32(BlockIndex)});
49+
assert(BlockIndex != UINT32_MAX &&
50+
"Expected BlockIndex to not overflow");
51+
BlockIndex++;
52+
}
53+
assert(FunctionIndex != UINT32_MAX &&
54+
"Expected FunctionIndex to not overflow");
55+
FunctionIndex++;
56+
}
57+
return true;
58+
}
59+
};
60+
} // namespace
61+
62+
char YkBasicBlockTracer::ID = 0;
63+
64+
INITIALIZE_PASS(YkBasicBlockTracer, DEBUG_TYPE, "yk basicblock tracer", false,
65+
false)
66+
67+
ModulePass *llvm::createYkBasicBlockTracerPass() {
68+
return new YkBasicBlockTracer();
69+
}

llvm/lib/Transforms/Yk/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ add_llvm_component_library(LLVMYkPasses
77
ShadowStack.cpp
88
NoCallsInEntryBlocks.cpp
99
SplitBlocksAfterCalls.cpp
10+
BasicBlockTracer.cpp
1011

1112
DEPENDS
1213
intrinsics_gen
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
; RUNNING TEST EXAMPLE: llvm-lit llvm/test/Transforms/Yk/BasicBlockTracer.ll
2+
; RUN: llc -stop-after yk-basicblock-tracer-pass --yk-basicblock-tracer < %s | FileCheck %s
3+
4+
; CHECK-LABEL: define dso_local noundef i32 @main()
5+
; CHECK-NEXT: call void @yk_trace_basicblock(i32 0, i32 0)
6+
define dso_local noundef i32 @main() #0 {
7+
%1 = alloca i32, align 4
8+
%2 = alloca i32, align 4
9+
%3 = alloca i32, align 4
10+
store i32 0, i32* %1, align 4
11+
store i32 0, i32* %2, align 4
12+
store i32 0, i32* %3, align 4
13+
br label %4
14+
15+
; CHECK-LABEL: 4:{{.*}}
16+
; CHECK-NEXT: call void @yk_trace_basicblock(i32 0, i32 1)
17+
4: ; preds = %13, %0
18+
%5 = load i32, i32* %3, align 4
19+
%6 = icmp slt i32 %5, 43
20+
br i1 %6, label %7, label %16
21+
22+
; CHECK-LABEL: 7:{{.*}}
23+
; CHECK-NEXT: call void @yk_trace_basicblock(i32 0, i32 2)
24+
7: ; preds = %4
25+
%8 = load i32, i32* %3, align 4
26+
%9 = icmp eq i32 %8, 42
27+
br i1 %9, label %10, label %12
28+
29+
; CHECK-LABEL: 10:{{.*}}
30+
; CHECK-NEXT: call void @yk_trace_basicblock(i32 0, i32 3)
31+
10: ; preds = %7
32+
%11 = load i32, i32* %3, align 4
33+
store i32 %11, i32* %1, align 4
34+
br label %17
35+
36+
; CHECK-LABEL: 12:{{.*}}
37+
; CHECK-NEXT: call void @yk_trace_basicblock(i32 0, i32 4)
38+
12: ; preds = %7
39+
br label %13
40+
41+
; CHECK-LABEL: 13:{{.*}}
42+
; CHECK-NEXT: call void @yk_trace_basicblock(i32 0, i32 5)
43+
13: ; preds = %12
44+
%14 = load i32, i32* %3, align 4
45+
%15 = add nsw i32 %14, 1
46+
store i32 %15, i32* %3, align 4
47+
br label %4, !llvm.loop !6
48+
49+
; CHECK-LABEL: 16:{{.*}}
50+
; CHECK-NEXT: call void @yk_trace_basicblock(i32 0, i32 6)
51+
16: ; preds = %4
52+
store i32 0, i32* %1, align 4
53+
br label %17
54+
55+
; CHECK-LABEL: 17:{{.*}}
56+
; CHECK-NEXT: call void @yk_trace_basicblock(i32 0, i32 7)
57+
17: ; preds = %16, %10
58+
%18 = load i32, i32* %1, align 4
59+
ret i32 %18
60+
}
61+
62+
; CHECK-LABEL: define dso_local noundef i32 @_Z5checki(i32 noundef %0)
63+
; CHECK-NEXT: call void @yk_trace_basicblock(i32 1, i32 0)
64+
define dso_local noundef i32 @_Z5checki(i32 noundef %0) #1 {
65+
%2 = alloca i32, align 4
66+
store i32 %0, i32* %2, align 4
67+
%3 = load i32, i32* %2, align 4
68+
%4 = icmp eq i32 %3, 42
69+
%5 = zext i1 %4 to i32
70+
ret i32 %5
71+
}
72+
73+
attributes #0 = { mustprogress noinline norecurse nounwind optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
74+
attributes #1 = { mustprogress noinline nounwind optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
75+
76+
!llvm.module.flags = !{!0, !1, !2, !3, !4}
77+
!llvm.ident = !{!5}
78+
79+
!0 = !{i32 1, !"wchar_size", i32 4}
80+
!1 = !{i32 7, !"PIC Level", i32 2}
81+
!2 = !{i32 7, !"PIE Level", i32 2}
82+
!3 = !{i32 7, !"uwtable", i32 1}
83+
!4 = !{i32 7, !"frame-pointer", i32 2}
84+
!5 = !{!"Debian clang version 14.0.6"}
85+
!6 = distinct !{!6, !7}
86+
!7 = !{!"llvm.loop.mustprogress"}

0 commit comments

Comments
 (0)