LLVM Passes Nick Sumner (see also - - PowerPoint PPT Presentation

llvm passes
SMART_READER_LITE
LIVE PREVIEW

LLVM Passes Nick Sumner (see also - - PowerPoint PPT Presentation

LLVM Passes Nick Sumner (see also https://github.com/nsumner/llvm-demo) Matt Dwyer (see also https://github.com/matthewbdwyer/tipc/) Where Can You Get Info? The online documentation is extensive: LLVM Programmers Manual LLVM


slide-1
SLIDE 1

LLVM Passes

Nick Sumner (see also https://github.com/nsumner/llvm-demo) Matt Dwyer (see also https://github.com/matthewbdwyer/tipc/)

slide-2
SLIDE 2

Where Can You Get Info?

  • The online documentation is extensive:

– LLVM Programmer’s Manual – LLVM Language Reference Manual

slide-3
SLIDE 3

Where Can You Get Info?

  • The online documentation is extensive:

– LLVM Programmer’s Manual – LLVM Language Reference Manual

  • The header files!

– All in llvm-9.x.src/include/llvm/

InstrTypes.h IRBuilder.h Support/InstVisitor.h Type.h BasicBlock.h CallSite.h DerivedTypes.h Function.h Instructions.h

slide-4
SLIDE 4

Where Can You Get Info?

The discussion in these slides is accompanied by:

  • https://github.com/nsumner/llvm-demo

Another very good resource is:

  • http://llvm.org/docs/WritingAnLLVMPass.html

An example of using passes is:

  • https://github.com/matthewbdwyer/tipc/
slide-5
SLIDE 5

Creating a Static Analysis

slide-6
SLIDE 6

Making a New Analysis

  • Analyses are organized into individual passes

– ModulePass – FunctionPass – LoopPass – …

Derive from the appropriate base class to make a Pass

slide-7
SLIDE 7

Making a New Analysis

  • Analyses are organized into individual passes

– ModulePass – FunctionPass – LoopPass – …

3 Steps 1) Declare your pass 2) Register your pass 3) Define your pass

Derive from the appropriate base class to make a Pass

slide-8
SLIDE 8

Making a New Analysis

  • Analyses are organized into individual passes

– ModulePass – FunctionPass – LoopPass – …

3 Steps 1) Declare your pass 2) Register your pass 3) Define your pass

Derive from the appropriate base class to make a Pass

Let's count the number of static direct calls to each function.

slide-9
SLIDE 9

Making a ModulePass (1)

  • Declare your ModulePass

struct StaticCallCounter : public llvm::ModulePass { static char ID; DenseMap<Function*, uint64_t> counts; StaticCallCounter() : ModulePass(ID) { } bool runOnModule(Module& m) override; void print(raw_ostream& out, const Module* m) const override; void handleInstruction(CallSite cs); };

slide-10
SLIDE 10

Making a ModulePass (1)

  • Declare your ModulePass

struct StaticCallCounter : public llvm::ModulePass { static char ID; DenseMap<Function*, uint64_t> counts; StaticCallCounter() : ModulePass(ID) { } bool runOnModule(Module& m) override; void print(raw_ostream& out, const Module* m) const override; void handleInstruction(CallSite cs); };

slide-11
SLIDE 11

Making a ModulePass (1)

  • Declare your ModulePass

struct StaticCallCounter : public llvm::ModulePass { static char ID; DenseMap<Function*, uint64_t> counts; StaticCallCounter() : ModulePass(ID) { } bool runOnModule(Module& m) override; void print(raw_ostream& out, const Module* m) const override; void handleInstruction(CallSite cs); };

slide-12
SLIDE 12

Making a ModulePass (2)

  • Register your ModulePass

– This allows it to by dynamically loaded as a plugin

char StaticCallCounter::ID = 0; RegisterPass<StaticCallCounter> SCCReg("callcounter", "Print the static count of direct calls");

slide-13
SLIDE 13

Making a ModulePass (3)

  • Define your ModulePass

– Need to override runOnModule() and print()

bool StaticCallCounter::runOnModule(Module& m) { for (auto& f : m) for (auto& bb : f) for (auto& i : bb) handleInstruction(CallSite{&i}); return false; // False because we didn't change the Module }

slide-14
SLIDE 14

Making a ModulePass (3)

  • analysis continued...

void StaticCallCounter::handleInstruction(CallSite cs) { // Check whether the instruction is actually a call if (!cs.getInstruction()) { return; } // Check whether the called function is directly invoked auto called = cs.getCalledValue()->stripPointerCasts(); auto fun = dyn_cast<Function>(called); if (!fun) { return; } // Update the count for the particular call auto count = counts.find(fun); if (counts.end() == count) { count = counts.insert(std::make_pair(fun, 0)).first; } ++count->second; }

slide-15
SLIDE 15

void StaticCallCounter::handleInstruction(CallSite cs) { // Check whether the instruction is actually a call if (!cs.getInstruction()) { return; } // Check whether the called function is directly invoked auto called = cs.getCalledValue()->stripPointerCasts(); auto fun = dyn_cast<Function>(called); if (!fun) { return; } // Update the count for the particular call auto count = counts.find(fun); if (counts.end() == count) { count = counts.insert(std::make_pair(fun, 0)).first; } ++count->second; }

Making a ModulePass (3)

  • analysis continued...
slide-16
SLIDE 16

void StaticCallCounter::handleInstruction(CallSite cs) { // Check whether the instruction is actually a call if (!cs.getInstruction()) { return; } // Check whether the called function is directly invoked auto called = cs.getCalledValue()->stripPointerCasts(); auto fun = dyn_cast<Function>(called); if (!fun) { return; } // Update the count for the particular call auto count = counts.find(fun); if (counts.end() == count) { count = counts.insert(std::make_pair(fun, 0)).first; } ++count->second; }

Making a ModulePass (3)

  • analysis continued...
slide-17
SLIDE 17

Making a ModulePass (3)

  • Printing out the results

void CallCounterPass::print(raw_ostream& out, const Module* m) const {

  • ut << "Function Counts\n"

<< "===============\n"; for (auto& kvPair : counts) { auto* function = kvPair.first; uint64_t count = kvPair.second;

  • ut << function->getName() << " : " << count << "\n";

} }

slide-18
SLIDE 18

Creating a Dynamic Analysis

slide-19
SLIDE 19

Making a Dynamic Analysis

  • We've counted the static direct calls to each

function.

  • How might we compute the dynamic calls to each

function?

slide-20
SLIDE 20

Making a Dynamic Analysis

  • We've counted the static direct calls to each

function.

  • How might we compute the dynamic calls to each

function?

  • Need to modify the original program!
slide-21
SLIDE 21

Making a Dynamic Analysis

  • We've counted the static direct calls to each

function.

  • How might we compute the dynamic calls to each

function?

  • Need to modify the original program!
  • Steps:

1) Modify the program using passes 2) Compile the modified version 3) Run the new program

slide-22
SLIDE 22

Modifying the Original Program

Goal: Count the dynamic calls to each function in an execution. So how do we want to modify the program?

void foo() bar(); }

?

slide-23
SLIDE 23

Modifying the Original Program

Goal: Count the dynamic calls to each function in an execution. So how do we want to modify the program?

void foo() bar(); }

?

Keep a counter for each function!

slide-24
SLIDE 24

Modifying the Original Program

Goal: Count the dynamic calls to each function in an execution. So how do we want to modify the program?

void foo() bar(); }

?

Keep a counter for each function! 2 Choices:

slide-25
SLIDE 25

Modifying the Original Program

Goal: Count the dynamic calls to each function in an execution. So how do we want to modify the program?

void foo() bar(); }

?

Keep a counter for each function! 2 Choices: 1) increment count for each function as it starts 2) increment count for each function at its call site

slide-26
SLIDE 26

Modifying the Original Program

Goal: Count the dynamic calls to each function in an execution. So how do we want to modify the program?

void foo() bar(); }

?

Keep a counter for each function! 2 Choices: 1) increment count for each function as it starts 2) increment count for each function at its call site Does that even matter? Are there trade offs?

slide-27
SLIDE 27

Goal: Count the dynamic calls to each function in an execution. So how do we want to modify the program? We'll increment at the function entry with a call

void foo() countCall(1); bar(); }

Modifying the Original Program

void foo() bar(); }

void countCall(id) count[id]++; }

slide-28
SLIDE 28

Modifying the Original Program

What might adding this call look like?

void DynamicCallCounter::handleInstruction(CallSite cs, Value* counter) { // Check whether the instruction is actually a call if (!cs.getInstruction()) { return; } // Check whether the called function is directly invoked auto calledValue = cs.getCalledValue()->stripPointerCasts(); auto calledFunction = dyn_cast<Function>(calledValue); if (!calledFunction) { return; } // Insert a call to the counting function. IRBuilder<> builder(cs.getInstruction()); builder.CreateCall(counter, builder.getInt64(ids[calledFunction])); }

slide-29
SLIDE 29

Modifying the Original Program

What might adding this call look like?

void DynamicCallCounter::handleInstruction(CallSite cs, Value* counter) { // Check whether the instruction is actually a call if (!cs.getInstruction()) { return; } // Check whether the called function is directly invoked auto calledValue = cs.getCalledValue()->stripPointerCasts(); auto calledFunction = dyn_cast<Function>(calledValue); if (!calledFunction) { return; } // Insert a call to the counting function. IRBuilder<> builder(cs.getInstruction()); builder.CreateCall(counter, builder.getInt64(ids[calledFunction])); }

slide-30
SLIDE 30

void DynamicCallCounter::handleInstruction(CallSite cs, Value* counter) { // Check whether the instruction is actually a call if (!cs.getInstruction()) { return; } // Check whether the called function is directly invoked auto calledValue = cs.getCalledValue()->stripPointerCasts(); auto calledFunction = dyn_cast<Function>(calledValue); if (!calledFunction) { return; } // Insert a call to the counting function. IRBuilder<> builder(cs.getInstruction()); builder.CreateCall(counter, builder.getInt64(ids[calledFunction])); }

Modifying the Original Program

What might adding this call look like? In practice, it's more complex. You can find details in the llvm-demo code.

slide-31
SLIDE 31

Using a Runtime Library

Don't forget that we need to put countCall() somewhere!

  • Placed in a library linked with the main executable

void countCalled(uint64_t id) { ++functionInfo[id]; }

slide-32
SLIDE 32

Dynamic Analysis Big Picture

Program/Module Analysis Tool Instrumentation Pass Compilation Modified Program Runtime Library Input

Results!

slide-33
SLIDE 33

Dynamic Analysis Big Picture

Program/Module Analysis Tool Instrumentation Pass Compilation Modified Program Runtime Library Input

Results!

Insert useful calls to a runtime library Step 1:

slide-34
SLIDE 34

Dynamic Analysis Big Picture

Program/Module Analysis Tool Instrumentation Pass Compilation Modified Program Runtime Library Input

Results!

Compile & link against runtime library. Step 2:

slide-35
SLIDE 35

Dynamic Analysis Big Picture

Program/Module Analysis Tool Instrumentation Pass Compilation Modified Program Runtime Library Input

Results!

Run the new program to produce your results Step 3:

slide-36
SLIDE 36

A Roadmap to LLVM Passes

LLVM has a rich set of passes available for you to study

  • Clone LLVM source tree

…/llvm/lib/Passes/PassRegistry.def

  • A file that registers all core passes in LLVM
  • A good reference to see what is available to study

…/llvm/lib/Analysis

  • These are the analysis passes

…/llvm/lib/Transforms

  • These are the transformation passes
  • /Hello gives a “hello world pass”
slide-37
SLIDE 37

Explore some LLVM Passes

After developing a basic familiarity with LLVM passes Explore …/llvm/lib/Transforms/Scalar/

  • ConstantProp, DCE

Explore the passes used in the tipc compiler As you will see the SSA form is key to LLVM

  • We will discuss it in some detail in the coming weeks