CACAO
LivetimeAnalysisPass.cpp
Go to the documentation of this file.
1 /* src/vm/jit/compiler2/LivetimeAnalysisPass.cpp - LivetimeAnalysisPass
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 
33 #include "toolbox/logging.hpp"
34 #include "toolbox/Option.hpp"
35 
36 #define DEBUG_NAME "compiler2/LivetimeAnalysis"
37 
38 namespace cacao {
39 namespace jit {
40 namespace compiler2 {
41 
43  lti_map.clear();
44  MIS = NULL;
45 }
46 
47 namespace {
48 
50 get_successor_begin(MachineBasicBlock* MBB) {
51  return MBB->back()->successor_begin();
52 }
53 
55 get_successor_end(MachineBasicBlock* MBB) {
56  return MBB->back()->successor_end();
57 }
58 
59 
60 typedef LivetimeAnalysisPass::LiveInSetTy LiveInSetTy;
61 typedef LivetimeAnalysisPass::LiveInMapTy LiveInMapTy;
62 typedef LivetimeAnalysisPass::LivetimeIntervalMapTy LivetimeIntervalMapTy;
63 
64 /**
65  * @Cpp11 use std::function
66  */
67 class InsertPhiOperands : public std::unary_function<MachineBasicBlock*,void> {
68 private:
69  /// Phi inserter
70  struct PhiOperandInserter : public std::unary_function<MachinePhiInst*,void> {
71  LiveInSetTy &live;
72  std::size_t index;
73  /// constructor
74  PhiOperandInserter(LiveInSetTy &live, std::size_t index)
75  : live(live), index(index) {}
76 
77  void operator()(MachinePhiInst* phi) {
78  live.insert(phi->get(index).op);
79  }
80  };
81 
82  LiveInSetTy &live;
83  MachineBasicBlock *current;
84 public:
85  /// constructor
86  InsertPhiOperands(LiveInSetTy &live, MachineBasicBlock *current)
87  : live(live), current(current) {}
88 
89  void operator()(MachineBasicBlock* MBB) {
90  std::for_each(MBB->phi_begin(), MBB->phi_end(),
91  PhiOperandInserter(live,MBB->get_predecessor_index(current)));
92  }
93 };
94 
95 /**
96  * @Cpp11 use std::function
97  */
98 struct UnionLiveIn : public std::unary_function<MachineBasicBlock*,void> {
99  LiveInSetTy &live_set;
100  LiveInMapTy &live_map;
101 
102  /// Constructor
103  UnionLiveIn(LiveInSetTy &live_set, LiveInMapTy &live_map)
104  : live_set(live_set), live_map(live_map) {}
105 
106  void operator()(MachineBasicBlock* MBB) {
107  LiveInSetTy &other_set = live_map[MBB];
108  live_set.insert(other_set.begin(), other_set.end());
109  }
110 };
111 
112 
113 inline LivetimeInterval& find_or_insert(LivetimeIntervalMapTy &lti_map, MachineOperand* op) {
114  LivetimeIntervalMapTy::iterator i = lti_map.find(op);
115  if (i == lti_map.end()) {
116  LivetimeInterval lti(op);
117  i = lti_map.insert(std::make_pair(op,lti)).first;
118  }
119  return i->second;
120 }
121 
122 /**
123  * @Cpp11 use std::function
124  */
125 class AddOperandInterval : public std::unary_function<MachineOperand*,void> {
126 private:
127  LivetimeIntervalMapTy &lti_map;
128  MachineBasicBlock *BB;
129 public:
130  /// Constructor
131  AddOperandInterval(LivetimeIntervalMapTy &lti_map, MachineBasicBlock *BB)
132  : lti_map(lti_map), BB(BB) {}
133  void operator()(MachineOperand* op) {
134  assert(op);
135  if (op->needs_allocation()) {
136  LOG2("AddOperandInterval: op=" << *op << " BasicBlock: " << *BB << nl);
137  find_or_insert(lti_map,op).add_range(UseDef(UseDef::PseudoUse,BB->mi_first()),
138  UseDef(UseDef::PseudoDef,BB->mi_last()));
139  }
140  }
141 };
142 
143 /**
144  * @Cpp11 use std::function
145  */
146 class ProcessOutOperands : public std::unary_function<MachineOperandDesc,void> {
147 private:
148  LivetimeIntervalMapTy &lti_map;
149  MIIterator i;
150  MIIterator e;
151  LiveInSetTy &live;
152 public:
153  /// Constructor
154  ProcessOutOperands(LivetimeIntervalMapTy &lti_map, MIIterator i, MIIterator e,
155  LiveInSetTy &live) : lti_map(lti_map), i(i), e(e), live(live) {}
156  void operator()(MachineOperandDesc &op) {
157  if (op.op && op.op->needs_allocation()) {
158  LOG2("ProcessOutOperand: op=" << *(op.op) << " set form: " << **i << nl);
159  LivetimeInterval &lti = find_or_insert(lti_map,op.op);
160  lti.set_from(UseDef(UseDef::Def,i,&op), UseDef(UseDef::PseudoDef,e));
161  live.erase(op.op);
162  // set register hints
163  if ((*i)->is_move()) {
164  MachineOperand *op = (*i)->get(0).op;
165  if (op->needs_allocation()) {
166  LOG2("set hint " << op << " inst: " << *i << " lti: " << lti << nl);
167  lti.set_hint(op);
168  }
169  }
170  }
171  }
172 };
173 /**
174  * @Cpp11 use std::function
175  */
176 class ProcessInOperands : public std::unary_function<MachineOperandDesc,void> {
177 private:
178  LivetimeIntervalMapTy &lti_map;
179  MachineBasicBlock *BB;
180  MIIterator i;
181  LiveInSetTy &live;
182 public:
183  /// Constructor
184  ProcessInOperands(LivetimeIntervalMapTy &lti_map, MachineBasicBlock *BB,
185  MIIterator i, LiveInSetTy &live) : lti_map(lti_map), BB(BB), i(i), live(live) {}
186  void operator()(MachineOperandDesc &op) {
187  if (op.op && op.op->needs_allocation()) {
188  LOG2("ProcessInOperand: op=" << *(op.op) << " range form: "
189  << BB->front() << " to " << **i << nl);
190  LivetimeInterval &lti = find_or_insert(lti_map,op.op);
191  lti.add_range(UseDef(UseDef::PseudoUse,BB->mi_first()),
192  UseDef(UseDef::Use,i,&op));
193  live.insert(op.op);
194  }
195  }
196 };
197 
198 /**
199  * @Cpp11 use std::function
200  */
201 struct RemovePhi : public std::unary_function<MachinePhiInst*,void> {
202  LiveInSetTy &live;
203  /// constructor
204  RemovePhi(LiveInSetTy &live) : live(live) {}
205 
206  void operator()(MachinePhiInst* phi) {
207  LOG2("Remove phi result" << *phi->get_result().op << nl);
208  live.erase(phi->get_result().op);
209  }
210 };
211 
212 /**
213  * @Cpp11 use std::function
214  */
215 class ProcessLoops : public std::unary_function<MachineLoop*,void> {
216 private:
217  struct ForEachLiveOperand : public std::unary_function<MachineOperand*,void> {
218  LivetimeIntervalMapTy &lti_map;
219  MachineBasicBlock *BB;
221  /// contructor
222  ForEachLiveOperand(LivetimeIntervalMapTy &lti_map, MachineBasicBlock *BB,MachineLoop *loop)
223  : lti_map(lti_map), BB(BB), loop(loop) {}
224  void operator()(MachineOperand* op) {
225  assert(op->needs_allocation());
226  LOG2("ProcessLoops: operand " << op << " range from " << BB->mi_first()
227  << " to " << loop->get_exit()->mi_last() << nl );
228  find_or_insert(lti_map,op).add_range(UseDef(UseDef::PseudoUse,BB->mi_first()),
229  UseDef(UseDef::PseudoDef,loop->get_exit()->mi_last()));
230  }
231  };
232  LivetimeIntervalMapTy &lti_map;
233  MachineBasicBlock *BB;
234  LiveInSetTy &live;
235 public:
236  /// Constructor
237  ProcessLoops(LivetimeIntervalMapTy &lti_map, MachineBasicBlock *BB,
238  LiveInSetTy &live) : lti_map(lti_map), BB(BB), live(live) {}
239  void operator()(MachineLoop* loop) {
240  LOG2(Cyan << "ProcessLoop: " << *loop << nl);
241  std::for_each(live.begin(),live.end(), ForEachLiveOperand(lti_map, BB, loop));
242  }
243 };
244 
245 namespace option {
246  Option<bool> print_intervals("PrintLivetimeIntervals","compiler2: print livetime intervals",false,::cacao::option::xx_root());
247 }
248 
249 } // end anonymous namespace
250 
252  LOG("LivetimeAnalysisPass::run()" << nl);
253  MIS = get_Pass<MachineInstructionSchedulingPass>();
254  MachineLoopTree *MLT = get_Pass<MachineLoopPass>();
255  // TODO use better data structure for the register set
256  LiveInMapTy liveIn;
257 
258  // for all basic blocks in reverse order
260  e = MIS->rend(); i != e ; ++i) {
261  MachineBasicBlock* BB = *i;
262  LOG1("BasicBlock: " << *BB << nl);
263  // get live set
264  LiveInSetTy &live = liveIn[BB];
265 
266  // live == union of successor.liveIn for each successor of BB
267  std::for_each(get_successor_begin(BB), get_successor_end(BB), UnionLiveIn(live,liveIn));
268 
269  // for each phi function of successors of BB
270  std::for_each(get_successor_begin(BB), get_successor_end(BB), InsertPhiOperands(live,BB));
271 
272  // for each operand in live
273  std::for_each(live.begin(),live.end(),AddOperandInterval(lti_map,BB));
274 
275  // for each operation op of BB in reverse order
276  for(MachineBasicBlock::reverse_iterator i = BB->rbegin(), e = BB->rend(); i != e ; ++i) {
277  // phis are handled separately
278  if ((*i)->is_phi()) continue;
279 
280  LOG2("MInst: " << **i << nl);
281  // for each output operand of MI
282  ProcessOutOperands(lti_map, BB->convert(i), BB->mi_last(), live)((*i)->get_result());
283 
284  // for each input operand of MI
285  std::for_each((*i)->begin(),(*i)->end(), ProcessInOperands(lti_map, BB, BB->convert(i), live));
286 
287  // for each dummy operand of MI
288  std::for_each((*i)->dummy_begin(),(*i)->dummy_end(), ProcessInOperands(lti_map, BB, BB->convert(i), live));
289  }
290 
291  // for each phi of BB
292  std::for_each(BB->phi_begin(), BB->phi_end(), RemovePhi(live));
293 
294  // if b is loop header
295  if (MLT->is_loop_header(BB)) {
296  MachineLoopTree::ConstLoopIteratorPair loops = MLT->get_Loops_from_header(BB);
297  std::for_each (loops.first, loops.second, ProcessLoops(lti_map, BB, live));
298  }
299 
300  LOG1("LiveIn " << *BB << ": ");
301  DEBUG1(print_container(dbg(),live.begin(), live.end()) << nl);
302  }
303 
304  if (option::print_intervals) {
305  OStream fout(fopen("LiveIntervalTable.csv","w"));
306  print(fout);
307  }
308  return true;
309 }
310 
311 namespace {
312 /**
313  * @Cpp11 use std::function
314  */
315 struct PrintLivetimeState : public std::unary_function<LivetimeIntervalMapTy::value_type,void> {
316  OStream &OS;
317  MIIterator pos;
318  PrintLivetimeState(OStream &OS, MIIterator pos) : OS(OS), pos(pos) {}
319  void operator()(LivetimeIntervalMapTy::value_type lti) {
320  switch (lti.second.get_State(pos)){
322  {
323  bool use = lti.second.is_use_at(pos);
324  bool def = lti.second.is_def_at(pos);
325  if (use)
326  OS << "use";
327  if (def)
328  OS << "def";
329  if (!(use || def))
330  OS << "active";
331  break;
332  }
333  case LivetimeInterval::Inactive: OS << "inactive"; break;
334  default: break;
335  }
336  OS << ";";
337  }
338 };
339 
340 } // end anonymous namespace
341 
343  OS << "BasicBlock;Instruction;";
344  for (LivetimeIntervalMapTy::const_iterator i = lti_map.begin(),
345  e = lti_map.end(); i != e ; ++i) {
346  MachineOperand *op = i->first;
347  OS << *op << ";";
348  }
349  OS << nl;
350  for (MachineInstructionSchedule::const_iterator i = MIS->begin(), e = MIS->end(); i != e; ++i) {
351  MachineBasicBlock *BB = *i;
352  // print label
353  MIIterator pos = BB->mi_first();
354  OS << *BB << ";" << **pos << ";";
355  std::for_each(lti_map.begin(),lti_map.end(),PrintLivetimeState(OS,pos));
356  OS << nl;
357  // print phis
358  for (MachineBasicBlock::const_phi_iterator i = BB->phi_begin(), e = BB->phi_end(); i != e; ++i) {
359  OS << *BB << ";" << **i << ";";
360  std::for_each(lti_map.begin(),lti_map.end(),PrintLivetimeState(OS,pos));
361  OS << nl;
362  }
363  // print other instructions
364  for (MachineBasicBlock::iterator i = ++BB->begin(), e = BB->end(); i != e; ++i) {
365  MIIterator pos = BB->convert(i);
366  OS << *BB << ";" << **pos << ";";
367  std::for_each(lti_map.begin(),lti_map.end(),PrintLivetimeState(OS,pos));
368  OS << nl;
369  }
370  }
371  return OS;
372 }
373 
375 #if 0
376  for (LivetimeIntervalMapTy::const_iterator i = lti_map.begin(),
377  e = lti_map.end(); i != e ; ++i) {
378  const LivetimeInterval &lti = i->second;
379  signed old = -1;
381  e = lti.use_end(); i != e; ++i) {
382  if ( old > (signed)i->first) {
383  err() << "use not ordered " << old << " > " << i->first << nl;
384  return false;
385  }
386  old = i->first;
387  }
388  old = -1;
390  e = lti.def_end(); i != e; ++i) {
391  if ( old > (signed)i->first) {
392  err() << "def not ordered " << old << " > " << i->first << nl;
393  return false;
394  }
395  old = i->first;
396  }
397  }
398 #endif
399  return true;
400 }
401 
402 // pass usage
406  return PU;
407 }
408 
409 // the address of this variable is used to identify the pass
410 char LivetimeAnalysisPass::ID = 0;
411 
412 // register pass
413 static PassRegistry<LivetimeAnalysisPass> X("LivetimeAnalysisPass");
414 
415 } // end namespace compiler2
416 } // end namespace jit
417 } // end namespace cacao
418 
419 
420 /*
421  * These are local overrides for various environment variables in Emacs.
422  * Please do not remove this and leave it at the end of the file, where
423  * Emacs will automagically detect them.
424  * ---------------------------------------------------------------------
425  * Local variables:
426  * mode: c++
427  * indent-tabs-mode: t
428  * c-basic-offset: 4
429  * tab-width: 4
430  * End:
431  * vim:noexpandtab:sw=4:ts=4:
432  */
std::size_t index
LiveInSetTy & live
virtual void initialize()
Initialize the Pass.
const_phi_iterator phi_end() const
returns an const iterator to the phi instructions
reverse_iterator rbegin()
returns an reverse_iterator to the beginning
std::reverse_iterator< const_iterator > const_reverse_iterator
reverse_iterator rend()
returns an reverse_iterator to the end
UseListTy::const_iterator const_use_iterator
#define DEBUG1(STMT)
Definition: Debug.hpp:126
alloc::map< MachineBasicBlock *, LiveInSetTy >::type LiveInMapTy
MIIterator mi_last()
returns an MIIterator to the last element (included)
u2 op
Definition: disass.cpp:129
A basic block of (scheduled) machine instructions.
MachineLoop * loop
OStream & print_container(OStream &OS, _ForwardIterator i, const _ForwardIterator &e)
Definition: OStream.hpp:436
iterator end()
returns an iterator to the end
#define LOG1(STMT)
Definition: logging.hpp:92
ordered iterator
MIIterator mi_first()
returns an MIIterator to the first element
iterator begin()
returns an iterator to the beginning
MachineBasicBlock * BB
LoopBase< MachineBasicBlock > MachineLoop
Definition: MachineLoop.hpp:35
alloc::map< MachineOperand *, LivetimeInterval, MachineOperandComp >::type LivetimeIntervalMapTy
const_phi_iterator phi_begin() const
returns an const iterator to the phi instructions
MachineBasicBlock * current
const_reference back() const
access the last element
iterator begin()
returns an iterator to the beginning
Container::reverse_iterator reverse_iterator
virtual bool run(JITData &JD)
Run the Pass.
Stores the interdependencies of a pass.
Definition: PassUsage.hpp:55
Simple stream class for formatted output.
Definition: OStream.hpp:141
virtual bool verify() const
Verify the Result.
MIIterator i
#define LOG2(STMT)
Definition: logging.hpp:93
MIIterator pos
OStream & OS
OStream & err()
Definition: OStream.cpp:33
LiveInMapTy & live_map
MIIterator e
This file contains the command line option parsing library.
#define LOG(STMT)
Analogous to DEBUG.
Definition: logging.hpp:91
Calculate the Loop Tree.
LivetimeIntervalMapTy & lti_map
MIIterator convert(iterator pos)
get a MIIterator form a iterator
Operands that can be directly used by the machine (register, memory, stackslot)
alloc::set< MachineOperand * >::type LiveInSetTy
OptionPrefix & xx_root()
Definition: Option.cpp:39
reverse_iterator rbegin()
returns an reverse_iterator to the beginning
virtual PassUsage & get_PassUsage(PassUsage &PA) const
Set the requirements for the pass.
std::pair< const_loop_iterator, const_loop_iterator > ConstLoopIteratorPair
Definition: LoopBase.hpp:93
reverse_iterator rend()
returns an reverse_iterator to the end
static PassRegistry< BasicBlockSchedulingPass > X("BasicBlockSchedulingPass")
Nl nl
Definition: OStream.cpp:56
OStream & dbg()
The default destination for logging messages.
LiveInSetTy & live_set
void add_requires()
PassName is required.
Definition: PassUsage.hpp:78
DefListTy::const_iterator const_def_iterator