src/share/vm/opto/postaloc.cpp
Index
Unified diffs
Context diffs
Sdiffs
Patch
New
Old
Previous File
Next File
*** old/src/share/vm/opto/postaloc.cpp Tue Jan 20 09:42:51 2015
--- new/src/share/vm/opto/postaloc.cpp Tue Jan 20 09:42:51 2015
*** 261,284 ****
--- 261,270 ----
// Skip through all copies to the _value_ being used. Do not change from
// int to pointer. This attempts to jump through a chain of copies, where
// intermediate copies might be illegal, i.e., value is stored down to stack
// then reloaded BUT survives in a register the whole way.
Node *val = skip_copies(n->in(k));
if (val == x && nk_idx != 0 &&
regnd[nk_reg] != NULL && regnd[nk_reg] != x &&
_lrg_map.live_range_id(x) == _lrg_map.live_range_id(regnd[nk_reg])) {
// When rematerialzing nodes and stretching lifetimes, the
// allocator will reuse the original def for multidef LRG instead
// of the current reaching def because it can't know it's safe to
// do so. After allocation completes if they are in the same LRG
// then it should use the current reaching def instead.
n->set_req(k, regnd[nk_reg]);
blk_adjust += yank_if_dead(val, current_block, &value, ®nd);
val = skip_copies(n->in(k));
}
if (val == x) return blk_adjust; // No progress?
int n_regs = RegMask::num_registers(val->ideal_reg());
uint val_idx = _lrg_map.live_range_id(val);
OptoReg::Name val_reg = lrgs(val_idx).reg();
*** 380,389 ****
--- 366,463 ----
return true;
}
return false;
}
+ // The algorithms works as follows:
+ // We traverse the block top to bottom. possibly_merge_multidef() is invoked for every input edge k
+ // of the instruction n. We check to see if the input is a multidef lrg. If it is, we record the fact that we've
+ // seen a definition (coming as an input) and add that fact to the reg2defuse array. The array maps registers to their
+ // current reaching definitions (we track only multidefs though). With each definition we also associate the first
+ // instruction we saw use it. If we encounter the situation when we observe an def (an input) that is a part of the
+ // same lrg but is different from the previous seen def we merge the two with a MachMerge node and substitute
+ // all the uses that we've seen so far to use the merge. After that we keep replacing the new defs in the same lrg
+ // as they get encountered with the merge node and keep adding these defs to the merge inputs.
+ void PhaseChaitin::merge_multidefs() {
+ NOT_PRODUCT( Compile::TracePhase t3("mergeMultidefs", &_t_mergeMultidefs, TimeCompiler); )
+ ResourceMark rm;
+ // Keep track of the defs seen in registers and collect their uses in the block.
+ RegToDefUseMap reg2defuse(_max_reg, _max_reg, RegDefUse());
+ for (uint i = 0; i < _cfg.number_of_blocks(); i++) {
+ Block* block = _cfg.get_block(i);
+ for (uint j = 1; j < block->number_of_nodes(); j++) {
+ Node* n = block->get_node(j);
+ if (n->is_Phi()) continue;
+ for (uint k = 1; k < n->req(); k++) {
+ j += possibly_merge_multidef(n, k, block, reg2defuse);
+ }
+ // Null out the value produced by the instruction itself, since we're only interested in defs
+ // implicitly defined by the uses. We are actually interested in tracking only redefinitions
+ // of the multidef lrgs in the same register. For that matter it's enough to track changes in
+ // the base register only and ignore other effects of multi-register lrgs and fat projections.
+ // It is also ok to ignore defs coming from singledefs. After an implicit overwrite by one of
+ // those our register is guaranteed to be used by another lrg and we won't attempt to merge it.
+ uint lrg = _lrg_map.live_range_id(n);
+ if (lrg > 0 && lrgs(lrg).is_multidef()) {
+ OptoReg::Name reg = lrgs(lrg).reg();
+ reg2defuse.at(reg).clear();
+ }
+ }
+ // Clear reg->def->use tracking for the next block
+ for (int j = 0; j < reg2defuse.length(); j++) {
+ reg2defuse.at(j).clear();
+ }
+ }
+ }
+
+ int PhaseChaitin::possibly_merge_multidef(Node *n, uint k, Block *block, RegToDefUseMap& reg2defuse) {
+ int blk_adjust = 0;
+
+ uint lrg = _lrg_map.live_range_id(n->in(k));
+ if (lrg > 0 && lrgs(lrg).is_multidef()) {
+ OptoReg::Name reg = lrgs(lrg).reg();
+
+ Node* def = reg2defuse.at(reg).def();
+ if (def != NULL && lrg == _lrg_map.live_range_id(def) && def != n->in(k)) {
+ // Same lrg but different node, we have to merge.
+ MachMergeNode* merge;
+ if (def->is_MachMerge()) { // is it already a merge?
+ merge = def->as_MachMerge();
+ } else {
+ merge = new (C) MachMergeNode(def);
+
+ // Insert the merge node into the block before the first use.
+ uint use_index = block->find_node(reg2defuse.at(reg).first_use());
+ block->insert_node(merge, use_index++);
+
+ // Let the allocator know about the new node, use the same lrg
+ _lrg_map.extend(merge->_idx, lrg);
+ blk_adjust++;
+
+ // Fixup all the uses (there is at least one) that happened between the first
+ // use and before the current one.
+ for (; use_index < block->number_of_nodes(); use_index++) {
+ Node* use = block->get_node(use_index);
+ if (use == n) {
+ break;
+ }
+ use->replace_edge(def, merge);
+ }
+ }
+ if (merge->find_edge(n->in(k)) == -1) {
+ merge->add_req(n->in(k));
+ }
+ n->set_req(k, merge);
+ }
+
+ // update the uses
+ reg2defuse.at(reg).update(n->in(k), n);
+ }
+
+ return blk_adjust;
+ }
+
//------------------------------post_allocate_copy_removal---------------------
// Post-Allocation peephole copy removal. We do this in 1 pass over the
// basic blocks. We maintain a mapping of registers to Nodes (an array of
// Nodes indexed by machine register or stack slot number). NULL means that a
src/share/vm/opto/postaloc.cpp
Index
Unified diffs
Context diffs
Sdiffs
Patch
New
Old
Previous File
Next File