CACAO
SSAPrinterPass.cpp
Go to the documentation of this file.
1 /* src/vm/jit/compiler2/SSAPrinterPass.cpp - SSAPrinterPass
2 
3  Copyright (C) 2013
4  CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5 
6  This file is part of CACAO.
7 
8  This program is free software; you can redistribute it and/or
9  modify it under the terms of the GNU General Public License as
10  published by the Free Software Foundation; either version 2, or (at
11  your option) any later version.
12 
13  This program is distributed in the hope that it will be useful, but
14  WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with this program; if not, write to the Free Software
20  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21  02110-1301, USA.
22 
23 */
24 
32 
37 
38 #include "toolbox/GraphPrinter.hpp"
39 
40 #include "vm/utf8.hpp"
41 #include "vm/jit/jit.hpp"
42 #include "vm/class.hpp"
43 
44 #include <sstream>
45 
46 namespace {
47 std::string get_filename(methodinfo *m, jitdata *jd, std::string prefix = "cfg_", std::string suffix=".dot");
48 std::string get_filename(methodinfo *m, jitdata *jd, std::string prefix, std::string suffix)
49 {
50  std::string filename = prefix;
51  filename += Utf8String(m->clazz->name).begin();
52  filename += ".";
53  filename += Utf8String(m->name).begin();
54  filename += Utf8String(m->descriptor).begin();
55  filename += suffix;
56  /* replace unprintable chars */
57  for (size_t i = filename.find_first_of('/');
58  i != std::string::npos;
59  i = filename.find_first_of('/',i+1)) {
60  filename.replace(i,1,1,'.');
61  }
62  const char *unchar = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.";
63  for (size_t i = filename.find_first_not_of(unchar);
64  i != std::string::npos;
65  i = filename.find_first_not_of(unchar,i+1)) {
66  filename.replace(i,1,1,'_');
67  }
68 
69  return filename;
70 }
71 } // end anonymous namespace
72 
73 namespace cacao {
74 namespace jit {
75 namespace compiler2 {
76 
77 namespace {
78 
79 class SSAGraph : public PrintableGraph<Method*,Instruction*> {
80 protected:
81  const Method &M;
82  std::string name;
83  GlobalSchedule *sched;
84  bool verbose;
85  alloc::set<EdgeType>::type data_dep;
86  alloc::set<EdgeType>::type sched_dep;
87  alloc::set<EdgeType>::type cfg_edges;
88  alloc::set<EdgeType>::type begin2end_edges;
89 
90 public:
91 
92  SSAGraph(const Method &M, std::string name, GlobalSchedule *sched = NULL, bool verbose = true)
93  : M(M), name(name), sched(sched), verbose(verbose) {
94  init();
95  }
96  SSAGraph(const Method &M, std::string name, bool verbose)
97  : M(M), name(name), sched(NULL), verbose(verbose) {
98  init();
99  }
100  void init() {
101  for(Method::InstructionListTy::const_iterator i = M.begin(),
102  e = M.end(); i != e; ++i) {
103  Instruction *I = *i;
104  if (I == NULL)
105  continue;
106  // if no verbose only print end begin
107  if (!verbose && (!(I->to_BeginInst() || I->to_EndInst())) )
108  continue;
109  nodes.insert(I);
110  if(verbose) {
111  // add operator link
112  for(Instruction::OperandListTy::const_iterator ii = I->op_begin(), ee = I->op_end();
113  ii != ee; ++ii) {
114  Value *v = (*ii);
115  if (v) {
116  Instruction *II = (*ii)->to_Instruction();
117  if (II) {
118  EdgeType edge = std::make_pair(II,I);
119  data_dep.insert(edge);
120  edges.insert(edge);
121  }
122  }
123  }
124  // add dependency link
125  for(Instruction::DepListTy::const_iterator ii = I->dep_begin(), ee = I->dep_end();
126  ii != ee; ++ii) {
127  Instruction *II = (*ii);
128  if (II) {
129  EdgeType edge = std::make_pair(II,I);
130  sched_dep.insert(edge);
131  edges.insert(edge);
132  }
133  }
134  }
135  // add successor link
136  EndInst *EI = I->to_EndInst();
137  if (EI) {
138  for(EndInst::SuccessorListTy::const_iterator ii = EI->succ_begin(), ee = EI->succ_end();
139  ii != ee; ++ii) {
140  Value *v = ii->get();
141  if (v) {
142  Instruction *II = ii->get()->to_Instruction();
143  if (II) {
144  EdgeType edge = std::make_pair(EI,II);
145  cfg_edges.insert(edge);
146  edges.insert(edge);
147  }
148  }
149  }
150  EdgeType edge = std::make_pair(EI->get_BeginInst(),EI);
151  begin2end_edges.insert(edge);
152  edges.insert(edge);
153  }
154  // clustering
155  BeginInst *bi = (sched) ? sched->get(I) : I->get_BeginInst();
156  if (bi) {
157  clusters[(unsigned long)bi].insert(I);
158  }
159  }
160  }
161 
162  virtual unsigned long getNodeID(Instruction *const &node) const {
163  return node->get_id();
164  }
165 
166  virtual OStream& getGraphName(OStream& OS) const {
167  return OS << name;
168  }
169 
170  virtual OStream& getNodeLabel(OStream& OS, Instruction *const &node) const {
171  #if 0
172  OS << "[" << node->get_id() << ": " << node->get_name() << " ("
173  << get_type_name(node->get_type()) << ")]";
174  #endif
175  OS << node;
176  for(Instruction::OperandListTy::const_iterator ii = node->op_begin(), ee = node->op_end();
177  ii != ee; ++ii) {
178  OS << " ";
179  Value *v = (*ii);
180  if (v) {
181  Instruction *II = (*ii)->to_Instruction();
182  OS << "[" << II->get_id() << "]";
183  } else {
184  OS << "NULL";
185  }
186  }
187  return OS;
188  }
189 
190 #if 0
191  StringBuf getNodeAttributes(const SSAGraph::NodeType &node) const ;
192 
193  StringBuf getEdgeLabel(const SSAGraph::EdgeType &e) const ;
194 
195 #endif
196  OStream& getEdgeAttributes(OStream& OS, const SSAGraph::EdgeType &e) const;
197 };
198 
199 class EdgeAttributeVisitor : public InstructionVisitor {
200 private:
201  OStream &OS;
202  BeginInst *target;
203 public:
204  EdgeAttributeVisitor(OStream &OS, BeginInst *target)
205  : OS(OS), target(target) {}
206  virtual void visit_default(Instruction *I) {
207  }
208  // make InstructionVisitors visit visible
210 
211  virtual void visit(TABLESWITCHInst* I);
212 
213 };
214 
215 void EdgeAttributeVisitor::visit(TABLESWITCHInst* I) {
216  int index = I->get_successor_index(target);
217  if (index == -1) return;
218  if (std::size_t(index) == I->succ_size() - 1) {
219  OS << "label=\"default\"";
220  }
221  else {
222  OS << "label=\"" << index << "\"";
223  }
224 }
225 
226 inline OStream& SSAGraph::getEdgeAttributes(OStream& OS, const SSAGraph::EdgeType &e) const {
227  if (data_dep.find(e) != data_dep.end()) {
228  OS << "color=red,";
229  }
230  if (sched_dep.find(e) != sched_dep.end()) {
231  OS << "color=blue,";
232  }
233  if (begin2end_edges.find(e) != begin2end_edges.end()) {
234  OS << "style=dashed,";
235  }
236  BeginInst* begin = e.second->to_BeginInst();
237  if (begin) {
238  EdgeAttributeVisitor visitor(OS,begin);
239  e.first->accept(visitor, true);
240  }
241  return OS;
242 }
243 
244 } // end anonymous namespace
245 
246 // BEGIN SSAPrinterPass
247 
250  return PU;
251 }
252 // the address of this variable is used to identify the pass
253 char SSAPrinterPass::ID = 0;
254 
255 Option<bool> SSAPrinterPass::enabled("SSAPrinterPass","compiler2: enable SSAPrinterPass",false,::cacao::option::xx_root());
256 
257 // register pass
258 static PassRegistry<SSAPrinterPass> X("SSAPrinterPass");
259 
260 // run pass
262  std::string name = get_filename(JD.get_jitdata()->m,JD.get_jitdata(),"","");
263  std::string filename = "ssa_";
264  filename+=name+".dot";
265  GraphPrinter<SSAGraph>::print(filename.c_str(), SSAGraph(*(JD.get_Method()), name));
266  return true;
267 }
268 // END SSAPrinterPass
269 
270 // BEGIN BasicBlockPrinterPass
271 
274  return PU;
275 }
276 // the address of this variable is used to identify the pass
278 
279 Option<bool> BasicBlockPrinterPass::enabled("BasicBlockPrinterPass","compiler2: enable BasicBlockPrinterPass",false,::cacao::option::xx_root());
280 
281 // register pass
282 static PassRegistry<BasicBlockPrinterPass> Z("BasicBlockPrinterPass");
283 
284 // run pass
286  std::string name = get_filename(JD.get_jitdata()->m,JD.get_jitdata(),"","");
287  std::string filename = "basicblocks_";
288  filename+=name+".dot";
289  GraphPrinter<SSAGraph>::print(filename.c_str(), SSAGraph(*(JD.get_Method()), name, false));
290  return true;
291 }
292 // END BasicBlockPrinterPass
293 
294 // BEGIN GlobalSchedulePrinterPass
295 
296 template <class _T>
298  PU.add_requires<_T>();
299  return PU;
300 }
301 // the address of this variable is used to identify the pass
302 template <class _T>
304 
305 Option<bool> schedule_printer_enabled("GlobalSchedulePrinterPass","compiler2: enable GlobalSchedulePrinterPass",false,::cacao::option::xx_root());
306 // run pass
307 template <class _T>
309  std::string name = get_filename(JD.get_jitdata()->m,JD.get_jitdata(),"","");
310  std::string filename = "bb_sched_";
311 
312  GlobalSchedule* sched = get_Pass<_T>();
313 
315  filename += "_" + name + ".dot";
316  GraphPrinter<SSAGraph>::print(filename.c_str(), SSAGraph(*(JD.get_Method()), name, sched));
317  return true;
318 }
319 
320 // set names
321 template <>
323 template <>
325 template <>
327 
328 
329 // register pass
330 static PassRegistry<GlobalSchedulePrinterPass<ScheduleLatePass> > X_late("GlobalSchedulePrinterPass(late)");
331 static PassRegistry<GlobalSchedulePrinterPass<ScheduleEarlyPass> > X_early("GlobalSchedulePrinterPass(early)");
332 static PassRegistry<GlobalSchedulePrinterPass<ScheduleClickPass> > X_click("GlobalSchedulePrinterPass(click)");
333 
334 // END GlobalSchedulePrinterPass
335 
336 } // end namespace cacao
337 } // end namespace jit
338 } // end namespace compiler2
339 
340 
341 /*
342  * These are local overrides for various environment variables in Emacs.
343  * Please do not remove this and leave it at the end of the file, where
344  * Emacs will automagically detect them.
345  * ---------------------------------------------------------------------
346  * Local variables:
347  * mode: c++
348  * indent-tabs-mode: t
349  * c-basic-offset: 4
350  * tab-width: 4
351  * End:
352  * vim:noexpandtab:sw=4:ts=4:
353  */
Utf8String name
Definition: method.hpp:71
GlobalSchedule TODO: more info.
std::size_t index
Option< bool > schedule_printer_enabled("GlobalSchedulePrinterPass","compiler2: enable GlobalSchedulePrinterPass", false,::cacao::option::xx_root())
Definition: jit.hpp:126
static PassRegistry< GlobalSchedulePrinterPass< ScheduleEarlyPass > > X_early("GlobalSchedulePrinterPass(early)")
static void print(const char *filename, const PrintableGraphTy &G)
const GlobalSchedule * sched
virtual PassUsage & get_PassUsage(PassUsage &PA) const
Set the requirements for the pass.
alloc::set< EdgeType >::type sched_dep
virtual bool run(JITData &JD)
Run the Pass.
JNIEnv jclass jobject const char * name
Definition: jvmti.h:312
jitdata * get_jitdata() const
Definition: JITData.hpp:51
std::set< EdgeType > & edges
const char * get_type_name(const Type::TypeID &type)
Definition: Type.cpp:91
virtual bool run(JITData &JD)
Run the Pass.
Utf8String descriptor
Definition: method.hpp:72
static PassRegistry< GlobalSchedulePrinterPass< ScheduleLatePass > > X_late("GlobalSchedulePrinterPass(late)")
static PassRegistry< BasicBlockPrinterPass > Z("BasicBlockPrinterPass")
classinfo * clazz
Definition: method.hpp:80
Utf8String name
Definition: class.hpp:91
Stores the interdependencies of a pass.
Definition: PassUsage.hpp:55
virtual void visit(LoadInst *I, bool copyOperands)
virtual PassUsage & get_PassUsage(PassUsage &PA) const
Set the requirements for the pass.
MIIterator i
virtual PassUsage & get_PassUsage(PassUsage &PA) const
Set the requirements for the pass.
static PassRegistry< GlobalSchedulePrinterPass< ScheduleClickPass > > X_click("GlobalSchedulePrinterPass(click)")
OStream & OS
MIIterator e
virtual bool run(JITData &JD)
Run the Pass.
GlobalSchedulePrinterPass TODO: more info.
bool verbose
byte_iterator begin() const
Definition: utf8.hpp:106
#define I(value)
Definition: codegen.c:279
Represents the result of the addition of a certain IR-variable with a certain constant.
Definition: Value.hpp:36
methodinfo * m
Definition: jit.hpp:127
alloc::set< EdgeType >::type cfg_edges
OptionPrefix & xx_root()
Definition: Option.cpp:39
const Method & M
alloc::set< EdgeType >::type data_dep
BeginInst * target
alloc::set< EdgeType >::type begin2end_edges
static PassRegistry< BasicBlockSchedulingPass > X("BasicBlockSchedulingPass")
void add_requires()
PassName is required.
Definition: PassUsage.hpp:78