/* * 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.ia32; import static org.jikesrvm.compilers.opt.ir.Operators.ADDR_2INT_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.ADDR_2LONG_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.ATTEMPT_ADDR_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.ATTEMPT_INT; import static org.jikesrvm.compilers.opt.ir.Operators.ATTEMPT_LONG; import static org.jikesrvm.compilers.opt.ir.Operators.BOOLEAN_CMP_ADDR_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.BOOLEAN_CMP_INT; import static org.jikesrvm.compilers.opt.ir.Operators.BOOLEAN_CMP_LONG; import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_ADD_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_COND_MOVE_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_DIV_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_MUL_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_NEG_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_REM_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_SUB_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_ADD_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_COND_MOVE_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_DIV_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_MUL_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_NEG_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_REM_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_SUB_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.GUARD_COND_MOVE_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.INT_2ADDRSigExt_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.INT_2ADDRZerExt_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.INT_2DOUBLE_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.INT_2FLOAT_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.INT_2LONG; import static org.jikesrvm.compilers.opt.ir.Operators.INT_ADD; import static org.jikesrvm.compilers.opt.ir.Operators.INT_ALOAD; import static org.jikesrvm.compilers.opt.ir.Operators.INT_AND; import static org.jikesrvm.compilers.opt.ir.Operators.INT_ASTORE; import static org.jikesrvm.compilers.opt.ir.Operators.INT_COND_MOVE_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.INT_IFCMP; import static org.jikesrvm.compilers.opt.ir.Operators.INT_LOAD; import static org.jikesrvm.compilers.opt.ir.Operators.INT_MOVE; import static org.jikesrvm.compilers.opt.ir.Operators.INT_NEG; import static org.jikesrvm.compilers.opt.ir.Operators.INT_NOT; import static org.jikesrvm.compilers.opt.ir.Operators.INT_OR; import static org.jikesrvm.compilers.opt.ir.Operators.INT_SHL; import static org.jikesrvm.compilers.opt.ir.Operators.INT_SHR; import static org.jikesrvm.compilers.opt.ir.Operators.INT_STORE; import static org.jikesrvm.compilers.opt.ir.Operators.INT_SUB; import static org.jikesrvm.compilers.opt.ir.Operators.INT_USHR; import static org.jikesrvm.compilers.opt.ir.Operators.INT_XOR; import static org.jikesrvm.compilers.opt.ir.Operators.LONG_2ADDR_opcode; 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_2INT; import static org.jikesrvm.compilers.opt.ir.Operators.LONG_ADD; import static org.jikesrvm.compilers.opt.ir.Operators.LONG_ALOAD; import static org.jikesrvm.compilers.opt.ir.Operators.LONG_AND; import static org.jikesrvm.compilers.opt.ir.Operators.LONG_ASTORE; import static org.jikesrvm.compilers.opt.ir.Operators.LONG_COND_MOVE_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.LONG_IFCMP; import static org.jikesrvm.compilers.opt.ir.Operators.LONG_LOAD; import static org.jikesrvm.compilers.opt.ir.Operators.LONG_MOVE; import static org.jikesrvm.compilers.opt.ir.Operators.LONG_NEG; import static org.jikesrvm.compilers.opt.ir.Operators.LONG_NOT; import static org.jikesrvm.compilers.opt.ir.Operators.LONG_OR; import static org.jikesrvm.compilers.opt.ir.Operators.LONG_SHL; import static org.jikesrvm.compilers.opt.ir.Operators.LONG_SHR; import static org.jikesrvm.compilers.opt.ir.Operators.LONG_STORE; import static org.jikesrvm.compilers.opt.ir.Operators.LONG_SUB; import static org.jikesrvm.compilers.opt.ir.Operators.LONG_USHR; import static org.jikesrvm.compilers.opt.ir.Operators.LONG_XOR; import static org.jikesrvm.compilers.opt.ir.Operators.PREPARE_ADDR_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.PREPARE_INT_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.PREPARE_LONG_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.REF_ADD_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.REF_ALOAD_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.REF_AND_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.REF_ASTORE_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.REF_COND_MOVE_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.REF_IFCMP_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.REF_LOAD_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.REF_MOVE_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.REF_NEG_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.REF_NOT_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.REF_OR_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.REF_SHL_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.REF_SHR_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.REF_STORE_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.REF_SUB_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.REF_USHR_opcode; import static org.jikesrvm.compilers.opt.ir.Operators.REF_XOR_opcode; import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.CMP_CMOV; import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.CMP_FCMOV; import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.FCMP_CMOV; import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.FCMP_FCMOV; import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.FP_ADD; import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.FP_DIV; import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.FP_MUL; import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.FP_NEG; import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.FP_REM; import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.FP_SUB; import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.INT_2FP; import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.LCMP_CMOV; import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.LONG_2FP; import static org.jikesrvm.ia32.ArchConstants.SSE2_FULL; import java.util.Enumeration; import org.jikesrvm.VM; import org.jikesrvm.compilers.opt.OptimizingCompilerException; import org.jikesrvm.compilers.opt.Simplifier; import org.jikesrvm.compilers.opt.driver.CompilerPhase; import org.jikesrvm.compilers.opt.ir.CondMove; import org.jikesrvm.compilers.opt.ir.IR; import org.jikesrvm.compilers.opt.ir.Instruction; /** * Reduce the number of ALU operators considered by BURS */ public final class ConvertALUOperators extends CompilerPhase { @Override public String getName() { return "ConvertALUOps"; } /** * Return this instance of this phase. This phase contains no * per-compilation instance fields. * @param ir not used * @return this */ @Override public CompilerPhase newExecution(IR ir) { return this; } @Override public void perform(IR ir) { // 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...) // BURS assumes that this has been done for (Enumeration<Instruction> instrs = ir.forwardInstrEnumerator(); instrs.hasMoreElements();) { Instruction s = instrs.nextElement(); Simplifier.simplify(false, ir.regpool, ir.options, s); } // Pass over instructions for (Enumeration<Instruction> e = ir.forwardInstrEnumerator(); e.hasMoreElements();) { Instruction s = e.nextElement(); // BURS doesn't really care, so consolidate to reduce rule space switch (s.getOpcode()) { case REF_ADD_opcode: s.changeOperatorTo(VM.BuildFor32Addr ? INT_ADD : LONG_ADD); break; case REF_SUB_opcode: s.changeOperatorTo(VM.BuildFor32Addr ? INT_SUB : LONG_SUB); break; case REF_NEG_opcode: s.changeOperatorTo(VM.BuildFor32Addr ? INT_NEG : LONG_NEG); break; case REF_NOT_opcode: s.changeOperatorTo(VM.BuildFor32Addr ? INT_NOT : LONG_NOT); break; case REF_AND_opcode: s.changeOperatorTo(VM.BuildFor32Addr ? INT_AND : LONG_AND); break; case REF_OR_opcode: s.changeOperatorTo(VM.BuildFor32Addr ? INT_OR : LONG_OR); break; case REF_XOR_opcode: s.changeOperatorTo(VM.BuildFor32Addr ? INT_XOR : LONG_XOR); break; case REF_SHL_opcode: s.changeOperatorTo(VM.BuildFor32Addr ? INT_SHL : LONG_SHL); break; case REF_SHR_opcode: s.changeOperatorTo(VM.BuildFor32Addr ? INT_SHR : LONG_SHR); break; case REF_USHR_opcode: s.changeOperatorTo(VM.BuildFor32Addr ? INT_USHR : LONG_USHR); break; case REF_LOAD_opcode: s.changeOperatorTo(VM.BuildFor32Addr ? INT_LOAD : LONG_LOAD); break; case REF_STORE_opcode: s.changeOperatorTo(VM.BuildFor32Addr ? INT_STORE : LONG_STORE); break; case REF_ALOAD_opcode: s.changeOperatorTo(VM.BuildFor32Addr ? INT_ALOAD : LONG_ALOAD); break; case REF_ASTORE_opcode: s.changeOperatorTo(VM.BuildFor32Addr ? INT_ASTORE : LONG_ASTORE); break; case REF_MOVE_opcode: s.changeOperatorTo(VM.BuildFor32Addr ? INT_MOVE : LONG_MOVE); break; case REF_IFCMP_opcode: s.changeOperatorTo(VM.BuildFor32Addr ? INT_IFCMP : LONG_IFCMP); break; case BOOLEAN_CMP_ADDR_opcode: s.changeOperatorTo(VM.BuildFor32Addr ? BOOLEAN_CMP_INT : BOOLEAN_CMP_LONG); break; case ATTEMPT_ADDR_opcode: s.changeOperatorTo(VM.BuildFor32Addr ? ATTEMPT_INT : ATTEMPT_LONG); break; case PREPARE_ADDR_opcode: s.changeOperatorTo(VM.BuildFor32Addr ? INT_LOAD : LONG_LOAD); break; case PREPARE_INT_opcode: s.changeOperatorTo(INT_LOAD); break; case PREPARE_LONG_opcode: s.changeOperatorTo(LONG_LOAD); break; case INT_2ADDRSigExt_opcode: s.changeOperatorTo(VM.BuildFor32Addr ? INT_MOVE : INT_2LONG); break; case INT_2ADDRZerExt_opcode: if (VM.BuildFor32Addr) { s.changeOperatorTo(INT_MOVE); } break; case ADDR_2INT_opcode: s.changeOperatorTo(VM.BuildFor32Addr ? INT_MOVE : LONG_2INT); break; case ADDR_2LONG_opcode: // Note that a 32-bit ADDR_2LONG cannot be changed to an INT_2LONG because // INT_2LONG uses the Java conventions for widening by default. Java widening // uses sign extension which is not appropriate for addresses. The unboxed // types that Jikes RVM uses define that the toLong() methods use zero-extension. // For example, for 0xFFFF FFFF (32 bit addresses) the result is supposed to be // 0x0000 0000 FFFF FFFF but with sign extension it would be // 0xFFFF FFFF FFFF FFFF. // Therefore, let BURS rules convert to ADDR_2LONG. The BURS rules can use // methods from BURS_Helpers which provide the possibility to emit code for an // INT_2LONG that uses zero-extension. if (VM.BuildFor64Addr) { s.changeOperatorTo(LONG_MOVE); } break; case LONG_2ADDR_opcode: s.changeOperatorTo(VM.BuildFor32Addr ? LONG_2INT : LONG_MOVE); break; case FLOAT_ADD_opcode: if (!SSE2_FULL) s.changeOperatorTo(FP_ADD); break; case DOUBLE_ADD_opcode: if (!SSE2_FULL) s.changeOperatorTo(FP_ADD); break; case FLOAT_SUB_opcode: if (!SSE2_FULL) s.changeOperatorTo(FP_SUB); break; case DOUBLE_SUB_opcode: if (!SSE2_FULL) s.changeOperatorTo(FP_SUB); break; case FLOAT_MUL_opcode: if (!SSE2_FULL) s.changeOperatorTo(FP_MUL); break; case DOUBLE_MUL_opcode: if (!SSE2_FULL) s.changeOperatorTo(FP_MUL); break; case FLOAT_DIV_opcode: if (!SSE2_FULL) s.changeOperatorTo(FP_DIV); break; case DOUBLE_DIV_opcode: if (!SSE2_FULL) s.changeOperatorTo(FP_DIV); break; case FLOAT_REM_opcode: if (!SSE2_FULL) s.changeOperatorTo(FP_REM); break; case DOUBLE_REM_opcode: if (!SSE2_FULL) s.changeOperatorTo(FP_REM); break; case FLOAT_NEG_opcode: if (!SSE2_FULL) s.changeOperatorTo(FP_NEG); break; case DOUBLE_NEG_opcode: if (!SSE2_FULL) s.changeOperatorTo(FP_NEG); break; case INT_COND_MOVE_opcode: case REF_COND_MOVE_opcode: s.changeOperatorTo(CondMove.getCond(s).isFLOATINGPOINT() ? FCMP_CMOV : (CondMove.getVal1(s).isLong() ? LCMP_CMOV : CMP_CMOV)); break; case FLOAT_COND_MOVE_opcode: case DOUBLE_COND_MOVE_opcode: s.changeOperatorTo(CondMove.getCond(s).isFLOATINGPOINT() ? FCMP_FCMOV : CMP_FCMOV); break; case GUARD_COND_MOVE_opcode: case LONG_COND_MOVE_opcode: OptimizingCompilerException.TODO("Unimplemented conversion" + s); break; case INT_2FLOAT_opcode: if (!SSE2_FULL) s.changeOperatorTo(INT_2FP); break; case INT_2DOUBLE_opcode: if (!SSE2_FULL) s.changeOperatorTo(INT_2FP); break; case LONG_2FLOAT_opcode: if (!SSE2_FULL) s.changeOperatorTo(LONG_2FP); break; case LONG_2DOUBLE_opcode: if (!SSE2_FULL) s.changeOperatorTo(LONG_2FP); break; } } } }