diff --git a/llvm/lib/Target/AVR/CMakeLists.txt b/llvm/lib/Target/AVR/CMakeLists.txt --- a/llvm/lib/Target/AVR/CMakeLists.txt +++ b/llvm/lib/Target/AVR/CMakeLists.txt @@ -32,5 +32,6 @@ add_subdirectory(AsmParser) add_subdirectory(Disassembler) +add_subdirectory(HarvardCheck) add_subdirectory(MCTargetDesc) add_subdirectory(TargetInfo) diff --git a/llvm/lib/Target/AVR/HarvardCheck/CMakeLists.txt b/llvm/lib/Target/AVR/HarvardCheck/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/AVR/HarvardCheck/CMakeLists.txt @@ -0,0 +1,7 @@ +add_llvm_library(libHarvardCheck MODULE + HarvardCheck.cpp + + PLUGIN_TOOL + opt +) + diff --git a/llvm/lib/Target/AVR/HarvardCheck/HarvardCheck.cpp b/llvm/lib/Target/AVR/HarvardCheck/HarvardCheck.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/AVR/HarvardCheck/HarvardCheck.cpp @@ -0,0 +1,89 @@ +//===-- HarvardCheck.cpp - Check Function Address Space -------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Visits all functions in a module and reports those that are not in the +// program memory address space. +// +// Usage: +// opt -load libHarvardCheck.dylib --harvard-check +// opt -load libHarvardCheck.dylib --harvard-check --harvard-abort-on-error +// opt -load libHarvardCheck.dylib --harvard-check +// --harvard-program-address-space 5 +// +//===----------------------------------------------------------------------===// + +#include "llvm/IR/Function.h" +#include "llvm/IR/LegacyPassManager.h" +#include "llvm/Pass.h" +#include "llvm/Passes/PassBuilder.h" +#include "llvm/Passes/PassPlugin.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Transforms/IPO/PassManagerBuilder.h" + +using namespace llvm; + +static cl::opt + ProgramAddressSpace("harvard-program-address-space", cl::init(-1), + cl::desc("override program address space")); + +static cl::opt AbortOnError("harvard-abort-on-error", cl::init(false), + cl::desc("abort on error")); + +namespace { + +struct HarvardCheck : FunctionPass { + static char ID; + HarvardCheck() : FunctionPass(ID), m_programAddressSpace(), m_errorCount() {} + + bool doInitialization(Module &M) override { + if (ProgramAddressSpace == -1) { + m_programAddressSpace = M.getDataLayout().getProgramAddressSpace(); + } else { + m_programAddressSpace = ProgramAddressSpace; + } + return false; + } + + bool runOnFunction(Function &F) override { + if (F.getAddressSpace() != m_programAddressSpace) { + errs() << "harvard check: Function '"; + errs().write_escaped(F.getName()) << "' is not in program memory. " + "Expected address space " + << m_programAddressSpace << ", but got " + << F.getAddressSpace() << ".\n"; + ++m_errorCount; + } + return false; + } + + bool doFinalization(Module &) override { + if (m_errorCount != 0 && AbortOnError) { + errs() << "harvard check: Aborting.\n"; + exit(1); + } + return false; + } + +private: + unsigned m_programAddressSpace; + unsigned m_errorCount; +}; // end of struct HarvardCheck + +} // end of anonymous namespace + +char HarvardCheck::ID = 0; + +static RegisterPass + X("harvard-check", "Verify that all code resides in program memory", false, + false); + +static RegisterStandardPasses Y(PassManagerBuilder::EP_OptimizerLast, + [](const PassManagerBuilder &Builder, + legacy::PassManagerBase &PM) { + PM.add(new HarvardCheck()); + });