/* * 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 org.jikesrvm.ArchitectureSpecific.OPT_CallingConvention; import org.jikesrvm.ArchitectureSpecific.OPT_ComplexLIR2MIRExpansion; import org.jikesrvm.ArchitectureSpecific.OPT_ConvertALUOperators; import org.jikesrvm.ArchitectureSpecific.OPT_NormalizeConstants; import org.jikesrvm.VM; import static org.jikesrvm.VM_SizeConstants.LOG_BYTES_IN_ADDRESS; import org.jikesrvm.classloader.VM_Type; import org.jikesrvm.compilers.opt.ir.Binary; import org.jikesrvm.compilers.opt.ir.Call; import org.jikesrvm.compilers.opt.ir.GuardedBinary; import org.jikesrvm.compilers.opt.ir.GuardedUnary; import org.jikesrvm.compilers.opt.ir.Load; import org.jikesrvm.compilers.opt.ir.OPT_AddressConstantOperand; import org.jikesrvm.compilers.opt.ir.OPT_BasicBlock; import org.jikesrvm.compilers.opt.ir.OPT_IR; import org.jikesrvm.compilers.opt.ir.OPT_IRTools; import org.jikesrvm.compilers.opt.ir.OPT_Instruction; import org.jikesrvm.compilers.opt.ir.OPT_LocationOperand; import org.jikesrvm.compilers.opt.ir.OPT_MIRInfo; import org.jikesrvm.compilers.opt.ir.OPT_MethodOperand; import org.jikesrvm.compilers.opt.ir.OPT_Operand; import org.jikesrvm.compilers.opt.ir.OPT_Operators; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.ARRAYLENGTH_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.DOUBLE_2LONG_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.DOUBLE_REM_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.FLOAT_2LONG_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.FLOAT_REM_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.GET_ARRAY_ELEMENT_TIB_FROM_TIB_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.GET_CLASS_TIB_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.GET_DOES_IMPLEMENT_FROM_TIB_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.GET_OBJ_TIB_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.GET_SUPERCLASS_IDS_FROM_TIB_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.GET_TYPE_FROM_TIB_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_LOAD; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_2DOUBLE_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_2FLOAT_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_DIV_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_REM_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.REF_LOAD; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.SYSCALL; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.SYSCALL_opcode; import org.jikesrvm.compilers.opt.ir.OPT_TypeOperand; import org.jikesrvm.compilers.opt.ir.Unary; import org.jikesrvm.objectmodel.VM_JavaHeader; import org.jikesrvm.objectmodel.VM_ObjectModel; import static org.jikesrvm.objectmodel.VM_TIBLayoutConstants.TIB_ARRAY_ELEMENT_TIB_INDEX; import static org.jikesrvm.objectmodel.VM_TIBLayoutConstants.TIB_DOES_IMPLEMENT_INDEX; import static org.jikesrvm.objectmodel.VM_TIBLayoutConstants.TIB_SUPERCLASS_IDS_INDEX; import static org.jikesrvm.objectmodel.VM_TIBLayoutConstants.TIB_TYPE_INDEX; import org.jikesrvm.runtime.VM_Entrypoints; import org.vmmagic.unboxed.Offset; /** * Convert an IR object from LIR to MIR via BURS */ public final class OPT_ConvertLIRtoMIR extends OPT_OptimizationPlanCompositeElement { /** * Create this phase element as a composite of other elements */ public OPT_ConvertLIRtoMIR() { super("Instruction Selection", new OPT_OptimizationPlanElement[]{ // Stage 1: Reduce the LIR operator set to a core set of operators. new OPT_OptimizationPlanAtomicElement(new ReduceOperators()), // Stage 2: Convert ALU operators new OPT_OptimizationPlanAtomicElement(new OPT_ConvertALUOperators()), // Stage 3: Normalize usage of constants to simplify Stage 3. new OPT_OptimizationPlanAtomicElement(new NormalizeConstants()), // Stage 4a: Compute liveness information for DepGraph new OPT_OptimizationPlanAtomicElement(new DoLiveness()), // Stage 4b: Block by block build DepGraph and do // BURS based instruction selection. new OPT_OptimizationPlanAtomicElement(new DoBURS()), // Stage 5: Handle complex operators // (those that expand to multiple basic blocks of MIR). new OPT_OptimizationPlanAtomicElement(new ComplexOperators()), // Stage 6: Use validation operands to do null check combining, // and then finish the removal off all validation // operands (they are not present in the MIR). new OPT_OptimizationPlanAtomicElement(new OPT_NullCheckCombining() { public void perform(OPT_IR ir) { super.perform(ir); // ir now contains well formed MIR. ir.IRStage = OPT_IR.MIR; ir.MIRInfo = new OPT_MIRInfo(ir); } })}); } /** * Stage 1: Reduce the LIR operator set to a core set of operators. */ private static final class ReduceOperators extends OPT_CompilerPhase { public String getName() { return "Reduce Operators"; } public OPT_CompilerPhase newExecution(OPT_IR ir) { return this; } public void perform(OPT_IR ir) { for (OPT_Instruction s = ir.firstInstructionInCodeOrder(); s != null; s = s.nextInstructionInCodeOrder()) { switch (s.getOpcode()) { case ARRAYLENGTH_opcode: { // array_ref[VM_ObjectModel.getArrayLengthOffset()] contains the length Load.mutate(s, INT_LOAD, GuardedUnary.getClearResult(s), GuardedUnary.getClearVal(s), OPT_IRTools.AC(VM_ObjectModel.getArrayLengthOffset()), new OPT_LocationOperand(), GuardedUnary.getClearGuard(s)); } break; case GET_OBJ_TIB_opcode: // TODO: valid location operand. OPT_Operand address = GuardedUnary.getClearVal(s); Load.mutate(s, OPT_Operators.REF_LOAD, GuardedUnary.getClearResult(s), address, new OPT_AddressConstantOperand(VM_JavaHeader.getTibOffset()), null, GuardedUnary.getClearGuard(s)); break; case GET_CLASS_TIB_opcode: { VM_Type type = ((OPT_TypeOperand) Unary.getVal(s)).getVMType(); Offset offset = type.getTibOffset(); Load.mutate(s, REF_LOAD, Unary.getClearResult(s), ir.regpool.makeJTOCOp(ir, s), OPT_IRTools.AC(offset), new OPT_LocationOperand(offset)); } break; case GET_TYPE_FROM_TIB_opcode: { // TODO: Valid location operand? Load.mutate(s, REF_LOAD, Unary.getClearResult(s), Unary.getClearVal(s), OPT_IRTools.AC(Offset.fromIntZeroExtend(TIB_TYPE_INDEX << LOG_BYTES_IN_ADDRESS)), null); } break; case GET_SUPERCLASS_IDS_FROM_TIB_opcode: { // TODO: Valid location operand? Load.mutate(s, REF_LOAD, Unary.getClearResult(s), Unary.getClearVal(s), OPT_IRTools.AC(Offset.fromIntZeroExtend(TIB_SUPERCLASS_IDS_INDEX << LOG_BYTES_IN_ADDRESS)), null); } break; case GET_DOES_IMPLEMENT_FROM_TIB_opcode: { // TODO: Valid location operand? Load.mutate(s, REF_LOAD, Unary.getClearResult(s), Unary.getClearVal(s), OPT_IRTools.AC(Offset.fromIntZeroExtend(TIB_DOES_IMPLEMENT_INDEX << LOG_BYTES_IN_ADDRESS)), null); } break; case GET_ARRAY_ELEMENT_TIB_FROM_TIB_opcode: { // TODO: Valid location operand? Load.mutate(s, REF_LOAD, Unary.getClearResult(s), Unary.getClearVal(s), OPT_IRTools.AC(Offset.fromIntZeroExtend(TIB_ARRAY_ELEMENT_TIB_INDEX << LOG_BYTES_IN_ADDRESS)), null); } break; case LONG_DIV_opcode: { if (VM.BuildForPowerPC && VM.BuildFor64Addr) break; // don't reduce operator -- leave for BURS Call.mutate2(s, SYSCALL, GuardedBinary.getClearResult(s), null, OPT_MethodOperand.STATIC(VM_Entrypoints.sysLongDivideIPField), GuardedBinary.getClearVal1(s), GuardedBinary.getClearVal2(s)); OPT_ConvertToLowLevelIR.expandSysCallTarget(s, ir); OPT_CallingConvention.expandSysCall(s, ir); } break; case LONG_REM_opcode: { if (VM.BuildForPowerPC && VM.BuildFor64Addr) break; // don't reduce operator -- leave for BURS Call.mutate2(s, SYSCALL, GuardedBinary.getClearResult(s), null, OPT_MethodOperand.STATIC(VM_Entrypoints.sysLongRemainderIPField), GuardedBinary.getClearVal1(s), GuardedBinary.getClearVal2(s)); OPT_ConvertToLowLevelIR.expandSysCallTarget(s, ir); OPT_CallingConvention.expandSysCall(s, ir); } break; case FLOAT_REM_opcode: case DOUBLE_REM_opcode: { if (VM.BuildForPowerPC) { Call.mutate2(s, SYSCALL, Binary.getClearResult(s), null, OPT_MethodOperand.STATIC(VM_Entrypoints.sysDoubleRemainderIPField), Binary.getClearVal1(s), Binary.getClearVal2(s)); OPT_ConvertToLowLevelIR.expandSysCallTarget(s, ir); OPT_CallingConvention.expandSysCall(s, ir); } } break; case LONG_2FLOAT_opcode: { if (VM.BuildForPowerPC) { Call.mutate1(s, SYSCALL, Unary.getClearResult(s), null, OPT_MethodOperand.STATIC(VM_Entrypoints.sysLongToFloatIPField), Unary.getClearVal(s)); OPT_ConvertToLowLevelIR.expandSysCallTarget(s, ir); OPT_CallingConvention.expandSysCall(s, ir); } } break; case LONG_2DOUBLE_opcode: { if (VM.BuildForPowerPC) { Call.mutate1(s, SYSCALL, Unary.getClearResult(s), null, OPT_MethodOperand.STATIC(VM_Entrypoints.sysLongToDoubleIPField), Unary.getClearVal(s)); OPT_ConvertToLowLevelIR.expandSysCallTarget(s, ir); OPT_CallingConvention.expandSysCall(s, ir); } } break; case FLOAT_2LONG_opcode: { if (VM.BuildForPowerPC && VM.BuildFor64Addr || VM.BuildForSSE2Full) break; // don't reduce operator -- leave for BURS Call.mutate1(s, SYSCALL, Unary.getClearResult(s), null, OPT_MethodOperand.STATIC(VM_Entrypoints.sysFloatToLongIPField), Unary.getClearVal(s)); OPT_ConvertToLowLevelIR.expandSysCallTarget(s, ir); OPT_CallingConvention.expandSysCall(s, ir); } break; case DOUBLE_2LONG_opcode: { if (VM.BuildForPowerPC && VM.BuildFor64Addr || VM.BuildForSSE2Full) break; // don't reduce operator -- leave for BURS Call.mutate1(s, SYSCALL, Unary.getClearResult(s), null, OPT_MethodOperand.STATIC(VM_Entrypoints.sysDoubleToLongIPField), Unary.getClearVal(s)); OPT_ConvertToLowLevelIR.expandSysCallTarget(s, ir); OPT_CallingConvention.expandSysCall(s, ir); } break; case SYSCALL_opcode: OPT_CallingConvention.expandSysCall(s, ir); break; default: break; } } } } /** * Stage 2: Normalize usage of int constants to make less work in Stage 3. */ private static final class NormalizeConstants extends OPT_CompilerPhase { public String getName() { return "Normalize Constants"; } public OPT_CompilerPhase newExecution(OPT_IR ir) { return this; } public void perform(OPT_IR ir) { OPT_NormalizeConstants.perform(ir); } } private static final class DoLiveness extends OPT_CompilerPhase { public String getName() { return "Live Handlers"; } public OPT_CompilerPhase newExecution(OPT_IR ir) { return this; } public void perform(OPT_IR ir) { if (ir.options.HANDLER_LIVENESS) { new OPT_LiveAnalysis(false, false, true).perform(ir); } } } /** * Stage 3: Block by block build DepGraph and do BURS based * instruction selection. */ private static final class DoBURS extends OPT_CompilerPhase { public String getName() { return "DepGraph & BURS"; } public OPT_CompilerPhase newExecution(OPT_IR ir) { return this; } public void reportAdditionalStats() { VM.sysWrite(" "); VM.sysWrite(container.counter1 / container.counter2 * 100, 2); VM.sysWrite("% Infrequent BBs"); } // IR is inconsistent state between DoBURS and ComplexOperators. // It isn't verifiable again until after ComplexOperators completes. public void verify(OPT_IR ir) { } public void perform(OPT_IR ir) { OPT_Options options = ir.options; OPT_DefUse.recomputeSpansBasicBlock(ir); OPT_MinimalBURS mburs = new OPT_MinimalBURS(ir); OPT_NormalBURS burs = new OPT_NormalBURS(ir); for (OPT_BasicBlock bb = ir.firstBasicBlockInCodeOrder(); bb != null; bb = bb.nextBasicBlockInCodeOrder()) { if (bb.isEmpty()) continue; container.counter2++; if (bb.getInfrequent()) { container.counter1++; if (options.FREQ_FOCUS_EFFORT) { // Basic block is infrequent -- use quick and dirty instruction selection mburs.prepareForBlock(bb); mburs.invoke(bb); mburs.finalizeBlock(bb); continue; } } // Use Normal instruction selection. burs.prepareForBlock(bb); // I. Build Dependence graph for the basic block OPT_DepGraph dgraph = new OPT_DepGraph(ir, bb.firstRealInstruction(), bb.lastRealInstruction(), bb); if (options.PRINT_DG_BURS) { // print dependence graph. OPT_Compiler.header("DepGraph", ir.method); dgraph.printDepGraph(); OPT_Compiler.bottom("DepGraph", ir.method); } if (options.VCG_DG_BURS) { // output dependence graph in VCG format. // CAUTION: creates A LOT of files (one per BB) OPT_VCG.printVCG("depgraph_BURS_" + ir.method + "_" + bb + ".vcg", dgraph); } // II. Invoke BURS and rewrite block from LIR to MIR try { burs.invoke(dgraph); } catch (OPT_OptimizingCompilerException e) { System.err.println("Exception occurred in OPT_ConvertLIRtoMIR"); e.printStackTrace(); ir.printInstructions(); throw e; } burs.finalizeBlock(bb); } } } /** * Stage 4: Handle complex operators * (those that expand to multiple basic blocks). */ private static final class ComplexOperators extends OPT_CompilerPhase { public String getName() { return "Complex Operators"; } public OPT_CompilerPhase newExecution(OPT_IR ir) { return this; } public void perform(OPT_IR ir) { OPT_ComplexLIR2MIRExpansion.convert(ir); } } }