summaryrefslogtreecommitdiff
path: root/lib/Target/PIC16/PIC16Passes/PIC16CallGraph.cpp
blob: accc4a4b14af18e72881c3013f1932d906b65af4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#include "llvm/Analysis/CallGraph.h"
#include "llvm/Pass.h"
#include "llvm/Module.h"
#include "llvm/Transforms/Utils/Cloning.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include <vector>
using namespace llvm;
using std::vector;
using std::string;

namespace {
  class PIC16CallGraph : public ModulePass { 
  public:
    static char ID; // Class identification 
    PIC16CallGraph() : ModulePass(&ID)  {}

    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AU.setPreservesAll();
      AU.addRequired<CallGraph>();
    }
    virtual bool runOnModule(Module &M) {
      // Initially record that no interrupt has been found
      InterruptFound = false;

      CallGraph &CG = getAnalysis<CallGraph>();
      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") {
          // See if the main itself is interrupt function then report an error.
          if (it->first->getSection().find("interrupt") != string::npos)
             reportError("Function 'main' can't be interrupt function");
          else  { 
            // Set the MainLine tag for function main also. 
            it->second->getFunction()->setSection("ML");
            // mark the hierarchy 
            markFunctionHierarchy(it->second, "ML");
          }
        } else if (it->first->getSection().find("interrupt") != string::npos) {
          if (InterruptFound)
            reportError("More than one interrupt functions defined in the module"); 

          InterruptFound = true;
          markFunctionHierarchy(it->second, "IL");
        }
      }
     return false;
    }
  private: // Functions
    // Makr function hierarchy for the MainLine or InterruptLine.
    void markFunctionHierarchy(CallGraphNode *CGN, string StringMark);

    // 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 InterruptFound; 
  };
  char PIC16CallGraph::ID =0;
  static RegisterPass<PIC16CallGraph>
  Y("pic16cg", "PIC16 CallGraph Construction");

}  // End of anonymous namespace

void PIC16CallGraph::reportError(string ErrorString) {
  errs() << "ERROR : " << ErrorString << "\n";
  exit(1);
}

void PIC16CallGraph::
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);
  //llvm_report_error(ErrorString);
}

void PIC16CallGraph::
markFunctionHierarchy(CallGraphNode *CGN, string StringMark) {
  string AlternateMark;
  string SharedMark = "SL";
  if (StringMark == "ML")
    AlternateMark = "IL";
  else
    AlternateMark = "ML";

  // 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 (CalledF->getSection().find("interrupt") != string::npos) {
       vector<string> Values;
       Values.push_back(CalledF->getName().str());
       reportError("Interrupt function (%0) can't be called", Values); 
     }

     // If already shared mark then no need to check any further.
     // Also a great potential for recursion.
     if (CalledF->getSection().find(SharedMark) != string::npos) {
       continue;
     }

     // Has already been mark 
     if (CalledF->getSection().find(StringMark) != string::npos) {
       // Issue diagnostic
       // Potential for recursion.
     } else {
       // Mark now
       if (CalledF->getSection().find(AlternateMark) != string::npos) {
         // Function is alternatively marked. It should be a shared one.
        
         // Shared functions should be clone. Clone here. 
         Function *ClonedFunc = CloneFunction(CalledF); 

         // Add the newly created function to the module.
         CalledF->getParent()->getFunctionList().push_back(ClonedFunc);

         // The new function should be for interrupt line. Therefore should have the
         // name suffixed with IL and section attribute marked with IL. 
         ClonedFunc->setName(CalledF->getName().str() + ".IL");
         ClonedFunc->setSection("IL");

         // Original function now should be for MainLine only. 
         CalledF->setSection("ML");

         // Update the CallSite 
         CallSite CS = cgn_it->first;
         CS.getInstruction()->getOperand(0)->setName(CalledF->getName().str() + ".shared");
       } else {
         // Function is not marked. It should be marked now.
         CalledF->setSection(StringMark);
       }
     }
     
     // Before going any further mark all the called function by current
     // function.
     markFunctionHierarchy(cgn_it->second ,StringMark);
  } // end of loop of all called functions.

}