diff options
Diffstat (limited to 'contrib/llvm/lib/Target/PIC16/PIC16Passes')
5 files changed, 638 insertions, 0 deletions
diff --git a/contrib/llvm/lib/Target/PIC16/PIC16Passes/Makefile b/contrib/llvm/lib/Target/PIC16/PIC16Passes/Makefile new file mode 100644 index 0000000..9684b8d --- /dev/null +++ b/contrib/llvm/lib/Target/PIC16/PIC16Passes/Makefile @@ -0,0 +1,15 @@ +##===- lib/Target/PIC16/PIC16Passes/Makefile -----------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## +LEVEL = ../../../.. +TARGET = PIC16 +LIBRARYNAME = LLVMpic16passes +BUILD_ARCHIVE = 1 + +include $(LEVEL)/Makefile.common + diff --git a/contrib/llvm/lib/Target/PIC16/PIC16Passes/PIC16Cloner.cpp b/contrib/llvm/lib/Target/PIC16/PIC16Passes/PIC16Cloner.cpp new file mode 100644 index 0000000..c282521 --- /dev/null +++ b/contrib/llvm/lib/Target/PIC16/PIC16Passes/PIC16Cloner.cpp @@ -0,0 +1,299 @@ +//===-- PIC16Cloner.cpp - PIC16 LLVM Cloner for shared functions -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains code to clone all functions that are shared between +// the main line code (ML) and interrupt line code (IL). It clones all such +// shared functions and their automatic global vars by adding the .IL suffix. +// +// This pass is supposed to be run on the linked .bc module. +// It traveses the module call graph twice. Once starting from the main function +// and marking each reached function as "ML". Again, starting from the ISR +// and cloning any reachable function that was marked as "ML". After cloning +// the function, it remaps all the call sites in IL functions to call the +// cloned functions. +//===----------------------------------------------------------------------===// + +#include "llvm/Analysis/CallGraph.h" +#include "llvm/Pass.h" +#include "llvm/Module.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Transforms/Utils/Cloning.h" +#include "PIC16Cloner.h" +#include "../PIC16ABINames.h" +#include <vector> + +using namespace llvm; +using std::vector; +using std::string; +using std::map; + +namespace llvm { + char PIC16Cloner::ID = 0; + + ModulePass *createPIC16ClonerPass() { return new PIC16Cloner(); } +} + +// We currently intend to run these passes in opt, which does not have any +// diagnostic support. So use these functions for now. In future +// we will probably write our own driver tool. +// +void PIC16Cloner::reportError(string ErrorString) { + errs() << "ERROR : " << ErrorString << "\n"; + exit(1); +} + +void PIC16Cloner:: +reportError (string ErrorString, vector<string> &Values) { + unsigned ValCount = Values.size(); + string TargetString; + for (unsigned i=0; i<ValCount; ++i) { + TargetString = "%"; + TargetString += ((char)i + '0'); + ErrorString.replace(ErrorString.find(TargetString), TargetString.length(), + Values[i]); + } + errs() << "ERROR : " << ErrorString << "\n"; + exit(1); +} + + +// Entry point +// +bool PIC16Cloner::runOnModule(Module &M) { + CallGraph &CG = getAnalysis<CallGraph>(); + + // Search for the "main" and "ISR" functions. + CallGraphNode *mainCGN = NULL, *isrCGN = NULL; + for (CallGraph::iterator it = CG.begin() ; it != CG.end(); it++) + { + // External calling node doesn't have any function associated with it. + if (! it->first) + continue; + + if (it->first->getName().str() == "main") { + mainCGN = it->second; + } + + if (PAN::isISR(it->first->getSection())) { + isrCGN = it->second; + } + + // Don't search further if we've found both. + if (mainCGN && isrCGN) + break; + } + + // We have nothing to do if any of the main or ISR is missing. + if (! mainCGN || ! isrCGN) return false; + + // Time for some diagnostics. + // See if the main itself is interrupt function then report an error. + if (PAN::isISR(mainCGN->getFunction()->getSection())) { + reportError("Function 'main' can't be interrupt function"); + } + + + // Mark all reachable functions from main as ML. + markCallGraph(mainCGN, "ML"); + + // And then all the functions reachable from ISR will be cloned. + cloneSharedFunctions(isrCGN); + + return true; +} + +// Mark all reachable functions from the given node, with the given mark. +// +void PIC16Cloner::markCallGraph(CallGraphNode *CGN, string StringMark) { + // Mark the top node first. + Function *thisF = CGN->getFunction(); + + thisF->setSection(StringMark); + + // Mark all the called functions + for(CallGraphNode::iterator cgn_it = CGN->begin(); + cgn_it != CGN->end(); ++cgn_it) { + Function *CalledF = cgn_it->second->getFunction(); + + // If calling an external function then CallGraphNode + // will not be associated with any function. + if (! CalledF) + continue; + + // Issue diagnostic if interrupt function is being called. + if (PAN::isISR(CalledF->getSection())) { + vector<string> Values; + Values.push_back(CalledF->getName().str()); + reportError("Interrupt function (%0) can't be called", Values); + } + + // Has already been mark + if (CalledF->getSection().find(StringMark) != string::npos) { + // Should we do anything here? + } else { + // Mark now + CalledF->setSection(StringMark); + } + + // Before going any further mark all the called function by current + // function. + markCallGraph(cgn_it->second ,StringMark); + } // end of loop of all called functions. +} + + +// For PIC16, automatic variables of a function are emitted as globals. +// Clone the auto variables of a function and put them in ValueMap, +// this ValueMap will be used while +// Cloning the code of function itself. +// +void PIC16Cloner::CloneAutos(Function *F) { + // We'll need to update module's globals list as well. So keep a reference + // handy. + Module *M = F->getParent(); + Module::GlobalListType &Globals = M->getGlobalList(); + + // Clear the leftovers in ValueMap by any previous cloning. + ValueMap.clear(); + + // Find the auto globls for this function and clone them, and put them + // in ValueMap. + std::string FnName = F->getName().str(); + std::string VarName, ClonedVarName; + for (Module::global_iterator I = M->global_begin(), E = M->global_end(); + I != E; ++I) { + VarName = I->getName().str(); + if (PAN::isLocalToFunc(FnName, VarName)) { + // Auto variable for current function found. Clone it. + const GlobalVariable *GV = I; + + const Type *InitTy = GV->getInitializer()->getType(); + GlobalVariable *ClonedGV = + new GlobalVariable(InitTy, false, GV->getLinkage(), + GV->getInitializer()); + ClonedGV->setName(PAN::getCloneVarName(FnName, VarName)); + // Add these new globals to module's globals list. + Globals.push_back(ClonedGV); + + // Update ValueMap. + ValueMap[GV] = ClonedGV; + } + } +} + + +// Clone all functions that are reachable from ISR and are already +// marked as ML. +// +void PIC16Cloner::cloneSharedFunctions(CallGraphNode *CGN) { + + // Check all the called functions from ISR. + for(CallGraphNode::iterator cgn_it = CGN->begin(); + cgn_it != CGN->end(); ++cgn_it) { + Function *CalledF = cgn_it->second->getFunction(); + + // If calling an external function then CallGraphNode + // will not be associated with any function. + if (!CalledF) + continue; + + // Issue diagnostic if interrupt function is being called. + if (PAN::isISR(CalledF->getSection())) { + vector<string> Values; + Values.push_back(CalledF->getName().str()); + reportError("Interrupt function (%0) can't be called", Values); + } + + if (CalledF->getSection().find("ML") != string::npos) { + // Function is alternatively marked. It should be a shared one. + // Create IL copy. Passing called function as first argument + // and the caller as the second argument. + + // Before making IL copy, first ensure that this function has a + // body. If the function does have a body. It can't be cloned. + // Such a case may occur when the function has been declarated + // in the C source code but its body exists in assembly file. + if (!CalledF->isDeclaration()) { + Function *cf = cloneFunction(CalledF); + remapAllSites(CGN->getFunction(), CalledF, cf); + } else { + // It is called only from ISR. Still mark it as we need this info + // in code gen while calling intrinsics.Function is not marked. + CalledF->setSection("IL"); + } + } + // Before going any further clone all the shared function reachaable + // by current function. + cloneSharedFunctions(cgn_it->second); + } // end of loop of all called functions. +} + +// Clone the given function and return it. +// Note: it uses the ValueMap member of the class, which is already populated +// by cloneAutos by the time we reach here. +// FIXME: Should we just pass ValueMap's ref as a parameter here? rather +// than keeping the ValueMap as a member. +Function * +PIC16Cloner::cloneFunction(Function *OrgF) { + Function *ClonedF; + + // See if we already cloned it. Return that. + cloned_map_iterator cm_it = ClonedFunctionMap.find(OrgF); + if(cm_it != ClonedFunctionMap.end()) { + ClonedF = cm_it->second; + return ClonedF; + } + + // Clone does not exist. + // First clone the autos, and populate ValueMap. + CloneAutos(OrgF); + + // Now create the clone. + ClonedF = CloneFunction(OrgF, ValueMap); + + // The new function should be for interrupt line. Therefore should have + // the name suffixed with IL and section attribute marked with IL. + ClonedF->setName(PAN::getCloneFnName(OrgF->getName())); + ClonedF->setSection("IL"); + + // Add the newly created function to the module. + OrgF->getParent()->getFunctionList().push_back(ClonedF); + + // Update the ClonedFunctionMap to record this cloning activity. + ClonedFunctionMap[OrgF] = ClonedF; + + return ClonedF; +} + + +// Remap the call sites of shared functions, that are in IL. +// Change the IL call site of a shared function to its clone. +// +void PIC16Cloner:: +remapAllSites(Function *Caller, Function *OrgF, Function *Clone) { + // First find the caller to update. If the caller itself is cloned + // then use the cloned caller. Otherwise use it. + cloned_map_iterator cm_it = ClonedFunctionMap.find(Caller); + if (cm_it != ClonedFunctionMap.end()) + Caller = cm_it->second; + + // For the lack of a better call site finding mechanism, iterate over + // all insns to find the uses of original fn. + for (Function::iterator BI = Caller->begin(); BI != Caller->end(); ++BI) { + BasicBlock &BB = *BI; + for (BasicBlock::iterator II = BB.begin(); II != BB.end(); ++II) { + if (II->getNumOperands() > 0 && II->getOperand(0) == OrgF) + II->setOperand(0, Clone); + } + } +} + + + diff --git a/contrib/llvm/lib/Target/PIC16/PIC16Passes/PIC16Cloner.h b/contrib/llvm/lib/Target/PIC16/PIC16Passes/PIC16Cloner.h new file mode 100644 index 0000000..24c1152 --- /dev/null +++ b/contrib/llvm/lib/Target/PIC16/PIC16Passes/PIC16Cloner.h @@ -0,0 +1,83 @@ +//===-- PIC16Cloner.h - PIC16 LLVM Cloner for shared functions --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains declaration of a cloner class clone all functions that +// are shared between the main line code (ML) and interrupt line code (IL). +// +//===----------------------------------------------------------------------===// + +#ifndef PIC16CLONER_H +#define PIC16CLONER_H + +#include "llvm/ADT/DenseMap.h" + +using namespace llvm; +using std::vector; +using std::string; +using std::map; + +namespace llvm { + // forward classes. + class Value; + class Function; + class Module; + class ModulePass; + class CallGraph; + class CallGraphNode; + class AnalysisUsage; + + class PIC16Cloner : public ModulePass { + public: + static char ID; // Class identification + PIC16Cloner() : ModulePass(&ID) {} + + virtual void getAnalysisUsage(AnalysisUsage &AU) const { + AU.addRequired<CallGraph>(); + } + virtual bool runOnModule(Module &M); + + private: // Functions + // Mark reachable functions for the MainLine or InterruptLine. + void markCallGraph(CallGraphNode *CGN, string StringMark); + + // Clone auto variables of function specified. + void CloneAutos(Function *F); + + // Clone the body of a function. + Function *cloneFunction(Function *F); + + // Clone all shared functions. + void cloneSharedFunctions(CallGraphNode *isrCGN); + + // Remap all call sites to the shared function. + void remapAllSites(Function *Caller, Function *OrgF, Function *Clone); + + // Error reporting for PIC16Pass + void reportError(string ErrorString, vector<string> &Values); + void reportError(string ErrorString); + + private: //data + // Records if the interrupt function has already been found. + // If more than one interrupt function is found then an error + // should be thrown. + bool foundISR; + + // This ValueMap maps the auto variables of the original functions with + // the corresponding cloned auto variable of the cloned function. + // This value map is passed during the function cloning so that all the + // uses of auto variables be updated properly. + DenseMap<const Value*, Value*> ValueMap; + + // Map of a already cloned functions. + map<Function *, Function *> ClonedFunctionMap; + typedef map<Function *, Function *>::iterator cloned_map_iterator; + }; +} // End of anonymous namespace + +#endif diff --git a/contrib/llvm/lib/Target/PIC16/PIC16Passes/PIC16Overlay.cpp b/contrib/llvm/lib/Target/PIC16/PIC16Passes/PIC16Overlay.cpp new file mode 100644 index 0000000..5ecb6aa --- /dev/null +++ b/contrib/llvm/lib/Target/PIC16/PIC16Passes/PIC16Overlay.cpp @@ -0,0 +1,181 @@ +//===-- PIC16Overlay.cpp - Implementation for PIC16 Frame Overlay===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the PIC16 Frame Overlay implementation. +// +//===----------------------------------------------------------------------===// + + +#include "llvm/Analysis/CallGraph.h" +#include "llvm/Pass.h" +#include "llvm/Module.h" +#include "llvm/Instructions.h" +#include "llvm/Value.h" +#include "PIC16Overlay.h" +#include "llvm/Function.h" +#include <cstdlib> +#include <sstream> +using namespace llvm; + +namespace llvm { + char PIC16Overlay::ID = 0; + ModulePass *createPIC16OverlayPass() { return new PIC16Overlay(); } +} + +void PIC16Overlay::getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesAll(); + AU.addRequired<CallGraph>(); +} + +void PIC16Overlay::DFSTraverse(CallGraphNode *CGN, unsigned Depth) { + // Do not set any color for external calling node. + if (Depth != 0 && CGN->getFunction()) { + unsigned Color = getColor(CGN->getFunction()); + + // Handle indirectly called functions + if (Color >= PIC16OVERLAY::StartIndirectCallColor || + Depth >= PIC16OVERLAY::StartIndirectCallColor) { + // All functions called from an indirectly called function are given + // an unique color. + if (Color < PIC16OVERLAY::StartIndirectCallColor && + Depth >= PIC16OVERLAY::StartIndirectCallColor) + setColor(CGN->getFunction(), Depth); + + for (unsigned int i = 0; i < CGN->size(); i++) + DFSTraverse((*CGN)[i], ++IndirectCallColor); + return; + } + // Just return if the node already has a color greater than the current + // depth. A node must be colored with the maximum depth that it has. + if (Color >= Depth) + return; + + Depth = ModifyDepthForInterrupt(CGN, Depth); + setColor(CGN->getFunction(), Depth); + } + + // Color all children of this node with color depth+1. + for (unsigned int i = 0; i < CGN->size(); i++) + DFSTraverse((*CGN)[i], Depth+1); +} + +unsigned PIC16Overlay::ModifyDepthForInterrupt(CallGraphNode *CGN, + unsigned Depth) { + Function *Fn = CGN->getFunction(); + + // Return original Depth if function or section for function do not exist. + if (!Fn || !Fn->hasSection()) + return Depth; + + // Return original Depth if this function is not marked as interrupt. + if (Fn->getSection().find("interrupt") == string::npos) + return Depth; + + Depth = Depth + InterruptDepth; + return Depth; +} + +void PIC16Overlay::setColor(Function *Fn, unsigned Color) { + std::string Section = ""; + if (Fn->hasSection()) + Section = Fn->getSection(); + + size_t Pos = Section.find(OverlayStr); + + // Convert Color to string. + std::stringstream ss; + ss << Color; + std::string ColorString = ss.str(); + + // If color is already set then reset it with the new value. Else append + // the Color string to section. + if (Pos != std::string::npos) { + Pos += OverlayStr.length(); + char c = Section.at(Pos); + unsigned OldColorLength = 0; + while (c >= '0' && c<= '9') { + OldColorLength++; + if (Pos < Section.length() - 1) + Pos++; + else + break; + c = Section.at(Pos); + } + // Replace old color with new one. + Section.replace(Pos-OldColorLength +1, OldColorLength, ColorString); + } + else { + // Append Color information to section string. + if (Fn->hasSection()) + Section.append(" "); + Section.append(OverlayStr + ColorString); + } + Fn->setSection(Section); +} + +unsigned PIC16Overlay::getColor(Function *Fn) { + int Color = 0; + if (!Fn->hasSection()) + return 0; + + std::string Section = Fn->getSection(); + size_t Pos = Section.find(OverlayStr); + + // Return 0 if Color is not set. + if (Pos == std::string::npos) + return 0; + + // Set Pos to after "Overlay=". + Pos += OverlayStr.length(); + char c = Section.at(Pos); + std::string ColorString = ""; + + // Find the string representing Color. A Color can only consist of digits. + while (c >= '0' && c<= '9') { + ColorString.append(1,c); + if (Pos < Section.length() - 1) + Pos++; + else + break; + c = Section.at(Pos); + } + Color = atoi(ColorString.c_str()); + + return Color; +} + +bool PIC16Overlay::runOnModule(Module &M) { + CallGraph &CG = getAnalysis<CallGraph>(); + CallGraphNode *ECN = CG.getExternalCallingNode(); + + MarkIndirectlyCalledFunctions(M); + // Since External Calling Node is the base function, do a depth first + // traversal of CallGraph with ECN as root. Each node with be marked with + // a color that is max(color(callers)) + 1. + if(ECN) { + DFSTraverse(ECN, 0); + } + return false; +} + +void PIC16Overlay::MarkIndirectlyCalledFunctions(Module &M) { + // If the use of a function is not a call instruction then this + // function might be called indirectly. In that case give it + // an unique color. + for (Module::iterator MI = M.begin(), E = M.end(); MI != E; ++MI) { + for (Value::use_iterator I = MI->use_begin(), E = MI->use_end(); I != E; + ++I) { + if ((!isa<CallInst>(I) && !isa<InvokeInst>(I)) + || !CallSite(cast<Instruction>(I)).isCallee(I)) { + setColor(MI, ++IndirectCallColor); + break; + } + } + } +} diff --git a/contrib/llvm/lib/Target/PIC16/PIC16Passes/PIC16Overlay.h b/contrib/llvm/lib/Target/PIC16/PIC16Passes/PIC16Overlay.h new file mode 100644 index 0000000..5a2551f --- /dev/null +++ b/contrib/llvm/lib/Target/PIC16/PIC16Passes/PIC16Overlay.h @@ -0,0 +1,60 @@ +//===-- PIC16Overlay.h - Interface for PIC16 Frame Overlay -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the PIC16 Overlay infrastructure. +// +//===----------------------------------------------------------------------===// + +#ifndef PIC16FRAMEOVERLAY_H +#define PIC16FRAMEOVERLAY_H + + +using std::string; +using namespace llvm; + +namespace llvm { + // Forward declarations. + class Function; + class Module; + class ModulePass; + class AnalysisUsage; + class CallGraphNode; + class CallGraph; + + namespace PIC16OVERLAY { + enum OverlayConsts { + StartInterruptColor = 200, + StartIndirectCallColor = 300 + }; + } + class PIC16Overlay : public ModulePass { + std::string OverlayStr; + unsigned InterruptDepth; + unsigned IndirectCallColor; + public: + static char ID; // Class identification + PIC16Overlay() : ModulePass(&ID) { + OverlayStr = "Overlay="; + InterruptDepth = PIC16OVERLAY::StartInterruptColor; + IndirectCallColor = PIC16OVERLAY::StartIndirectCallColor; + } + + virtual void getAnalysisUsage(AnalysisUsage &AU) const; + virtual bool runOnModule(Module &M); + + private: + unsigned getColor(Function *Fn); + void setColor(Function *Fn, unsigned Color); + unsigned ModifyDepthForInterrupt(CallGraphNode *CGN, unsigned Depth); + void MarkIndirectlyCalledFunctions(Module &M); + void DFSTraverse(CallGraphNode *CGN, unsigned Depth); + }; +} // End of namespace + +#endif |