blob: ae2428e5e1e32a078dc96b43a5a7eadb1cc466c7 [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
75/// Builds a call to one of the signature begin/end hooks.
76static void BuildSignatureCall(StringRef SymName, BasicBlock &BB, Function &F) {
77 LLVMContext &Ctx = F.getContext();
78 IntegerType *I16 = Type::getInt16Ty(Ctx);
79
80 FunctionType *FnType = FunctionType::get(Type::getVoidTy(Ctx),
81 {Type::getInt8PtrTy(Ctx), I16}, false);
82
83 Constant *Fn = F.getParent()->getOrInsertFunction(SymName, FnType);
84 Value *FunctionName = CreateStringPtr(BB, F.getName());
85
86 Value *Args[] = {FunctionName,
87 ConstantInt::get(I16, F.getArgumentList().size())};
88 CallInst::Create(Fn, Args, "", &BB);
89}
90
91/// Builds instructions to call into an external function to
92/// notify about a function signature beginning.
93static void BuildBeginSignature(BasicBlock &BB, Function &F) {
94 return BuildSignatureCall(symbols::BEGIN_FUNCTION_SIGNATURE, BB, F);
95}
96
97/// Builds instructions to call into an external function to
98/// notify about a function signature ending.
99static void BuildEndSignature(BasicBlock &BB, Function &F) {
100 return BuildSignatureCall(symbols::END_FUNCTION_SIGNATURE, BB, F);
101}
102
103/// Get the name of the external symbol that we need to call
104/// to notify about this argument.
105static std::string GetArgumentSymbolName(Argument &Arg) {
106 Type *Ty = Arg.getType();
107
108 if (auto *IntTy = dyn_cast<IntegerType>(Ty)) {
109 return (symbols::PREFIX + "_argument_i" + std::to_string(IntTy->getBitWidth())).str();
110 }
111
112 llvm_unreachable("unknown argument type");
113}
114
115/// Builds a call to one of the argument hooks.
116static void BuildArgument(BasicBlock &BB, Argument &Arg) {
117 Function &F = *Arg.getParent();
118 LLVMContext &Ctx = F.getContext();
119
120 FunctionType *FnType = FunctionType::get(Type::getVoidTy(Ctx),
121 {Type::getInt8PtrTy(Ctx), Arg.getType()}, false);
122
123 Constant *Fn = F.getParent()->getOrInsertFunction(
124 GetArgumentSymbolName(Arg), FnType);
125 Value *ArgName = CreateStringPtr(BB, Arg.getName());
126
127 Value *Args[] = {ArgName, &Arg};
128 CallInst::Create(Fn, Args, "", &BB);
129}
130
131/// Builds a call to all of the function signature hooks.
132static void BuildSignature(BasicBlock &BB, Function &F) {
133 BuildBeginSignature(BB, F);
134 for (Argument &Arg : F.args()) { BuildArgument(BB, Arg); }
135 BuildEndSignature(BB, F);
136}
137
138/// Builds the instrumentation entry block.
139static void BuildEntryBlock(Function &F) {
140 BasicBlock &EntryBlock = F.getEntryBlock();
141
142 // Create a new basic block at the start of the existing entry block.
143 BasicBlock *BB = BasicBlock::Create(F.getContext(),
144 "instrumentation_entry",
145 &F, &EntryBlock);
146
147 BuildSignature(*BB, F);
148
149 // Jump to the actual entry block.
150 BranchInst::Create(&EntryBlock, BB);
151}
152
153static std::string GetReturnSymbolName(Value &Val) {
154 Type *Ty = Val.getType();
155
156 if (auto *IntTy = dyn_cast<IntegerType>(Ty)) {
157 return (symbols::PREFIX + "_result_u" + std::to_string(IntTy->getBitWidth())).str();
158 }
159
160 llvm_unreachable("unknown return type");
161}
162
163static void BuildExitHook(Instruction &I) {
164 Function &F = *I.getParent()->getParent();
165 LLVMContext &Ctx = F.getContext();
166
167 if (auto *Ret = dyn_cast<ReturnInst>(&I)) {
168 Value *RetVal = Ret->getReturnValue();
169 assert(RetVal && "should only be instrumenting functions with return values");
170
171 FunctionType *FnType = FunctionType::get(Type::getVoidTy(Ctx),
172 {RetVal->getType()}, false);
173
174 Constant *Fn = F.getParent()->getOrInsertFunction(
175 GetReturnSymbolName(*RetVal), FnType);
176
177 // Call the result hook just before the return.
178 CallInst::Create(Fn, {RetVal}, "", &I);
179 }
180}
181
182/// Runs return hooks before all returns in a function.
183static void BuildExitHooks(Function &F) {
184 for (BasicBlock &BB : F) {
185 auto BBI = BB.begin(), E = BB.end();
186 while (BBI != E) {
187 auto NBBI = std::next(BBI);
188
189 BuildExitHook(*BBI);
190
191 // Modified |= expandMI(BB, MBBI);
192 BBI = NBBI;
193 }
194 }
195}
196
197static bool ShouldInstrument(Function &F) {
198 // No point reporting results if there are none.
199 return !F.getReturnType()->isVoidTy();
200}
201
202bool AVRInstrumentFunctions::runOnFunction(Function &F) {
203 if (ShouldInstrument(F)) {
204 BuildEntryBlock(F);
205 BuildExitHooks(F);
206 }
207
208 return true;
209}
210
211} // end of anonymous namespace
212
213INITIALIZE_PASS(AVRInstrumentFunctions, "avr-instrument-functions",
214 AVR_INSTRUMENT_FUNCTIONS_NAME, false, false)
215
216namespace llvm {
217
218FunctionPass *createAVRInstrumentFunctionsPass() { return new AVRInstrumentFunctions(); }
219
220} // end of namespace llvm