use of org.jikesrvm.compilers.opt.OptimizingCompilerException in project JikesRVM by JikesRVM.
the class BURS_Helpers method LONG_USHR.
/**
* Expansion of LONG_USHR
* @param s the instruction to expand
* @param result the result operand
* @param val1 the shifted operand
* @param val2 the shift amount operand
* @param maskWith3f should the shift operand by masked with 0x3f? This is
* default behaviour on Intel but it differs from how we combine
* shift operands in HIR
*/
protected final void LONG_USHR(Instruction s, Operand result, Operand val1, Operand val2, boolean maskWith3f) {
if (!val2.isIntConstant()) {
// the most efficient form of expanding a shift by a variable amount
// requires a branch so leave for complex operators
// NB if !maskWith3f - we assume that a mask with 0x3F was required as
// no optimizations currently exploits shift by registers of > 63
// returning 0
Binary.mutate(s, LONG_USHR, result.asRegister(), val1, val2);
EMIT(s);
} else if (result.isRegister()) {
int shift = val2.asIntConstant().value;
if (maskWith3f) {
shift = shift & 0x3F;
}
Register lhsReg = result.asRegister().getRegister();
Register lowlhsReg = burs.ir.regpool.getSecondReg(lhsReg);
Register rhsReg1 = val1.asRegister().getRegister();
Register lowrhsReg1 = burs.ir.regpool.getSecondReg(rhsReg1);
if (shift == 0) {
// operation is a nop.
if (!result.similar(val1)) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new RegisterOperand(lowlhsReg, TypeReference.Int), new RegisterOperand(lowrhsReg1, TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new RegisterOperand(lhsReg, TypeReference.Int), new RegisterOperand(rhsReg1, TypeReference.Int))));
}
} else if (shift == 1) {
if (!result.similar(val1)) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new RegisterOperand(lowlhsReg, TypeReference.Int), new RegisterOperand(lowrhsReg1, TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new RegisterOperand(lhsReg, TypeReference.Int), new RegisterOperand(rhsReg1, TypeReference.Int))));
}
// lhsReg = lhsReg >>> 1
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SHR, new RegisterOperand(lhsReg, TypeReference.Int), IC(1))));
// lowlhsReg = (lhsReg << 31) | (lowlhsReg >>> 1)
EMIT(MIR_BinaryAcc.mutate(s, IA32_RCR, new RegisterOperand(lowlhsReg, TypeReference.Int), IC(1)));
} else if (shift < 32) {
// bits to shift in: tmp = rhsReg << (32 - shift)
// TODO: use LEA for SHL operator
Register tmp = regpool.getInteger();
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new RegisterOperand(tmp, TypeReference.Int), new RegisterOperand(rhsReg1, TypeReference.Int))));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SHL, new RegisterOperand(tmp, TypeReference.Int), IC(32 - shift))));
// compute bottom half: lowlhsReg = (lowlhsReg1 >>> shift) | tmp
if (!result.similar(val1)) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new RegisterOperand(lowlhsReg, TypeReference.Int), new RegisterOperand(lowrhsReg1, TypeReference.Int))));
}
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SHR, new RegisterOperand(lowlhsReg, TypeReference.Int), IC(shift))));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_OR, new RegisterOperand(lowlhsReg, TypeReference.Int), new RegisterOperand(tmp, TypeReference.Int))));
// compute top half: lhsReg = lhsReg >>> shift
if (!result.similar(val1)) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new RegisterOperand(lhsReg, TypeReference.Int), new RegisterOperand(rhsReg1, TypeReference.Int))));
}
EMIT(MIR_BinaryAcc.mutate(s, IA32_SHR, new RegisterOperand(lhsReg, TypeReference.Int), IC(shift)));
} else if (shift == 32) {
// lowlhsReg = rhsReg1
EMIT(MIR_Move.mutate(s, IA32_MOV, new RegisterOperand(lowlhsReg, TypeReference.Int), new RegisterOperand(rhsReg1, TypeReference.Int)));
// lhsReg = 0
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new RegisterOperand(lhsReg, TypeReference.Int), IC(0))));
} else {
if (maskWith3f || (shift < 64)) {
// lowlhsReg = rhsReg1 >>> (shift & 0x1F)
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new RegisterOperand(lowlhsReg, TypeReference.Int), new RegisterOperand(rhsReg1, TypeReference.Int))));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SHR, new RegisterOperand(lowlhsReg, TypeReference.Int), IC(shift & 0x1F))));
} else {
// lowlhsReg = 0
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new RegisterOperand(lowlhsReg, TypeReference.Int), IC(0))));
}
// lhsReg = 0
EMIT(MIR_Move.mutate(s, IA32_MOV, new RegisterOperand(lhsReg, TypeReference.Int), IC(0)));
}
} else {
throw new OptimizingCompilerException("BURS_Helpers", "unexpected parameters: " + result + "=" + val1 + ">>" + val2);
}
}
use of org.jikesrvm.compilers.opt.OptimizingCompilerException in project JikesRVM by JikesRVM.
the class BURS_MemOp_Helpers method combineAddresses.
protected final void combineAddresses() {
if (VM.VerifyAssertions)
VM._assert(AddrStack != null, "No address to combine");
AddrStackElement tmp = AddrStack;
AddrStack = AddrStack.next;
if (VM.VerifyAssertions)
VM._assert(AddrStack != null, "only 1 address to combine");
if (tmp.base != null) {
if (AddrStack.base == null) {
AddrStack.base = tmp.base;
} else if (AddrStack.index == null) {
if (VM.VerifyAssertions)
VM._assert(AddrStack.scale == (byte) 0);
AddrStack.index = tmp.base;
} else {
throw new OptimizingCompilerException("three base registers in address");
}
}
if (tmp.index != null) {
if (AddrStack.index == null) {
if (VM.VerifyAssertions)
VM._assert(AddrStack.scale == (byte) 0);
AddrStack.index = tmp.index;
AddrStack.scale = tmp.scale;
} else if (AddrStack.base == null && tmp.scale == (byte) 0) {
AddrStack.base = tmp.base;
} else {
throw new OptimizingCompilerException("two scaled registers in address");
}
}
AddrStack.displacement = AddrStack.displacement.plus(tmp.displacement);
}
use of org.jikesrvm.compilers.opt.OptimizingCompilerException in project JikesRVM by JikesRVM.
the class BC2IR method _refIfNullHelper.
// helper function for ifnull/ifnonnull bytecodes
private Instruction _refIfNullHelper(ConditionOperand cond) {
if (VM.VerifyAssertions)
opt_assert(cond.isEQUAL() || cond.isNOT_EQUAL());
int offset = bcodes.getBranchOffset();
Operand op0 = popRef();
if (offset == 3) {
// remove frivolous REF_IFs
return null;
}
if (CF_REFIF) {
if (op0.isDefinitelyNull()) {
if (cond.isEQUAL()) {
if (DBG_CF) {
db(cond + ": changed branch to goto because predicate is true");
}
return _gotoHelper(offset);
} else {
if (DBG_CF) {
db(cond + ": eliminated branch because predicate is false");
}
return null;
}
}
if (isNonNull(op0)) {
if (cond.isNOT_EQUAL()) {
if (DBG_CF) {
db(cond + ": changed branch to goto because predicate is true");
}
return _gotoHelper(offset);
} else {
if (DBG_CF) {
db(cond + ": eliminated branch because predicate is false");
}
return null;
}
}
}
RegisterOperand ref = (RegisterOperand) op0;
BranchOperand branch = null;
RegisterOperand guard = null;
// Check for incorrect null checks on unboxed types
if (ref.getType().isUnboxedType()) {
throw new OptimizingCompilerException("Detected incorrect null check of unboxed type in " + gc.getMethod() + " at bytecode index " + instrIndex + " from class " + gc.getMethod().getDeclaringClass() + " . Use the methods provided on the unboxed types to do null checks!");
}
if (cond.isEQUAL()) {
branch = generateTarget(offset);
if (ref.getRegister().isLocal()) {
int locNum = gc.getLocalNumberFor(ref.getRegister(), ref.getType());
if (locNum != -1) {
Operand loc = getLocal(locNum);
if (loc instanceof RegisterOperand) {
RegisterOperand locr = (RegisterOperand) loc;
guard = gc.makeNullCheckGuard(locr.getRegister());
setGuardForRegOp(locr, guard.copyD2U());
setLocal(locNum, loc);
}
}
}
} else {
boolean generated = false;
if (ref.getRegister().isLocal()) {
int locNum = gc.getLocalNumberFor(ref.getRegister(), ref.getType());
if (locNum != -1) {
Operand loc = getLocal(locNum);
if (loc instanceof RegisterOperand) {
RegisterOperand locr = (RegisterOperand) loc;
RegisterOperand tlocr = locr.copyU2U();
guard = gc.makeNullCheckGuard(locr.getRegister());
setGuardForRegOp(tlocr, guard.copyD2U());
setLocal(locNum, tlocr);
branch = generateTarget(offset);
generated = true;
setLocal(locNum, locr);
}
}
}
if (!generated) {
branch = generateTarget(offset);
}
}
fallThrough = true;
if (guard == null) {
guard = gc.getTemps().makeTempValidation();
}
return IfCmp.create(REF_IFCMP, guard, ref, new NullConstantOperand(), cond, branch, gc.getConditionalBranchProfileOperand(instrIndex - bciAdjustment, offset < 0));
}
use of org.jikesrvm.compilers.opt.OptimizingCompilerException 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.OptimizingCompilerException in project JikesRVM by JikesRVM.
the class LoadElimination method replaceDefs.
/**
* Perform scalar replacement actions for a Def of a heap variable.
* <p>
* NOTE: Even loads can def a heap variable.
*
* @param ir the governing IR
* @param UseRepSet stores the uses(loads) that have been eliminated
* @param registers mapping from valueNumber -> temporary register
*/
static void replaceDefs(IR ir, UseRecordSet UseRepSet, HashMap<UseRecord, Register> registers) {
SSADictionary ssa = ir.HIRInfo.dictionary;
for (Enumeration<Instruction> e = ir.forwardInstrEnumerator(); e.hasMoreElements(); ) {
Instruction s = e.nextElement();
if (!GetField.conforms(s) && !GetStatic.conforms(s) && !PutField.conforms(s) && !PutStatic.conforms(s) && !ALoad.conforms(s) && !AStore.conforms(s)) {
continue;
}
if (!ssa.defsHeapVariable(s)) {
continue;
}
// this instruction is a DEF of heap variable H.
// Check if UseRepSet needs the scalar assigned by this def
HeapOperand<?>[] H = ssa.getHeapDefs(s);
if (H.length != 1) {
throw new OptimizingCompilerException("LoadElimination: encountered a store with more than one def? " + s);
}
int valueNumber = -1;
Object index = null;
if (AStore.conforms(s)) {
Object address = AStore.getArray(s);
index = AStore.getIndex(s);
valueNumber = ir.HIRInfo.valueNumbers.getValueNumber(address);
} else if (GetField.conforms(s)) {
Object address = GetField.getRef(s);
valueNumber = ir.HIRInfo.valueNumbers.getValueNumber(address);
} else if (PutField.conforms(s)) {
Object address = PutField.getRef(s);
valueNumber = ir.HIRInfo.valueNumbers.getValueNumber(address);
} else if (GetStatic.conforms(s)) {
valueNumber = 0;
} else if (PutStatic.conforms(s)) {
valueNumber = 0;
} else if (ALoad.conforms(s)) {
Object address = ALoad.getArray(s);
valueNumber = ir.HIRInfo.valueNumbers.getValueNumber(address);
index = ALoad.getIndex(s);
}
if (index == null) {
// Load/Store
if (UseRepSet.containsMatchingUse(H[0].getHeapVariable(), valueNumber)) {
Operand value = null;
if (PutField.conforms(s)) {
value = PutField.getValue(s);
} else if (PutStatic.conforms(s)) {
value = PutStatic.getValue(s);
} else if (GetField.conforms(s) || GetStatic.conforms(s)) {
value = ResultCarrier.getResult(s);
}
TypeReference type = value.getType();
Register r = findOrCreateRegister(H[0].getHeapType(), valueNumber, registers, ir.regpool, type);
appendMove(r, value, s);
}
} else {
// ALoad / AStore
int v1 = valueNumber;
int v2 = ir.HIRInfo.valueNumbers.getValueNumber(index);
if (UseRepSet.containsMatchingUse(H[0].getHeapVariable(), v1, v2)) {
Operand value = null;
if (AStore.conforms(s)) {
value = AStore.getValue(s);
} else if (ALoad.conforms(s)) {
value = ALoad.getResult(s);
}
TypeReference type = value.getType();
Register r = findOrCreateRegister(H[0].getHeapType(), v1, v2, registers, ir.regpool, type);
appendMove(r, value, s);
}
}
}
}
Aggregations