41 #include "llvm/IR/DataLayout.h"
42 #include "llvm/IR/IRBuilder.h"
43 #include "llvm/IR/Module.h"
44 #include "llvm/Support/raw_ostream.h"
57 llvm::Value*
ConstructKey(llvm::IRBuilder<>& Builder, llvm::Module& M,
58 llvm::Function::ArgumentListType& InstrumentationArgs,
59 FunctionEvent FnEventDescription);
61 BasicBlock*
MatchPattern(LLVMContext& Ctx, StringRef Name, Function *Fn,
62 BasicBlock *MatchTarget, BasicBlock *NonMatchTarget,
65 BasicBlock *
FindBlock(StringRef Name, Function& Fn) {
67 if (B.getName() == Name)
70 panic(
"instrumentation function '" + Fn.getName()
71 +
"' has no '" + Name +
"' block");
74 void FnInstrumentation::AppendInstrumentation(
77 LLVMContext& Ctx = TargetFn->getContext();
80 assert(Fn.name() == TargetFn->getName());
87 auto *Instr = BasicBlock::Create(Ctx, A.
Name() +
":instr", InstrFn, Exit);
88 Exit->replaceAllUsesWith(Instr);
92 for (
auto& InstrArg : InstrFn->getArgumentList()) {
95 Instr, Exit, &InstrArg, Arg);
98 if (++i == Ev.argument_size())
102 if (Dir == FunctionEvent::Exit && Ev.has_expectedreturnvalue()) {
103 const Argument &Arg = Ev.expectedreturnvalue();
104 Value *ReturnValue = --(InstrFn->arg_end());
106 Instr, Exit, ReturnValue, Arg);
109 IRBuilder<> Builder(Instr);
110 Type* IntType = Type::getInt32Ty(Ctx);
114 Args.push_back(ConstantInt::get(IntType, A.
ID()));
115 Args.push_back(
ConstructKey(Builder, M, InstrFn->getArgumentList(), Ev));
116 Args.push_back(Builder.CreateGlobalStringPtr(A.
Name()));
117 Args.push_back(Builder.CreateGlobalStringPtr(A.
String()));
121 assert(Args.size() == UpdateStateFn->arg_size());
122 Builder.CreateCall(UpdateStateFn, Args);
123 Builder.CreateBr(Exit);
128 const char Name[] =
"tesla_key";
129 StructType *T = M.getTypeByName(Name);
134 KeyElements.push_back(Type::getInt32Ty(M.getContext()));
135 T = StructType::create(KeyElements, Name);
144 auto& Ctx = Mod.getContext();
146 FunctionType *PrintfType = FunctionType::get(
147 IntegerType::get(Ctx, 32),
148 PointerType::getUnqual(IntegerType::get(Ctx, 8)),
151 Function*
Printf = cast<Function>(
152 Mod.getOrInsertFunction(
"printf", PrintfType));
159 auto& Ctx = Mod.getContext();
161 FunctionType *FnType = FunctionType::get(
162 IntegerType::get(Ctx, 32),
163 PointerType::getUnqual(IntegerType::get(Ctx, 8)));
165 return cast<Function>(Mod.getOrInsertFunction(
"tesla_debugging", FnType));
169 if (T->isPointerTy())
return " 0x%llx";
170 if (T->isIntegerTy())
return " %d";
171 if (T->isFloatTy())
return " %f";
172 if (T->isDoubleTy())
return " %f";
174 assert(
false &&
"Unhandled arg type");
182 FunctionEvent::Direction Dir,
183 FunctionEvent::CallContext Context,
184 bool SuppressDebugInstr) {
186 LLVMContext& Ctx = Mod.getContext();
188 string Name = (Twine()
190 + ((Context == FunctionEvent::Callee) ?
CALLEE :
CALLER)
191 + ((Dir == FunctionEvent::Entry) ?
ENTER :
EXIT)
195 string Tag = (Twine()
197 + ((Dir == FunctionEvent::Entry) ?
"CAL" :
"RET")
198 + ((Context == FunctionEvent::Callee) ?
"E" :
"R")
204 FunctionType *SubType = Subject.getFunctionType();
205 TypeVector Args(SubType->param_begin(), SubType->param_end());
207 if (Dir == FunctionEvent::Exit) {
208 Type *RetType = Subject.getReturnType();
209 if (!RetType->isVoidTy())
210 Args.push_back(RetType);
213 Type *Void = Type::getVoidTy(Ctx);
214 FunctionType *InstrType = FunctionType::get(Void, Args, SubType->isVarArg());
218 auto *InstrFn = dyn_cast<Function>(Mod.getOrInsertFunction(Name, InstrType));
219 assert(InstrFn != NULL);
221 if (Context == FunctionEvent::Caller)
222 InstrFn->setLinkage(GlobalValue::PrivateLinkage);
226 if (InstrFn->empty()) {
229 auto *Exit = BasicBlock::Create(Ctx,
"exit", InstrFn);
230 IRBuilder<>(Entry).CreateBr(Exit);
231 IRBuilder<>(Exit).CreateRetVoid();
239 StringRef FieldName,
size_t FieldIndex,
240 bool Store,
bool SuppressDebugInstr) {
242 LLVMContext& Ctx = Mod.getContext();
243 StringRef StructName = Type->getName();
245 string Name = (Twine()
254 Name.resize(
strnlen(Name.c_str(), Name.length()));
260 Function *InstrFn = dyn_cast_or_null<Function>(Mod.getFunction(Name));
265 if (Type->getNumElements() <= FieldIndex)
266 panic(
"struct " + Type->getName() +
" does not have "
267 + Twine(FieldIndex) +
" elements");
269 auto *FieldTy = Type->getElementType(FieldIndex);
273 Args.push_back(PointerType::getUnqual(Type));
274 Args.push_back(FieldTy);
275 Args.push_back(PointerType::getUnqual(FieldTy));
277 auto *Void = Type::getVoidTy(Ctx);
278 FunctionType *InstrType = FunctionType::get(Void, Args,
false);
280 InstrFn = dyn_cast<Function>(Mod.getOrInsertFunction(Name, InstrType));
281 assert(InstrFn->empty());
283 InstrFn->setLinkage(GlobalValue::PrivateLinkage);
288 string Tag = (Twine() +
"[F" + (Store ?
"SET" :
"GET") +
"] ").str();
293 auto *Exit = BasicBlock::Create(Ctx,
"exit", InstrFn);
294 IRBuilder<>(Entry).CreateBr(Exit);
295 IRBuilder<>(Exit).CreateRetVoid();
302 return DataLayout(&M).getIntPtrType(M.getContext());
306 const char Name[] =
"tesla_transition";
307 StructType *T = M.getTypeByName(Name);
312 LLVMContext& Ctx = M.getContext();
313 Type *IntType = Type::getInt32Ty(Ctx);
315 return StructType::create(Name,
325 const char Name[] =
"tesla_transitions";
326 StructType *T = M.getTypeByName(Name);
331 Type *IntTy = IntegerType::get(M.getContext(), 32);
334 return StructType::create(Name,
341 const Twine& Prefix,
bool SuppressDI) {
343 auto& Ctx = Mod.getContext();
344 auto *Entry = BasicBlock::Create(Ctx,
"entry", F);
349 auto *Preamble = BasicBlock::Create(Ctx,
"preamble", F, Entry);
350 auto *PrintBB = BasicBlock::Create(Ctx,
"printf", F);
351 IRBuilder<> Builder(Preamble);
354 Value *DebugName = Mod.getGlobalVariable(
"debug_name",
true);
356 DebugName = Builder.CreateGlobalStringPtr(
"tesla.events",
"debug_name");
358 Value *Debugging = Builder.CreateCall(
TeslaDebugging(Mod), DebugName);
360 Constant *Zero = ConstantInt::get(IntegerType::get(Ctx, 32), 0);
361 Debugging = Builder.CreateICmpNE(Debugging, Zero);
363 Builder.CreateCondBr(Debugging, PrintBB, Entry);
365 string FormatStr(Prefix.str());
366 for (
auto& Arg : F->getArgumentList()) FormatStr +=
Format(Arg.getType());
369 ArgVector PrintfArgs(1, Builder.CreateGlobalStringPtr(FormatStr));
370 for (
auto& Arg : F->getArgumentList()) PrintfArgs.push_back(&Arg);
372 IRBuilder<> PrintBuilder(PrintBB);
373 PrintBuilder.CreateCall(
Printf(Mod), PrintfArgs);
374 PrintBuilder.CreateBr(Entry);
380 Value*
tesla::Cast(Value *From, StringRef Name, Type *NewType,
381 IRBuilder<>& Builder) {
383 assert(From != NULL);
384 Type *CurrentType = From->getType();
386 if (CurrentType == NewType)
389 if (!CastInst::isCastable(CurrentType, NewType)) {
390 string CurrentTypeName;
391 raw_string_ostream CurrentOut(CurrentTypeName);
392 CurrentType->print(CurrentOut);
395 raw_string_ostream NameOut(NewTypeName);
396 NewType->print(NameOut);
399 "Instrumentation argument "
400 + (Name.empty() ?
"" : (
"'" + Name +
"' "))
401 +
"cannot be cast from '" + CurrentOut.str()
402 +
"' to '" + NameOut.str() +
"'"
406 if (isa<PointerType>(CurrentType))
407 return Builder.CreatePointerCast(From, NewType);
409 else if (isa<IntegerType>(CurrentType))
410 return Builder.CreateIntCast(From, NewType,
false);
412 llvm_unreachable(
"failed to cast something castable");
417 BasicBlock *MatchTarget,
418 BasicBlock *NonMatchTarget,
421 if (Pattern.
type() != Argument::Constant)
424 auto *MatchBlock = BasicBlock::Create(Ctx, Name, Fn, MatchTarget);
425 MatchTarget->replaceAllUsesWith(MatchBlock);
427 IRBuilder<> M(MatchBlock);
428 Value *PatternValue = ConstantInt::getSigned(Val->getType(), Pattern.
value());
431 switch (Pattern.constantmatch()) {
432 case Argument::Exact:
433 Cmp = M.CreateICmpEQ(Val, PatternValue);
436 case Argument::Flags:
438 Cmp = M.CreateICmpEQ(M.CreateAnd(Val, PatternValue), PatternValue);
443 Cmp = M.CreateICmpEQ(M.CreateAnd(Val, PatternValue), Val);
447 M.CreateCondBr(Cmp, MatchTarget, NonMatchTarget);
455 LLVMContext& Ctx = M.getContext();
457 Type *Char = IntegerType::get(Ctx, 8);
458 Type *CharStar = PointerType::getUnqual(Char);
460 Type *KeyStar = PointerType::getUnqual(
KeyType(M));
461 Type *Void = Type::getVoidTy(Ctx);
463 Constant *Fn = M.getOrInsertFunction(
"tesla_update_state",
474 assert(isa<Function>(Fn));
475 return cast<Function>(Fn);
481 static Type *IntType = Type::getInt32Ty(Ctx);
487 case AutomatonDescription::Global:
return Global;
488 case AutomatonDescription::ThreadLocal:
return PerThread;
494 Function::ArgumentListType& InstrArgs,
495 FunctionEvent FnEvent) {
497 bool HaveRetVal = FnEvent.has_expectedreturnvalue();
498 const size_t TotalArgs = FnEvent.argument_size() + (HaveRetVal ? 1 : 0);
500 if (InstrArgs.size() != TotalArgs)
502 "instrumentation for '" + FnEvent.function().name() +
"' takes "
503 + Twine(InstrArgs.size())
504 +
" arguments but description in manifest provides "
505 + Twine(FnEvent.argument_size())
506 + (HaveRetVal ?
" and a return value" :
"")
509 vector<Value*> Args(TotalArgs, NULL);
513 for (
auto& InstrArg : InstrArgs) {
514 auto& Arg = (HaveRetVal && (i == (TotalArgs - 1)))
515 ? FnEvent.expectedreturnvalue()
516 : FnEvent.argument(i);
519 if (Arg.type() != Argument::Variable)
522 size_t Index = Arg.index();
524 assert(Index < TotalArgs);
525 Args[Index] = &InstrArg;
532 ArrayRef<Value*> Args) {
534 Value *Key = Builder.CreateAlloca(
KeyType(M), 0,
"key");
536 Type *IntTy = Type::getInt32Ty(M.getContext());
540 for (
size_t i = 0; i < Args.size(); i++) {
541 Value* Arg = Args[i];
548 Cast(Arg, Twine(i - 1).str(), IntPtrTy, Builder),
549 Builder.CreateStructGEP(Key, i));
555 Builder.CreateStore(ConstantInt::get(IntTy, KeyMask), Mask);
561 const Transition& T) {
567 uint32_t Values[] = {
568 (uint32_t) T.Source().ID(),
570 (uint32_t) T.Destination().ID(),
571 T.Destination().Mask(),
575 Type *IntType = Type::getInt32Ty(M.getContext());
577 vector<Constant*> Elements;
578 for (
auto Val : Values)
579 Elements.push_back(ConstantInt::get(IntType, Val));
588 vector<Constant*> Transitions;
595 Type *IntType = Type::getInt32Ty(M.getContext());
596 Constant *Zero = ConstantInt::get(IntType, 0);
597 Constant *Zeroes[] = { Zero, Zero };
599 Constant *Count = ConstantInt::get(IntType, Transitions.size());
601 assert(Tr.size() > 0);
602 string Name =
"transition_array_" + (*Tr.begin())->String();
604 ArrayType *ArrayT = ArrayType::get(
TransitionType(M), Transitions.size());
605 auto *Array =
new GlobalVariable(M, ArrayT,
true, GlobalValue::PrivateLinkage,
606 ConstantArray::get(ArrayT, Transitions),
610 Constant *ArrayPtr = ConstantExpr::getInBoundsGetElementPtr(Array, Zeroes);
612 Constant *TransitionsInit = ConstantStruct::get(T, Count, ArrayPtr, NULL);
614 return new GlobalVariable(M, T,
true, GlobalValue::PrivateLinkage,
615 TransitionsInit,
"transitions");