CACAO
GlobalValueNumberingPass.cpp
Go to the documentation of this file.
1 /* src/vm/jit/compiler2/GlobalValueNumberingPass.cpp - GlobalValueNumberingPass
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 
35 #include "toolbox/logging.hpp"
36 
37 // define name for debugging (see logging.hpp)
38 #define DEBUG_NAME "compiler2/GlobalValueNumberingPass"
39 
40 STAT_DECLARE_GROUP(compiler2_stat)
41 STAT_REGISTER_SUBGROUP(compiler2_globalvaluenumberingpass_stat,
42  "globalvaluenumberingpass","globalvaluenumberingpass",compiler2_stat)
43 STAT_REGISTER_GROUP_VAR(std::size_t,num_total_const,0,"# CONSTInsts",
44  "total number of CONSTInst nodes",compiler2_globalvaluenumberingpass_stat)
45 STAT_REGISTER_GROUP_VAR(std::size_t,num_total_arith,0,"# arithmetical nodes",
46  "total number of arithmetical nodes",compiler2_globalvaluenumberingpass_stat)
47 STAT_REGISTER_GROUP_VAR(std::size_t,num_total_phi,0,"# PHIInsts",
48  "total number of PHIInst nodes",compiler2_globalvaluenumberingpass_stat)
49 STAT_REGISTER_GROUP_VAR(std::size_t,num_total_arraybc,0,"# ARRAYBOUNDSCHECKInsts",
50  "total number of ARRAYBOUNDSCHECKInst nodes",compiler2_globalvaluenumberingpass_stat)
51 STAT_REGISTER_GROUP_VAR(std::size_t,num_redundant_const,0,"# redundant CONSTInsts",
52  "number of redundant CONSTInst nodes",compiler2_globalvaluenumberingpass_stat)
53 STAT_REGISTER_GROUP_VAR(std::size_t,num_redundant_arith,0,"# redundant arithmetical nodes",
54  "number of redundant arithmetical nodes",compiler2_globalvaluenumberingpass_stat)
55 STAT_REGISTER_GROUP_VAR(std::size_t,num_redundant_phi,0,"# redundant PHIInsts",
56  "number of redundant PHIInst nodes",compiler2_globalvaluenumberingpass_stat)
57 STAT_REGISTER_GROUP_VAR(std::size_t,num_redundant_arraybc,0,"# redundant ARRAYBOUNDSCHECKInsts",
58  "number of redundant ARRAYBOUNDSCHECKInst nodes",compiler2_globalvaluenumberingpass_stat)
59 
60 #define STAT_NODE_COUNT_HELPER(INST, CNT, INFIX) \
61  if ((INST)->get_opcode() == Instruction::CONSTInstID) { \
62  STATISTICS(num_##INFIX##_const += (CNT)); \
63  } else if ((INST)->is_arithmetic()) { \
64  STATISTICS(num_##INFIX##_arith += (CNT)); \
65  } else if ((INST)->get_opcode() == Instruction::PHIInstID) { \
66  STATISTICS(num_##INFIX##_phi += (CNT)); \
67  } else if ((INST)->get_opcode() == Instruction::ARRAYBOUNDSCHECKInstID) { \
68  STATISTICS(num_##INFIX##_arraybc += (CNT)); \
69  }
70 #define STAT_TOTAL_NODES(INST) STAT_NODE_COUNT_HELPER(INST, 1, total)
71 #define STAT_REDUNDANT_NODES(INST, CNT) STAT_NODE_COUNT_HELPER(INST, CNT, redundant)
72 
73 namespace cacao {
74 namespace jit {
75 namespace compiler2 {
76 
78 
79  OpcodeBlockMapTy opcodeToBlock;
80  LongBlockMapTy longToBlock;
81  IntBlockMapTy intToBlock;
82  FloatBlockMapTy floatToBlock;
83  DoubleBlockMapTy doubleToBlock;
84  BBBlockMapTy bbToBlock;
85 
86  for (Method::const_iterator i = begin, e = end; i != e; ++i) {
87  Instruction *I = *i;
88  BlockTy *block = (BlockTy*) 0;
89 
91 
92  if (I->has_side_effects()
93  || !I->is_floating()
94  || I->get_opcode() == Instruction::LOADInstID
95  || I->get_opcode() == Instruction::ALOADInstID
96  || I->get_opcode() == Instruction::SourceStateInstID
97  || I->get_opcode() == Instruction::DeoptimizeInstID
98  || I->get_opcode() == Instruction::AssumptionInstID
99  || I->get_opcode() == Instruction::CHECKNULLInstID) {
100  // instructions which change the global state or depend on it
101  // will be in a separate block each, because they are congruent
102  // only with themselves
103 
104  block = create_block();
105  } else if (I->get_opcode() == Instruction::CONSTInstID) {
106  CONSTInst *constInst = I->to_CONSTInst();
107  // for each constant an initial block will be created,
108  // holding all the nodes of the same constant type that have
109  // equal values.
110 
111  switch (constInst->get_type()) {
112  case Type::IntTypeID:
113  block = get_or_create_block(intToBlock,
114  constInst->get_Int());
115  break;
116  case Type::LongTypeID:
117  block = get_or_create_block(longToBlock,
118  constInst->get_Long());
119  break;
120  case Type::FloatTypeID:
121  block = get_or_create_block(floatToBlock,
122  constInst->get_Float());
123  break;
124  case Type::DoubleTypeID:
125  block = get_or_create_block(doubleToBlock,
126  constInst->get_Double());
127  break;
128  default:
129  block = create_block();
130  break;
131  }
132  } else if (I->get_opcode() == Instruction::PHIInstID) {
133  // all PHIInsts which belong to the same basic block
134  // will be pooled into a common initial block
135  // TODO: generally this should hold for other instructions
136  // that are floating
137 
138  PHIInst *phiInst = I->to_PHIInst();
139  assert(phiInst);
140  BeginInst *bb = phiInst->get_BeginInst();
141  block = get_or_create_block(bbToBlock, bb);
142  } else if (I->get_opcode() != Instruction::BeginInstID
143  && !I->to_EndInst()) {
144  // all other instructions which are no control flow
145  // instructions will be pooled into a common block
146  // per opcode
147 
148  block = get_or_create_block(opcodeToBlock,
149  I->get_opcode());
150  }
151 
152  if (block) {
153  add_to_block(block, I);
154  }
155  }
156 }
157 
158 /**
159  * creates and returns a new block and does some setup work needed
160  * for the further execution of the partitioning algorithm
161  */
164  BlockTy *block = new BlockTy();
165  partition.push_back(block);
167  return block;
168 }
169 
171  block->insert(inst);
172  inst2BlockMap[inst] = block;
173 }
174 
176  BlockTy::const_iterator i = block->begin();
177  Instruction *I = *i;
178  return I->op_size();
179 }
180 
183  std::size_t max = 0;
184  for (Method::const_iterator i = begin, e = end; i != e; i++) {
185  Instruction *I = *i;
186  if (I->op_size() > max) {
187  max = I->op_size();
188  }
189  }
190  return max;
191 }
192 
194  // TODO: clear all the containers
195  for (PartitionTy::const_iterator i = partition.begin(),
196  e = partition.end(); i != e; i++) {
197  BlockTy *block = *i;
198 
199  for (int operandIndex = 0; operandIndex < max_arity; operandIndex++) {
200  // create new work list pair
201  WorkListPairTy *pair = new WorkListPairTy();
202  pair->first = block;
203  pair->second = operandIndex;
204  workList.push_back(pair);
205 
206  // mark work list pair
207  set_in_worklist(block, operandIndex, true);
208  }
209  }
210 }
211 
214  OperandIndex2UsersTy *inverseVector = operandInverseMap[inst];
215  if (!inverseVector) {
216  inverseVector = new OperandIndex2UsersTy();
217  operandInverseMap[inst] = inverseVector;
218  for (int i = 0; i < max_arity; i++) {
219  InstructionListTy *users = new InstructionListTy();
220  inverseVector->push_back(users);
221  }
222  }
223  return (*inverseVector)[op_index];
224 }
225 
227  for (Method::const_iterator i = begin, e = end; i != e; ++i) {
228  Instruction *I = *i;
229  int op_index = 0;
231  oe = I->op_end(); oi != oe; oi++) {
232  Instruction *Op = (*oi)->to_Instruction();
233  assert(Op);
234  InstructionListTy *users = get_users(Op, op_index);
235  users->push_back(I);
236  op_index++;
237  }
238  }
239 }
240 
242  std::vector<bool> *flags = inWorkList[block];
243  if (!flags) {
244  flags = new std::vector<bool>(max_arity);
245  inWorkList[block] = flags;
246  }
247  return flags;
248 }
249 
251  std::vector<bool> *flags = get_worklist_flags(block);
252  (*flags)[index] = flag;
253 }
254 
256  std::vector<bool> *flags = get_worklist_flags(block);
257  return (*flags)[index];
258 }
259 
261  // create new work list pair
262  WorkListPairTy *pair = new WorkListPairTy();
263  pair->first = block;
264  pair->second = index;
265  workList.push_back(pair);
266 
267  // mark work list pair
268  set_in_worklist(block, index, true);
269 }
270 
272  WorkListPairTy *pair = workList.front();
273  workList.pop_front();
274  set_in_worklist(pair->first, pair->second, false);
275  return pair;
276 }
277 
281 }
282 
285  return inst2BlockMap[inst];
286 }
287 
289  BlockTy *new_block = create_block();
290 
291  assert(block->size() > instructions->size());
292 
293  // remove the given instructions from the given block and move them
294  // to the new one
295  for (TouchedInstListTy::const_iterator i = instructions->begin(),
296  e = instructions->end(); i != e; i++) {
297  Instruction *I = *i;
298  block->erase(I);
299  add_to_block(new_block, I);
300  }
301 
302  for (int operandIndex = 0; operandIndex < max_arity; operandIndex++) {
303  if (!is_in_worklist(block, operandIndex)
304  && block->size() <= new_block->size()) {
305  add_to_worklist(block, operandIndex);
306  } else {
307  add_to_worklist(new_block, operandIndex);
308  }
309  }
310 }
311 
313  for (PartitionTy::const_iterator i = partition.begin(),
314  e = partition.end(); i != e; i++) {
315  BlockTy *block = *i;
316  if (block->size() > 1) {
318  }
319  }
320 }
321 
323  Instruction *inst = *(block->begin());
324 
325  // A CONSTInst does not represent a computation, hence CONSTInsts that
326  // represent the same constant value don't need to be consolidated.
327  if (inst->to_CONSTInst()) {
328  return;
329  }
330 
331  // the first node in the block will be used to replace all the others in
332  // the block, the rest of them (i.e. block->size() - 1) is redundant
333  STAT_REDUNDANT_NODES(inst, block->size() - 1);
334 
335  for (auto i = std::next(block->begin()); i != block->end(); i++) {
336  Instruction *replacable = *i;
337  replacable->replace_value(inst);
338 
339  alloc::vector<Instruction*>::type rdeps(replacable->rdep_begin(), replacable->rdep_end());
340 
341  for (Instruction *dependent : rdeps) {
342  dependent->append_dep(inst);
343  dependent->remove_dep(replacable);
344  }
345  }
346 }
347 
349  #if ENABLE_LOGGING
350  for (TouchedInstListTy::const_iterator i = instructions->begin(),
351  e = instructions->end(); i != e; i++) {
352  LOG(*i << nl);
353  }
354  #endif
355 }
356 
358  #if ENABLE_LOGGING
359  for (BlockTy::const_iterator i = block->begin(),
360  e = block->end(); i != e; i++) {
361  Instruction *I = *i;
362  LOG(I << nl);
363  }
364  #endif
365 }
366 
368  #if ENABLE_LOGGING
369  for (PartitionTy::const_iterator i = partition.begin(),
370  e = partition.end(); i != e; i++) {
371  LOG("=============================================================" << nl);
372  LOG("Block:" << nl);
373  BlockTy *block = *i;
374  print_block(block);
375  }
376  #endif
377 }
378 
379 template <typename T>
380 void delete_all(T *lst) {
381  while (!lst->empty()) {
382  delete lst->back();
383  lst->pop_back();
384  }
385 }
386 
387 template <typename T1, typename T2, typename Iterator>
388 void delete_in_range(std::unordered_map<T1,T2> *map, Iterator begin, Iterator end) {
389  Iterator i = begin;
390  while (i != end) {
391  delete i->second;
392  map->erase(i++);
393  }
394 }
395 
396 template <typename T1, typename T2>
397 void delete_all(std::unordered_map<T1,T2> *map) {
398  delete_in_range(map, map->begin(), map->end());
399 }
400 
402  OperandInverseMapTy::const_iterator i = operandInverseMap.begin();
403  OperandInverseMapTy::const_iterator e = operandInverseMap.end();
404  while (i != e) {
405  OperandIndex2UsersTy *opUsers = i->second;
406  delete_all(opUsers);
407  delete opUsers;
408  operandInverseMap.erase(i++);
409  }
410 }
411 
413  Method *M = JD.get_Method();
414 
415  max_arity = compute_max_arity(M->begin(), M->end());
416  init_partition(M->begin(), M->end());
418  init_operand_inverse(M->begin(), M->end());
419 
420  LOG("BEFORE PARTITIONING" << nl);
421  print_blocks();
422 
423  while (!workList.empty()) {
425  BlockTy *block = workListPair->first;
426  int operandIndex = workListPair->second;
427  delete workListPair;
428 
429  std::list<BlockTy*> touched;
430 
431  for (BlockTy::const_iterator i = block->begin(),
432  e = block->end(); i != e; i++) {
433  Instruction *I = *i;
434  InstructionListTy *usersForIndex = get_users(I, operandIndex);
435 
436  for (InstructionListTy::const_iterator ui = usersForIndex->begin(),
437  ue = usersForIndex->end(); ui != ue; ui++) {
438  Instruction *user = *ui;
439  BlockTy *userBlock = get_block(user);
440 
441  // the user's block can be 0 if it is an end inst
442  if (userBlock) {
443  touched.push_back(userBlock);
444  TouchedInstListTy *touchedInstructions =
445  get_touched_instructions(userBlock);
446  touchedInstructions->insert(user);
447  }
448  }
449  }
450 
451  // we have to look at every block that contains instructions
452  // whose operand at index operandIndex is in the current block
453  for (std::list<BlockTy*>::const_iterator i = touched.begin(),
454  e = touched.end(); i != e; i++) {
455  BlockTy *touchedBlock = *i;
456  TouchedInstListTy *touchedInstructions = get_touched_instructions(touchedBlock);
457 
458  if (touchedInstructions->size() > 0
459  && touchedBlock->size() != touchedInstructions->size()) {
460  LOG("split block (" << touchedBlock->size() << ", " << touchedInstructions->size() << ")" << nl);
461  print_block(touchedBlock);
462  LOG("remove" << nl);
463  print_instructions(touchedInstructions);
464  split(touchedBlock, touchedInstructions);
465  }
466  touchedInstructions->clear();
467  }
468  }
469 
470  LOG(nl << "AFTER PARTITIONING" << nl);
471  print_blocks();
473 
479 
480  return true;
481 }
482 
483 // pass usage
488  return PU;
489 }
490 
491 Option<bool> GlobalValueNumberingPass::enabled("GlobalValueNumberingPass","compiler2: enable global value numbering (default = true)",true,::cacao::option::xx_root());
492 
493 // register pass
494 static PassRegistry<GlobalValueNumberingPass> X("GlobalValueNumberingPass");
495 
496 } // end namespace compiler2
497 } // end namespace jit
498 } // end namespace cacao
499 
500 
501 /*
502  * These are local overrides for various environment variables in Emacs.
503  * Please do not remove this and leave it at the end of the file, where
504  * Emacs will automagically detect them.
505  * ---------------------------------------------------------------------
506  * Local variables:
507  * mode: c++
508  * indent-tabs-mode: t
509  * c-basic-offset: 4
510  * tab-width: 4
511  * End:
512  * vim:noexpandtab:sw=4:ts=4:
513  */
std::unordered_map< int32_t, BlockTy * > IntBlockMapTy
std::size_t index
void delete_all(T *lst)
#define STATISTICS(x)
Wrapper for statistics only code.
Definition: statistics.hpp:975
std::unordered_map< Instruction::InstID, BlockTy *, std::hash< int > > OpcodeBlockMapTy
these types are needed for the creation of the inital blocks
const_dep_iterator rdep_begin() const
#define STAT_REGISTER_SUBGROUP(var, name, description, group)
Register a statistics group and add it to a group.
Definition: statistics.hpp:974
#define max(a, b)
Definition: lsra.hpp:80
virtual CONSTInst * to_CONSTInst()
Definition: Instruction.hpp:51
alloc::unordered_set< Instruction * >::type BlockTy
InstructionListTy * get_users(Instruction *inst, int op_index)
alloc::unordered_set< Instruction * >::type TouchedInstListTy
OperandListTy::const_iterator const_op_iterator
Definition: Instruction.hpp:82
void add_schedule_before()
Schedule before PassName.
Definition: PassUsage.hpp:127
BeginInst *& block
void replace_value(Value *v)
Replace this Value this the new one in all users.
Definition: Value.cpp:55
void set_in_worklist(BlockTy *block, int index, bool flag)
#define STAT_REDUNDANT_NODES(INST, CNT)
std::vector< bool > * get_worklist_flags(BlockTy *block)
std::vector< T, Allocator< T > > type
Definition: vector.hpp:38
Stores the interdependencies of a pass.
Definition: PassUsage.hpp:55
void init_operand_inverse(Method::const_iterator begin, Method::const_iterator end)
#define STAT_REGISTER_GROUP_VAR(type, var, init, name, description, group)
Register an statistics variable and add it to a group.
Definition: statistics.hpp:967
std::unordered_map< int64_t, BlockTy * > LongBlockMapTy
virtual Instruction * to_Instruction()
Instruction super class.
Definition: Instruction.hpp:75
void split(BlockTy *block, TouchedInstListTy *instructions)
std::unordered_map< double, BlockTy * > DoubleBlockMapTy
void delete_in_range(std::unordered_map< T1, T2 > *map, Iterator begin, Iterator end)
const_dep_iterator rdep_end() const
void add_to_worklist(BlockTy *block, int operandIndex)
MIIterator i
InstructionListTy::const_iterator const_iterator
Definition: MethodC2.hpp:69
const_iterator end() const
Definition: MethodC2.hpp:147
const_op_iterator op_begin() const
std::vector< InstructionListTy * > OperandIndex2UsersTy
MIIterator e
#define LOG(STMT)
Analogous to DEBUG.
Definition: logging.hpp:91
#define I(value)
Definition: codegen.c:279
static int compute_max_arity(Method::const_iterator begin, Method::const_iterator end)
jmethodID jint const void jint const jvmtiAddrLocationMap * map
Definition: jvmti.h:338
#define STAT_TOTAL_NODES(INST)
OptionPrefix & xx_root()
Definition: Option.cpp:39
#define STAT_DECLARE_GROUP(var)
Declare an external group (or subgroup).
Definition: statistics.hpp:970
const Method & M
const_iterator begin() const
Definition: MethodC2.hpp:143
TouchedInstListTy * get_touched_instructions(BlockTy *block)
void init_partition(Method::const_iterator begin, Method::const_iterator end)
void add_to_block(BlockTy *block, Instruction *inst)
virtual PassUsage & get_PassUsage(PassUsage &PU) const
Set the requirements for the pass.
static java_object_t * next
Definition: copy.c:43
std::unordered_map< float, BlockTy * > FloatBlockMapTy
std::unordered_map< BeginInst *, BlockTy * > BBBlockMapTy
static PassRegistry< BasicBlockSchedulingPass > X("BasicBlockSchedulingPass")
Nl nl
Definition: OStream.cpp:56
BlockTy * create_block()
creates and returns a new block and does some setup work needed for the further execution of the part...
void print_instructions(TouchedInstListTy *instructions)
const_op_iterator op_end() const
void add_requires()
PassName is required.
Definition: PassUsage.hpp:78
#define STAT_NODE_COUNT_HELPER(INST, CNT, INFIX)