summaryrefslogtreecommitdiff
path: root/lib/Target/PIC16/PIC16Passes/PIC16Overlay.cpp
blob: 197c3987d29666246c45334805d13e14c6f2581f (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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
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 PIC16FrameOverlay::ID = 0;
  ModulePass *createPIC16OverlayPass() { return new PIC16FrameOverlay(); }
}

void PIC16FrameOverlay::getAnalysisUsage(AnalysisUsage &AU) const {
  AU.setPreservesAll();
  AU.addRequired<CallGraph>();
}

void PIC16FrameOverlay::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 PIC16FrameOverlay::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 PIC16FrameOverlay::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 PIC16FrameOverlay::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 PIC16FrameOverlay::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 PIC16FrameOverlay::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;
      }
    }
  }
}