[llvm] r289641 - [AVR] Add a function instrumentation pass

Dylan McKay via llvm-commits llvm-commits at lists.llvm.org
Wed Dec 14 02:15:01 PST 2016


Author: dylanmckay
Date: Wed Dec 14 04:15:00 2016
New Revision: 289641

URL: http://llvm.org/viewvc/llvm-project?rev=289641&view=rev
Log:
[AVR] Add a function instrumentation pass

This will be used for an on-chip test suite.

Added:
    llvm/trunk/lib/Target/AVR/AVRInstrumentFunctions.cpp
    llvm/trunk/test/CodeGen/AVR/instrumentation/
    llvm/trunk/test/CodeGen/AVR/instrumentation/basic.ll
Modified:
    llvm/trunk/lib/Target/AVR/AVR.h
    llvm/trunk/lib/Target/AVR/AVRTargetMachine.cpp
    llvm/trunk/lib/Target/AVR/CMakeLists.txt

Modified: llvm/trunk/lib/Target/AVR/AVR.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AVR/AVR.h?rev=289641&r1=289640&r2=289641&view=diff
==============================================================================
--- llvm/trunk/lib/Target/AVR/AVR.h (original)
+++ llvm/trunk/lib/Target/AVR/AVR.h Wed Dec 14 04:15:00 2016
@@ -27,11 +27,13 @@ FunctionPass *createAVRISelDag(AVRTarget
                                CodeGenOpt::Level OptLevel);
 FunctionPass *createAVRExpandPseudoPass();
 FunctionPass *createAVRFrameAnalyzerPass();
+FunctionPass *createAVRInstrumentFunctionsPass();
 FunctionPass *createAVRRelaxMemPass();
 FunctionPass *createAVRDynAllocaSRPass();
 FunctionPass *createAVRBranchSelectionPass();
 
 void initializeAVRExpandPseudoPass(PassRegistry&);
+void initializeAVRInstrumentFunctionsPass(PassRegistry&);
 void initializeAVRRelaxMemPass(PassRegistry&);
 
 /// Contains the AVR backend.

Added: llvm/trunk/lib/Target/AVR/AVRInstrumentFunctions.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AVR/AVRInstrumentFunctions.cpp?rev=289641&view=auto
==============================================================================
--- llvm/trunk/lib/Target/AVR/AVRInstrumentFunctions.cpp (added)
+++ llvm/trunk/lib/Target/AVR/AVRInstrumentFunctions.cpp Wed Dec 14 04:15:00 2016
@@ -0,0 +1,220 @@
+//===-- AVRInstrumentFunctions.cpp - Insert instrumentation for testing ---===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This pass takes a function and inserts calls to hook functions which are
+// told the name, arguments, and results of function calls.
+//
+// The hooks can do anything with the information given. It is possible to
+// send the data through a serial connection in order to runs tests on
+// bare metal.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AVR.h"
+
+#include <llvm/IR/Function.h>
+#include <llvm/IR/Module.h>
+
+using namespace llvm;
+
+#define AVR_INSTRUMENT_FUNCTIONS_NAME "AVR function instrumentation pass"
+
+namespace {
+
+// External symbols that we emit calls to.
+namespace symbols {
+
+#define SYMBOL_PREFIX "avr_instrumentation"
+
+  const StringRef PREFIX = SYMBOL_PREFIX;
+
+  // void (i16 argCount);
+  const StringRef BEGIN_FUNCTION_SIGNATURE = SYMBOL_PREFIX "_begin_signature";
+  // void(i16 argCount);
+  const StringRef END_FUNCTION_SIGNATURE = SYMBOL_PREFIX "_end_signature";
+
+#undef SYMBOL_PREFIX
+}
+
+class AVRInstrumentFunctions : public FunctionPass {
+public:
+  static char ID;
+
+  AVRInstrumentFunctions() : FunctionPass(ID) {
+    initializeAVRInstrumentFunctionsPass(*PassRegistry::getPassRegistry());
+  }
+
+  bool runOnFunction(Function &F) override;
+
+  StringRef getPassName() const override { return AVR_INSTRUMENT_FUNCTIONS_NAME; }
+};
+
+char AVRInstrumentFunctions::ID = 0;
+
+/// Creates a pointer to a string.
+static Value *CreateStringPtr(BasicBlock &BB, StringRef Str) {
+  LLVMContext &Ctx = BB.getContext();
+  IntegerType *I8 = Type::getInt8Ty(Ctx);
+
+  Constant *ConstantStr = ConstantDataArray::getString(Ctx, Str);
+  GlobalVariable *GlobalStr = new GlobalVariable(*BB.getParent()->getParent(),
+                                                 ConstantStr->getType(),
+                                                 true, /* is a constant */
+                                                 GlobalValue::PrivateLinkage,
+                                                 ConstantStr);
+  return GetElementPtrInst::CreateInBounds(GlobalStr,
+    {ConstantInt::get(I8, 0), ConstantInt::get(I8, 0)}, "", &BB);
+}
+
+/// Builds a call to one of the signature begin/end hooks.
+static void BuildSignatureCall(StringRef SymName, BasicBlock &BB, Function &F) {
+  LLVMContext &Ctx = F.getContext();
+  IntegerType *I16 = Type::getInt16Ty(Ctx);
+
+  FunctionType *FnType = FunctionType::get(Type::getVoidTy(Ctx),
+    {Type::getInt8PtrTy(Ctx), I16}, false);
+
+  Constant *Fn = F.getParent()->getOrInsertFunction(SymName, FnType);
+  Value *FunctionName = CreateStringPtr(BB, F.getName());
+
+  Value *Args[] = {FunctionName,
+                   ConstantInt::get(I16, F.getArgumentList().size())};
+  CallInst::Create(Fn, Args, "", &BB);
+}
+
+/// Builds instructions to call into an external function to
+/// notify about a function signature beginning.
+static void BuildBeginSignature(BasicBlock &BB, Function &F) {
+  return BuildSignatureCall(symbols::BEGIN_FUNCTION_SIGNATURE, BB, F);
+}
+
+/// Builds instructions to call into an external function to
+/// notify about a function signature ending.
+static void BuildEndSignature(BasicBlock &BB, Function &F) {
+  return BuildSignatureCall(symbols::END_FUNCTION_SIGNATURE, BB, F);
+}
+
+/// Get the name of the external symbol that we need to call
+/// to notify about this argument.
+static std::string GetArgumentSymbolName(Argument &Arg) {
+  Type *Ty = Arg.getType();
+
+  if (auto *IntTy = dyn_cast<IntegerType>(Ty)) {
+    return (symbols::PREFIX + "_argument_i" + std::to_string(IntTy->getBitWidth())).str();
+  }
+
+  llvm_unreachable("unknown argument type");
+}
+
+/// Builds a call to one of the argument hooks.
+static void BuildArgument(BasicBlock &BB, Argument &Arg) {
+  Function &F = *Arg.getParent();
+  LLVMContext &Ctx = F.getContext();
+
+  FunctionType *FnType = FunctionType::get(Type::getVoidTy(Ctx),
+    {Type::getInt8PtrTy(Ctx), Arg.getType()}, false);
+
+  Constant *Fn = F.getParent()->getOrInsertFunction(
+    GetArgumentSymbolName(Arg), FnType);
+  Value *ArgName = CreateStringPtr(BB, Arg.getName());
+
+  Value *Args[] = {ArgName, &Arg};
+  CallInst::Create(Fn, Args, "", &BB);
+}
+
+/// Builds a call to all of the function signature hooks.
+static void BuildSignature(BasicBlock &BB, Function &F) {
+  BuildBeginSignature(BB, F);
+  for (Argument &Arg : F.args()) { BuildArgument(BB, Arg); }
+  BuildEndSignature(BB, F);
+}
+
+/// Builds the instrumentation entry block.
+static void BuildEntryBlock(Function &F) {
+  BasicBlock &EntryBlock = F.getEntryBlock();
+
+  // Create a new basic block at the start of the existing entry block.
+  BasicBlock *BB = BasicBlock::Create(F.getContext(),
+                                      "instrumentation_entry",
+                                      &F, &EntryBlock);
+
+  BuildSignature(*BB, F);
+
+  // Jump to the actual entry block.
+  BranchInst::Create(&EntryBlock, BB);
+}
+
+static std::string GetReturnSymbolName(Value &Val) {
+  Type *Ty = Val.getType();
+
+  if (auto *IntTy = dyn_cast<IntegerType>(Ty)) {
+    return (symbols::PREFIX + "_result_u" + std::to_string(IntTy->getBitWidth())).str();
+  }
+
+  llvm_unreachable("unknown return type");
+}
+
+static void BuildExitHook(Instruction &I) {
+  Function &F = *I.getParent()->getParent();
+  LLVMContext &Ctx = F.getContext();
+
+  if (auto *Ret = dyn_cast<ReturnInst>(&I)) {
+    Value *RetVal = Ret->getReturnValue();
+    assert(RetVal && "should only be instrumenting functions with return values");
+
+    FunctionType *FnType = FunctionType::get(Type::getVoidTy(Ctx),
+      {RetVal->getType()}, false);
+
+    Constant *Fn = F.getParent()->getOrInsertFunction(
+      GetReturnSymbolName(*RetVal), FnType);
+
+    // Call the result hook just before the return.
+    CallInst::Create(Fn, {RetVal}, "", &I);
+  }
+}
+
+/// Runs return hooks before all returns in a function.
+static void BuildExitHooks(Function &F) {
+  for (BasicBlock &BB : F) {
+    auto BBI = BB.begin(), E = BB.end();
+    while (BBI != E) {
+      auto NBBI = std::next(BBI);
+
+      BuildExitHook(*BBI);
+
+      // Modified |= expandMI(BB, MBBI);
+      BBI = NBBI;
+    }
+  }
+}
+
+static bool ShouldInstrument(Function &F) {
+  // No point reporting results if there are none.
+  return !F.getReturnType()->isVoidTy();
+}
+
+bool AVRInstrumentFunctions::runOnFunction(Function &F) {
+  if (ShouldInstrument(F)) {
+    BuildEntryBlock(F);
+    BuildExitHooks(F);
+  }
+
+  return true;
+}
+
+} // end of anonymous namespace
+
+INITIALIZE_PASS(AVRInstrumentFunctions, "avr-instrument-functions",
+                AVR_INSTRUMENT_FUNCTIONS_NAME, false, false)
+
+namespace llvm {
+
+FunctionPass *createAVRInstrumentFunctionsPass() { return new AVRInstrumentFunctions(); }
+
+} // end of namespace llvm

Modified: llvm/trunk/lib/Target/AVR/AVRTargetMachine.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AVR/AVRTargetMachine.cpp?rev=289641&r1=289640&r2=289641&view=diff
==============================================================================
--- llvm/trunk/lib/Target/AVR/AVRTargetMachine.cpp (original)
+++ llvm/trunk/lib/Target/AVR/AVRTargetMachine.cpp Wed Dec 14 04:15:00 2016
@@ -80,6 +80,7 @@ extern "C" void LLVMInitializeAVRTarget(
 
   auto &PR = *PassRegistry::getPassRegistry();
   initializeAVRExpandPseudoPass(PR);
+  initializeAVRInstrumentFunctionsPass(PR);
   initializeAVRRelaxMemPass(PR);
 }
 

Modified: llvm/trunk/lib/Target/AVR/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AVR/CMakeLists.txt?rev=289641&r1=289640&r2=289641&view=diff
==============================================================================
--- llvm/trunk/lib/Target/AVR/CMakeLists.txt (original)
+++ llvm/trunk/lib/Target/AVR/CMakeLists.txt Wed Dec 14 04:15:00 2016
@@ -21,6 +21,7 @@ add_llvm_target(AVRCodeGen
   AVRExpandPseudoInsts.cpp
   AVRFrameLowering.cpp
   AVRInstrInfo.cpp
+  AVRInstrumentFunctions.cpp
   AVRISelDAGToDAG.cpp
   AVRISelLowering.cpp
   AVRMCInstLower.cpp

Added: llvm/trunk/test/CodeGen/AVR/instrumentation/basic.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/AVR/instrumentation/basic.ll?rev=289641&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/AVR/instrumentation/basic.ll (added)
+++ llvm/trunk/test/CodeGen/AVR/instrumentation/basic.ll Wed Dec 14 04:15:00 2016
@@ -0,0 +1,45 @@
+; RUN: opt -S -avr-instrument-functions < %s | FileCheck %s
+
+; Functions returning void should not be instrumented.
+; CHECK-LABEL: do_nothing
+define void @do_nothing(i8 %c) {
+  ; CHECK-NEXT: ret void
+  ret void
+}
+
+; CHECK-LABEL: do_something
+define i8 @do_something(i16 %a, i16 %b) {
+  ; CHECK: instrumentation_entry
+  ; CHECK-NEXT: %0 = getelementptr inbounds [13 x i8], [13 x i8]* @0, i8 0, i8 0
+  ; CHECK-NEXT: call void @avr_instrumentation_begin_signature(i8* %0, i16 2)
+
+  ; CHECK-NEXT: %1 = getelementptr inbounds [2 x i8], [2 x i8]* @1, i8 0, i8 0
+  ; CHECK-NEXT: call void @avr_instrumentation_argument_i16(i8* %1, i16 %a)
+
+  ; CHECK-NEXT: %2 = getelementptr inbounds [2 x i8], [2 x i8]* @2, i8 0, i8 0
+  ; CHECK-NEXT: call void @avr_instrumentation_argument_i16(i8* %2, i16 %b)
+
+  ; CHECK-NEXT: %3 = getelementptr inbounds [13 x i8], [13 x i8]* @3, i8 0, i8 0
+  ; CHECK-NEXT: call void @avr_instrumentation_end_signature(i8* %3, i16 2)
+
+  ; CHECK-NEXT: br label %4
+
+  ; CHECK: call void @avr_instrumentation_result_u8(i8 1)
+  ; CHECK-NEXT: ret i8 1
+  ret i8 1
+}
+
+; CHECK-LABEL: foo
+define i32 @foo() {
+  ; CHECK: instrumentation_entry:
+  ; CHECK-NEXT:   %0 = getelementptr inbounds [4 x i8], [4 x i8]* @4, i8 0, i8 0
+  ; CHECK-NEXT:   call void @avr_instrumentation_begin_signature(i8* %0, i16 0)
+  ; CHECK-NEXT:   %1 = getelementptr inbounds [4 x i8], [4 x i8]* @5, i8 0, i8 0
+  ; CHECK-NEXT:   call void @avr_instrumentation_end_signature(i8* %1, i16 0)
+
+  ; CHECK-NEXT:   br label %2
+
+  ; CHECK:         call void @avr_instrumentation_result_u32(i32 50)
+  ; CHECK-NEXT:   ret i32 50
+  ret i32 50
+}




More information about the llvm-commits mailing list