/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Common Public License (CPL);
* 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/cpl1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
package org.jikesrvm.compilers.opt;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import org.jikesrvm.VM;
import org.jikesrvm.compilers.opt.ir.Move;
import org.jikesrvm.compilers.opt.ir.OPT_BasicBlock;
import org.jikesrvm.compilers.opt.ir.OPT_IR;
import org.jikesrvm.compilers.opt.ir.OPT_Instruction;
import org.jikesrvm.compilers.opt.ir.OPT_Operand;
import org.jikesrvm.compilers.opt.ir.OPT_OperandEnumeration;
import org.jikesrvm.compilers.opt.ir.OPT_Register;
import org.jikesrvm.compilers.opt.ir.OPT_RegisterOperand;
/**
* Perform local copy propagation for a factored basic block.
* Orthogonal to the copy propagation performed in OPT_Simple
* since here we use flow-sensitive analysis within a basic block.
*
* TODO: factor out common functionality in the various local propagation
* phases?
*/
public class OPT_LocalCopyProp extends OPT_CompilerPhase {
public final boolean shouldPerform(OPT_Options options) {
return options.LOCAL_COPY_PROP;
}
public final String getName() {
return "Local CopyProp";
}
public void reportAdditionalStats() {
VM.sysWrite(" ");
VM.sysWrite(container.counter1 / container.counter2 * 100, 2);
VM.sysWrite("% Infrequent BBs");
}
/**
* Return this instance of this phase. This phase contains no
* per-compilation instance fields.
* @param ir not used
* @return this
*/
public OPT_CompilerPhase newExecution(OPT_IR ir) {
return this;
}
/**
* Perform local constant propagation for a method.
*
* @param ir the IR to optimize
*/
public void perform(OPT_IR ir) {
// info is a mapping from OPT_Register to OPT_Register
HashMap<OPT_Register, OPT_Operand> info = new HashMap<OPT_Register, OPT_Operand>();
for (OPT_BasicBlock bb = ir.firstBasicBlockInCodeOrder(); bb != null; bb = bb.nextBasicBlockInCodeOrder()) {
if (bb.isEmpty()) continue;
container.counter2++;
if (bb.getInfrequent()) {
container.counter1++;
if (ir.options.FREQ_FOCUS_EFFORT) continue;
}
// iterate over all instructions in the basic block
for (OPT_Instruction s = bb.firstRealInstruction(),
sentinel = bb.lastInstruction(); s != sentinel; s = s.nextInstructionInCodeOrder()) {
if (!info.isEmpty()) {
// PROPAGATE COPIES
int numUses = s.getNumberOfUses();
if (numUses > 0) {
boolean didSomething = false;
for (OPT_OperandEnumeration e = s.getUses(); e.hasMoreElements();) {
OPT_Operand use = e.next();
if (use instanceof OPT_RegisterOperand) {
OPT_RegisterOperand rUse = (OPT_RegisterOperand) use;
OPT_Operand value = info.get(rUse.getRegister());
if (value != null) {
didSomething = true;
value = value.copy();
if (value instanceof OPT_RegisterOperand) {
// preserve program point specific typing!
((OPT_RegisterOperand) value).copyType(rUse);
}
s.replaceOperand(use, value);
}
}
}
if (didSomething) OPT_Simplifier.simplify(ir.regpool, s);
}
// KILL
boolean killPhysicals = s.isTSPoint() || s.operator().implicitDefs != 0;
// kill any physical registers
// TODO: use a better data structure for efficiency.
// I'm being lazy for now in the name of avoiding
// premature optimization.
if (killPhysicals) {
HashSet<OPT_Register> toRemove = new HashSet<OPT_Register>();
for (Map.Entry<OPT_Register, OPT_Operand> entry : info.entrySet()) {
OPT_Register eR = entry.getValue().
asRegister().getRegister();
if (killPhysicals && eR.isPhysical()) {
// delay the removal to avoid ConcurrentModification
// with iterator.
toRemove.add(entry.getKey());
}
}
// Now perform the removals.
for (final OPT_Register aToRemove : toRemove) {
info.remove(aToRemove);
}
}
for (OPT_OperandEnumeration e = s.getDefs(); e.hasMoreElements();) {
OPT_Operand def = e.next();
if (def != null && def.isRegister()) {
OPT_Register r = def.asRegister().getRegister();
info.remove(r);
// also must kill any registers mapped to r
// TODO: use a better data structure for efficiency.
// I'm being lazy for now in the name of avoiding
// premature optimization.
HashSet<OPT_Register> toRemove = new HashSet<OPT_Register>();
for (Map.Entry<OPT_Register, OPT_Operand> entry : info.entrySet()) {
OPT_Register eR = ((OPT_RegisterOperand) entry.getValue()).getRegister();
if (eR == r) {
// delay the removal to avoid ConcurrentModification
// with iterator.
toRemove.add(entry.getKey());
}
}
// Now perform the removals.
for (final OPT_Register register : toRemove) {
info.remove(register);
}
}
}
}
// GEN
if (Move.conforms(s)) {
OPT_Operand val = Move.getVal(s);
if (val.isRegister() && !val.asRegister().getRegister().isPhysical()) {
info.put(Move.getResult(s).getRegister(), val);
}
}
}
info.clear();
}
}
}