use of org.jikesrvm.compilers.opt.ir.operand.ConstantOperand in project JikesRVM by JikesRVM.
the class LeaveSSA method scheduleCopies.
/**
* Record pending copy operations needed to insert at the end of a basic
* block.<p>
*
* TODO: this procedure is getting long and ugly. Rewrite or refactor
* it.
* @param bb the basic block to process
* @param live valid liveness information for the IR
*/
private void scheduleCopies(BasicBlock bb, LiveAnalysis live) {
if (DEBUG)
VM.sysWriteln("scheduleCopies: " + bb);
// compute out liveness from information in LiveAnalysis
LiveSet out = new LiveSet();
for (Enumeration<BasicBlock> outBlocks = bb.getOut(); outBlocks.hasMoreElements(); ) {
BasicBlock ob = outBlocks.nextElement();
LiveAnalysis.BBLiveElement le = live.getLiveInfo(ob);
out.add(le.getIn());
}
// usedByAnother represents the set of registers that appear on the
// left-hand side of subsequent phi nodes. This is important, since
// we be careful to order copies if the same register appears as the
// source and dest of copies in the same basic block.
HashSet<Register> usedByAnother = new HashSet<Register>(4);
// for each basic block successor b of bb, if we make a block on the
// critical edge bb->b, then store this critical block.
HashMap<BasicBlock, BasicBlock> criticalBlocks = new HashMap<BasicBlock, BasicBlock>(4);
// For each critical basic block b in which we are inserting copies: return the
// mapping of registers to names implied by the copies that have
// already been inserted into b.
HashMap<BasicBlock, HashMap<Register, Register>> currentNames = new HashMap<BasicBlock, HashMap<Register, Register>>(4);
// Additionally store the current names for the current basic block bb.
HashMap<Register, Register> bbNames = new HashMap<Register, Register>(4);
// copySet is a linked-list of copies we need to insert in this block.
final LinkedList<Copy> copySet = new LinkedList<Copy>();
/* Worklist is actually used like a stack - should we make this an Stack ?? */
final LinkedList<Copy> workList = new LinkedList<Copy>();
// collect copies required in this block. These copies move
// the appropriate rval into the lval of each phi node in
// control children of the current block.
Enumeration<BasicBlock> e = bb.getOut();
while (e.hasMoreElements()) {
BasicBlock bbs = e.nextElement();
if (bbs.isExit())
continue;
for (Instruction phi = bbs.firstInstruction(); phi != bbs.lastInstruction(); phi = phi.nextInstructionInCodeOrder()) {
if (phi.operator() != PHI)
continue;
for (int index = 0; index < Phi.getNumberOfPreds(phi); index++) {
if (Phi.getPred(phi, index).block != bb)
continue;
Operand rval = Phi.getValue(phi, index);
if (rval.isRegister() && Phi.getResult(phi).asRegister().getRegister() == rval.asRegister().getRegister()) {
continue;
}
Copy c = new Copy(phi, index);
copySet.add(0, c);
if (c.source instanceof RegisterOperand) {
Register r = c.source.asRegister().getRegister();
usedByAnother.add(r);
}
}
}
}
// the set of needed copies.
for (Iterator<Copy> copySetIter = copySet.iterator(); copySetIter.hasNext(); ) {
Copy c = copySetIter.next();
if (!usedByAnother.contains(c.destination.getRegister())) {
workList.add(0, c);
copySetIter.remove();
}
}
// while there is any more work to do.
while (!workList.isEmpty() || !copySet.isEmpty()) {
// while there are copies that can be correctly inserted.
while (!workList.isEmpty()) {
Copy c = workList.remove(0);
Register r = c.destination.getRegister();
TypeReference tt = c.destination.getType();
if (VM.VerifyAssertions && tt == null) {
tt = TypeReference.Int;
VM.sysWriteln("SSA, warning: null type in " + c.destination);
}
Register rr = null;
if (c.source.isRegister())
rr = c.source.asRegister().getRegister();
boolean shouldSplitBlock = !c.phi.getBasicBlock().isExceptionHandlerBasicBlock() && ((ir.options.SSA_SPLITBLOCK_TO_AVOID_RENAME && out.contains(r)) || (rr != null && ir.options.SSA_SPLITBLOCK_FOR_LOCAL_LIVE && usedBelowCopy(bb, rr)));
if (ir.options.SSA_SPLITBLOCK_INTO_INFREQUENT) {
if (!bb.getInfrequent() && c.phi.getBasicBlock().getInfrequent() && !c.phi.getBasicBlock().isExceptionHandlerBasicBlock()) {
shouldSplitBlock = true;
}
}
// new name.
if (out.contains(r) && !shouldSplitBlock) {
if (!globalRenamePhis.contains(r)) {
Register t = ir.regpool.getReg(r);
Instruction save = SSA.makeMoveInstruction(ir, t, r, tt);
if (DEBUG) {
VM.sysWriteln("Inserting " + save + " before " + c.phi + " in " + c.phi.getBasicBlock());
}
c.phi.insertAfter(save);
globalRenamePhis.add(r);
globalRenameTable.add(save);
}
}
Instruction ci = null;
// insert copy operation required to remove phi
if (c.source instanceof ConstantOperand) {
if (c.source instanceof UnreachableOperand) {
ci = null;
} else {
ci = SSA.makeMoveInstruction(ir, r, (ConstantOperand) c.source);
}
} else if (c.source instanceof RegisterOperand) {
if (shouldSplitBlock) {
if (DEBUG)
VM.sysWriteln("splitting edge: " + bb + "->" + c.phi.getBasicBlock());
BasicBlock criticalBlock = criticalBlocks.get(c.phi.getBasicBlock());
if (criticalBlock == null) {
criticalBlock = IRTools.makeBlockOnEdge(bb, c.phi.getBasicBlock(), ir);
if (c.phi.getBasicBlock().getInfrequent()) {
criticalBlock.setInfrequent();
}
splitSomeBlock = true;
criticalBlocks.put(c.phi.getBasicBlock(), criticalBlock);
HashMap<Register, Register> newNames = new HashMap<Register, Register>(4);
currentNames.put(criticalBlock, newNames);
}
Register sr = c.source.asRegister().getRegister();
HashMap<Register, Register> criticalBlockNames = currentNames.get(criticalBlock);
Register nameForSR = criticalBlockNames.get(sr);
if (nameForSR == null) {
nameForSR = bbNames.get(sr);
if (nameForSR == null)
nameForSR = sr;
}
if (DEBUG)
VM.sysWriteln("dest(r): " + r);
if (DEBUG)
VM.sysWriteln("sr: " + sr + ", nameForSR: " + nameForSR);
ci = SSA.makeMoveInstruction(ir, r, nameForSR, tt);
criticalBlockNames.put(sr, r);
criticalBlock.appendInstructionRespectingTerminalBranch(ci);
} else {
Register sr = c.source.asRegister().getRegister();
Register nameForSR = bbNames.get(sr);
if (nameForSR == null)
nameForSR = sr;
if (DEBUG)
VM.sysWriteln("not splitting edge: " + bb + "->" + c.phi.getBasicBlock());
if (DEBUG)
VM.sysWriteln("dest(r): " + r);
if (DEBUG)
VM.sysWriteln("sr: " + sr + ", nameForSR: " + nameForSR);
ci = SSA.makeMoveInstruction(ir, r, nameForSR, tt);
bbNames.put(sr, r);
SSA.addAtEnd(ir, bb, ci, c.phi.getBasicBlock().isExceptionHandlerBasicBlock());
}
// ugly hack: having already added ci; set ci to null to skip remaining code;
ci = null;
} else {
throw new OptimizingCompilerException("Unexpected phi operand " + c.source + " encountered during SSA teardown", true);
}
if (ci != null) {
if (shouldSplitBlock) {
if (DEBUG)
VM.sysWriteln("splitting edge: " + bb + "->" + c.phi.getBasicBlock());
BasicBlock criticalBlock = criticalBlocks.get(c.phi.getBasicBlock());
if (criticalBlock == null) {
criticalBlock = IRTools.makeBlockOnEdge(bb, c.phi.getBasicBlock(), ir);
if (c.phi.getBasicBlock().getInfrequent()) {
criticalBlock.setInfrequent();
}
splitSomeBlock = true;
criticalBlocks.put(c.phi.getBasicBlock(), criticalBlock);
HashMap<Register, Register> newNames = new HashMap<Register, Register>(4);
currentNames.put(criticalBlock, newNames);
}
criticalBlock.appendInstructionRespectingTerminalBranch(ci);
} else {
SSA.addAtEnd(ir, bb, ci, c.phi.getBasicBlock().isExceptionHandlerBasicBlock());
}
}
// current copy to the work list.
if (c.source instanceof RegisterOperand) {
Register saved = c.source.asRegister().getRegister();
Iterator<Copy> copySetIter = copySet.iterator();
while (copySetIter.hasNext()) {
Copy cc = copySetIter.next();
if (cc.destination.asRegister().getRegister() == saved) {
workList.add(0, cc);
copySetIter.remove();
}
}
}
}
// safely overwritten. so, add that copy to the work list.
if (!copySet.isEmpty()) {
Copy c = copySet.remove(0);
Register tt = ir.regpool.getReg(c.destination.getRegister());
SSA.addAtEnd(ir, bb, SSA.makeMoveInstruction(ir, tt, c.destination.getRegister(), c.destination.getType()), c.phi.getBasicBlock().isExceptionHandlerBasicBlock());
bbNames.put(c.destination.getRegister(), tt);
workList.add(0, c);
}
}
}
use of org.jikesrvm.compilers.opt.ir.operand.ConstantOperand in project JikesRVM by JikesRVM.
the class SSA method makeMoveInstruction.
/**
* Create a move instruction r1 := c.<p>
*
* !!TODO: put this functionality elsewhere.
*
* @param ir the governing ir
* @param r1 the destination
* @param c the source
* @return the created move instruction
*/
static Instruction makeMoveInstruction(IR ir, Register r1, ConstantOperand c) {
Operator mv = IRTools.getMoveOp(c.getType());
RegisterOperand o1 = new RegisterOperand(r1, c.getType());
Operand o2 = c.copy();
Instruction s = Move.create(mv, o1, o2);
s.setSourcePosition(SSA_SYNTH_BCI, ir.getGc().getInlineSequence());
return s;
}
use of org.jikesrvm.compilers.opt.ir.operand.ConstantOperand in project JikesRVM by JikesRVM.
the class Simplifier method multiplyByConstant.
private static DefUseEffect multiplyByConstant(AbstractRegisterPool regpool, Instruction s, Operand op1, Operand op2, OptOptions opts) {
Operator addOperator, moveOperator, negateOperator, shiftLeftOperator;
ConstantOperand zero;
long val2;
int numBits;
if (op2.isIntConstant()) {
val2 = op2.asIntConstant().value;
addOperator = INT_ADD;
moveOperator = INT_MOVE;
negateOperator = INT_NEG;
shiftLeftOperator = INT_SHL;
zero = IntConstantOperand.zero;
numBits = 32;
} else {
val2 = op2.asLongConstant().value;
addOperator = LONG_ADD;
moveOperator = LONG_MOVE;
negateOperator = LONG_NEG;
shiftLeftOperator = LONG_SHL;
zero = LongConstantOperand.zero;
numBits = 64;
}
// ATTEMPT TO APPLY AXIOMS
if (val2 == 0) {
// x * 0 == 0
Move.mutate(s, moveOperator, Binary.getClearResult(s), zero.copy());
return DefUseEffect.MOVE_FOLDED;
} else if (numBits == 32 && ((int) val2 == ((int) -val2))) {
// x * MIN_INT == x << 31
Binary.mutate(s, INT_SHL, Binary.getClearResult(s), op1, IC(31));
return DefUseEffect.REDUCED;
} else if (numBits == 64 && val2 == -val2) {
// x * MIN_LONG == x << 63
Binary.mutate(s, LONG_SHL, Binary.getClearResult(s), op1, IC(63));
return DefUseEffect.REDUCED;
}
// Try to reduce x*c into shift and adds, but only if cost is cheap
if (s.hasPrev()) {
// don't attempt to reduce if this instruction isn't
// part of a well-formed sequence
// Cost of shift and add replacement
int cost = 0;
boolean negative = val2 < 0;
if (negative) {
val2 = -val2;
cost++;
}
if (VM.BuildForIA32 && numBits <= BITS_IN_ADDRESS) {
int lastShift = 0;
boolean lastShiftWasShort = false;
for (int i = 1; i < numBits; i++) {
if ((val2 & (1L << i)) != 0) {
// the original operand)
if (i < 4) {
// can use LEA of operand
cost++;
} else if ((i - lastShift) < 4 && !lastShiftWasShort) {
// can use LEA of last shift
cost++;
lastShiftWasShort = true;
} else {
// need separate shift and add
cost += 2;
lastShiftWasShort = false;
}
lastShift = i;
}
}
} else if (numBits > BITS_IN_ADDRESS) {
for (int i = 1; i < BITS_IN_ADDRESS; i++) {
if ((val2 & (1L << i)) != 0) {
// each 1 requires a shift and add
cost += 2;
}
}
for (int i = BITS_IN_ADDRESS; i < numBits; i++) {
if ((val2 & (1L << i)) != 0) {
// when the shift is > than the bits in the address we can just 0
// the bottom word, make the cost cheaper
cost++;
}
}
} else {
for (int i = 1; i < numBits; i++) {
if ((val2 & (1L << i)) != 0) {
// each 1 requires a shift and add
cost += 2;
}
}
}
int targetCost;
if (VM.BuildForIA32) {
targetCost = numBits == 64 ? 6 : 4;
} else {
targetCost = 2;
}
if (cost <= targetCost) {
// generate shift and adds
RegisterOperand val1Operand = op1.copy().asRegister();
RegisterOperand resultOperand = numBits == 32 ? regpool.makeTempInt() : regpool.makeTempLong();
Instruction move;
if ((val2 & 1) == 1) {
// result = val1 * 1
move = Move.create(moveOperator, resultOperand, val1Operand);
} else {
// result = 0
move = Move.create(moveOperator, resultOperand, zero.copy());
}
move.copyPosition(s);
s.insertBefore(move);
int lastShift = 0;
RegisterOperand lastShiftResult = null;
boolean lastShiftWasShort = false;
for (int i = 1; i < numBits; i++) {
if ((val2 & (1L << i)) != 0) {
Instruction shift;
RegisterOperand shiftResult = numBits == 32 ? regpool.makeTempInt() : regpool.makeTempLong();
if (VM.BuildForIA32 && numBits <= BITS_IN_ADDRESS && lastShiftResult != null && ((i - lastShift) <= 3) && (i > 3) && !lastShiftWasShort) {
// We can produce a short shift (1, 2 or 3) using the result of the last shift
shift = Binary.create(shiftLeftOperator, shiftResult, lastShiftResult.copyRO(), IC(i - lastShift));
lastShiftWasShort = true;
} else {
shift = Binary.create(shiftLeftOperator, shiftResult, val1Operand.copyRO(), IC(i));
lastShiftWasShort = false;
}
shift.copyPosition(s);
s.insertBefore(shift);
lastShiftResult = shiftResult;
lastShift = i;
RegisterOperand addResult = numBits == 32 ? regpool.makeTempInt() : regpool.makeTempLong();
Instruction add = Binary.create(addOperator, addResult, resultOperand.copyRO(), shiftResult.copyRO());
add.copyPosition(s);
s.insertBefore(add);
resultOperand = addResult;
}
}
if (negative) {
Unary.mutate(s, negateOperator, Binary.getClearResult(s), resultOperand.copyRO());
} else {
Move.mutate(s, moveOperator, Binary.getClearResult(s), resultOperand.copyRO());
}
return DefUseEffect.REDUCED;
}
}
return DefUseEffect.UNCHANGED;
}
use of org.jikesrvm.compilers.opt.ir.operand.ConstantOperand in project JikesRVM by JikesRVM.
the class LocalConstantProp method perform.
/**
* Perform Local Constant propagation for a method.
*
* @param ir the IR to optimize
*/
@Override
public void perform(IR ir) {
// info is a mapping from Register to ConstantOperand.
HashMap<Register, ConstantOperand> info = new HashMap<Register, ConstantOperand>();
boolean runBranchOpts = false;
/* Visit each basic block and apply the optimization */
for (BasicBlock bb = ir.firstBasicBlockInCodeOrder(); bb != null; bb = bb.nextBasicBlockInCodeOrder()) {
if (bb.isEmpty())
continue;
/* skip over trivial blocks */
container.counter2++;
if (bb.getInfrequent()) {
container.counter1++;
if (ir.options.FREQ_FOCUS_EFFORT)
continue;
}
/* Iterate over all instructions in the basic block */
for (Instruction s = bb.firstRealInstruction(), next, sentinel = bb.lastInstruction(); s != sentinel; s = next) {
next = s.nextInstructionInCodeOrder();
/* Do we known anything ? */
if (!info.isEmpty()) {
/* Transform: attempt to propagate constants */
int numUses = s.getNumberOfPureUses();
if (numUses > 0) {
boolean didSomething = false;
int numDefs = s.getNumberOfDefs();
for (int idx = numDefs; idx < numUses + numDefs; idx++) {
Operand use = s.getOperand(idx);
if (use instanceof RegisterOperand) {
RegisterOperand rUse = (RegisterOperand) use;
Operand value = info.get(rUse.getRegister());
if (value != null) {
didSomething = true;
s.putOperand(idx, value.copy());
}
}
}
if (didSomething) {
Simplifier.simplify(ir.isHIR(), ir.regpool, ir.options, s);
}
}
/* KILL: Remove bindings for all registers defined by this instruction */
for (Enumeration<Operand> e = s.getDefs(); e.hasMoreElements(); ) {
Operand def = e.nextElement();
if (def != null) {
/* Don't bother special casing the case where we are defining another constant; GEN will handle that */
/* Don't attempt to remove redundant assignments; let dead code elimination handle that */
Register defReg = ((RegisterOperand) def).getRegister();
info.remove(defReg);
}
}
}
/* GEN: If this is a move operation with a constant RHS, then it defines a constant */
if (Move.conforms(s) && Move.getVal(s).isConstant()) {
info.put(Move.getResult(s).getRegister(), (ConstantOperand) Move.getVal(s));
}
}
/* End of basic block; clean up and prepare for next block */
info.clear();
runBranchOpts |= BranchSimplifier.simplify(bb, ir);
}
/* End of IR. If we simplified a branch instruction, then run branch optimizations */
if (runBranchOpts) {
new BranchOptimizations(0, true, false, false).perform(ir);
}
}
use of org.jikesrvm.compilers.opt.ir.operand.ConstantOperand in project JikesRVM by JikesRVM.
the class NormalizeConstants method asImmediateOrRegInt.
static Operand asImmediateOrRegInt(Operand addr, Instruction s, IR ir, boolean signed) {
if (addr instanceof IntConstantOperand) {
if (!canBeImmediate(((IntConstantOperand) addr).value, signed)) {
RegisterOperand rop = ir.regpool.makeTempInt();
s.insertBefore(Move.create(REF_MOVE, rop, addr));
return rop.copyD2U();
}
} else if (addr instanceof ConstantOperand) {
// must not happen
if (VM.VerifyAssertions)
VM._assert(VM.NOT_REACHED);
}
// Operand was OK as is.
return addr;
}
Aggregations