/*
* 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;
import static org.jikesrvm.compilers.opt.ir.Operators.PHI;
import java.util.Enumeration;
import org.jikesrvm.VM;
import org.jikesrvm.classloader.TypeReference;
import org.jikesrvm.compilers.opt.ir.BasicBlock;
import org.jikesrvm.compilers.opt.ir.IR;
import org.jikesrvm.compilers.opt.ir.Instruction;
import org.jikesrvm.compilers.opt.ir.InstructionEnumeration;
import org.jikesrvm.compilers.opt.ir.OperandEnumeration;
import org.jikesrvm.compilers.opt.ir.Register;
import org.jikesrvm.compilers.opt.ir.RegisterOperandEnumeration;
import org.jikesrvm.compilers.opt.ir.operand.Operand;
import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand;
import org.vmmagic.pragma.NoInline;
/**
* This class computes du-lists and associated information.
*
* <P> Note: DU operands are stored on the USE lists, but not the DEF
* lists.
*/
public final class DefUse {
static final boolean DEBUG = false;
static final boolean TRACE_DU_ACTIONS = false;
static final boolean SUPRESS_DU_FOR_PHYSICALS = true;
/**
* Clear defList, useList for an IR.
*
* @param ir the IR in question
*/
public static void clearDU(IR ir) {
for (Register reg = ir.regpool.getFirstSymbolicRegister(); reg != null; reg = reg.getNext()) {
reg.defList = null;
reg.useList = null;
reg.scratch = -1;
reg.clearSeenUse();
}
for (Enumeration<Register> e = ir.regpool.getPhysicalRegisterSet().enumerateAll(); e.hasMoreElements();) {
Register reg = e.nextElement();
reg.defList = null;
reg.useList = null;
reg.scratch = -1;
reg.clearSeenUse();
}
if (TRACE_DU_ACTIONS || DEBUG) {
VM.sysWrite("Cleared DU\n");
}
}
/**
* Compute the register list and def-use lists for a method.
*
* @param ir the IR in question
*/
@NoInline
public static void computeDU(IR ir) {
// Clear old register list (if any)
clearDU(ir);
// Create register defList and useList
for (Instruction instr = ir.firstInstructionInCodeOrder(); instr != null; instr =
instr.nextInstructionInCodeOrder()) {
OperandEnumeration defs = instr.getPureDefs();
OperandEnumeration uses = instr.getUses();
while (defs.hasMoreElements()) {
Operand op = defs.next();
if (op instanceof RegisterOperand) {
RegisterOperand rop = (RegisterOperand) op;
recordDef(rop);
}
} // for ( defs = ... )
while (uses.hasMoreElements()) {
Operand op = uses.next();
if (op instanceof RegisterOperand) {
RegisterOperand rop = (RegisterOperand) op;
recordUse(rop);
}
} // for ( uses = ... )
} // for ( instr = ... )
// Remove any symbloic registers with no uses/defs from
// the register pool. We'll waste analysis time keeping them around.
Register next;
for (Register reg = ir.regpool.getFirstSymbolicRegister(); reg != null; reg = next) {
next = reg.getNext();
if (reg.defList == null && reg.useList == null) {
if (DEBUG) {
VM.sysWrite("Removing " + reg + " from the register pool\n");
}
ir.regpool.removeRegister(reg);
}
}
}
/**
* Record a use of a register
* @param regOp the operand that uses the register
*/
public static void recordUse(RegisterOperand regOp) {
Register reg = regOp.getRegister();
regOp.append(reg.useList);
reg.useList = regOp;
reg.useCount++;
}
/**
* Record a def/use of a register
* TODO: For now we just pretend this is a use!!!!
*
* @param regOp the operand that uses the register
*/
public static void recordDefUse(RegisterOperand regOp) {
Register reg = regOp.getRegister();
if (SUPRESS_DU_FOR_PHYSICALS && reg.isPhysical()) return;
regOp.append(reg.useList);
reg.useList = regOp;
}
/**
* Record a def of a register
* @param regOp the operand that uses the register
*/
public static void recordDef(RegisterOperand regOp) {
Register reg = regOp.getRegister();
if (SUPRESS_DU_FOR_PHYSICALS && reg.isPhysical()) return;
regOp.append(reg.defList);
reg.defList = regOp;
}
/**
* Record that a use of a register no longer applies
* @param regOp the operand that uses the register
*/
public static void removeUse(RegisterOperand regOp) {
Register reg = regOp.getRegister();
if (SUPRESS_DU_FOR_PHYSICALS && reg.isPhysical()) return;
if (regOp == reg.useList) {
reg.useList = reg.useList.getNext();
} else {
RegisterOperand prev = reg.useList;
RegisterOperand curr = prev.getNext();
while (curr != regOp) {
prev = curr;
curr = curr.getNext();
}
prev.setNext(curr.getNext());
}
reg.useCount--;
if (DEBUG) {
VM.sysWrite("removed a use " + regOp.instruction + "\n");
printUses(reg);
}
}
/**
* Record that a def of a register no longer applies
* @param regOp the operand that uses the register
*/
public static void removeDef(RegisterOperand regOp) {
Register reg = regOp.getRegister();
if (SUPRESS_DU_FOR_PHYSICALS && reg.isPhysical()) return;
if (regOp == reg.defList) {
reg.defList = reg.defList.getNext();
} else {
RegisterOperand prev = reg.defList;
RegisterOperand curr = prev.getNext();
while (curr != regOp) {
prev = curr;
curr = curr.getNext();
}
prev.setNext(curr.getNext());
}
if (DEBUG) {
VM.sysWrite("removed a def " + regOp.instruction + "\n");
printDefs(reg);
}
}
/**
* This code changes the use in <code>origRegOp</code> to use
* the use in <code>newRegOp</code>.
*
* <p> If the type of <code>origRegOp</code> is not a reference, but the
* type of <code>newRegOp</code> is a reference, we need to update
* <code>origRegOp</code> to be a reference.
* Otherwise, the GC map code will be incorrect. -- Mike Hind
* @param origRegOp the register operand to change
* @param newRegOp the register operand to use for the change
*/
public static void transferUse(RegisterOperand origRegOp, RegisterOperand newRegOp) {
if (VM.VerifyAssertions) {
VM._assert(origRegOp.getRegister().getType() == newRegOp.getRegister().getType());
}
Instruction inst = origRegOp.instruction;
if (DEBUG) {
VM.sysWrite("Transfering a use of " + origRegOp + " in " + inst + " to " + newRegOp + "\n");
}
removeUse(origRegOp);
// check to see if the regOp type is NOT a ref, but the newRegOp type
// is a reference. This can occur because of magic calls.
if (!origRegOp.getType().isReferenceType() && newRegOp.getType().isReferenceType()) {
// clone the newRegOp object and use it to replace the regOp object
RegisterOperand copiedRegOp = (RegisterOperand) newRegOp.copy();
inst.replaceOperand(origRegOp, copiedRegOp);
recordUse(copiedRegOp);
} else {
// just copy the register
origRegOp.setRegister(newRegOp.getRegister());
if (newRegOp.getType() != TypeReference.ObjectReference &&
!newRegOp.getType().isUnboxedType() && !origRegOp.isPreciseType()) {
// copy type information from new to orig unless its an unboxed type
// (we don't want to copy type information for unboxed types as it is
// likely the result of inlining new) or the type of the original is
// precise
origRegOp.copyType(newRegOp);
}
recordUse(origRegOp);
}
if (DEBUG) {
printUses(origRegOp.getRegister());
printUses(newRegOp.getRegister());
}
}
/**
* Remove an instruction and update register lists.
*/
public static void removeInstructionAndUpdateDU(Instruction s) {
for (OperandEnumeration e = s.getPureDefs(); e.hasMoreElements();) {
Operand op = e.next();
if (op instanceof RegisterOperand) {
removeDef((RegisterOperand) op);
}
}
for (OperandEnumeration e = s.getUses(); e.hasMoreElements();) {
Operand op = e.next();
if (op instanceof RegisterOperand) {
removeUse((RegisterOperand) op);
}
}
s.remove();
}
/**
* Update register lists to account for the effect of a new
* instruction s
*/
public static void updateDUForNewInstruction(Instruction s) {
for (OperandEnumeration e = s.getPureDefs(); e.hasMoreElements();) {
Operand op = e.next();
if (op instanceof RegisterOperand) {
recordDef((RegisterOperand) op);
}
}
for (OperandEnumeration e = s.getUses(); e.hasMoreElements();) {
Operand op = e.next();
if (op instanceof RegisterOperand) {
recordUse((RegisterOperand) op);
}
}
}
/**
* Replace an instruction and update register lists.
*/
public static void replaceInstructionAndUpdateDU(Instruction oldI, Instruction newI) {
oldI.insertBefore(newI);
removeInstructionAndUpdateDU(oldI);
updateDUForNewInstruction(newI);
}
/**
* Enumerate all operands that use a given register.
*/
public static RegisterOperandEnumeration uses(Register reg) {
return new RegOpListWalker(reg.useList);
}
/**
* Enumerate all operands that def a given register.
*/
public static RegisterOperandEnumeration defs(Register reg) {
return new RegOpListWalker(reg.defList);
}
/**
* Does a given register have exactly one use?
*/
static boolean exactlyOneUse(Register reg) {
return (reg.useList != null) && (reg.useList.getNext() == null);
}
/**
* Print all the instructions that def a register.
* @param reg
*/
static void printDefs(Register reg) {
VM.sysWrite("Definitions of " + reg + '\n');
for (RegisterOperandEnumeration e = defs(reg); e.hasMoreElements();) {
VM.sysWrite("\t" + e.next().instruction + "\n");
}
}
/**
* Print all the instructions that usea register.
* @param reg
*/
static void printUses(Register reg) {
VM.sysWrite("Uses of " + reg + '\n');
for (RegisterOperandEnumeration e = uses(reg); e.hasMoreElements();) {
VM.sysWrite("\t" + e.next().instruction + "\n");
}
}
/**
* Recompute <code> isSSA </code> for all registers by traversing register
* list.
* NOTE: the DU MUST be computed BEFORE calling this function
*
* @param ir the IR in question
*/
public static void recomputeSSA(IR ir) {
// Use register /ist to enumerate register objects (FAST)
for (Register reg = ir.regpool.getFirstSymbolicRegister(); reg != null; reg = reg.getNext()) {
// Set isSSA = true iff reg has exactly one static definition.
reg.putSSA((reg.defList != null && reg.defList.getNext() == null));
}
}
/**
* Merge register reg2 into register reg1.
* Remove reg2 from the DU information
*/
public static void mergeRegisters(IR ir, Register reg1, Register reg2) {
RegisterOperand lastOperand;
if (reg1 == reg2) {
return;
}
if (DEBUG) {
VM.sysWrite("Merging " + reg2 + " into " + reg1 + "\n");
printDefs(reg2);
printUses(reg2);
printDefs(reg1);
printUses(reg1);
}
// first loop through defs of reg2 (currently, there will only be one def)
lastOperand = null;
for (RegisterOperand def = reg2.defList; def != null; lastOperand = def, def = def.getNext()) {
// Change def to refer to reg1 instead
def.setRegister(reg1);
// Track lastOperand
lastOperand = def;
}
if (lastOperand != null) {
// Set reg1.defList = concat(reg2.defList, reg1.deflist)
lastOperand.setNext(reg1.defList);
reg1.defList = reg2.defList;
}
// now loop through uses
lastOperand = null;
for (RegisterOperand use = reg2.useList; use != null; use = use.getNext()) {
// Change use to refer to reg1 instead
use.setRegister(reg1);
// Track lastOperand
lastOperand = use;
}
if (lastOperand != null) {
// Set reg1.useList = concat(reg2.useList, reg1.uselist)
lastOperand.setNext(reg1.useList);
reg1.useList = reg2.useList;
}
// Remove reg2 from RegisterPool
ir.regpool.removeRegister(reg2);
if (DEBUG) {
VM.sysWrite("Merge complete\n");
printDefs(reg1);
printUses(reg1);
}
}
/**
* Recompute spansBasicBlock flags for all registers.
*
* @param ir the IR in question
*/
public static void recomputeSpansBasicBlock(IR ir) {
// clear fields
for (Register reg = ir.regpool.getFirstSymbolicRegister(); reg != null; reg = reg.getNext()) {
reg.scratch = -1;
reg.clearSpansBasicBlock();
}
// iterate over the basic blocks
for (BasicBlock bb = ir.firstBasicBlockInCodeOrder(); bb != null; bb = bb.nextBasicBlockInCodeOrder()) {
int bbNum = bb.getNumber();
// enumerate the instructions in the basic block
for (InstructionEnumeration e = bb.forwardRealInstrEnumerator(); e.hasMoreElements();) {
Instruction inst = e.next();
// check each Operand in the instruction
for (OperandEnumeration ops = inst.getOperands(); ops.hasMoreElements();) {
Operand op = ops.next();
if (op instanceof RegisterOperand) {
Register reg = ((RegisterOperand) op).getRegister();
if (reg.isPhysical()) {
continue;
}
if (reg.spansBasicBlock()) {
continue;
}
if (seenInDifferentBlock(reg, bbNum)) {
reg.setSpansBasicBlock();
continue;
}
if (inst.operator() == PHI) {
reg.setSpansBasicBlock();
continue;
}
logAppearance(reg, bbNum);
}
}
}
}
}
/**
* Mark that we have seen a register in a particular
* basic block, and whether we saw a use
*
* @param reg the register
* @param bbNum the number of the basic block
*/
private static void logAppearance(Register reg, int bbNum) {
reg.scratch = bbNum;
}
/**
* Have we seen this register in a different basic block?
*
* @param reg the register
* @param bbNum the number of the basic block
*/
private static boolean seenInDifferentBlock(Register reg, int bbNum) {
int bb = reg.scratch;
return (bb != -1) && (bb != bbNum);
}
/**
* Utility class to encapsulate walking a use/def list.
*/
private static final class RegOpListWalker implements RegisterOperandEnumeration {
private RegisterOperand current;
RegOpListWalker(RegisterOperand start) {
current = start;
}
public boolean hasMoreElements() {
return current != null;
}
public RegisterOperand nextElement() {
return next();
}
public RegisterOperand next() {
if (current == null) raiseNoSuchElementException();
RegisterOperand tmp = current;
current = current.getNext();
return tmp;
}
@NoInline
private static void raiseNoSuchElementException() {
throw new java.util.NoSuchElementException("RegOpListWalker");
}
}
}