| //===-- 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 VMap, |
| // this VMap 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 VMap by any previous cloning. |
| VMap.clear(); |
| |
| // Find the auto globls for this function and clone them, and put them |
| // in VMap. |
| 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 VMap. |
| VMap[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 VMap member of the class, which is already populated |
| // by cloneAutos by the time we reach here. |
| // FIXME: Should we just pass VMap's ref as a parameter here? rather |
| // than keeping the VMap 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 VMap. |
| CloneAutos(OrgF); |
| |
| // Now create the clone. |
| ClonedF = CloneFunction(OrgF, VMap); |
| |
| // 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); |
| } |
| } |
| } |
| |
| |
| |