/* * 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.lir2mir; import static org.jikesrvm.compilers.opt.ir.Operators.ARRAYLENGTH_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_2LONG_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_REM_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_2LONG_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_REM_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.GET_ARRAY_ELEMENT_TIB_FROM_TIB_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.GET_CLASS_TIB_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.GET_DOES_IMPLEMENT_FROM_TIB_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.GET_OBJ_TIB_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.GET_SUPERCLASS_IDS_FROM_TIB_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.GET_TYPE_FROM_TIB_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.INT_LOAD; import static org.jikesrvm.compilers.opt.ir.Operators.LONG_2DOUBLE_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.LONG_2FLOAT_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.LONG_DIV_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.LONG_REM_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.REF_LOAD; import static org.jikesrvm.compilers.opt.ir.Operators.SYSCALL; import static org.jikesrvm.compilers.opt.ir.Operators.SYSCALL_opcode; import static org.jikesrvm.objectmodel.TIBLayoutConstants.TIB_ARRAY_ELEMENT_TIB_INDEX; import static org.jikesrvm.objectmodel.TIBLayoutConstants.TIB_DOES_IMPLEMENT_INDEX; import static org.jikesrvm.objectmodel.TIBLayoutConstants.TIB_SUPERCLASS_IDS_INDEX; import static org.jikesrvm.objectmodel.TIBLayoutConstants.TIB_TYPE_INDEX; import static org.jikesrvm.runtime.UnboxedSizeConstants.LOG_BYTES_IN_ADDRESS; import org.jikesrvm.VM; import org.jikesrvm.classloader.RVMType; import org.jikesrvm.compilers.opt.DefUse; import org.jikesrvm.compilers.opt.NullCheckCombining; import org.jikesrvm.compilers.opt.OptOptions; import org.jikesrvm.compilers.opt.OptimizingCompilerException; import org.jikesrvm.compilers.opt.driver.CompilerPhase; import org.jikesrvm.compilers.opt.driver.OptimizationPlanAtomicElement; import org.jikesrvm.compilers.opt.driver.OptimizationPlanCompositeElement; import org.jikesrvm.compilers.opt.driver.OptimizationPlanElement; import org.jikesrvm.compilers.opt.driver.OptimizingCompiler; import org.jikesrvm.compilers.opt.hir2lir.ConvertToLowLevelIR; import org.jikesrvm.compilers.opt.ir.BasicBlock; 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.IR; import org.jikesrvm.compilers.opt.ir.IRTools; import org.jikesrvm.compilers.opt.ir.Instruction; import org.jikesrvm.compilers.opt.ir.Load; import org.jikesrvm.compilers.opt.ir.Operators; import org.jikesrvm.compilers.opt.ir.Unary; import org.jikesrvm.compilers.opt.ir.operand.AddressConstantOperand; import org.jikesrvm.compilers.opt.ir.operand.LocationOperand; import org.jikesrvm.compilers.opt.ir.operand.MethodOperand; import org.jikesrvm.compilers.opt.ir.operand.Operand; import org.jikesrvm.compilers.opt.ir.operand.TypeOperand; import org.jikesrvm.compilers.opt.liveness.LiveAnalysis; import org.jikesrvm.objectmodel.JavaHeader; import org.jikesrvm.objectmodel.ObjectModel; import org.jikesrvm.runtime.Entrypoints; import org.vmmagic.unboxed.Offset; /** * Convert an IR object from LIR to MIR via BURS */ public final class ConvertLIRtoMIR extends OptimizationPlanCompositeElement { /** * Create this phase element as a composite of other elements */ public ConvertLIRtoMIR() { super("Instruction Selection", new OptimizationPlanElement[]{ // Stage 1: Reduce the LIR operator set to a core set of operators. new OptimizationPlanAtomicElement(new ReduceOperators()), // Stage 2: Convert ALU operators new OptimizationPlanAtomicElement( VM.BuildForIA32 ? new org.jikesrvm.compilers.opt.lir2mir.ia32.ConvertALUOperators() : new org.jikesrvm.compilers.opt.lir2mir.ppc.ConvertALUOperators()), // Stage 3: Normalize usage of constants to simplify Stage 3. new OptimizationPlanAtomicElement(new NormalizeConstantsPhase()), // Stage 4a: Compute liveness information for DepGraph new OptimizationPlanAtomicElement(new DoLiveness()), // Stage 4b: Block by block build DepGraph and do // BURS based instruction selection. new OptimizationPlanAtomicElement(new DoBURS()), // Stage 5: Handle complex operators // (those that expand to multiple basic blocks of MIR). new OptimizationPlanAtomicElement(new ComplexOperators()), // Stage 6: x64-specific cleanups new OptimizationPlanAtomicElement(new InsertIMMQ_MOVForX64()), // Stage 7: 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 OptimizationPlanAtomicElement(new NullCheckCombining()), // Stage 8: Leave LIR. Do this in an extra phase to make it // easier to insert new phases. new OptimizationPlanAtomicElement(new CompilerPhase() { @Override public void perform(IR ir) { ir.initializeStateForMIR(); } @Override public String getName() { return "Leave LIR and initialize State for MIR"; } @Override public void verify(IR ir) { // Skip verification because IR didn't change } @Override public CompilerPhase newExecution(IR ir) { return this; } }) }); } /** * Stage 1: Reduce the LIR operator set to a core set of operators. */ private static final class ReduceOperators extends CompilerPhase { @Override public String getName() { return "Reduce Operators"; } @Override public CompilerPhase newExecution(IR ir) { return this; } private void expandSysCall(Instruction s, IR ir) { if (VM.BuildForIA32) { org.jikesrvm.compilers.opt.regalloc.ia32.CallingConvention.expandSysCall(s, ir); } else { if (VM.VerifyAssertions) VM._assert(VM.BuildForPowerPC); org.jikesrvm.compilers.opt.regalloc.ppc.CallingConvention.expandSysCall(s, ir); } } @Override public void perform(IR ir) { for (Instruction s = ir.firstInstructionInCodeOrder(); s != null; s = s.nextInstructionInCodeOrder()) { switch (s.getOpcode()) { case ARRAYLENGTH_opcode: { // array_ref[ObjectModel.getArrayLengthOffset()] contains the length Load.mutate(s, INT_LOAD, GuardedUnary.getClearResult(s), GuardedUnary.getClearVal(s), IRTools.AC(ObjectModel.getArrayLengthOffset()), new LocationOperand(), GuardedUnary.getClearGuard(s)); } break; case GET_OBJ_TIB_opcode: // TODO: valid location operand. Operand address = GuardedUnary.getClearVal(s); Load.mutate(s, Operators.REF_LOAD, GuardedUnary.getClearResult(s), address, new AddressConstantOperand(JavaHeader.getTibOffset()), null, GuardedUnary.getClearGuard(s)); break; case GET_CLASS_TIB_opcode: { RVMType type = ((TypeOperand) Unary.getVal(s)).getVMType(); Offset offset = type.getTibOffset(); Load.mutate(s, REF_LOAD, Unary.getClearResult(s), ir.regpool.makeJTOCOp(), IRTools.AC(offset), new LocationOperand(offset)); } break; case GET_TYPE_FROM_TIB_opcode: { // TODO: Valid location operand? Load.mutate(s, REF_LOAD, Unary.getClearResult(s), Unary.getClearVal(s), 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), 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), 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), IRTools.AC(Offset.fromIntZeroExtend(TIB_ARRAY_ELEMENT_TIB_INDEX << LOG_BYTES_IN_ADDRESS)), null); } break; case LONG_DIV_opcode: { if (VM.BuildFor64Addr) break; // don't reduce operator -- leave for BURS Call.mutate2(s, SYSCALL, GuardedBinary.getClearResult(s), null, MethodOperand.STATIC(Entrypoints.sysLongDivideIPField), GuardedBinary.getClearVal1(s), GuardedBinary.getClearVal2(s)); ConvertToLowLevelIR.expandSysCallTarget(s, ir); expandSysCall(s, ir); } break; case LONG_REM_opcode: { if (VM.BuildFor64Addr) break; // don't reduce operator -- leave for BURS Call.mutate2(s, SYSCALL, GuardedBinary.getClearResult(s), null, MethodOperand.STATIC(Entrypoints.sysLongRemainderIPField), GuardedBinary.getClearVal1(s), GuardedBinary.getClearVal2(s)); ConvertToLowLevelIR.expandSysCallTarget(s, ir); expandSysCall(s, ir); } break; case FLOAT_REM_opcode: case DOUBLE_REM_opcode: { if (VM.BuildForPowerPC) { Call.mutate2(s, SYSCALL, Binary.getClearResult(s), null, MethodOperand.STATIC(Entrypoints.sysDoubleRemainderIPField), Binary.getClearVal1(s), Binary.getClearVal2(s)); ConvertToLowLevelIR.expandSysCallTarget(s, ir); expandSysCall(s, ir); } } break; case LONG_2FLOAT_opcode: { if (VM.BuildForPowerPC) { Call.mutate1(s, SYSCALL, Unary.getClearResult(s), null, MethodOperand.STATIC(Entrypoints.sysLongToFloatIPField), Unary.getClearVal(s)); ConvertToLowLevelIR.expandSysCallTarget(s, ir); expandSysCall(s, ir); } } break; case LONG_2DOUBLE_opcode: { if (VM.BuildForPowerPC) { Call.mutate1(s, SYSCALL, Unary.getClearResult(s), null, MethodOperand.STATIC(Entrypoints.sysLongToDoubleIPField), Unary.getClearVal(s)); ConvertToLowLevelIR.expandSysCallTarget(s, ir); 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, MethodOperand.STATIC(Entrypoints.sysFloatToLongIPField), Unary.getClearVal(s)); ConvertToLowLevelIR.expandSysCallTarget(s, ir); 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, MethodOperand.STATIC(Entrypoints.sysDoubleToLongIPField), Unary.getClearVal(s)); ConvertToLowLevelIR.expandSysCallTarget(s, ir); expandSysCall(s, ir); } break; case SYSCALL_opcode: expandSysCall(s, ir); break; default: break; } } } } /** * Stage 2: Normalize usage of int constants to make less work in Stage 3. */ private static final class NormalizeConstantsPhase extends CompilerPhase { @Override public String getName() { return "Normalize Constants"; } @Override public CompilerPhase newExecution(IR ir) { return this; } @Override public void perform(IR ir) { if (VM.BuildForIA32) { org.jikesrvm.compilers.opt.lir2mir.ia32.NormalizeConstants.perform(ir); } else { if (VM.VerifyAssertions) VM._assert(VM.BuildForPowerPC); org.jikesrvm.compilers.opt.lir2mir.ppc.NormalizeConstants.perform(ir); } } } private static final class DoLiveness extends CompilerPhase { @Override public String getName() { return "Live Handlers"; } @Override public CompilerPhase newExecution(IR ir) { return this; } @Override public void perform(IR ir) { if (ir.options.L2M_HANDLER_LIVENESS) { new LiveAnalysis(false, false, true).perform(ir); } else { ir.setHandlerLivenessComputed(false); } } } /** * Stage 3: Block by block build DepGraph and do BURS based * instruction selection. */ private static final class DoBURS extends CompilerPhase { @Override public String getName() { return "DepGraph & BURS"; } @Override public CompilerPhase newExecution(IR ir) { return this; } @Override 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. @Override public void verify(IR ir) { } @Override public void perform(IR ir) { OptOptions options = ir.options; DefUse.recomputeSpansBasicBlock(ir); MinimalBURS mburs = new MinimalBURS(ir); NormalBURS burs = new NormalBURS(ir); for (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 NormalBURS_DepGraph dgraph = new NormalBURS_DepGraph(ir, bb.firstRealInstruction(), bb.lastRealInstruction(), bb); if (options.PRINT_DG_BURS) { // print dependence graph. OptimizingCompiler.header("DepGraph", ir.method); dgraph.printDepGraph(); OptimizingCompiler.bottom("DepGraph", ir.method); } // II. Invoke BURS and rewrite block from LIR to MIR try { burs.invoke(dgraph); } catch (OptimizingCompilerException e) { System.err.println("Exception occurred in 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 CompilerPhase { @Override public String getName() { return "Complex Operators"; } @Override public CompilerPhase newExecution(IR ir) { return this; } @Override public void perform(IR ir) { if (VM.BuildForIA32) { org.jikesrvm.compilers.opt.lir2mir.ia32.ComplexLIR2MIRExpansion.convert(ir); } else { if (VM.VerifyAssertions) VM._assert(VM.BuildForPowerPC); org.jikesrvm.compilers.opt.lir2mir.ppc.ComplexLIR2MIRExpansion.convert(ir); } } } private static final class InsertIMMQ_MOVForX64 extends CompilerPhase { @Override public String getName() { return "Insert IMMQ_MOV instructions for 64-bit immediate values"; } @Override public boolean shouldPerform(OptOptions options) { return VM.BuildForIA32 && VM.BuildFor64Addr; } @Override public CompilerPhase newExecution(IR ir) { return this; } @Override public void perform(IR ir) { if (VM.BuildForIA32) { org.jikesrvm.compilers.opt.lir2mir.ia32.ComplexLIR2MIRExpansion.process64BitImmediateValues(ir); } } } }