use of org.jikesrvm.compilers.opt.ir.operand.NullConstantOperand in project JikesRVM by JikesRVM.
the class NormalizeConstants method perform.
/**
* Doit.
*
* @param ir IR to normalize
*/
public static void perform(IR ir) {
// This greatly reduces the number of cases we have to worry about below.
if (VM.VerifyAssertions)
VM._assert(ir.options.SIMPLIFY_INTEGER_OPS && ir.options.SIMPLIFY_LONG_OPS && ir.options.SIMPLIFY_REF_OPS);
for (Instruction s = ir.firstInstructionInCodeOrder(); s != null; s = s.nextInstructionInCodeOrder()) {
// STEP ONE: Get 'large' constants into a form that the PPC BURS rules
// are prepared to deal with.
// Constants can't appear as defs, so only scan the uses.
//
int numUses = s.getNumberOfUses();
if (numUses > 0) {
int numDefs = s.getNumberOfDefs();
for (int idx = numDefs; idx < numUses + numDefs; idx++) {
Operand use = s.getOperand(idx);
if (use != null) {
if (use instanceof ObjectConstantOperand) {
RegisterOperand rop = ir.regpool.makeTemp(use.getType());
RegisterOperand jtoc = (RegisterOperand) ir.regpool.makeJTOCOp();
ObjectConstantOperand oc = (ObjectConstantOperand) use;
Offset offset = oc.offset;
if (offset.isZero()) {
if (use instanceof StringConstantOperand) {
throw new OptimizingCompilerException("String constant w/o valid JTOC offset");
} else if (use instanceof ClassConstantOperand) {
throw new OptimizingCompilerException("Class constant w/o valid JTOC offset");
}
offset = Offset.fromIntSignExtend(Statics.findOrCreateObjectLiteral(oc.value));
}
LocationOperand loc = new LocationOperand(offset);
s.insertBefore(Load.create(VM.BuildFor32Addr ? INT_LOAD : LONG_LOAD, rop, jtoc, asImmediateOrRegOffset(AC(offset), s, ir, true), loc));
s.putOperand(idx, rop.copyD2U());
} else if (use instanceof DoubleConstantOperand) {
RegisterOperand rop = ir.regpool.makeTemp(TypeReference.Double);
RegisterOperand jtoc = (RegisterOperand) ir.regpool.makeJTOCOp();
DoubleConstantOperand dc = (DoubleConstantOperand) use;
Offset offset = dc.offset;
if (offset.isZero()) {
offset = Offset.fromIntSignExtend(Statics.findOrCreateLongSizeLiteral(Double.doubleToLongBits(dc.value)));
}
LocationOperand loc = new LocationOperand(offset);
s.insertBefore(Load.create(DOUBLE_LOAD, rop, jtoc, asImmediateOrRegOffset(AC(offset), s, ir, true), loc));
s.putOperand(idx, rop.copyD2U());
} else if (use instanceof FloatConstantOperand) {
RegisterOperand rop = ir.regpool.makeTemp(TypeReference.Float);
RegisterOperand jtoc = (RegisterOperand) ir.regpool.makeJTOCOp();
FloatConstantOperand fc = (FloatConstantOperand) use;
Offset offset = fc.offset;
if (offset.isZero()) {
offset = Offset.fromIntSignExtend(Statics.findOrCreateIntSizeLiteral(Float.floatToIntBits(fc.value)));
}
LocationOperand loc = new LocationOperand(offset);
s.insertBefore(Load.create(FLOAT_LOAD, rop, jtoc, asImmediateOrRegOffset(AC(offset), s, ir, true), loc));
s.putOperand(idx, rop.copyD2U());
} else if (use instanceof LongConstantOperand) {
if (!VM.BuildFor64Addr) {
if (s.getOpcode() != TRAP_IF_opcode) {
RegisterOperand rop = ir.regpool.makeTemp(TypeReference.Long);
s.insertBefore(Move.create(LONG_MOVE, rop, use.copy()));
s.putOperand(idx, rop.copyD2U());
}
}
} else if (use instanceof NullConstantOperand) {
s.putOperand(idx, AC(Address.zero()));
} else if (use instanceof TIBConstantOperand) {
RegisterOperand rop = ir.regpool.makeTemp(TypeReference.JavaLangObjectArray);
Operand jtoc = ir.regpool.makeJTOCOp();
Offset offset = ((TIBConstantOperand) use).value.getTibOffset();
LocationOperand loc = new LocationOperand(offset);
s.insertBefore(Load.create(VM.BuildFor32Addr ? INT_LOAD : LONG_LOAD, rop, jtoc, asImmediateOrRegOffset(AC(offset), s, ir, true), loc));
s.putOperand(idx, rop.copyD2U());
} else if (use instanceof CodeConstantOperand) {
RegisterOperand rop = ir.regpool.makeTemp(TypeReference.CodeArray);
Operand jtoc = ir.regpool.makeJTOCOp();
Offset offset = ((CodeConstantOperand) use).value.findOrCreateJtocOffset();
LocationOperand loc = new LocationOperand(offset);
s.insertBefore(Load.create(VM.BuildFor32Addr ? INT_LOAD : LONG_LOAD, rop, jtoc, asImmediateOrRegOffset(AC(offset), s, ir, true), loc));
s.putOperand(idx, rop.copyD2U());
}
}
}
}
// Calling Simplifier.simplify ensures that the instruction is
// in normalized form. This reduces the number of cases we have to
// worry about (and does last minute constant folding on the off chance
// we've missed an opportunity...)
Simplifier.simplify(false, ir.regpool, ir.options, s);
switch(s.getOpcode()) {
// ////////
case REF_STORE_opcode:
s.changeOperatorTo(VM.BuildFor32Addr ? INT_STORE : LONG_STORE);
// On PowerPC, the value being stored must be in a register
Store.setValue(s, asRegPolymorphic(Store.getClearValue(s), s, ir));
// Supported addressing modes are quite limited.
Store.setAddress(s, asRegAddress(Store.getClearAddress(s), s, ir));
Store.setOffset(s, asImmediateOrRegOffset(Store.getClearOffset(s), s, ir, true));
break;
case BYTE_STORE_opcode:
case SHORT_STORE_opcode:
case INT_STORE_opcode:
case LONG_STORE_opcode:
// On PowerPC, the value being stored must be in a register
Store.setValue(s, asRegPolymorphic(Store.getClearValue(s), s, ir));
// Supported addressing modes are quite limited.
Store.setAddress(s, asRegAddress(Store.getClearAddress(s), s, ir));
Store.setOffset(s, asImmediateOrRegOffset(Store.getClearOffset(s), s, ir, true));
break;
case FLOAT_STORE_opcode:
case DOUBLE_STORE_opcode:
// Supported addressing modes are quite limited.
Store.setAddress(s, asRegAddress(Store.getClearAddress(s), s, ir));
Store.setOffset(s, asImmediateOrRegOffset(Store.getClearOffset(s), s, ir, true));
break;
case REF_LOAD_opcode:
s.changeOperatorTo(VM.BuildFor32Addr ? INT_LOAD : LONG_LOAD);
// Supported addressing modes are quite limited.
Load.setAddress(s, asRegAddress(Load.getClearAddress(s), s, ir));
Load.setOffset(s, asImmediateOrRegOffset(Load.getClearOffset(s), s, ir, true));
break;
case BYTE_LOAD_opcode:
case UBYTE_LOAD_opcode:
case SHORT_LOAD_opcode:
case USHORT_LOAD_opcode:
case INT_LOAD_opcode:
case LONG_LOAD_opcode:
case FLOAT_LOAD_opcode:
case DOUBLE_LOAD_opcode:
// Supported addressing modes are quite limited.
Load.setAddress(s, asRegAddress(Load.getClearAddress(s), s, ir));
Load.setOffset(s, asImmediateOrRegOffset(Load.getClearOffset(s), s, ir, true));
break;
case ATTEMPT_INT_opcode:
case ATTEMPT_LONG_opcode:
case ATTEMPT_ADDR_opcode:
// On PowerPC, the value being stored must be in a register
Attempt.setNewValue(s, asRegPolymorphic(Attempt.getClearNewValue(s), s, ir));
// not used on powerpc.
Attempt.setOldValue(s, null);
// Supported addressing modes are quite limited.
Attempt.setAddress(s, asRegAddress(Attempt.getClearAddress(s), s, ir));
Attempt.setOffset(s, asRegOffset(Attempt.getClearOffset(s), s, ir));
break;
case PREPARE_INT_opcode:
case PREPARE_LONG_opcode:
case PREPARE_ADDR_opcode:
// Supported addressing modes are quite limited.
Prepare.setAddress(s, asRegAddress(Prepare.getClearAddress(s), s, ir));
Prepare.setOffset(s, asRegOffset(Prepare.getClearOffset(s), s, ir));
break;
case LONG_MOVE_opcode:
if (VM.BuildFor64Addr) {
s.changeOperatorTo(REF_MOVE);
}
break;
case INT_MOVE_opcode:
s.changeOperatorTo(REF_MOVE);
break;
case REF_COND_MOVE_opcode:
s.changeOperatorTo(VM.BuildFor32Addr ? INT_COND_MOVE : LONG_COND_MOVE);
break;
case REF_IFCMP_opcode:
s.changeOperatorTo(VM.BuildFor32Addr ? INT_IFCMP : LONG_IFCMP);
// val1 can't be a constant, val2 must be small enough.
IfCmp.setVal1(s, asRegPolymorphic(IfCmp.getClearVal1(s), s, ir));
IfCmp.setVal2(s, asImmediateOrRegPolymorphic(IfCmp.getClearVal2(s), s, ir, true));
case LONG_IFCMP_opcode:
if (VM.BuildFor64Addr) {
// val1 can't be a constant, val2 must be small enough.
IfCmp.setVal1(s, asRegPolymorphic(IfCmp.getClearVal1(s), s, ir));
IfCmp.setVal2(s, asImmediateOrRegPolymorphic(IfCmp.getClearVal2(s), s, ir, true));
}
break;
case INT_IFCMP_opcode:
// val1 can't be a constant, val2 must be small enough.
IfCmp.setVal1(s, asRegPolymorphic(IfCmp.getClearVal1(s), s, ir));
IfCmp.setVal2(s, asImmediateOrRegPolymorphic(IfCmp.getClearVal2(s), s, ir, true));
break;
case INT_IFCMP2_opcode:
// val1 can't be a constant, val2 must be small enough.
IfCmp2.setVal1(s, asRegInt(IfCmp2.getClearVal1(s), s, ir));
IfCmp2.setVal2(s, asImmediateOrRegInt(IfCmp2.getClearVal2(s), s, ir, true));
break;
case BOOLEAN_CMP_INT_opcode:
case BOOLEAN_CMP_ADDR_opcode:
// val2 must be small enough.
BooleanCmp.setVal2(s, asImmediateOrRegPolymorphic(BooleanCmp.getClearVal2(s), s, ir, !BooleanCmp.getCond(s).isUNSIGNED()));
break;
case LONG_CMP_opcode:
Binary.setVal1(s, asRegPolymorphic(Binary.getVal1(s), s, ir));
Binary.setVal2(s, asRegPolymorphic(Binary.getVal2(s), s, ir));
break;
case LONG_ADD_opcode:
if (VM.BuildFor64Addr) {
s.changeOperatorTo(REF_ADD);
Binary.setVal2(s, asImmediateOrRegPolymorphic(Binary.getClearVal2(s), s, ir, true));
}
break;
case INT_ADD_opcode:
s.changeOperatorTo(REF_ADD);
Binary.setVal2(s, asImmediateOrRegPolymorphic(Binary.getClearVal2(s), s, ir, true));
break;
case REF_ADD_opcode:
Binary.setVal2(s, asImmediateOrRegPolymorphic(Binary.getClearVal2(s), s, ir, true));
break;
case LONG_SUB_opcode:
if (VM.BuildFor64Addr) {
s.changeOperatorTo(REF_SUB);
Binary.setVal1(s, asImmediateOrRegPolymorphic(Binary.getClearVal1(s), s, ir, true));
// val2 isn't be constant (if it were, Simplifier would have
// converted this into an ADD of -Val2).
}
break;
case INT_SUB_opcode:
s.changeOperatorTo(REF_SUB);
Binary.setVal1(s, asImmediateOrRegPolymorphic(Binary.getClearVal1(s), s, ir, true));
// converted this into an ADD of -Val2).
break;
case REF_SUB_opcode:
Binary.setVal1(s, asImmediateOrRegPolymorphic(Binary.getClearVal1(s), s, ir, true));
// converted this into an ADD of -Val2).
break;
case INT_MUL_opcode:
Binary.setVal2(s, asImmediateOrRegInt(Binary.getClearVal2(s), s, ir, true));
break;
case LONG_MUL_opcode:
if (VM.BuildFor64Addr) {
Binary.setVal2(s, asImmediateOrRegLong(Binary.getClearVal2(s), s, ir, true));
}
break;
// seem to expect constant operands at all.
case INT_REM_opcode:
case INT_DIV_opcode:
GuardedBinary.setVal1(s, asRegInt(GuardedBinary.getClearVal1(s), s, ir));
GuardedBinary.setVal2(s, asRegInt(GuardedBinary.getClearVal2(s), s, ir));
break;
case LONG_REM_opcode:
case LONG_DIV_opcode:
if (VM.BuildFor64Addr) {
GuardedBinary.setVal1(s, asRegLong(GuardedBinary.getClearVal1(s), s, ir));
GuardedBinary.setVal2(s, asRegLong(GuardedBinary.getClearVal2(s), s, ir));
}
break;
case LONG_NEG_opcode:
if (VM.BuildFor64Addr) {
s.changeOperatorTo(REF_NEG);
}
break;
case INT_NEG_opcode:
s.changeOperatorTo(REF_NEG);
break;
case LONG_NOT_opcode:
if (VM.BuildFor64Addr) {
s.changeOperatorTo(REF_NOT);
}
break;
case INT_NOT_opcode:
s.changeOperatorTo(REF_NOT);
break;
case LONG_AND_opcode:
if (VM.BuildFor64Addr) {
s.changeOperatorTo(REF_AND);
// unsigned immediate
Binary.setVal2(s, asImmediateOrRegPolymorphic(Binary.getClearVal2(s), s, ir, false));
}
break;
case INT_AND_opcode:
s.changeOperatorTo(REF_AND);
// unsigned immediate
Binary.setVal2(s, asImmediateOrRegPolymorphic(Binary.getClearVal2(s), s, ir, false));
break;
case REF_AND_opcode:
// unsigned immediate
Binary.setVal2(s, asImmediateOrRegPolymorphic(Binary.getClearVal2(s), s, ir, false));
break;
case LONG_OR_opcode:
if (VM.BuildFor64Addr) {
s.changeOperatorTo(REF_OR);
// unsigned immediate
Binary.setVal2(s, asImmediateOrRegPolymorphic(Binary.getClearVal2(s), s, ir, false));
}
break;
case INT_OR_opcode:
s.changeOperatorTo(REF_OR);
// unsigned immediate
Binary.setVal2(s, asImmediateOrRegPolymorphic(Binary.getClearVal2(s), s, ir, false));
break;
case REF_OR_opcode:
// unsigned immediate
Binary.setVal2(s, asImmediateOrRegPolymorphic(Binary.getClearVal2(s), s, ir, false));
break;
case LONG_XOR_opcode:
if (VM.BuildFor64Addr) {
s.changeOperatorTo(REF_XOR);
// unsigned immediate
Binary.setVal2(s, asImmediateOrRegPolymorphic(Binary.getClearVal2(s), s, ir, false));
}
break;
case INT_XOR_opcode:
s.changeOperatorTo(REF_XOR);
// unsigned immediate
Binary.setVal2(s, asImmediateOrRegPolymorphic(Binary.getClearVal2(s), s, ir, false));
break;
case REF_XOR_opcode:
// unsigned immediate
Binary.setVal2(s, asImmediateOrRegPolymorphic(Binary.getClearVal2(s), s, ir, false));
break;
case REF_SHL_opcode:
s.changeOperatorTo(VM.BuildFor32Addr ? INT_SHL : LONG_SHL);
// Val2 could be a constant, but Val1 apparently can't be.
Binary.setVal1(s, asRegPolymorphic(Binary.getClearVal1(s), s, ir));
break;
case LONG_SHL_opcode:
if (VM.BuildFor64Addr) {
// Val2 could be a constant, but Val1 apparently can't be.
Binary.setVal1(s, asRegPolymorphic(Binary.getClearVal1(s), s, ir));
}
break;
case INT_SHL_opcode:
// Val2 could be a constant, but Val1 apparently can't be.
Binary.setVal1(s, asRegPolymorphic(Binary.getClearVal1(s), s, ir));
break;
case REF_SHR_opcode:
s.changeOperatorTo(VM.BuildFor32Addr ? INT_SHR : LONG_SHR);
// Val2 could be a constant, but Val1 apparently can't be.
Binary.setVal1(s, asRegPolymorphic(Binary.getClearVal1(s), s, ir));
break;
case LONG_SHR_opcode:
if (VM.BuildFor64Addr) {
// Val2 could be a constant, but Val1 apparently can't be.
Binary.setVal1(s, asRegPolymorphic(Binary.getClearVal1(s), s, ir));
}
break;
case INT_SHR_opcode:
// Val2 could be a constant, but Val1 apparently can't be.
Binary.setVal1(s, asRegPolymorphic(Binary.getClearVal1(s), s, ir));
break;
case REF_USHR_opcode:
s.changeOperatorTo(VM.BuildFor32Addr ? INT_USHR : LONG_USHR);
// Val2 could be a constant, but Val1 apparently can't be.
Binary.setVal1(s, asRegPolymorphic(Binary.getClearVal1(s), s, ir));
break;
case LONG_USHR_opcode:
if (VM.BuildFor64Addr) {
// Val2 could be a constant, but Val1 apparently can't be.
Binary.setVal1(s, asRegPolymorphic(Binary.getClearVal1(s), s, ir));
}
break;
case INT_USHR_opcode:
// Val2 could be a constant, but Val1 apparently can't be.
Binary.setVal1(s, asRegPolymorphic(Binary.getClearVal1(s), s, ir));
break;
// Deal with Simplifier.CF_FLOAT or Simplifier.CF_DOUBLE being false
case INT_2DOUBLE_opcode:
case INT_2FLOAT_opcode:
case INT_BITS_AS_FLOAT_opcode:
Unary.setVal(s, asRegInt(Unary.getVal(s), s, ir));
break;
case ADDR_2INT_opcode:
s.changeOperatorTo(VM.BuildFor32Addr ? REF_MOVE : LONG_2INT);
break;
case ADDR_2LONG_opcode:
s.changeOperatorTo(VM.BuildFor32Addr ? INT_2LONG : REF_MOVE);
break;
case INT_2ADDRSigExt_opcode:
s.changeOperatorTo(VM.BuildFor32Addr ? REF_MOVE : INT_2LONG);
break;
case INT_2ADDRZerExt_opcode:
if (VM.BuildFor32Addr) {
s.changeOperatorTo(REF_MOVE);
}
break;
case LONG_2ADDR_opcode:
s.changeOperatorTo(VM.BuildFor64Addr ? REF_MOVE : LONG_2INT);
break;
case NULL_CHECK_opcode:
NullCheck.setRef(s, asRegAddress(NullCheck.getClearRef(s), s, ir));
break;
// Force all call parameters to be in registers
case SYSCALL_opcode:
case CALL_opcode:
{
int numArgs = Call.getNumberOfParams(s);
for (int i = 0; i < numArgs; i++) {
Call.setParam(s, i, asRegPolymorphic(Call.getClearParam(s, i), s, ir));
}
}
break;
case RETURN_opcode:
if (Return.hasVal(s)) {
Return.setVal(s, asRegPolymorphic(Return.getClearVal(s), s, ir));
}
break;
}
}
}
use of org.jikesrvm.compilers.opt.ir.operand.NullConstantOperand in project JikesRVM by JikesRVM.
the class LoopVersioning method generateNullCheckBranchBlocks.
/**
* Generate null check branch blocks
*
* @param loop the current loop where checks are being eliminated
* @param checksToEliminate all of the checks that are being eliminated in the pass
* @param optimalRegMap a map from original register to the register used in the optimal loop
* @param block the block to generate code into
* @param unoptimizedLoopEntry entry to the unoptimized loop for if the check fails
* @return the new block to generate code into
*/
private BasicBlock generateNullCheckBranchBlocks(AnnotatedLSTNode loop, ArrayList<Instruction> checksToEliminate, HashMap<Register, Register> optimalRegMap, BasicBlock block, BasicBlock unoptimizedLoopEntry) {
// Map of already generated null check references to their
// corresponding guard result
HashMap<Register, Operand> refToGuardMap = new HashMap<Register, Operand>();
// Iterate over checks
for (Instruction instr : checksToEliminate) {
// Is this a null check
if (NullCheck.conforms(instr)) {
// the generated branch instruction
Instruction branch;
// the reference to compare
Operand ref = AnnotatedLSTNode.follow(NullCheck.getRef(instr));
// the guard result to define
RegisterOperand guardResult = NullCheck.getGuardResult(instr).copyRO();
guardResult.setRegister(optimalRegMap.get(guardResult.getRegister()));
// check if we've generated this test already
if (ref.isRegister() && refToGuardMap.containsKey(ref.asRegister().getRegister())) {
// yes - generate just a guard move
branch = Move.create(GUARD_MOVE, guardResult, refToGuardMap.get(ref.asRegister().getRegister()).copy());
branch.setBytecodeIndex(SYNTH_LOOP_VERSIONING_BCI);
block.appendInstruction(branch);
} else {
// check if we can just move a guard from the loop predecessors
RegisterOperand guard = nullCheckPerformedInLoopPredecessors(loop.header, instr);
if (guard != null) {
// yes - generate just a guard move
branch = Move.create(GUARD_MOVE, guardResult, guard.copyRO());
branch.setBytecodeIndex(SYNTH_LOOP_VERSIONING_BCI);
block.appendInstruction(branch);
} else {
// generate explicit null test
branch = IfCmp.create(REF_IFCMP, guardResult, ref.copy(), new NullConstantOperand(), ConditionOperand.EQUAL(), unoptimizedLoopEntry.makeJumpTarget(), BranchProfileOperand.unlikely());
if (ref.isRegister()) {
refToGuardMap.put(ref.asRegister().getRegister(), guardResult);
}
branch.setBytecodeIndex(SYNTH_LOOP_VERSIONING_BCI);
block.appendInstruction(branch);
// Adjust block
block.insertOut(unoptimizedLoopEntry);
BasicBlock new_block = block.createSubBlock(SYNTH_LOOP_VERSIONING_BCI, ir);
BasicBlock temp = (BasicBlock) block.next;
ir.cfg.breakCodeOrder(block, temp);
ir.cfg.linkInCodeOrder(block, new_block);
ir.cfg.linkInCodeOrder(new_block, temp);
block.insertOut(new_block);
block = new_block;
}
}
}
}
return block;
}
use of org.jikesrvm.compilers.opt.ir.operand.NullConstantOperand in project JikesRVM by JikesRVM.
the class DynamicTypeCheckExpansion method instanceOf.
/**
* Expand an instanceof instruction into the LIR sequence that implements
* the dynamic type check. Ref may contain a null ptr at runtime.
*
* @param s an INSTANCEOF or INSTANCEOF_UNRESOLVED instruction to expand
* @param ir the enclosing IR
* @return the last Instruction in the generated LIR sequence.
*/
static Instruction instanceOf(Instruction s, IR ir) {
RegisterOperand result = InstanceOf.getClearResult(s);
TypeReference LHStype = InstanceOf.getType(s).getTypeRef();
Operand ref = InstanceOf.getClearRef(s);
Instruction next = s.nextInstructionInCodeOrder();
if (next.operator() == INT_IFCMP && IfCmp.getVal1(next) instanceof RegisterOperand && result.similar(IfCmp.getVal1(next))) {
// The result of instanceof is being consumed by a conditional branch.
// Optimize this case by generating a branching type check
// instead of producing a value.
// TODO: This is really not safe: suppose the if is NOT the
// only use of the result of the instanceof.
// The way to fix this is to add ifInstanceOf and ifNotInstanceOf
// operators to the IR and have Simple transform
// instanceof, intIfCmp based on the U/D chains.
// See defect 2114.
Operand val2 = IfCmp.getVal2(next);
if (VM.VerifyAssertions)
VM._assert(val2.isIntConstant());
int ival2 = ((IntConstantOperand) val2).value;
ConditionOperand cond = IfCmp.getCond(next);
boolean branchCondition = (((ival2 == 0) && (cond.isNOT_EQUAL() || cond.isLESS_EQUAL())) || ((ival2 == 1) && (cond.isEQUAL() || cond.isGREATER_EQUAL())));
BasicBlock branchBB = next.getBranchTarget();
RegisterOperand oldGuard = IfCmp.getGuardResult(next);
next.remove();
BasicBlock fallThroughBB = fallThroughBB(s, ir);
BasicBlock falseBranch = branchCondition ? fallThroughBB : branchBB;
BasicBlock trueBranch = branchCondition ? branchBB : fallThroughBB;
BranchProfileOperand bp = IfCmp.getClearBranchProfile(next);
if (branchCondition)
bp = bp.flip();
Instruction nullComp = IfCmp.create(REF_IFCMP, oldGuard.copyRO(), ref.copy(), new NullConstantOperand(), ConditionOperand.EQUAL(), falseBranch.makeJumpTarget(), BranchProfileOperand.unlikely());
s.insertBefore(nullComp);
BasicBlock myBlock = s.getBasicBlock();
BasicBlock instanceOfBlock = myBlock.splitNodeAt(nullComp, ir);
myBlock.insertOut(instanceOfBlock);
myBlock.insertOut(falseBranch);
ir.cfg.linkInCodeOrder(myBlock, instanceOfBlock);
Operand RHStib = getTIB(s, ir, ref, oldGuard.copyRO());
return generateBranchingTypeCheck(s, ir, ref.copy(), LHStype, RHStib, trueBranch, falseBranch, oldGuard.copy().asRegister(), bp);
} else {
// Not a branching pattern
RegisterOperand guard = ir.regpool.makeTempValidation();
BasicBlock instanceOfBlock = s.getBasicBlock().segregateInstruction(s, ir);
BasicBlock prevBB = instanceOfBlock.prevBasicBlockInCodeOrder();
BasicBlock nextBB = instanceOfBlock.nextBasicBlockInCodeOrder();
BasicBlock nullCaseBB = instanceOfBlock.createSubBlock(s.getBytecodeIndex(), ir, .01f);
prevBB.appendInstruction(IfCmp.create(REF_IFCMP, guard, ref.copy(), new NullConstantOperand(), ConditionOperand.EQUAL(), nullCaseBB.makeJumpTarget(), BranchProfileOperand.unlikely()));
nullCaseBB.appendInstruction(Move.create(INT_MOVE, result.copyD2D(), IC(0)));
nullCaseBB.appendInstruction(Goto.create(GOTO, nextBB.makeJumpTarget()));
// Stitch together the CFG; add nullCaseBB to the end of code array.
prevBB.insertOut(nullCaseBB);
nullCaseBB.insertOut(nextBB);
ir.cfg.addLastInCodeOrder(nullCaseBB);
Operand RHStib = getTIB(s, ir, ref, guard.copyD2U());
return generateValueProducingTypeCheck(s, ir, ref.copy(), LHStype, RHStib, result);
}
}
use of org.jikesrvm.compilers.opt.ir.operand.NullConstantOperand in project JikesRVM by JikesRVM.
the class LocalCastOptimization method pushTypeCheckBelowIf.
/**
* Where legal, move a type check below an if instruction.
* @param s the potential typecheck instruction
* @param ir the governing IR
* @return {@code true} if and only if a type check was moved
*/
private boolean pushTypeCheckBelowIf(Instruction s, IR ir) {
if (s.operator() == CHECKCAST) {
Register r = TypeCheck.getRef(s).asRegister().getRegister();
Instruction n = s.nextInstructionInCodeOrder();
/* find moves of the checked value, so that we can also
optimize cases where the checked value is moved before
it is used
*/
while (n.operator() == REF_MOVE && Move.getVal(n) instanceof RegisterOperand && Move.getVal(n).asRegister().getRegister() == r) {
r = Move.getResult(n).asRegister().getRegister();
n = n.nextInstructionInCodeOrder();
}
if (n.operator() == REF_IFCMP && IfCmp.getVal2(n) instanceof NullConstantOperand && IfCmp.getVal1(n) instanceof RegisterOperand && r == IfCmp.getVal1(n).asRegister().getRegister()) {
BasicBlock newBlock, patchBlock;
BasicBlock myBlock = n.getBasicBlock();
Instruction after = n.nextInstructionInCodeOrder();
if (IfCmp.getCond(n).isEQUAL()) /* We fall through on non-NULL values, so the
checkcast must be on the not-taken path
from the branch. There are 3 cases:
1. n is the last instruction in its basic block,
in which case control falls through to the next
block in code order. This case is if the
instruction after n is a BBEND
*/
{
if (after.operator() == BBEND) {
patchBlock = myBlock.nextBasicBlockInCodeOrder();
} else if (after.operator() == GOTO) {
/* 2. n is followed by an unconditional goto. In
this case control jumps to the target of the
goto.
*/
patchBlock = after.getBranchTarget();
} else if (after.operator() == REF_IFCMP) {
/* 3. n is followed by another conditional branch. In
this case, we will split the basic block to make
n the last instruction in the block, and then
we have the fall through case again.
*/
patchBlock = myBlock.splitNodeAt(n, ir);
myBlock.insertOut(patchBlock);
ir.cfg.linkInCodeOrder(myBlock, patchBlock);
} else {
/* this is a bad thing */
return false;
}
} else /* We branch on not-NULL values, so the checkcast
must be spliced in before the branch target
*/
{
patchBlock = n.getBranchTarget();
}
/* add block between branch and appropriate successor */
newBlock = IRTools.makeBlockOnEdge(myBlock, patchBlock, ir);
/* put check in new block */
s.remove();
TypeCheck.mutate(s, CHECKCAST_NOTNULL, TypeCheck.getClearResult(s), TypeCheck.getClearRef(s), TypeCheck.getClearType(s), IfCmp.getGuardResult(n).copyRO());
newBlock.prependInstruction(s);
return true;
}
}
return false;
}
use of org.jikesrvm.compilers.opt.ir.operand.NullConstantOperand in project JikesRVM by JikesRVM.
the class Simplifier method refLoad.
private static DefUseEffect refLoad(Instruction s, OptOptions opts) {
if (opts.SIMPLIFY_TIB_OPS) {
Operand base = Load.getAddress(s);
if (base.isTIBConstant()) {
TIBConstantOperand tib = base.asTIBConstant();
Operand offset = Load.getOffset(s);
if (tib.value.isInstantiated() && offset.isConstant()) {
// Reading from a fixed offset from an effectively
// constant array
int intOffset;
if (offset.isIntConstant()) {
intOffset = offset.asIntConstant().value;
} else {
intOffset = offset.asAddressConstant().value.toInt();
}
int intSlot = intOffset >> LOG_BYTES_IN_ADDRESS;
// Create appropriate constant operand for TIB slot
ConstantOperand result;
TIB tibArray = tib.value.getTypeInformationBlock();
if (tibArray.slotContainsTib(intSlot)) {
RVMType typeOfTIB = ((TIB) tibArray.get(intSlot)).getType();
result = new TIBConstantOperand(typeOfTIB);
} else if (tibArray.slotContainsCode(intSlot)) {
// some virtual calls go via the JTOC
if (opts.H2L_CALL_VIA_JTOC) {
RVMMethod method = tib.value.getTIBMethodAtSlot(intSlot);
result = new CodeConstantOperand(method);
} else {
return DefUseEffect.UNCHANGED;
}
} else {
if (tibArray.get(intSlot) == null) {
result = new NullConstantOperand();
} else {
result = new ObjectConstantOperand(tibArray.get(intSlot), Offset.zero());
}
}
Move.mutate(s, REF_MOVE, Load.getClearResult(s), result);
return DefUseEffect.MOVE_FOLDED;
}
}
}
return DefUseEffect.UNCHANGED;
}
Aggregations