/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Eclipse Public License (EPL);
* You may not use this file except in compliance with the License. You
* may obtain a copy of the License at
*
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
package org.jikesrvm.compilers.opt.regalloc;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Map;
import org.jikesrvm.compilers.opt.DefUse;
import org.jikesrvm.compilers.opt.ir.BasicBlock;
import org.jikesrvm.compilers.opt.ir.Instruction;
import static org.jikesrvm.compilers.opt.ir.Operators.SPLIT;
import org.jikesrvm.compilers.opt.ir.Register;
import org.jikesrvm.compilers.opt.ir.Unary;
import org.jikesrvm.compilers.opt.ir.operand.Operand;
import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand;
import org.jikesrvm.compilers.opt.liveness.LiveAnalysis;
/**
* Utility to help coalesce registers.
*
* @see CoalesceMoves
*/
class Coalesce {
private final Map<Instruction, Integer> instNumbers;
Coalesce(Map<Instruction, Integer> instNumbers) {
this.instNumbers = instNumbers;
}
/**
* Attempt to coalesce register r2 into register r1. If this is legal,
* <ul>
* <li> rewrite all defs and uses of r2 as defs and uses of r1
* <li> update the liveness information
* <li> update the def-use chains
* </ul>
* <strong>PRECONDITION </strong> def-use chains must be computed and valid.
* @param live liveness information for the IR
* @param r1 the register that is the target of coalescing (i.e. the one that will remain)
* @param r2 the register that we want to coalesce (i.e. the one that will be "removed")
*
* @return {@code true} if the transformation succeeded, {@code false} otherwise.
*/
public boolean attempt(LiveAnalysis live, Register r1, Register r2) {
// make sure r1 and r2 are not simultaneously live
if (isLiveAtDef(r2, r1, live)) return false;
if (isLiveAtDef(r1, r2, live)) return false;
// Liveness is OK. Check for SPLIT operations
if (split(r1, r2)) return false;
// Don't merge a register with itself
if (r1 == r2) return false;
// Update liveness information to reflect the merge.
live.merge(r1, r2);
// Merge the defs.
for (Enumeration<RegisterOperand> e = DefUse.defs(r2); e.hasMoreElements();) {
RegisterOperand def = e.nextElement();
DefUse.removeDef(def);
def.setRegister(r1);
DefUse.recordDef(def);
}
// Merge the uses.
for (Enumeration<RegisterOperand> e = DefUse.uses(r2); e.hasMoreElements();) {
RegisterOperand use = e.nextElement();
DefUse.removeUse(use);
use.setRegister(r1);
DefUse.recordUse(use);
}
return true;
}
/**
* Is register r1 live at any def of register r2?
* <p>
* <strong>PRECONDITION </strong> def-use chains must be computed and valid.
*
* <p> Note: this implementation is not efficient. The liveness data
* structures must be re-designed to support this efficiently.
*
* @param r1 the register that is checked for liveness
* @param r2 the register whose defs are checked against liveness
* @param live live analysis phase
* @return {@code true} if the register is live at any point where the other
* register is defined
*/
private boolean isLiveAtDef(Register r1, Register r2, LiveAnalysis live) {
for (Iterator<LiveIntervalElement> e = live.iterateLiveIntervals(r1); e.hasNext();) {
LiveIntervalElement elem = e.next();
BasicBlock bb = elem.getBasicBlock();
Instruction begin = (elem.getBegin() == null) ? bb.firstInstruction() : elem.getBegin();
Instruction end = (elem.getEnd() == null) ? bb.lastInstruction() : elem.getEnd();
int low = instNumbers.get(begin);
int high = instNumbers.get(end);
for (Enumeration<RegisterOperand> defs = DefUse.defs(r2); defs.hasMoreElements();) {
Operand def = defs.nextElement();
int n = instNumbers.get(def.instruction);
if (n >= low && n < high) {
return true;
}
}
}
// no conflict was found.
return false;
}
/**
* Is there an instruction r1 = split r2 or r2 = split r1??
*
* @param r1 a register
* @param r2 another register
* @return {@code true} if there's an operation that's a split and
* has occurrences of both registers
*/
private boolean split(Register r1, Register r2) {
for (Enumeration<RegisterOperand> e = DefUse.defs(r1); e.hasMoreElements();) {
RegisterOperand def = e.nextElement();
Instruction s = def.instruction;
if (s.operator() == SPLIT) {
Operand rhs = Unary.getVal(s);
if (rhs.similar(def)) return true;
}
}
for (Enumeration<RegisterOperand> e = DefUse.defs(r2); e.hasMoreElements();) {
RegisterOperand def = e.nextElement();
Instruction s = def.instruction;
if (s.operator() == SPLIT) {
Operand rhs = Unary.getVal(s);
if (rhs.similar(def)) return true;
}
}
return false;
}
}