blob: 5553dc2da31b50964cecf502fe8ae6551a25d3fb [file] [log] [blame]
Dylan McKay3abd1d32016-12-14 10:15:00 +00001//===-- AVRInstrumentFunctions.cpp - Insert instrumentation for testing ---===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This pass takes a function and inserts calls to hook functions which are
11// told the name, arguments, and results of function calls.
12//
13// The hooks can do anything with the information given. It is possible to
14// send the data through a serial connection in order to runs tests on
15// bare metal.
16//
17//===----------------------------------------------------------------------===//
18
19#include "AVR.h"
20
21#include <llvm/IR/Function.h>
22#include <llvm/IR/Module.h>
23
24using namespace llvm;
25
26#define AVR_INSTRUMENT_FUNCTIONS_NAME "AVR function instrumentation pass"
27
28namespace {
29
30// External symbols that we emit calls to.
31namespace symbols {
32
33#define SYMBOL_PREFIX "avr_instrumentation"
34
35 const StringRef PREFIX = SYMBOL_PREFIX;
36
37 // void (i16 argCount);
38 const StringRef BEGIN_FUNCTION_SIGNATURE = SYMBOL_PREFIX "_begin_signature";
39 // void(i16 argCount);
40 const StringRef END_FUNCTION_SIGNATURE = SYMBOL_PREFIX "_end_signature";
41
42#undef SYMBOL_PREFIX
43}
44
45class AVRInstrumentFunctions : public FunctionPass {
46public:
47 static char ID;
48
49 AVRInstrumentFunctions() : FunctionPass(ID) {
50 initializeAVRInstrumentFunctionsPass(*PassRegistry::getPassRegistry());
51 }
52
53 bool runOnFunction(Function &F) override;
54
55 StringRef getPassName() const override { return AVR_INSTRUMENT_FUNCTIONS_NAME; }
56};
57
58char AVRInstrumentFunctions::ID = 0;
59
60/// Creates a pointer to a string.
61static Value *CreateStringPtr(BasicBlock &BB, StringRef Str) {
62 LLVMContext &Ctx = BB.getContext();
63 IntegerType *I8 = Type::getInt8Ty(Ctx);
64
65 Constant *ConstantStr = ConstantDataArray::getString(Ctx, Str);
66 GlobalVariable *GlobalStr = new GlobalVariable(*BB.getParent()->getParent(),
67 ConstantStr->getType(),
68 true, /* is a constant */
69 GlobalValue::PrivateLinkage,
70 ConstantStr);
71 return GetElementPtrInst::CreateInBounds(GlobalStr,
72 {ConstantInt::get(I8, 0), ConstantInt::get(I8, 0)}, "", &BB);
73}
74
Dylan McKay4f590f22016-12-15 11:02:41 +000075static std::string GetTypeName(Type &Ty) {
76 if (auto *IntTy = dyn_cast<IntegerType>(&Ty)) {
77 return std::string("i") + std::to_string(IntTy->getBitWidth());
78 }
79
80 if (Ty.isFloatingPointTy()) {
81 return std::string("f") + std::to_string(Ty.getPrimitiveSizeInBits());
82 }
83
84 llvm_unreachable("unknown return type");
85}
86
Dylan McKay3abd1d32016-12-14 10:15:00 +000087/// Builds a call to one of the signature begin/end hooks.
88static void BuildSignatureCall(StringRef SymName, BasicBlock &BB, Function &F) {
89 LLVMContext &Ctx = F.getContext();
90 IntegerType *I16 = Type::getInt16Ty(Ctx);
91
92 FunctionType *FnType = FunctionType::get(Type::getVoidTy(Ctx),
93 {Type::getInt8PtrTy(Ctx), I16}, false);
94
95 Constant *Fn = F.getParent()->getOrInsertFunction(SymName, FnType);
96 Value *FunctionName = CreateStringPtr(BB, F.getName());
97
98 Value *Args[] = {FunctionName,
99 ConstantInt::get(I16, F.getArgumentList().size())};
100 CallInst::Create(Fn, Args, "", &BB);
101}
102
103/// Builds instructions to call into an external function to
104/// notify about a function signature beginning.
105static void BuildBeginSignature(BasicBlock &BB, Function &F) {
106 return BuildSignatureCall(symbols::BEGIN_FUNCTION_SIGNATURE, BB, F);
107}
108
109/// Builds instructions to call into an external function to
110/// notify about a function signature ending.
111static void BuildEndSignature(BasicBlock &BB, Function &F) {
112 return BuildSignatureCall(symbols::END_FUNCTION_SIGNATURE, BB, F);
113}
114
115/// Get the name of the external symbol that we need to call
116/// to notify about this argument.
117static std::string GetArgumentSymbolName(Argument &Arg) {
Dylan McKay4f590f22016-12-15 11:02:41 +0000118 return (symbols::PREFIX + "_argument_" + GetTypeName(*Arg.getType())).str();
Dylan McKay3abd1d32016-12-14 10:15:00 +0000119}
120
121/// Builds a call to one of the argument hooks.
122static void BuildArgument(BasicBlock &BB, Argument &Arg) {
123 Function &F = *Arg.getParent();
124 LLVMContext &Ctx = F.getContext();
125
Dylan McKay4b028e22016-12-15 09:38:09 +0000126 Type *I8 = Type::getInt8Ty(Ctx);
127
Dylan McKay3abd1d32016-12-14 10:15:00 +0000128 FunctionType *FnType = FunctionType::get(Type::getVoidTy(Ctx),
Dylan McKay4b028e22016-12-15 09:38:09 +0000129 {Type::getInt8PtrTy(Ctx), I8, Arg.getType()}, false);
Dylan McKay3abd1d32016-12-14 10:15:00 +0000130
131 Constant *Fn = F.getParent()->getOrInsertFunction(
132 GetArgumentSymbolName(Arg), FnType);
133 Value *ArgName = CreateStringPtr(BB, Arg.getName());
134
Dylan McKay4b028e22016-12-15 09:38:09 +0000135 Value *Args[] = {ArgName, ConstantInt::get(I8, Arg.getArgNo()), &Arg};
Dylan McKay3abd1d32016-12-14 10:15:00 +0000136 CallInst::Create(Fn, Args, "", &BB);
137}
138
139/// Builds a call to all of the function signature hooks.
140static void BuildSignature(BasicBlock &BB, Function &F) {
141 BuildBeginSignature(BB, F);
142 for (Argument &Arg : F.args()) { BuildArgument(BB, Arg); }
143 BuildEndSignature(BB, F);
144}
145
146/// Builds the instrumentation entry block.
147static void BuildEntryBlock(Function &F) {
148 BasicBlock &EntryBlock = F.getEntryBlock();
149
150 // Create a new basic block at the start of the existing entry block.
151 BasicBlock *BB = BasicBlock::Create(F.getContext(),
152 "instrumentation_entry",
153 &F, &EntryBlock);
154
155 BuildSignature(*BB, F);
156
157 // Jump to the actual entry block.
158 BranchInst::Create(&EntryBlock, BB);
159}
160
161static std::string GetReturnSymbolName(Value &Val) {
Dylan McKay4f590f22016-12-15 11:02:41 +0000162 return (symbols::PREFIX + "_result_" + GetTypeName(*Val.getType())).str();
Dylan McKay3abd1d32016-12-14 10:15:00 +0000163}
164
165static void BuildExitHook(Instruction &I) {
166 Function &F = *I.getParent()->getParent();
167 LLVMContext &Ctx = F.getContext();
168
169 if (auto *Ret = dyn_cast<ReturnInst>(&I)) {
170 Value *RetVal = Ret->getReturnValue();
171 assert(RetVal && "should only be instrumenting functions with return values");
172
173 FunctionType *FnType = FunctionType::get(Type::getVoidTy(Ctx),
174 {RetVal->getType()}, false);
175
176 Constant *Fn = F.getParent()->getOrInsertFunction(
177 GetReturnSymbolName(*RetVal), FnType);
178
179 // Call the result hook just before the return.
180 CallInst::Create(Fn, {RetVal}, "", &I);
181 }
182}
183
184/// Runs return hooks before all returns in a function.
185static void BuildExitHooks(Function &F) {
186 for (BasicBlock &BB : F) {
187 auto BBI = BB.begin(), E = BB.end();
188 while (BBI != E) {
189 auto NBBI = std::next(BBI);
190
191 BuildExitHook(*BBI);
192
193 // Modified |= expandMI(BB, MBBI);
194 BBI = NBBI;
195 }
196 }
197}
198
199static bool ShouldInstrument(Function &F) {
200 // No point reporting results if there are none.
201 return !F.getReturnType()->isVoidTy();
202}
203
204bool AVRInstrumentFunctions::runOnFunction(Function &F) {
205 if (ShouldInstrument(F)) {
206 BuildEntryBlock(F);
207 BuildExitHooks(F);
208 }
209
210 return true;
211}
212
213} // end of anonymous namespace
214
215INITIALIZE_PASS(AVRInstrumentFunctions, "avr-instrument-functions",
216 AVR_INSTRUMENT_FUNCTIONS_NAME, false, false)
217
218namespace llvm {
219
220FunctionPass *createAVRInstrumentFunctionsPass() { return new AVRInstrumentFunctions(); }
221
222} // end of namespace llvm