66 xhandler->add_predecessor(block); |
68 xhandler->add_predecessor(block); |
67 } |
69 } |
68 } |
70 } |
69 } |
71 } |
70 |
72 |
71 virtual void block_do(BlockBegin* block) { |
73 virtual void block_do(BlockBegin* block); |
72 // 1) find conditional expression |
74 |
73 // check if block ends with an If |
75 private: |
74 If* if_ = block->end()->as_If(); |
76 Value make_ifop(Value x, Instruction::Condition cond, Value y, Value tval, Value fval); |
75 if (if_ == NULL) return; |
77 }; |
76 |
78 |
77 // check if If works on int or object types |
79 void CE_Eliminator::block_do(BlockBegin* block) { |
78 // (we cannot handle If's working on long, float or doubles yet, |
80 // 1) find conditional expression |
79 // since IfOp doesn't support them - these If's show up if cmp |
81 // check if block ends with an If |
80 // operations followed by If's are eliminated) |
82 If* if_ = block->end()->as_If(); |
81 ValueType* if_type = if_->x()->type(); |
83 if (if_ == NULL) return; |
82 if (!if_type->is_int() && !if_type->is_object()) return; |
84 |
83 |
85 // check if If works on int or object types |
84 BlockBegin* t_block = if_->tsux(); |
86 // (we cannot handle If's working on long, float or doubles yet, |
85 BlockBegin* f_block = if_->fsux(); |
87 // since IfOp doesn't support them - these If's show up if cmp |
86 Instruction* t_cur = t_block->next(); |
88 // operations followed by If's are eliminated) |
87 Instruction* f_cur = f_block->next(); |
89 ValueType* if_type = if_->x()->type(); |
88 |
90 if (!if_type->is_int() && !if_type->is_object()) return; |
89 // one Constant may be present between BlockBegin and BlockEnd |
91 |
90 Value t_const = NULL; |
92 BlockBegin* t_block = if_->tsux(); |
91 Value f_const = NULL; |
93 BlockBegin* f_block = if_->fsux(); |
92 if (t_cur->as_Constant() != NULL && !t_cur->can_trap()) { |
94 Instruction* t_cur = t_block->next(); |
93 t_const = t_cur; |
95 Instruction* f_cur = f_block->next(); |
94 t_cur = t_cur->next(); |
96 |
95 } |
97 // one Constant may be present between BlockBegin and BlockEnd |
96 if (f_cur->as_Constant() != NULL && !f_cur->can_trap()) { |
98 Value t_const = NULL; |
97 f_const = f_cur; |
99 Value f_const = NULL; |
98 f_cur = f_cur->next(); |
100 if (t_cur->as_Constant() != NULL && !t_cur->can_trap()) { |
99 } |
101 t_const = t_cur; |
100 |
102 t_cur = t_cur->next(); |
101 // check if both branches end with a goto |
103 } |
102 Goto* t_goto = t_cur->as_Goto(); |
104 if (f_cur->as_Constant() != NULL && !f_cur->can_trap()) { |
103 if (t_goto == NULL) return; |
105 f_const = f_cur; |
104 Goto* f_goto = f_cur->as_Goto(); |
106 f_cur = f_cur->next(); |
105 if (f_goto == NULL) return; |
107 } |
106 |
108 |
107 // check if both gotos merge into the same block |
109 // check if both branches end with a goto |
108 BlockBegin* sux = t_goto->default_sux(); |
110 Goto* t_goto = t_cur->as_Goto(); |
109 if (sux != f_goto->default_sux()) return; |
111 if (t_goto == NULL) return; |
110 |
112 Goto* f_goto = f_cur->as_Goto(); |
111 // check if at least one word was pushed on sux_state |
113 if (f_goto == NULL) return; |
112 ValueStack* sux_state = sux->state(); |
114 |
113 if (sux_state->stack_size() <= if_->state()->stack_size()) return; |
115 // check if both gotos merge into the same block |
114 |
116 BlockBegin* sux = t_goto->default_sux(); |
115 // check if phi function is present at end of successor stack and that |
117 if (sux != f_goto->default_sux()) return; |
116 // only this phi was pushed on the stack |
118 |
117 Value sux_phi = sux_state->stack_at(if_->state()->stack_size()); |
119 // check if at least one word was pushed on sux_state |
118 if (sux_phi == NULL || sux_phi->as_Phi() == NULL || sux_phi->as_Phi()->block() != sux) return; |
120 ValueStack* sux_state = sux->state(); |
119 if (sux_phi->type()->size() != sux_state->stack_size() - if_->state()->stack_size()) return; |
121 if (sux_state->stack_size() <= if_->state()->stack_size()) return; |
120 |
122 |
121 // get the values that were pushed in the true- and false-branch |
123 // check if phi function is present at end of successor stack and that |
122 Value t_value = t_goto->state()->stack_at(if_->state()->stack_size()); |
124 // only this phi was pushed on the stack |
123 Value f_value = f_goto->state()->stack_at(if_->state()->stack_size()); |
125 Value sux_phi = sux_state->stack_at(if_->state()->stack_size()); |
124 |
126 if (sux_phi == NULL || sux_phi->as_Phi() == NULL || sux_phi->as_Phi()->block() != sux) return; |
125 // backend does not support floats |
127 if (sux_phi->type()->size() != sux_state->stack_size() - if_->state()->stack_size()) return; |
126 assert(t_value->type()->base() == f_value->type()->base(), "incompatible types"); |
128 |
127 if (t_value->type()->is_float_kind()) return; |
129 // get the values that were pushed in the true- and false-branch |
128 |
130 Value t_value = t_goto->state()->stack_at(if_->state()->stack_size()); |
129 // check that successor has no other phi functions but sux_phi |
131 Value f_value = f_goto->state()->stack_at(if_->state()->stack_size()); |
130 // this can happen when t_block or f_block contained additonal stores to local variables |
132 |
131 // that are no longer represented by explicit instructions |
133 // backend does not support floats |
132 for_each_phi_fun(sux, phi, |
134 assert(t_value->type()->base() == f_value->type()->base(), "incompatible types"); |
133 if (phi != sux_phi) return; |
135 if (t_value->type()->is_float_kind()) return; |
134 ); |
136 |
135 // true and false blocks can't have phis |
137 // check that successor has no other phi functions but sux_phi |
136 for_each_phi_fun(t_block, phi, return; ); |
138 // this can happen when t_block or f_block contained additonal stores to local variables |
137 for_each_phi_fun(f_block, phi, return; ); |
139 // that are no longer represented by explicit instructions |
138 |
140 for_each_phi_fun(sux, phi, |
139 // 2) substitute conditional expression |
141 if (phi != sux_phi) return; |
140 // with an IfOp followed by a Goto |
142 ); |
141 // cut if_ away and get node before |
143 // true and false blocks can't have phis |
142 Instruction* cur_end = if_->prev(block); |
144 for_each_phi_fun(t_block, phi, return; ); |
143 |
145 for_each_phi_fun(f_block, phi, return; ); |
144 // append constants of true- and false-block if necessary |
146 |
145 // clone constants because original block must not be destroyed |
147 // 2) substitute conditional expression |
146 assert((t_value != f_const && f_value != t_const) || t_const == f_const, "mismatch"); |
148 // with an IfOp followed by a Goto |
147 if (t_value == t_const) { |
149 // cut if_ away and get node before |
148 t_value = new Constant(t_const->type()); |
150 Instruction* cur_end = if_->prev(block); |
149 NOT_PRODUCT(t_value->set_printable_bci(if_->printable_bci())); |
151 |
150 cur_end = cur_end->set_next(t_value); |
152 // append constants of true- and false-block if necessary |
151 } |
153 // clone constants because original block must not be destroyed |
152 if (f_value == f_const) { |
154 assert((t_value != f_const && f_value != t_const) || t_const == f_const, "mismatch"); |
153 f_value = new Constant(f_const->type()); |
155 if (t_value == t_const) { |
154 NOT_PRODUCT(f_value->set_printable_bci(if_->printable_bci())); |
156 t_value = new Constant(t_const->type()); |
155 cur_end = cur_end->set_next(f_value); |
157 NOT_PRODUCT(t_value->set_printable_bci(if_->printable_bci())); |
156 } |
158 cur_end = cur_end->set_next(t_value); |
157 |
159 } |
158 // it is very unlikely that the condition can be statically decided |
160 if (f_value == f_const) { |
159 // (this was checked previously by the Canonicalizer), so always |
161 f_value = new Constant(f_const->type()); |
160 // append IfOp |
162 NOT_PRODUCT(f_value->set_printable_bci(if_->printable_bci())); |
161 Value result = new IfOp(if_->x(), if_->cond(), if_->y(), t_value, f_value); |
163 cur_end = cur_end->set_next(f_value); |
|
164 } |
|
165 |
|
166 Value result = make_ifop(if_->x(), if_->cond(), if_->y(), t_value, f_value); |
|
167 assert(result != NULL, "make_ifop must return a non-null instruction"); |
|
168 if (!result->is_linked() && result->can_be_linked()) { |
162 NOT_PRODUCT(result->set_printable_bci(if_->printable_bci())); |
169 NOT_PRODUCT(result->set_printable_bci(if_->printable_bci())); |
163 cur_end = cur_end->set_next(result); |
170 cur_end = cur_end->set_next(result); |
164 |
171 } |
165 // append Goto to successor |
172 |
166 ValueStack* state_before = if_->is_safepoint() ? if_->state_before() : NULL; |
173 // append Goto to successor |
167 Goto* goto_ = new Goto(sux, state_before, if_->is_safepoint() || t_goto->is_safepoint() || f_goto->is_safepoint()); |
174 ValueStack* state_before = if_->is_safepoint() ? if_->state_before() : NULL; |
168 |
175 Goto* goto_ = new Goto(sux, state_before, if_->is_safepoint() || t_goto->is_safepoint() || f_goto->is_safepoint()); |
169 // prepare state for Goto |
176 |
170 ValueStack* goto_state = if_->state(); |
177 // prepare state for Goto |
171 while (sux_state->scope() != goto_state->scope()) { |
178 ValueStack* goto_state = if_->state(); |
172 goto_state = goto_state->caller_state(); |
179 while (sux_state->scope() != goto_state->scope()) { |
173 assert(goto_state != NULL, "states do not match up"); |
180 goto_state = goto_state->caller_state(); |
174 } |
181 assert(goto_state != NULL, "states do not match up"); |
175 goto_state = goto_state->copy(ValueStack::StateAfter, goto_state->bci()); |
182 } |
176 goto_state->push(result->type(), result); |
183 goto_state = goto_state->copy(ValueStack::StateAfter, goto_state->bci()); |
177 assert(goto_state->is_same(sux_state), "states must match now"); |
184 goto_state->push(result->type(), result); |
178 goto_->set_state(goto_state); |
185 assert(goto_state->is_same(sux_state), "states must match now"); |
179 |
186 goto_->set_state(goto_state); |
180 cur_end = cur_end->set_next(goto_, goto_state->bci()); |
187 |
181 |
188 cur_end = cur_end->set_next(goto_, goto_state->bci()); |
182 // Adjust control flow graph |
189 |
183 BlockBegin::disconnect_edge(block, t_block); |
190 // Adjust control flow graph |
184 BlockBegin::disconnect_edge(block, f_block); |
191 BlockBegin::disconnect_edge(block, t_block); |
185 if (t_block->number_of_preds() == 0) { |
192 BlockBegin::disconnect_edge(block, f_block); |
186 BlockBegin::disconnect_edge(t_block, sux); |
193 if (t_block->number_of_preds() == 0) { |
187 } |
194 BlockBegin::disconnect_edge(t_block, sux); |
188 adjust_exception_edges(block, t_block); |
195 } |
189 if (f_block->number_of_preds() == 0) { |
196 adjust_exception_edges(block, t_block); |
190 BlockBegin::disconnect_edge(f_block, sux); |
197 if (f_block->number_of_preds() == 0) { |
191 } |
198 BlockBegin::disconnect_edge(f_block, sux); |
192 adjust_exception_edges(block, f_block); |
199 } |
193 |
200 adjust_exception_edges(block, f_block); |
194 // update block end |
201 |
195 block->set_end(goto_); |
202 // update block end |
196 |
203 block->set_end(goto_); |
197 // substitute the phi if possible |
204 |
198 if (sux_phi->as_Phi()->operand_count() == 1) { |
205 // substitute the phi if possible |
199 assert(sux_phi->as_Phi()->operand_at(0) == result, "screwed up phi"); |
206 if (sux_phi->as_Phi()->operand_count() == 1) { |
200 sux_phi->set_subst(result); |
207 assert(sux_phi->as_Phi()->operand_at(0) == result, "screwed up phi"); |
201 _has_substitution = true; |
208 sux_phi->set_subst(result); |
202 } |
209 _has_substitution = true; |
203 |
210 } |
204 // 3) successfully eliminated a conditional expression |
211 |
205 _cee_count++; |
212 // 3) successfully eliminated a conditional expression |
206 if (PrintCEE) { |
213 _cee_count++; |
207 tty->print_cr("%d. CEE in B%d (B%d B%d)", cee_count(), block->block_id(), t_block->block_id(), f_block->block_id()); |
214 if (PrintCEE) { |
208 } |
215 tty->print_cr("%d. CEE in B%d (B%d B%d)", cee_count(), block->block_id(), t_block->block_id(), f_block->block_id()); |
209 |
216 tty->print_cr("%d. IfOp in B%d", ifop_count(), block->block_id()); |
210 _hir->verify(); |
217 } |
211 } |
218 |
212 }; |
219 _hir->verify(); |
213 |
220 } |
|
221 |
|
222 Value CE_Eliminator::make_ifop(Value x, Instruction::Condition cond, Value y, Value tval, Value fval) { |
|
223 if (!OptimizeIfOps) { |
|
224 return new IfOp(x, cond, y, tval, fval); |
|
225 } |
|
226 |
|
227 tval = tval->subst(); |
|
228 fval = fval->subst(); |
|
229 if (tval == fval) { |
|
230 _ifop_count++; |
|
231 return tval; |
|
232 } |
|
233 |
|
234 x = x->subst(); |
|
235 y = y->subst(); |
|
236 |
|
237 Constant* y_const = y->as_Constant(); |
|
238 if (y_const != NULL) { |
|
239 IfOp* x_ifop = x->as_IfOp(); |
|
240 if (x_ifop != NULL) { // x is an ifop, y is a constant |
|
241 Constant* x_tval_const = x_ifop->tval()->subst()->as_Constant(); |
|
242 Constant* x_fval_const = x_ifop->fval()->subst()->as_Constant(); |
|
243 |
|
244 if (x_tval_const != NULL && x_fval_const != NULL) { |
|
245 Instruction::Condition x_ifop_cond = x_ifop->cond(); |
|
246 |
|
247 Constant::CompareResult t_compare_res = x_tval_const->compare(cond, y_const); |
|
248 Constant::CompareResult f_compare_res = x_fval_const->compare(cond, y_const); |
|
249 |
|
250 guarantee(t_compare_res != Constant::not_comparable && f_compare_res != Constant::not_comparable, "incomparable constants in IfOp"); |
|
251 |
|
252 Value new_tval = t_compare_res == Constant::cond_true ? tval : fval; |
|
253 Value new_fval = f_compare_res == Constant::cond_true ? tval : fval; |
|
254 |
|
255 _ifop_count++; |
|
256 if (new_tval == new_fval) { |
|
257 return new_tval; |
|
258 } else { |
|
259 return new IfOp(x_ifop->x(), x_ifop_cond, x_ifop->y(), new_tval, new_fval); |
|
260 } |
|
261 } |
|
262 } else { |
|
263 Constant* x_const = x->as_Constant(); |
|
264 if (x_const != NULL) { // x and y are constants |
|
265 Constant::CompareResult x_compare_res = x_const->compare(cond, y_const); |
|
266 guarantee(x_compare_res != Constant::not_comparable, "incomparable constants in IfOp"); |
|
267 |
|
268 _ifop_count++; |
|
269 return x_compare_res == Constant::cond_true ? tval : fval; |
|
270 } |
|
271 } |
|
272 } |
|
273 return new IfOp(x, cond, y, tval, fval); |
|
274 } |
214 |
275 |
215 void Optimizer::eliminate_conditional_expressions() { |
276 void Optimizer::eliminate_conditional_expressions() { |
216 // find conditional expressions & replace them with IfOps |
277 // find conditional expressions & replace them with IfOps |
217 CE_Eliminator ce(ir()); |
278 CE_Eliminator ce(ir()); |
218 } |
279 } |
219 |
|
220 |
280 |
221 class BlockMerger: public BlockClosure { |
281 class BlockMerger: public BlockClosure { |
222 private: |
282 private: |
223 IR* _hir; |
283 IR* _hir; |
224 int _merge_count; // the number of block pairs successfully merged |
284 int _merge_count; // the number of block pairs successfully merged |