/* * 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.bc2ir.ppc; import static org.jikesrvm.compilers.opt.ir.IRTools.AC; import static org.jikesrvm.compilers.opt.ir.IRTools.offsetOperand; import static org.jikesrvm.compilers.opt.ir.Operators.ILLEGAL_INSTRUCTION; import static org.jikesrvm.compilers.opt.ir.Operators.INT_LOAD; import static org.jikesrvm.compilers.opt.ir.Operators.INT_STORE; import static org.jikesrvm.compilers.opt.ir.Operators.READ_CEILING; import static org.jikesrvm.compilers.opt.ir.Operators.REF_ADD; import static org.jikesrvm.compilers.opt.ir.Operators.REF_LOAD; import static org.jikesrvm.compilers.opt.ir.Operators.REF_STORE; import static org.jikesrvm.compilers.opt.ir.Operators.WRITE_FLOOR; import static org.jikesrvm.compilers.opt.ir.ppc.ArchOperators.DCBST; import static org.jikesrvm.compilers.opt.ir.ppc.ArchOperators.DCBT; import static org.jikesrvm.compilers.opt.ir.ppc.ArchOperators.DCBTST; import static org.jikesrvm.compilers.opt.ir.ppc.ArchOperators.DCBZ; import static org.jikesrvm.compilers.opt.ir.ppc.ArchOperators.DCBZL; import static org.jikesrvm.compilers.opt.ir.ppc.ArchOperators.ICBI; import static org.jikesrvm.ppc.StackframeLayoutConstants.STACKFRAME_FRAME_POINTER_OFFSET; import static org.jikesrvm.ppc.StackframeLayoutConstants.STACKFRAME_METHOD_ID_OFFSET; import static org.jikesrvm.ppc.StackframeLayoutConstants.STACKFRAME_RETURN_ADDRESS_OFFSET; import org.jikesrvm.classloader.Atom; import org.jikesrvm.classloader.MethodReference; import org.jikesrvm.classloader.TypeReference; import org.jikesrvm.compilers.opt.MagicNotImplementedException; import org.jikesrvm.compilers.opt.bc2ir.BC2IR; import org.jikesrvm.compilers.opt.bc2ir.GenerationContext; import org.jikesrvm.compilers.opt.ir.CacheOp; import org.jikesrvm.compilers.opt.ir.Empty; import org.jikesrvm.compilers.opt.ir.Instruction; import org.jikesrvm.compilers.opt.ir.Load; import org.jikesrvm.compilers.opt.ir.Store; import org.jikesrvm.compilers.opt.ir.operand.Operand; import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand; import org.jikesrvm.runtime.MagicNames; /** * This class implements the machine-specific magics for the opt compiler. * * @see org.jikesrvm.compilers.opt.bc2ir.GenerateMagic for the machine-independent magics. */ public abstract class GenerateMachineSpecificMagic { /** * "Semantic inlining" of methods of the Magic class * Based on the methodName, generate a sequence of opt instructions * that implement the magic, updating the stack as necessary * * @param bc2ir the bc2ir object that is generating the * ir containing this magic * @param gc == bc2ir.gc * @param meth the RVMMethod that is the magic method * @return {@code true} if and only if magic was generated */ public static boolean generateMagic(BC2IR bc2ir, GenerationContext gc, MethodReference meth) throws MagicNotImplementedException { Atom methodName = meth.getName(); if (methodName == MagicNames.getFramePointer) { bc2ir.push(gc.getTemps().makeFPOp()); gc.forceFrameAllocation(); } else if (methodName == MagicNames.getTocPointer) { bc2ir.push(gc.getTemps().makeJTOCOp()); } else if (methodName == MagicNames.getJTOC) { bc2ir.push(gc.getTemps().makeTocOp()); } else if (methodName == MagicNames.getCallerFramePointer) { Operand fp = bc2ir.popAddress(); RegisterOperand val = gc.getTemps().makeTemp(TypeReference.Address); bc2ir.appendInstruction(Load.create(REF_LOAD, val, fp, AC(STACKFRAME_FRAME_POINTER_OFFSET), null)); bc2ir.push(val.copyD2U()); } else if (methodName == MagicNames.setCallerFramePointer) { Operand val = bc2ir.popAddress(); Operand fp = bc2ir.popAddress(); bc2ir.appendInstruction(Store.create(REF_STORE, val, fp, AC(STACKFRAME_FRAME_POINTER_OFFSET), null)); } else if (methodName == MagicNames.getCompiledMethodID) { Operand fp = bc2ir.popAddress(); RegisterOperand val = gc.getTemps().makeTempInt(); bc2ir.appendInstruction(Load.create(INT_LOAD, val, fp, AC(STACKFRAME_METHOD_ID_OFFSET), null)); bc2ir.push(val.copyD2U()); } else if (methodName == MagicNames.setCompiledMethodID) { Operand val = bc2ir.popInt(); Operand fp = bc2ir.popAddress(); bc2ir.appendInstruction(Store.create(INT_STORE, val, fp, AC(STACKFRAME_METHOD_ID_OFFSET), null)); } else if (methodName == MagicNames.getNextInstructionAddress) { Operand fp = bc2ir.popAddress(); RegisterOperand val = gc.getTemps().makeTemp(TypeReference.Address); bc2ir.appendInstruction(Load.create(REF_LOAD, val, fp, AC(STACKFRAME_RETURN_ADDRESS_OFFSET), null)); bc2ir.push(val.copyD2U()); } else if (methodName == MagicNames.getReturnAddressLocation) { Operand fp = bc2ir.popAddress(); RegisterOperand callerFP = gc.getTemps().makeTemp(TypeReference.Address); bc2ir.appendInstruction(Load.create(REF_LOAD, callerFP, fp, AC(STACKFRAME_FRAME_POINTER_OFFSET), null)); Instruction s = bc2ir._binaryHelper(REF_ADD, callerFP.copyRO(), offsetOperand(STACKFRAME_RETURN_ADDRESS_OFFSET), TypeReference.Address); bc2ir.appendInstruction(s); } else if (methodName == MagicNames.isync) { bc2ir.appendInstruction(Empty.create(READ_CEILING)); } else if (methodName == MagicNames.sync) { bc2ir.appendInstruction(Empty.create(WRITE_FLOOR)); } else if (methodName == MagicNames.pause) { // IA-specific } else if (methodName == MagicNames.illegalInstruction) { bc2ir.appendInstruction(Empty.create(ILLEGAL_INSTRUCTION)); } else if (methodName == MagicNames.dcbst) { bc2ir.appendInstruction(CacheOp.create(DCBST, bc2ir.popAddress())); } else if (methodName == MagicNames.dcbt || methodName == MagicNames.prefetch) { bc2ir.appendInstruction(CacheOp.create(DCBT, bc2ir.popAddress())); } else if (methodName == MagicNames.dcbtst) { bc2ir.appendInstruction(CacheOp.create(DCBTST, bc2ir.popAddress())); } else if (methodName == MagicNames.dcbz) { bc2ir.appendInstruction(CacheOp.create(DCBZ, bc2ir.popAddress())); } else if (methodName == MagicNames.dcbzl) { bc2ir.appendInstruction(CacheOp.create(DCBZL, bc2ir.popAddress())); } else if (methodName == MagicNames.icbi) { bc2ir.appendInstruction(CacheOp.create(ICBI, bc2ir.popAddress())); } else { // Distinguish between magics that we know we don't implement // (and never plan to implement) and those (usually new ones) // that we want to be warned that we don't implement. String msg = "Magic method not implemented: " + meth; if (methodName == MagicNames.returnToNewStack) { throw MagicNotImplementedException.EXPECTED(msg); } else { return false; // throw MagicNotImplementedException.UNEXPECTED(msg); } } return true; } }