CACAO
ConstantPropagationPass.cpp
Go to the documentation of this file.
1 /* src/vm/jit/compiler2/ConstantPropagationPass.cpp - ConstantPropagationPass
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 
36 
37 #define DEBUG_NAME "compiler2/ConstantPropagationPass"
38 
39 STAT_DECLARE_GROUP(compiler2_stat)
40 STAT_REGISTER_SUBGROUP(compiler2_constantpropagationpass_stat,
41  "constantpropagationpass","constantpropagationpass",compiler2_stat)
42 STAT_REGISTER_GROUP_VAR(std::size_t,num_constant_expr,0,"# evaluated expressions",
43  "number of nodes which could be folded",compiler2_constantpropagationpass_stat)
44 STAT_REGISTER_GROUP_VAR(std::size_t,num_constant_phis,0,"# evaluated phi functions",
45  "number of PHIInsts which could be replaced",compiler2_constantpropagationpass_stat)
46 
47 
48 namespace cacao {
49 namespace jit {
50 namespace compiler2 {
51 
52 /// BinaryOperation function object class
53 template <typename T, Instruction::InstID ID>
54 struct BinaryOperation : public std::binary_function<T,T,T> {
55  T operator()(const T &lhs, const T &rhs) const ;
56 };
57 
58 /// Template specialization for ADDInstID
59 template <typename T>
60 struct BinaryOperation<T, Instruction::ADDInstID> :
61  public std::binary_function<T,T,T> {
62  T operator()(const T &lhs, const T &rhs) const {
63  return lhs + rhs;
64  }
65 };
66 
67 /// Template specialization for SUBInstID
68 template <typename T>
69 struct BinaryOperation<T, Instruction::SUBInstID> :
70  public std::binary_function<T,T,T> {
71  T operator()(const T &lhs, const T &rhs) const {
72  return lhs - rhs;
73  }
74 };
75 
76 /// Template specialization for MULInstID
77 template <typename T>
78 struct BinaryOperation<T, Instruction::MULInstID> :
79  public std::binary_function<T,T,T> {
80  T operator()(const T &lhs, const T &rhs) const {
81  return lhs * rhs;
82  }
83 };
84 
85 /// Template specialization for DIVInstID
86 template <typename T>
87 struct BinaryOperation<T, Instruction::DIVInstID> :
88  public std::binary_function<T,T,T> {
89  T operator()(const T &lhs, const T &rhs) const {
90  return lhs / rhs;
91  }
92 };
93 
94 /// Template specialization for ANDInstID
95 template <typename T>
96 struct BinaryOperation<T, Instruction::ANDInstID> :
97  public std::binary_function<T,T,T> {
98  T operator()(const T &lhs, const T &rhs) const {
99  return lhs & rhs;
100  }
101 };
102 
103 /// function wrapper for BinaryOperation
104 template <typename T>
105 inline T binaryOperate(Instruction::InstID ID, const T &lhs, const T &rhs) {
106  switch (ID) {
115  default:
116  assert(0 && "not implemented");
117  break;
118  }
119  // unreachable - dummy result
120  return lhs;
121 }
122 
123 CONSTInst *foldBinaryInst(BinaryInst *inst) {
124  CONSTInst *op1 = inst->get_operand(0)->to_Instruction()->to_CONSTInst();
125  CONSTInst *op2 = inst->get_operand(1)->to_Instruction()->to_CONSTInst();
126  assert(op1 && op2);
127 
128  switch (inst->get_type()) {
129  case Type::IntTypeID:
130  return new CONSTInst(binaryOperate(inst->get_opcode(),
131  op1->get_Int(), op2->get_Int()), Type::IntType());
132  case Type::LongTypeID:
133  return new CONSTInst(binaryOperate(inst->get_opcode(),
134  op1->get_Long(), op2->get_Long()), Type::LongType());
135  case Type::FloatTypeID:
136  return new CONSTInst(binaryOperate(inst->get_opcode(),
137  op1->get_Float(), op2->get_Float()), Type::FloatType());
138  case Type::DoubleTypeID:
139  return new CONSTInst(binaryOperate(inst->get_opcode(),
140  op1->get_Double(), op2->get_Double()), Type::DoubleType());
141  default:
142  assert(0);
143  return 0;
144  }
145 }
146 
147 /// UnaryOperation function object class
148 template <typename T, Instruction::InstID ID>
149 struct UnaryOperation :public std::unary_function<T,T> {
150  T operator()(const T &op) const;
151 };
152 
153 /// Template specialization for NEGInstID
154 template <typename T>
155 struct UnaryOperation<T, Instruction::NEGInstID> :
156  public std::unary_function<T,T> {
157  T operator()(const T &op) const {
158  return -op;
159  }
160 };
161 
162 /// function wrapper for UnaryOperation
163 template <typename T>
164 inline T unaryOperate(Instruction::InstID ID, const T &op) {
165  switch (ID) {
168  default:
169  assert(0 && "not implemented");
170  break;
171  }
172  // unreachable - dummy result
173  return op;
174 }
175 
176 
177 CONSTInst *foldUnaryInst(UnaryInst *inst) {
178  CONSTInst *op = inst->get_operand(0)->to_Instruction()->to_CONSTInst();
179  assert(op);
180  assert(inst->get_type() == op->get_type());
181 
182  switch (inst->get_type()) {
183  case Type::IntTypeID:
184  return new CONSTInst(unaryOperate(inst->get_opcode(),
185  op->get_Int()), Type::IntType());
186  case Type::LongTypeID:
187  return new CONSTInst(unaryOperate(inst->get_opcode(),
188  op->get_Long()), Type::LongType());
189  case Type::FloatTypeID:
190  return new CONSTInst(unaryOperate(inst->get_opcode(),
191  op->get_Float()), Type::FloatType());
192  case Type::DoubleTypeID:
193  return new CONSTInst(unaryOperate(inst->get_opcode(),
194  op->get_Double()), Type::DoubleType());
195  default:
196  assert(0);
197  return 0;
198  }
199 }
200 
201 template <typename T>
202 CONSTInst *castOperate(CASTInst *inst, const T &op) {
203  switch (inst->get_type()) {
204  case Type::IntTypeID:
205  return new CONSTInst((int32_t) op, Type::IntType());
206  case Type::LongTypeID:
207  return new CONSTInst((int64_t) op, Type::LongType());
208  case Type::FloatTypeID:
209  return new CONSTInst((float) op, Type::FloatType());
210  case Type::DoubleTypeID:
211  return new CONSTInst((double) op, Type::DoubleType());
212  default:
213  assert(0);
214  return 0;
215  }
216 }
217 
218 CONSTInst *foldCASTInst(CASTInst *inst) {
219  CONSTInst *op = inst->get_operand(0)->to_Instruction()->to_CONSTInst();
220  assert(op);
221 
222  switch (op->get_type()) {
223  case Type::IntTypeID:
224  return castOperate(inst, op->get_Int());
225  case Type::LongTypeID:
226  return castOperate(inst, op->get_Long());
227  case Type::FloatTypeID:
228  return castOperate(inst, op->get_Float());
229  case Type::DoubleTypeID:
230  return castOperate(inst, op->get_Double());
231  default:
232  assert(0);
233  return 0;
234  }
235 }
236 
237 CONSTInst *foldInstruction(Instruction *inst) {
238  // TODO: distinguish arithmetical and bitwise operations
239  if (inst->get_opcode() == Instruction::CASTInstID) {
240  return foldCASTInst(inst->to_CASTInst());
241  } else if (inst->to_UnaryInst()) {
242  return foldUnaryInst(inst->to_UnaryInst());
243  } else if (inst->to_BinaryInst()) {
244  return foldBinaryInst(inst->to_BinaryInst());
245  }
246 
247  return 0;
248 }
249 
251  for (Value::UserListTy::const_iterator i = inst->user_begin(),
252  e = inst->user_end(); i != e; i++) {
253  Instruction *user = *i;
254  constantOperands[user]++;
255  if (!inWorkList[user]) {
256  workList.push_back(user);
257  inWorkList[user] = true;
258  }
259  }
260 }
261 
263  CONSTInst *c, Method *M) {
264  assert(inst);
265  assert(c);
266 
267  LOG("replace " << inst << " by " << c << nl);
268  inst->replace_value(c);
269  propagate(c);
270 }
271 
272 bool has_only_constant_operands(Instruction *inst) {
273  assert(inst->op_size() > 0);
274  CONSTInst *firstOp = inst->get_operand(0)->to_Instruction()->to_CONSTInst();
275  for (Instruction::const_op_iterator i = inst->op_begin(),
276  e = inst->op_end(); i != e; i++) {
277  CONSTInst *op = (*i)->to_Instruction()->to_CONSTInst();
278  bool equal;
279 
280  switch (inst->get_type()) {
281  case Type::IntTypeID:
282  equal = firstOp->get_Int() == op->get_Int();
283  break;
284  case Type::LongTypeID:
285  equal = firstOp->get_Long() == op->get_Long();
286  break;
287  case Type::FloatTypeID:
288  equal = firstOp->get_Float() == op->get_Float();
289  break;
290  case Type::DoubleTypeID:
291  equal = firstOp->get_Double() == op->get_Double();
292  break;
293  default:
294  assert(0);
295  return false;
296  }
297 
298  if (!equal)
299  return false;
300  }
301  return true;
302 }
303 
304 bool can_be_statically_evaluated(Instruction *inst) {
305  return inst->is_arithmetic()
306  || inst->get_opcode() == Instruction::CASTInstID;
307 }
308 
310  Method *M = JD.get_Method();
311 
312  workList.clear();
313  workList.insert(workList.begin(), M->begin(), M->end());
314 
315  inWorkList.clear();
316  for (Method::const_iterator i = workList.begin(), e = workList.end();
317  i != e; i++) {
318  inWorkList[*i] = true;
319  }
320 
321  constantOperands.clear();
322 
323  // The actual optimization steps are done within this loop.
324  while (!workList.empty()) {
325  Instruction *I = workList.front();
326  workList.pop_front();
327  inWorkList[I] = false;
328 
329  if (constantOperands[I] == I->op_size()) {
330  if (I->get_opcode() == Instruction::CONSTInstID) {
331  propagate(I);
332  } else if (can_be_statically_evaluated(I)) {
333  CONSTInst *foldedInst = foldInstruction(I);
334  if (foldedInst) {
335  STATISTICS(num_constant_expr++);
336  M->add_Instruction(foldedInst);
337  replace_by_constant(I, foldedInst, M);
338  }
339  } else if (I->get_opcode() == Instruction::PHIInstID
341  assert(I->op_size() > 0);
342  STATISTICS(num_constant_phis++);
343  CONSTInst *firstOp = I->get_operand(0)->to_Instruction()
344  ->to_CONSTInst();
345  replace_by_constant(I, firstOp, M);
346  }
347  }
348  }
349 
350  return true;
351 }
352 
353 // pass usage
359  return PU;
360 }
361 
362 Option<bool> ConstantPropagationPass::enabled("ConstantPropagationPass","compiler2: enable constant propagation (default = true)",true,::cacao::option::xx_root());
363 
364 // register pass
365 static PassRegistry<ConstantPropagationPass> X("ConstantPropagationPass");
366 
367 } // end namespace compiler2
368 } // end namespace jit
369 } // end namespace cacao
370 
371 
372 /*
373  * These are local overrides for various environment variables in Emacs.
374  * Please do not remove this and leave it at the end of the file, where
375  * Emacs will automagically detect them.
376  * ---------------------------------------------------------------------
377  * Local variables:
378  * mode: c++
379  * indent-tabs-mode: t
380  * c-basic-offset: 4
381  * tab-width: 4
382  * End:
383  * vim:noexpandtab:sw=4:ts=4:
384  */
Template specialization for NEGInstID.
#define STATISTICS(x)
Wrapper for statistics only code.
Definition: statistics.hpp:975
virtual Instruction * to_Instruction()
Definition: Value.hpp:88
#define STAT_REGISTER_SUBGROUP(var, name, description, group)
Register a statistics group and add it to a group.
Definition: statistics.hpp:974
Template specialization for DIVInstID.
virtual bool run(JITData &JD)
Run the Pass.
UserListTy::const_iterator user_begin() const
Definition: Value.hpp:72
virtual CONSTInst * to_CONSTInst()
Definition: Instruction.hpp:51
WorkListTy workList
This work list is used by the algorithm to store the instructions which have to be reconsidered...
u2 op
Definition: disass.cpp:129
T operator()(const T &lhs, const T &rhs) const
T operator()(const T &lhs, const T &rhs) const
T operator()(const T &lhs, const T &rhs) const
UserListTy::const_iterator user_end() const
Definition: Value.hpp:73
InstBoolMapTy inWorkList
will be used to look up whether an instruction is currently contained in the worklist to avoid insert...
InstIntMapTy constantOperands
used to track for each instruction the number of its operands which are already known to be constant ...
OperandListTy::const_iterator const_op_iterator
Definition: Instruction.hpp:82
void add_schedule_before()
Schedule before PassName.
Definition: PassUsage.hpp:127
InstID get_opcode() const
return the opcode of the instruction
CONSTInst * foldBinaryInst(BinaryInst *inst)
CONSTInst * foldUnaryInst(UnaryInst *inst)
T operator()(const T &lhs, const T &rhs) const
void replace_value(Value *v)
Replace this Value this the new one in all users.
Definition: Value.cpp:55
T unaryOperate(Instruction::InstID ID, const T &op)
function wrapper for UnaryOperation
Template specialization for MULInstID.
Template specialization for SUBInstID.
Template specialization for ADDInstID.
Stores the interdependencies of a pass.
Definition: PassUsage.hpp:55
virtual PassUsage & get_PassUsage(PassUsage &PA) const
Set the requirements for the pass.
#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
Instruction super class.
Definition: Instruction.hpp:75
bool has_only_constant_operands(Instruction *inst)
void add_Instruction(Instruction *I)
Add instructions to a Method.
Definition: MethodC2.cpp:82
MIIterator i
T operator()(const T &lhs, const T &rhs) const
InstructionListTy::const_iterator const_iterator
Definition: MethodC2.hpp:69
const_iterator end() const
Definition: MethodC2.hpp:147
bool can_be_statically_evaluated(Instruction *inst)
CONSTInst * foldInstruction(Instruction *inst)
MIIterator e
#define LOG(STMT)
Analogous to DEBUG.
Definition: logging.hpp:91
#define I(value)
Definition: codegen.c:279
CONSTInst * castOperate(CASTInst *inst, const T &op)
UnaryOperation function object class.
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
T binaryOperate(Instruction::InstID ID, const T &lhs, const T &rhs)
function wrapper for BinaryOperation
CONSTInst * foldCASTInst(CASTInst *inst)
static PassRegistry< BasicBlockSchedulingPass > X("BasicBlockSchedulingPass")
Nl nl
Definition: OStream.cpp:56
void replace_by_constant(Instruction *isnt, CONSTInst *c, Method *M)
void add_requires()
PassName is required.
Definition: PassUsage.hpp:78