| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /** |
| * @author Intel, Pavel A. Ozhdikhin |
| */ |
| |
| #include "CodeSelectors.h" |
| |
| namespace Jitrino { |
| |
| void _VarCodeSelector::genCode(Callback& callback) { |
| VarOpnd * v0 = varOpnds; |
| if (v0) { |
| VarOpnd * v = v0; |
| do { |
| if (!(v->isDead())) { // currently need to check, though dead items should be removed in future |
| assert(!(v->isDead())); |
| varIdMap[v->getId()] = |
| callback.defVar(v->getType(),v->isAddrTaken(), |
| v->isPinned()); |
| if(Log::isEnabled()) { |
| Log::out() << "Opt var "; |
| v->print(Log::out()); |
| Log::out() << " is CG var " << (int) varIdMap[v->getId()] << ::std::endl; |
| } |
| } |
| v=v->getNextVarOpnd(); |
| } while (v != v0); |
| } |
| |
| GCBasePointerMap::iterator i; |
| for(i = gcMap.begin(); i != gcMap.end(); ++i) { |
| if(Log::isEnabled()) { |
| Log::out() << "Set GC base of "; |
| i->first->print(Log::out()); |
| Log::out() << "(" << (int) varIdMap[i->first->getId()] << ") to "; |
| i->second->print(Log::out()); |
| Log::out() << "(" << (int) varIdMap[i->second->getId()] << ")" << ::std::endl; |
| } |
| callback.setManagedPointerBase(varIdMap[i->first->getId()], varIdMap[i->second->getId()]); |
| } |
| } |
| |
| U_32 _VarCodeSelector::getNumVarOpnds() { |
| VarOpnd* v0 = varOpnds; |
| U_32 numVars = 0; |
| if (v0) { |
| VarOpnd* v = v0; |
| do { |
| if (!(v->isDead())) { // currently need to check, though in future dead items should be removed |
| assert(!(v->isDead())); |
| numVars++; |
| } |
| v = v->getNextVarOpnd(); |
| } while (v != v0); |
| } |
| return numVars; |
| } |
| |
| // |
| // maps type and overflow modifier to a ArithmeticOp::Types |
| // |
| ArithmeticOp::Types _BlockCodeSelector::mapToArithmOpType(Inst* inst) { |
| Type::Tag type = inst->getType(); |
| OverflowModifier modifier = inst->getOverflowModifier(); |
| ExceptionModifier excModifier = inst->getExceptionModifier(); |
| switch (type) { |
| case Type::Int32: |
| if ((modifier == Overflow_None) || (excModifier == Exception_Never)) |
| return ArithmeticOp::I4; |
| if (modifier == Overflow_Signed) |
| return ArithmeticOp::I4_Ovf; |
| return ArithmeticOp::U4_Ovf; |
| case Type::Int64: |
| if ((modifier == Overflow_None) || (excModifier == Exception_Never)) |
| return ArithmeticOp::I8; |
| if (modifier == Overflow_Signed) |
| return ArithmeticOp::I8_Ovf; |
| return ArithmeticOp::U8_Ovf; |
| case Type::IntPtr: |
| case Type::UIntPtr: |
| if ((modifier == Overflow_None) || (excModifier == Exception_Never)) |
| return ArithmeticOp::I; |
| if (modifier == Overflow_Signed) |
| return ArithmeticOp::I_Ovf; |
| return ArithmeticOp::U_Ovf; |
| case Type::Float: |
| return ArithmeticOp::F; |
| case Type::Single: |
| return ArithmeticOp::S; |
| case Type::Double: |
| return ArithmeticOp::D; |
| default: assert(0); |
| } |
| assert(0); |
| return ArithmeticOp::I; // to keep the compiler quiet |
| } |
| |
| // |
| // maps type and overflow modifier to a RefArithmeticOp::Type |
| // |
| RefArithmeticOp::Types _BlockCodeSelector::mapToRefArithmOpType(Inst* inst, Opnd *src) { |
| Type::Tag type = src->getType()->tag; |
| OverflowModifier modifier = inst->getOverflowModifier(); |
| ExceptionModifier excModifier = inst->getExceptionModifier(); |
| assert(modifier != Overflow_Signed); |
| switch (type) { |
| case Type::Int32: |
| if ((modifier == Overflow_None) || (excModifier == Exception_Never)) |
| return RefArithmeticOp::I4; |
| return RefArithmeticOp::U4_Ovf; |
| case Type::IntPtr: |
| if ((modifier == Overflow_None) || (excModifier == Exception_Never)) |
| return RefArithmeticOp::I; |
| return RefArithmeticOp::U_Ovf; |
| default: assert(0); |
| } |
| assert(0); |
| return RefArithmeticOp::I; // to keep the compiler quiet |
| } |
| |
| // |
| // checks if instruction has an overflow modifier |
| // |
| bool _BlockCodeSelector::isOverflow(Inst* inst) { |
| Modifier mod = inst->getModifier(); |
| if (mod.hasOverflowModifier()) { |
| OverflowModifier modifier = mod.getOverflowModifier(); |
| return modifier != Overflow_None; |
| } else |
| return false; |
| } |
| |
| // |
| // checks if instruction has an exception modifier that can never except |
| // |
| bool _BlockCodeSelector::isExceptionNever(Inst* inst) { |
| Modifier mod = inst->getModifier(); |
| if (mod.hasExceptionModifier()) { |
| ExceptionModifier modifier = mod.getExceptionModifier(); |
| return modifier == Exception_Never; |
| } else |
| return false; |
| } |
| |
| // |
| // checks if instruction is unsigned |
| // |
| bool _BlockCodeSelector::isUnsigned(Inst *inst) { |
| Modifier mod = inst->getModifier(); |
| if (mod.hasSignedModifier()) { |
| SignedModifier modifier = mod.getSignedModifier(); |
| return modifier == UnsignedOp; |
| } else { |
| assert(0); |
| return false; |
| } |
| } |
| |
| // |
| // checks if shift instruction needs shift mask |
| // |
| bool _BlockCodeSelector::isShiftMask(Inst *inst) { |
| assert(inst->getModifier().hasShiftMaskModifier()); |
| ShiftMaskModifier modifier = inst->getModifier().getShiftMaskModifier(); |
| return modifier == ShiftMask_Masked; |
| } |
| |
| DivOp::Types _BlockCodeSelector::mapToDivOpType(Inst* inst) { |
| Type::Tag type = inst->getType(); |
| SignedModifier modifier = inst->getSignedModifier(); |
| bool unsignedDiv = (modifier == UnsignedOp); |
| |
| switch (type) { |
| case Type::Int32: |
| return unsignedDiv ? DivOp::U4 : DivOp::I4; |
| case Type::Int64: |
| return unsignedDiv ? DivOp::U8 : DivOp::I8; |
| case Type::IntPtr: |
| return unsignedDiv ? DivOp::U : DivOp::I; |
| case Type::Float: |
| return DivOp::F; |
| case Type::Single: |
| return DivOp::S; |
| case Type::Double: |
| return DivOp::D; |
| default: assert(0); |
| } |
| assert(0); |
| return DivOp::I; // to keep compiler quiet |
| } |
| |
| MulHiOp::Types _BlockCodeSelector::mapToMulHiOpType(Inst * inst) { |
| Type::Tag type = inst->getType(); |
| SignedModifier modifier = inst->getSignedModifier(); |
| bool unsignedMulhi = (modifier == UnsignedOp); |
| |
| switch (type) { |
| case Type::Int32: |
| return unsignedMulhi ? MulHiOp::U4 : MulHiOp::I4; |
| case Type::Int64: |
| return unsignedMulhi ? MulHiOp::U8 : MulHiOp::I8; |
| case Type::IntPtr: |
| return unsignedMulhi ? MulHiOp::U : MulHiOp::I; |
| default: assert(0); |
| } |
| assert(0); |
| return MulHiOp::I; // to keep compiler quiet |
| } |
| |
| NegOp::Types _BlockCodeSelector::mapToNegOpType(Inst* inst) { |
| Type::Tag type = inst->getType(); |
| switch(type) { |
| case Type::Int32: |
| return NegOp::I4; |
| case Type::Int64: |
| return NegOp::I8; |
| case Type::IntPtr: |
| return NegOp::I; |
| case Type::Float: |
| return NegOp::F; |
| case Type::Single: |
| return NegOp::S; |
| case Type::Double: |
| return NegOp::D; |
| default: assert(0); |
| } |
| assert(0); |
| return NegOp::I; // to keep compiler quiet |
| } |
| |
| // |
| // Maps instruction type to IntegerOp::Types |
| // |
| IntegerOp::Types _BlockCodeSelector::mapToIntegerOpType(Inst* inst) { |
| Type::Tag type = inst->getType(); |
| switch (type) { |
| case Type::Int32: |
| return IntegerOp::I4; |
| case Type::Int64: |
| return IntegerOp::I8; |
| case Type::IntPtr: |
| case Type::UIntPtr: |
| return IntegerOp::I; |
| default: assert(0); |
| } |
| assert(0); |
| return IntegerOp::I; // to keep compiler quiet |
| } |
| |
| // |
| // maps type to CompareOp::Types |
| // |
| CompareOp::Types _BlockCodeSelector::mapToCompareOpType(Inst* inst) { |
| Type::Tag type = inst->getType(); |
| switch (type) { |
| case Type::Int32: |
| return CompareOp::I4; |
| case Type::Int64: |
| return CompareOp::I8; |
| case Type::IntPtr: |
| case Type::UIntPtr: |
| return CompareOp::I; |
| case Type::Float: |
| return CompareOp::F; |
| case Type::Single: |
| return CompareOp::S; |
| case Type::Double: |
| return CompareOp::D; |
| default: |
| |
| assert(Type::isReference(type)); |
| return CompareOp::Ref; |
| } |
| } |
| |
| // |
| // maps type to CompareZeroOp::Types |
| // |
| CompareZeroOp::Types _BlockCodeSelector::mapToCompareZeroOpType(Inst *inst) { |
| Type::Tag type = inst->getType(); |
| switch (type) { |
| case Type::Int32: |
| return CompareZeroOp::I4; |
| case Type::Int64: |
| return CompareZeroOp::I8; |
| case Type::IntPtr: |
| return CompareZeroOp::I; |
| default: |
| assert(Type::isReference(type)); |
| return CompareZeroOp::Ref; |
| } |
| } |
| |
| // |
| // Maps compare inst to the CompareOp::Operator |
| // |
| CompareOp::Operators _BlockCodeSelector::mapToComparisonOp(Inst* inst) { |
| ComparisonModifier modifier = inst->getComparisonModifier(); |
| switch (modifier) { |
| case Cmp_EQ: return CompareOp::Eq; |
| case Cmp_NE_Un: return CompareOp::Ne; |
| case Cmp_GT: return CompareOp::Gt; |
| case Cmp_GT_Un: return CompareOp::Gtu; |
| case Cmp_GTE: return CompareOp::Ge; |
| case Cmp_GTE_Un: return CompareOp::Geu; |
| // unary boolean comparisons |
| case Cmp_Zero: |
| case Cmp_NonZero: |
| default: |
| assert(0); |
| } |
| return CompareOp::Eq; // to keep compiler quiet |
| } |
| |
| // |
| // Maps instruction to ConvertToFpOp::Types |
| // |
| ConvertToFpOp::Types _BlockCodeSelector::mapToFpConvertOpType(Inst *inst) { |
| Type::Tag type = inst->getType(); |
| switch (type) { |
| case Type::Single: return ConvertToFpOp::Single; |
| case Type::Double: return ConvertToFpOp::Double; |
| case Type::Float: return ConvertToFpOp::FloatFromUnsigned; |
| default: assert(0); |
| } |
| assert(0); |
| return ConvertToFpOp::Single; // to keep the compiler quiet |
| } |
| |
| // |
| // Maps instruction to ConvertToIntOp::Types |
| // |
| ConvertToIntOp::Types _BlockCodeSelector::mapToIntConvertOpType(Inst *inst) { |
| Type::Tag type = inst->getType(); |
| switch (type) { |
| case Type::Int8: |
| case Type::UInt8: |
| return ConvertToIntOp::I1; |
| case Type::Int16: |
| case Type::UInt16: |
| return ConvertToIntOp::I2; |
| case Type::Int32: |
| case Type::UInt32: |
| return ConvertToIntOp::I4; |
| case Type::Int64: |
| case Type::UInt64: |
| return ConvertToIntOp::I8; |
| case Type::IntPtr: |
| case Type::UIntPtr: |
| return ConvertToIntOp::I; |
| default: assert(0); |
| } |
| assert(0); |
| return ConvertToIntOp::I; // to keep the compiler quiet |
| } |
| |
| // |
| // Maps instruction to ConvertToIntOp::OverflowMod |
| // |
| ConvertToIntOp::OverflowMod _BlockCodeSelector::mapToIntConvertOvfMod(Inst *inst) { |
| if (isExceptionNever(inst)) { return ConvertToIntOp::NoOvf; }; |
| OverflowModifier modifier = inst->getOverflowModifier(); |
| switch (modifier) { |
| case Overflow_None: |
| return ConvertToIntOp::NoOvf; |
| case Overflow_Signed: |
| return ConvertToIntOp::SignedOvf; |
| case Overflow_Unsigned: |
| return ConvertToIntOp::UnsignedOvf; |
| default: assert(0); |
| } |
| return ConvertToIntOp::NoOvf; // to keep the compiler quiet |
| } |
| |
| JitHelperCallOp::Id _BlockCodeSelector::convertJitHelperId(JitHelperCallId callId) { |
| switch(callId) { |
| case Prefetch: return JitHelperCallOp::Prefetch; |
| case Memset0: return JitHelperCallOp::Memset0; |
| case InitializeArray: return JitHelperCallOp::InitializeArray; |
| case SaveThisState: return JitHelperCallOp::SaveThisState; |
| case ReadThisState: return JitHelperCallOp::ReadThisState; |
| case LockedCompareAndExchange: return JitHelperCallOp::LockedCompareAndExchange; |
| case AddValueProfileValue: return JitHelperCallOp::AddValueProfileValue; |
| case FillArrayWithConst: return JitHelperCallOp::FillArrayWithConst; |
| case ArrayCopyDirect: return JitHelperCallOp::ArrayCopyDirect; |
| case ArrayCopyReverse: return JitHelperCallOp::ArrayCopyReverse; |
| case StringCompareTo: return JitHelperCallOp::StringCompareTo; |
| case StringRegionMatches: return JitHelperCallOp::StringRegionMatches; |
| case StringIndexOf: return JitHelperCallOp::StringIndexOf; |
| default: break; |
| } |
| crash("\n JIT helper in not supported in LIR : %d\n", callId); |
| |
| return JitHelperCallOp::InitializeArray; // to keep compiler quiet |
| } |
| |
| CG_OpndHandle ** _BlockCodeSelector::genCallArgs(Inst * call, U_32 arg0Pos) { |
| U_32 nSrc = call->getNumSrcOperands(); |
| CG_OpndHandle ** args = new(memManager) CG_OpndHandle*[nSrc - arg0Pos]; |
| for (U_32 i = arg0Pos; i < nSrc; i++) |
| args[i - arg0Pos] = getCGInst(call->getSrc(i)); |
| return args; |
| } |
| |
| CG_OpndHandle ** _BlockCodeSelector::genCallArgs(Opnd *extraArg, Inst * call, U_32 arg0Pos) { |
| U_32 nSrc = call->getNumSrcOperands(); |
| CG_OpndHandle ** args = new(memManager) CG_OpndHandle*[nSrc - arg0Pos + 1]; |
| args[0] = getCGInst(extraArg); |
| for (U_32 i = arg0Pos; i < nSrc; i++) |
| args[i - arg0Pos + 1] = getCGInst(call->getSrc(i)); |
| return args; |
| } |
| |
| void _BlockCodeSelector::genInstCode(InstructionCallback& instructionCallback, Inst *inst, bool genConsts) |
| { |
| uint16 bcOffset = inst->getBCOffset(); |
| instructionCallback.setCurrentHIRInstBCOffset(bcOffset); |
| |
| if(Log::isEnabled()) { |
| Log::out() << "genInstCode "; |
| inst->print(Log::out()); |
| if (genConsts) { |
| Log::out() << "; genConsts=true" << ::std::endl; |
| } else { |
| Log::out() << "; genConsts=false" << ::std::endl; |
| } |
| } |
| |
| CG_OpndHandle* cgInst = NULL; |
| Opnd *dst = inst->getDst(); |
| bool isConstant = false; |
| switch(inst->getOpcode()) { |
| case Op_Add: |
| { |
| assert(inst->getNumSrcOperands() == 2); |
| Opnd* src1 = inst->getSrc(0); |
| Opnd* src2 = inst->getSrc(1); |
| CG_OpndHandle* src1CGInst = getCGInst(src1); |
| CG_OpndHandle* src2CGInst = getCGInst(src2); |
| if (src1->getType()->isReference()) { |
| cgInst = instructionCallback.addRef(mapToRefArithmOpType(inst,src2), |
| src1CGInst,src2CGInst); |
| } else { |
| cgInst = instructionCallback.add(mapToArithmOpType(inst), |
| src1CGInst,src2CGInst); |
| } |
| } |
| break; |
| case Op_Mul: |
| { |
| assert(inst->getNumSrcOperands() == 2); |
| cgInst = instructionCallback.mul(mapToArithmOpType(inst), |
| getCGInst(inst->getSrc(0)), |
| getCGInst(inst->getSrc(1))); |
| } |
| break; |
| case Op_Sub: |
| { |
| assert(inst->getNumSrcOperands() == 2); |
| Opnd *src1 = inst->getSrc(0); |
| Opnd *src2 = inst->getSrc(1); |
| CG_OpndHandle* src1CGInst = getCGInst(src1); |
| CG_OpndHandle* src2CGInst = getCGInst(src2); |
| |
| if (src1->getType()->isReference()) { |
| if (src2->getType()->isReference()) { |
| cgInst = instructionCallback.diffRef(isOverflow(inst) && !isExceptionNever(inst), |
| src1CGInst, |
| src2CGInst); |
| } |
| else { |
| cgInst = instructionCallback.subRef(mapToRefArithmOpType(inst,src2), |
| src1CGInst, |
| src2CGInst); |
| } |
| } |
| else { |
| cgInst = instructionCallback.sub(mapToArithmOpType(inst), |
| src1CGInst, |
| src2CGInst); |
| } |
| } |
| break; |
| case Op_TauDiv: |
| { |
| assert(inst->getNumSrcOperands() == 3); |
| Opnd *tauOpnd = inst->getSrc(2); |
| assert(tauOpnd->getType()->tag == Type::Tau); |
| cgInst = instructionCallback.tau_div(mapToDivOpType(inst), |
| getCGInst(inst->getSrc(0)), |
| getCGInst(inst->getSrc(1)), |
| getCGInst(tauOpnd)); |
| } |
| break; |
| case Op_TauRem: |
| { |
| assert(inst->getNumSrcOperands() == 3); |
| Opnd *tauOpnd = inst->getSrc(2); |
| assert(tauOpnd->getType()->tag == Type::Tau); |
| |
| cgInst = instructionCallback.tau_rem(mapToDivOpType(inst), |
| getCGInst(inst->getSrc(0)), |
| getCGInst(inst->getSrc(1)), |
| getCGInst(tauOpnd)); |
| } |
| break; |
| case Op_Neg: |
| { |
| assert(inst->getNumSrcOperands() == 1); |
| cgInst = instructionCallback.neg(mapToNegOpType(inst), |
| getCGInst(inst->getSrc(0))); |
| } |
| break; |
| case Op_MulHi: |
| { |
| assert(inst->getNumSrcOperands() == 2); |
| cgInst = instructionCallback.mulhi(mapToMulHiOpType(inst), |
| getCGInst(inst->getSrc(0)), |
| getCGInst(inst->getSrc(1))); |
| } |
| break; |
| case Op_Min: |
| { |
| assert(inst->getNumSrcOperands() == 2); |
| cgInst = instructionCallback.min_op(mapToNegOpType(inst), |
| getCGInst(inst->getSrc(0)), |
| getCGInst(inst->getSrc(1))); |
| } |
| break; |
| case Op_Max: |
| { |
| assert(inst->getNumSrcOperands() == 2); |
| cgInst = instructionCallback.max_op(mapToNegOpType(inst), |
| getCGInst(inst->getSrc(0)), |
| getCGInst(inst->getSrc(1))); |
| } |
| break; |
| case Op_Abs: |
| { |
| assert(inst->getNumSrcOperands() == 1); |
| cgInst = instructionCallback.abs_op(mapToNegOpType(inst), |
| getCGInst(inst->getSrc(0))); |
| } |
| break; |
| case Op_TauCheckFinite: |
| { |
| assert(inst->getNumSrcOperands() == 1); |
| cgInst = instructionCallback.tau_ckfinite(getCGInst(inst->getSrc(0))); |
| } |
| break; |
| case Op_And: |
| { |
| assert(inst->getNumSrcOperands() == 2); |
| cgInst = instructionCallback.and_(mapToIntegerOpType(inst), |
| getCGInst(inst->getSrc(0)), |
| getCGInst(inst->getSrc(1))); |
| } |
| break; |
| case Op_Or: |
| { |
| assert(inst->getNumSrcOperands() == 2); |
| cgInst = instructionCallback.or_(mapToIntegerOpType(inst), |
| getCGInst(inst->getSrc(0)), |
| getCGInst(inst->getSrc(1))); |
| } |
| break; |
| case Op_Xor: |
| { |
| assert(inst->getNumSrcOperands() == 2); |
| cgInst = instructionCallback.xor_(mapToIntegerOpType(inst), |
| getCGInst(inst->getSrc(0)), |
| getCGInst(inst->getSrc(1))); |
| } |
| break; |
| case Op_Not: |
| { |
| assert(inst->getNumSrcOperands() == 1); |
| cgInst = instructionCallback.not_(mapToIntegerOpType(inst), |
| getCGInst(inst->getSrc(0))); |
| } |
| break; |
| case Op_Select: |
| { |
| assert(inst->getNumSrcOperands() == 3); |
| cgInst = instructionCallback.select(mapToCompareOpType(inst), |
| getCGInst(inst->getSrc(0)), |
| getCGInst(inst->getSrc(1)), |
| getCGInst(inst->getSrc(2))); |
| } |
| break; |
| case Op_Conv: |
| case Op_ConvZE: |
| case Op_ConvUnmanaged: |
| { |
| assert(inst->getNumSrcOperands() == 1); |
| Type * dstType = inst->getDst()->getType(); |
| if (dstType->isFP()) { |
| cgInst = instructionCallback.convToFp(mapToFpConvertOpType(inst), |
| dstType, |
| getCGInst(inst->getSrc(0))); |
| } else if (dstType->isObject()){ |
| cgInst = instructionCallback.convUPtrToObject(dstType->asObjectType(), getCGInst(inst->getSrc(0))); |
| } else if (dstType->isUnmanagedPtr()) { |
| cgInst = instructionCallback.convToUPtr(dstType->asPtrType(), getCGInst(inst->getSrc(0))); |
| } else { |
| bool isSigned = Type::isSignedInteger(inst->getType()); |
| bool isZeroExtend = inst->getOpcode() == Op_ConvZE; |
| cgInst = instructionCallback.convToInt(mapToIntConvertOpType(inst), |
| isSigned, |
| isZeroExtend, |
| mapToIntConvertOvfMod(inst), |
| dstType, |
| getCGInst(inst->getSrc(0))); |
| } |
| } |
| break; |
| case Op_Shladd: |
| { |
| assert(inst->getNumSrcOperands() == 3); |
| Opnd *op1 = inst->getSrc(1); |
| ConstInst *op1ci = op1->getInst()->asConstInst(); |
| assert(op1ci); |
| assert(op1ci->getType() == Type::Int32); |
| I_32 shiftby = op1ci->getValue().i4; |
| cgInst = instructionCallback.shladd(mapToIntegerOpType(inst), |
| getCGInst(inst->getSrc(0)), |
| shiftby, |
| getCGInst(inst->getSrc(2))); |
| } |
| break; |
| case Op_Shl: |
| { |
| assert(inst->getNumSrcOperands() == 2); |
| cgInst = instructionCallback.shl(mapToIntegerOpType(inst), |
| getCGInst(inst->getSrc(0)), |
| getCGInst(inst->getSrc(1))); |
| } |
| break; |
| case Op_Shr: |
| { |
| assert(inst->getNumSrcOperands() == 2); |
| IntegerOp::Types opType = mapToIntegerOpType(inst); |
| CG_OpndHandle* src1CGInst = getCGInst(inst->getSrc(0)); |
| CG_OpndHandle* src2CGInst = getCGInst(inst->getSrc(1)); |
| |
| if (isUnsigned(inst)) |
| cgInst = instructionCallback.shru(opType,src1CGInst,src2CGInst); |
| else |
| cgInst = instructionCallback.shr(opType,src1CGInst,src2CGInst); |
| } |
| break; |
| case Op_Cmp: |
| { |
| if (inst->getNumSrcOperands() == 2) { |
| // binary comparison |
| CompareOp::Operators cmpOp = mapToComparisonOp(inst); |
| CompareOp::Types opType = mapToCompareOpType(inst); |
| cgInst = instructionCallback.cmp(cmpOp, opType, |
| getCGInst(inst->getSrc(0)), |
| getCGInst(inst->getSrc(1))); |
| } else { |
| assert(inst->getNumSrcOperands() == 1); |
| // unary comparison against zero |
| if (inst->getComparisonModifier() == Cmp_Zero) { |
| cgInst = instructionCallback.czero(mapToCompareZeroOpType(inst), |
| getCGInst(inst->getSrc(0))); |
| } else { |
| // Nonzero |
| cgInst = instructionCallback.cnzero(mapToCompareZeroOpType(inst), |
| getCGInst(inst->getSrc(0))); |
| } |
| } |
| } |
| break; |
| case Op_Cmp3: |
| { |
| #ifndef BACKEND_HAS_CMP3 |
| |
| // always binary comparison |
| CompareOp::Types opType = mapToCompareOpType(inst); |
| CompareOp::Operators cmpOp = mapToComparisonOp(inst); |
| CompareOp::Operators cmpOp2 = cmpOp; |
| |
| int ifNaNResult = -1; |
| if (cmpOp == CompareOp::Gtu || cmpOp == CompareOp::Geu) |
| ifNaNResult = 1; |
| |
| CG_OpndHandle* cgInst1 = |
| instructionCallback.cmp(cmpOp, opType, |
| getCGInst(inst->getSrc(0)), |
| getCGInst(inst->getSrc(1)), ifNaNResult); |
| |
| // second operator has opposite NaN behavior for Floats |
| if ((opType==CompareOp::F) || |
| (opType==CompareOp::S) || |
| (opType==CompareOp::D)) { |
| switch (cmpOp) { |
| case CompareOp::Gt: cmpOp2 = CompareOp::Gtu; ifNaNResult = 1; break; |
| case CompareOp::Gtu: cmpOp2 = CompareOp::Gt; ifNaNResult = -1; break; |
| case CompareOp::Ge: cmpOp2 = CompareOp::Geu; ifNaNResult = 1; break; |
| case CompareOp::Geu: cmpOp2 = CompareOp::Ge; ifNaNResult = -1; break; |
| default: break; |
| }; |
| } |
| |
| CG_OpndHandle* cgInst2 = |
| instructionCallback.cmp(cmpOp2, opType, |
| getCGInst(inst->getSrc(1)), |
| getCGInst(inst->getSrc(0)), ifNaNResult); |
| cgInst = |
| instructionCallback.sub(ArithmeticOp::I4, |
| cgInst1, |
| cgInst2); |
| #else |
| // always binary comparison |
| CompareOp::Operators cmpOp = mapToComparisonOp(inst); |
| CompareOp::Types opType = mapToCompareOpType(inst); |
| cgInst = instructionCallback.cmp3(cmpOp, opType, |
| getCGInst(inst->getSrc(0)), |
| getCGInst(inst->getSrc(1))); |
| #endif |
| } |
| break; |
| case Op_Branch: |
| { |
| if (inst->getNumSrcOperands() == 2) { |
| // binary comparison |
| instructionCallback.branch(mapToComparisonOp(inst), |
| mapToCompareOpType(inst), |
| getCGInst(inst->getSrc(0)), |
| getCGInst(inst->getSrc(1))); |
| } else { |
| assert(inst->getNumSrcOperands() == 1); |
| // unary comparison against zero |
| if (inst->getComparisonModifier() == Cmp_Zero) { |
| instructionCallback.bzero(mapToCompareZeroOpType(inst), |
| getCGInst(inst->getSrc(0))); |
| } else { |
| // Nonzero |
| instructionCallback.bnzero(mapToCompareZeroOpType(inst), |
| getCGInst(inst->getSrc(0))); |
| } |
| } |
| } |
| break; |
| case Op_Jump: |
| { |
| instructionCallback.jump(); |
| } |
| break; |
| case Op_Switch: |
| { |
| assert(inst->getNumSrcOperands() == 1); |
| SwitchInst *swInst = (SwitchInst *)inst; |
| instructionCallback.tableSwitch(getCGInst(inst->getSrc(0)), |
| swInst->getNumTargets()); |
| } |
| break; |
| case Op_DirectCall: |
| { |
| assert(inst->getNumSrcOperands() >= 2); |
| Opnd *tauNullChecked = inst->getSrc(0); |
| assert(tauNullChecked->getType()->tag == Type::Tau); |
| Opnd *tauTypesChecked = inst->getSrc(1); |
| assert(tauTypesChecked->getType()->tag == Type::Tau); |
| |
| MethodCallInst * call = (MethodCallInst *)inst; |
| MethodDesc * methodDesc = call->getMethodDesc(); |
| CG_OpndHandle ** args = genCallArgs(call,2); // omit tau operands |
| U_32 numArgs = inst->getNumSrcOperands()-2; // also omit from count |
| cgInst = |
| instructionCallback.tau_call(numArgs, |
| args, |
| inst->getDst()->getType(), |
| methodDesc, |
| getCGInst(tauNullChecked), |
| getCGInst(tauTypesChecked)); |
| } |
| break; |
| case Op_TauVirtualCall: |
| { |
| assert(inst->getNumSrcOperands() >= 3); |
| Opnd *tauNullChecked = inst->getSrc(0); |
| Opnd *tauTypesChecked = inst->getSrc(1); |
| assert(tauNullChecked->getType()->tag == Type::Tau); |
| assert(tauTypesChecked->getType()->tag == Type::Tau); |
| |
| MethodCallInst * call = (MethodCallInst *)inst; |
| MethodDesc * methodDesc = call->getMethodDesc(); |
| cgInst = |
| instructionCallback.tau_callvirt(inst->getNumSrcOperands()-2, // omit taus |
| genCallArgs(call, 2), // omit taus |
| inst->getDst()->getType(), |
| methodDesc, |
| getCGInst(tauNullChecked), |
| getCGInst(tauTypesChecked)); |
| } |
| break; |
| case Op_IndirectCall: |
| { |
| assert(inst->getNumSrcOperands() >= 3); |
| Opnd *fnAddr = inst->getSrc(0); |
| Opnd *tauNullChecked = inst->getSrc(1); |
| Opnd *tauTypesChecked = inst->getSrc(2); |
| assert(tauNullChecked->getType()->tag == Type::Tau); |
| assert(tauTypesChecked->getType()->tag == Type::Tau); |
| assert(inst->isCall()); |
| cgInst = |
| instructionCallback.tau_calli(inst->getNumSrcOperands() - 3, // omit taus and fnAddr |
| genCallArgs(inst, 3), // omit taus and fnAddr |
| inst->getDst()->getType(), |
| getCGInst(fnAddr), |
| getCGInst(tauNullChecked), |
| getCGInst(tauTypesChecked)); |
| } |
| break; |
| case Op_IndirectMemoryCall: |
| { |
| assert(inst->getNumSrcOperands() >= 3); |
| Opnd *fnAddr = inst->getSrc(0); |
| Opnd *tauNullChecked = inst->getSrc(1); |
| Opnd *tauTypesChecked = inst->getSrc(2); |
| assert(tauNullChecked->getType()->tag == Type::Tau); |
| assert(tauTypesChecked->getType()->tag == Type::Tau); |
| assert(inst->isCall()); |
| cgInst = |
| instructionCallback.tau_calli(inst->getNumSrcOperands() - 3, // omit taus andfnAddr |
| genCallArgs(inst, 3), // omit taus and fnAddr |
| inst->getDst()->getType(), |
| getCGInst(fnAddr), |
| getCGInst(tauNullChecked), |
| getCGInst(tauTypesChecked)); |
| } |
| break; |
| case Op_JitHelperCall: |
| { |
| JitHelperCallInst* call = inst->asJitHelperCallInst(); |
| JitHelperCallId callId = call->getJitHelperId(); |
| if (callId == ArrayCopyDirect || callId == ArrayCopyReverse) |
| cgInst = |
| instructionCallback.callhelper(inst->getNumSrcOperands()-2, // omit taus |
| genCallArgs(call,2), // omit taus |
| inst->getDst()->getType(), |
| convertJitHelperId(callId)); |
| else |
| cgInst = |
| instructionCallback.callhelper(inst->getNumSrcOperands(), |
| genCallArgs(call,0), |
| inst->getDst()->getType(), |
| convertJitHelperId(callId)); |
| } |
| break; |
| case Op_VMHelperCall: |
| { |
| VMHelperCallInst* call = inst->asVMHelperCallInst(); |
| VM_RT_SUPPORT callId = call->getVMHelperId(); |
| cgInst = |
| instructionCallback.callvmhelper(inst->getNumSrcOperands(), |
| genCallArgs(call,0), |
| inst->getDst()->getType(), |
| callId); |
| } |
| break; |
| case Op_Return: |
| { |
| if (inst->getType() == Type::Void) { |
| instructionCallback.ret(); |
| } else { |
| instructionCallback.ret(getCGInst(inst->getSrc(0))); |
| } |
| } |
| break; |
| case Op_Throw: |
| { |
| instructionCallback.throwException(getCGInst(inst->getSrc(0)), inst->getThrowModifier() == Throw_CreateStackTrace); |
| } |
| break; |
| case Op_PseudoThrow: |
| instructionCallback.pseudoInst(); |
| break; |
| case Op_ThrowSystemException: |
| { |
| TokenInst *tokenInst = (TokenInst *)inst; |
| U_32 token = tokenInst->getToken(); |
| CompilationInterface::SystemExceptionId id |
| = (CompilationInterface::SystemExceptionId)token; |
| instructionCallback.throwSystemException(id); |
| } |
| break; |
| case Op_ThrowLinkingException: |
| { |
| LinkingExcInst *linkExcInst = (LinkingExcInst *)inst; |
| Class_Handle encClass = linkExcInst->getEnclosingClass(); |
| U_32 constPoolIndex = linkExcInst->getCPIndex(); |
| U_32 opcode = linkExcInst->getOperation(); |
| instructionCallback.throwLinkingException(encClass, constPoolIndex, opcode); |
| } |
| break; |
| case Op_Catch: |
| cgInst = instructionCallback.catchException(inst->getDst()->getType()); |
| break; |
| case Op_Copy: |
| { |
| cgInst = instructionCallback.copy(getCGInst(inst->getSrc(0))); |
| } |
| break; |
| case Op_DefArg: |
| { |
| cgInst = instructionCallback.defArg(argCount, |
| inst->getDst()->getType()); |
| argCount += 1; |
| } |
| break; |
| case Op_LdConstant: |
| { |
| if (!genConsts) break; |
| ConstInst* constInst = (ConstInst*)inst; |
| switch (inst->getType()) { |
| #ifdef _IA32_ |
| case Type::UIntPtr: |
| case Type::IntPtr: |
| case Type::UnmanagedPtr: |
| #endif |
| case Type::Int32: |
| cgInst = instructionCallback.ldc_i4(constInst->getValue().i4); |
| break; |
| #ifdef _EM64T_ |
| case Type::UIntPtr: |
| case Type::IntPtr: |
| case Type::UnmanagedPtr: |
| #endif |
| case Type::Int64: |
| cgInst = instructionCallback.ldc_i8(constInst->getValue().i8); |
| break; |
| case Type::Single: |
| cgInst = instructionCallback.ldc_s(constInst->getValue().s); |
| break; |
| case Type::Double: |
| cgInst = instructionCallback.ldc_d(constInst->getValue().d); |
| break; |
| case Type::NullObject: |
| cgInst = instructionCallback.ldnull(false); |
| break; |
| case Type::CompressedNullObject: |
| cgInst = instructionCallback.ldnull(true); |
| break; |
| default: assert(0); |
| } |
| isConstant = true; |
| } |
| break; |
| case Op_LdRef: |
| { |
| if (!genConsts) break; |
| |
| AutoCompressModifier acmod = inst->getAutoCompressModifier(); |
| |
| TokenInst *tokenInst = (TokenInst *)inst; |
| U_32 token = tokenInst->getToken(); |
| cgInst = instructionCallback.ldRef(inst->getDst()->getType(), |
| tokenInst->getEnclosingMethod(), |
| token, acmod==AutoCompress_Yes); |
| isConstant = true; |
| } |
| break; |
| case Op_LdVar: |
| { |
| VarAccessInst * varInst = (VarAccessInst *)inst; |
| cgInst = instructionCallback.ldVar(inst->getDst()->getType(), |
| getVarHandle(varInst->getVar())); |
| } |
| break; |
| case Op_LdVarAddr: |
| { |
| if (!genConsts) break; |
| VarAccessInst * varInst = (VarAccessInst *)inst; |
| cgInst = instructionCallback.ldVarAddr(getVarHandle(varInst->getVar())); |
| isConstant = true; |
| } |
| break; |
| case Op_TauLdInd: |
| { |
| assert(inst->getNumSrcOperands() == 3); |
| AutoCompressModifier acmod = inst->getAutoCompressModifier(); |
| SpeculativeModifier smod = inst->getSpeculativeModifier(); |
| |
| instructionCallback.setCurrentPersistentId(inst->getPersistentInstructionId()); |
| Opnd *ptr = inst->getSrc(0); |
| Opnd *tauNonNullBase = inst->getSrc(1); |
| Opnd *tauAddressInRange = inst->getSrc(2); |
| |
| assert(tauNonNullBase->getType()->tag == Type::Tau); |
| assert(tauAddressInRange->getType()->tag == Type::Tau); |
| |
| cgInst = instructionCallback.tau_ldInd(inst->getDst()->getType(), |
| getCGInst(ptr), |
| inst->getType(), |
| acmod == AutoCompress_Yes, |
| smod == Speculative_Yes, |
| getCGInst(tauNonNullBase), |
| getCGInst(tauAddressInRange)); |
| instructionCallback.clearCurrentPersistentId(); |
| } |
| break; |
| case Op_TauLdField: |
| { |
| assert(inst->getNumSrcOperands() == 3); |
| AutoCompressModifier acmod = inst->getAutoCompressModifier(); |
| |
| FieldAccessInst* fieldInst = (FieldAccessInst*)inst; |
| FieldDesc* fieldDesc = fieldInst->getFieldDesc(); |
| Opnd *base = inst->getSrc(0); |
| Opnd *tauNonNullBase = inst->getSrc(1); |
| Opnd *tauObjectTypeChecked = inst->getSrc(2); |
| |
| assert(tauNonNullBase->getType()->tag == Type::Tau); |
| assert(tauObjectTypeChecked->getType()->tag == Type::Tau); |
| |
| cgInst = instructionCallback.tau_ldField(inst->getDst()->getType(), |
| getCGInst(base), |
| inst->getType(), |
| fieldDesc, |
| acmod == AutoCompress_Yes, |
| getCGInst(tauNonNullBase), |
| getCGInst(tauObjectTypeChecked)); |
| } |
| break; |
| case Op_LdStatic: |
| { |
| AutoCompressModifier acmod = inst->getAutoCompressModifier(); |
| |
| FieldAccessInst* fieldInst = (FieldAccessInst *)inst; |
| FieldDesc* fieldDesc = fieldInst->getFieldDesc(); |
| cgInst = instructionCallback.ldStatic(inst->getDst()->getType(), |
| fieldDesc, |
| inst->getType(), |
| acmod == AutoCompress_Yes); |
| } |
| break; |
| case Op_TauLdElem: |
| { |
| assert(inst->getNumSrcOperands() == 4); |
| AutoCompressModifier acmod = inst->getAutoCompressModifier(); |
| |
| Opnd *array = inst->getSrc(0); |
| Opnd *index = inst->getSrc(1); |
| Opnd *tauNonNullBase = inst->getSrc(2); |
| Opnd *tauAddressInRange = inst->getSrc(3); |
| |
| assert(tauNonNullBase->getType()->tag == Type::Tau); |
| assert(tauAddressInRange->getType()->tag == Type::Tau); |
| |
| cgInst = instructionCallback.tau_ldElem(inst->getDst()->getType(), |
| getCGInst(array), |
| getCGInst(index), |
| acmod == AutoCompress_Yes, |
| getCGInst(tauNonNullBase), |
| getCGInst(tauAddressInRange)); |
| } |
| break; |
| case Op_LdFieldAddr: |
| { |
| assert(inst->getNumSrcOperands() == 1); |
| FieldAccessInst* fieldInst = (FieldAccessInst*)inst; |
| FieldDesc* fieldDesc = fieldInst->getFieldDesc(); |
| cgInst = instructionCallback.ldFieldAddr(inst->getDst()->getType(), |
| getCGInst(inst->getSrc(0)), |
| fieldDesc); |
| } |
| break; |
| case Op_LdStaticAddr: |
| { |
| assert(inst->getNumSrcOperands() == 0); |
| FieldAccessInst* fieldInst = (FieldAccessInst *)inst; |
| FieldDesc* fieldDesc = fieldInst->getFieldDesc(); |
| cgInst = instructionCallback.ldStaticAddr(inst->getDst()->getType(), |
| fieldDesc); |
| } |
| break; |
| case Op_LdElemAddr: |
| { |
| assert(inst->getNumSrcOperands() == 2); |
| cgInst = instructionCallback.ldElemAddr(getCGInst(inst->getSrc(0)), |
| getCGInst(inst->getSrc(1))); |
| } |
| break; |
| case Op_LdFunAddr: |
| { |
| assert(inst->getNumSrcOperands() == 0); |
| MethodInst * methodInst = (MethodInst *)inst; |
| MethodDesc * methodDesc = methodInst->getMethodDesc(); |
| cgInst = |
| instructionCallback.ldFunAddr(inst->getDst()->getType(), |
| methodDesc); |
| } |
| break; |
| case Op_TauLdVirtFunAddr: |
| { |
| assert(inst->getNumSrcOperands() == 2); |
| MethodInst * methodInst = (MethodInst *)inst; |
| MethodDesc * methodDesc = methodInst->getMethodDesc(); |
| Opnd *vtable = inst->getSrc(0); |
| Opnd *tauBaseHasMethod = inst->getSrc(1); |
| |
| assert(tauBaseHasMethod->getType()->tag == Type::Tau); |
| |
| cgInst = |
| instructionCallback.tau_ldVirtFunAddr(inst->getDst()->getType(), |
| getCGInst(vtable), |
| methodDesc, |
| getCGInst(tauBaseHasMethod)); |
| } |
| break; |
| case Op_LdFunAddrSlot: |
| { |
| assert(inst->getNumSrcOperands() == 0); |
| MethodInst * methodInst = (MethodInst *)inst; |
| MethodDesc * methodDesc = methodInst->getMethodDesc(); |
| cgInst = |
| instructionCallback.ldFunAddr(inst->getDst()->getType(), |
| methodDesc); |
| } |
| break; |
| case Op_TauLdVirtFunAddrSlot: |
| { |
| assert(inst->getNumSrcOperands() == 2); |
| MethodInst * methodInst = (MethodInst *)inst; |
| MethodDesc * methodDesc = methodInst->getMethodDesc(); |
| Opnd *vtable = inst->getSrc(0); |
| Opnd *tauBaseHasMethod = inst->getSrc(1); |
| |
| assert(tauBaseHasMethod->getType()->tag == Type::Tau); |
| |
| cgInst = |
| instructionCallback.tau_ldVirtFunAddr(inst->getDst()->getType(), |
| getCGInst(vtable), |
| methodDesc, |
| getCGInst(tauBaseHasMethod)); |
| } |
| break; |
| case Op_TauLdVTableAddr: |
| { |
| assert(inst->getNumSrcOperands() == 2); |
| instructionCallback.setCurrentPersistentId(inst->getPersistentInstructionId()); |
| Type * dstType = inst->getDst()->getType(); |
| assert(dstType->isVTablePtr() || dstType->isVTablePtrObj()); |
| Opnd *base = inst->getSrc(0); |
| Opnd *tauBaseNonNull = inst->getSrc(1); |
| |
| assert(tauBaseNonNull->getType()->tag == Type::Tau); |
| |
| cgInst = instructionCallback.tau_ldVTableAddr(dstType, |
| getCGInst(base), |
| getCGInst(tauBaseNonNull)); |
| instructionCallback.clearCurrentPersistentId(); |
| } |
| break; |
| case Op_GetVTableAddr: |
| { |
| assert(inst->getNumSrcOperands() == 0); |
| if (!genConsts) break; |
| Type *type = ((TypeInst*)inst)->getTypeInfo(); |
| assert(type->isObject()); |
| Type * dstType = inst->getDst()->getType(); |
| assert(dstType->isVTablePtr()); |
| cgInst = instructionCallback.getVTableAddr( dstType,(ObjectType*)type); |
| isConstant = true; |
| } |
| break; |
| case Op_GetClassObj: |
| { |
| assert(inst->getNumSrcOperands() == 0); |
| Type *type = ((TypeInst*)inst)->getTypeInfo(); |
| assert(type->isObject() || type->isUserValue()); |
| Type * dstType = inst->getDst()->getType(); |
| assert(type->isObject()); |
| cgInst = instructionCallback.getClassObj( dstType,(ObjectType*)type); |
| } |
| break; |
| case Op_TauLdIntfcVTableAddr: |
| { |
| assert(inst->getNumSrcOperands() == 1); |
| TypeInst *typeInst = (TypeInst*)inst; |
| Type * vtableType = typeInst->getTypeInfo(); |
| assert(vtableType->isUserObject()); |
| Opnd *base = inst->getSrc(0); |
| cgInst = instructionCallback.tau_ldIntfTableAddr(inst->getDst()->getType(), |
| getCGInst(base), |
| (NamedType*)vtableType); |
| } |
| break; |
| case Op_TauArrayLen: |
| { |
| assert(inst->getNumSrcOperands() == 3); |
| Opnd *array = inst->getSrc(0); |
| Opnd *tauNonNullArray = inst->getSrc(1); |
| Opnd *tauIsArray = inst->getSrc(2); |
| |
| assert(tauNonNullArray->getType()->tag == Type::Tau); |
| |
| Type* dstType = inst->getDst()->getType(); |
| Type* arrayType = inst->getSrc(0)->getType(); |
| assert(arrayType->isArrayType()); |
| Type* arrayLenType = dstType; |
| instructionCallback.setCurrentPersistentId(inst->getPersistentInstructionId()); |
| cgInst = instructionCallback.tau_arrayLen(dstType, |
| (ArrayType*)arrayType, |
| arrayLenType, |
| getCGInst(array), |
| getCGInst(tauNonNullArray), |
| getCGInst(tauIsArray)); |
| instructionCallback.clearCurrentPersistentId(); |
| } |
| break; |
| // load the base (zero element) address of array |
| case Op_LdArrayBaseAddr: |
| { |
| assert(inst->getNumSrcOperands() == 1); |
| cgInst = instructionCallback.ldElemBaseAddr(getCGInst(inst->getSrc(0))); |
| } |
| break; |
| // Add a scaled index to an array element address |
| case Op_AddScaledIndex: |
| { |
| PtrType* arrType = (PtrType*) inst->getSrc(0)->getType(); |
| Type* refType = arrType->getPointedToType(); |
| |
| assert(inst->getNumSrcOperands() == 2); |
| cgInst = instructionCallback.addElemIndex(refType, |
| getCGInst(inst->getSrc(0)), |
| getCGInst(inst->getSrc(1))); |
| } |
| break; |
| case Op_UncompressRef: |
| { |
| assert(inst->getNumSrcOperands() == 1); |
| cgInst = instructionCallback.uncompressRef(getCGInst(inst->getSrc(0))); |
| } |
| break; |
| case Op_CompressRef: |
| { |
| assert(inst->getNumSrcOperands() == 1); |
| cgInst = instructionCallback.compressRef(getCGInst(inst->getSrc(0))); |
| } |
| break; |
| case Op_LdFieldOffset: |
| { |
| assert(inst->getNumSrcOperands() == 0); |
| if (!genConsts) break; |
| FieldAccessInst* fieldInst = (FieldAccessInst*)inst; |
| FieldDesc* fieldDesc = fieldInst->getFieldDesc(); |
| cgInst = instructionCallback.ldFieldOffset(fieldDesc); |
| isConstant = true; |
| } |
| break; |
| case Op_LdFieldOffsetPlusHeapbase: |
| { |
| assert(inst->getNumSrcOperands() == 0); |
| if (!genConsts) break; |
| FieldAccessInst* fieldInst = (FieldAccessInst*)inst; |
| FieldDesc* fieldDesc = fieldInst->getFieldDesc(); |
| cgInst = instructionCallback.ldFieldOffsetPlusHeapbase(fieldDesc); |
| isConstant = true; |
| } |
| break; |
| case Op_LdArrayBaseOffset: |
| { |
| assert(inst->getNumSrcOperands() == 0); |
| if (!genConsts) break; |
| TypeInst *typeInst = (TypeInst*)inst; |
| Type *elemType = typeInst->getTypeInfo(); |
| cgInst = instructionCallback.ldArrayBaseOffset(elemType); |
| isConstant = true; |
| } |
| break; |
| case Op_LdArrayBaseOffsetPlusHeapbase: |
| { |
| assert(inst->getNumSrcOperands() == 0); |
| if (!genConsts) break; |
| TypeInst *typeInst = (TypeInst*)inst; |
| Type *elemType = typeInst->getTypeInfo(); |
| cgInst = instructionCallback.ldArrayBaseOffsetPlusHeapbase(elemType); |
| isConstant = true; |
| } |
| break; |
| case Op_LdArrayLenOffset: |
| { |
| assert(inst->getNumSrcOperands() == 0); |
| if (!genConsts) break; |
| TypeInst *typeInst = (TypeInst*)inst; |
| Type *elemType = typeInst->getTypeInfo(); |
| cgInst = instructionCallback.ldArrayLenOffset(elemType); |
| isConstant = true; |
| } |
| break; |
| case Op_LdArrayLenOffsetPlusHeapbase: |
| { |
| assert(inst->getNumSrcOperands() == 0); |
| if (!genConsts) break; |
| TypeInst *typeInst = (TypeInst*)inst; |
| Type *elemType = typeInst->getTypeInfo(); |
| cgInst = instructionCallback.ldArrayLenOffsetPlusHeapbase(elemType); |
| isConstant = true; |
| } |
| break; |
| case Op_AddOffset: |
| { |
| assert(inst->getNumSrcOperands() == 2); |
| Opnd *dstop = inst->getDst(); |
| Opnd *ref = inst->getSrc(0); |
| Opnd *offset = inst->getSrc(1); |
| Type *dstType = dstop->getType(); |
| cgInst = instructionCallback.addOffset(dstType, getCGInst(ref), getCGInst(offset)); |
| } |
| break; |
| case Op_AddOffsetPlusHeapbase: |
| { |
| assert(inst->getNumSrcOperands() == 2); |
| Opnd *dstop = inst->getDst(); |
| Opnd *ref = inst->getSrc(0); |
| Opnd *offset = inst->getSrc(1); |
| Type *dstType = dstop->getType(); |
| cgInst = instructionCallback.addOffsetPlusHeapbase(dstType, |
| getCGInst(ref), |
| getCGInst(offset)); |
| } |
| break; |
| case Op_StVar: |
| { |
| assert(inst->getNumSrcOperands() == 1); |
| VarAccessInst * varInst = (VarAccessInst *)inst; |
| instructionCallback.stVar(getCGInst(inst->getSrc(0)), |
| getVarHandle(varInst->getVar())); |
| |
| } |
| break; |
| case Op_TauStInd: |
| { |
| assert(inst->getNumSrcOperands() == 5); |
| Opnd *src = inst->getSrc(0); |
| Opnd *ptr = inst->getSrc(1); |
| Opnd *tauNonNullBase = inst->getSrc(2); |
| Opnd *tauAddressInRange = inst->getSrc(3); |
| Opnd *tauElemTypeChecked = inst->getSrc(4); |
| |
| assert(tauNonNullBase->getType()->tag == Type::Tau); |
| assert(tauAddressInRange->getType()->tag == Type::Tau); |
| assert(tauElemTypeChecked->getType()->tag == Type::Tau); |
| |
| AutoCompressModifier acmod = inst->getAutoCompressModifier(); |
| bool autocompress = (acmod == AutoCompress_Yes); |
| Type::Tag type = inst->getType(); |
| if (acmod == AutoCompress_Yes) { |
| assert(Type::isReference(type)); |
| assert(!Type::isCompressedReference(type)); |
| } |
| instructionCallback.tau_stInd(getCGInst(src), |
| getCGInst(ptr), |
| type, |
| autocompress, |
| getCGInst(tauNonNullBase), |
| getCGInst(tauAddressInRange), |
| getCGInst(tauElemTypeChecked)); |
| } |
| break; |
| case Op_TauStField: |
| { |
| assert(inst->getNumSrcOperands() == 5); |
| Opnd *src = inst->getSrc(0); |
| Opnd *base = inst->getSrc(1); |
| Opnd *tauNonNullBase = inst->getSrc(2); |
| Opnd *tauTypeHasField = inst->getSrc(3); |
| Opnd *tauFieldTypeChecked = inst->getSrc(4); |
| |
| assert(tauNonNullBase->getType()->tag == Type::Tau); |
| assert(tauTypeHasField->getType()->tag == Type::Tau); |
| assert(tauFieldTypeChecked->getType()->tag == Type::Tau); |
| |
| AutoCompressModifier acmod = inst->getAutoCompressModifier(); |
| |
| FieldAccessInst* fieldInst = (FieldAccessInst*)inst; |
| FieldDesc* fieldDesc = fieldInst->getFieldDesc(); |
| |
| bool autocompress = (acmod == AutoCompress_Yes); |
| Type::Tag type = inst->getType(); |
| if (acmod == AutoCompress_Yes) { |
| assert(Type::isReference(type)); |
| assert(!Type::isCompressedReference(type)); |
| } |
| instructionCallback.tau_stField(getCGInst(src), |
| getCGInst(base), |
| type, |
| fieldDesc, |
| autocompress, |
| getCGInst(tauNonNullBase), |
| getCGInst(tauTypeHasField), |
| getCGInst(tauFieldTypeChecked)); |
| } |
| break; |
| |
| case Op_TauStStatic: |
| { |
| assert(inst->getNumSrcOperands() == 2); |
| Opnd *src = inst->getSrc(0); |
| Opnd *tauFieldTypeOk = inst->getSrc(1); |
| |
| AutoCompressModifier acmod = inst->getAutoCompressModifier(); |
| bool autocompress = (acmod == AutoCompress_Yes); |
| Type::Tag type = inst->getType(); |
| if (acmod == AutoCompress_Yes) { |
| assert(Type::isReference(type)); |
| assert(!Type::isCompressedReference(type)); |
| } |
| FieldAccessInst* fieldInst = (FieldAccessInst *)inst; |
| FieldDesc* fieldDesc = fieldInst->getFieldDesc(); |
| instructionCallback.tau_stStatic(getCGInst(src), |
| fieldDesc, |
| type, |
| autocompress, |
| getCGInst(tauFieldTypeOk)); |
| } |
| break; |
| case Op_TauStElem: |
| { |
| assert(inst->getNumSrcOperands() == 6); |
| Opnd *src = inst->getSrc(0); |
| Opnd *array = inst->getSrc(1); |
| Opnd *index = inst->getSrc(2); |
| AutoCompressModifier acmod = inst->getAutoCompressModifier(); |
| Opnd *tauNonNullBase = inst->getSrc(3); |
| Opnd *tauAddressInRange = inst->getSrc(4); |
| Opnd *tauElemTypeChecked = inst->getSrc(5); |
| |
| assert(tauNonNullBase->getType()->tag == Type::Tau); |
| assert(tauAddressInRange->getType()->tag == Type::Tau); |
| assert(tauElemTypeChecked->getType()->tag == Type::Tau); |
| |
| |
| instructionCallback.tau_stElem(getCGInst(src), |
| getCGInst(array), |
| getCGInst(index), |
| acmod == AutoCompress_Yes, |
| getCGInst(tauNonNullBase), |
| getCGInst(tauAddressInRange), |
| getCGInst(tauElemTypeChecked)); |
| } |
| break; |
| case Op_TauStRef: |
| { |
| assert(inst->getNumSrcOperands() == 6); |
| |
| Opnd *src = inst->getSrc(0); |
| Opnd *ptr = inst->getSrc(1); |
| Opnd *base = inst->getSrc(2); |
| |
| Opnd *tauNonNullBase = inst->getSrc(3); |
| Opnd *tauTypeHasField = inst->getSrc(4); |
| Opnd *tauFieldTypeChecked = inst->getSrc(5); |
| |
| assert(tauNonNullBase->getType()->tag == Type::Tau); |
| assert(tauTypeHasField->getType()->tag == Type::Tau); |
| assert(tauFieldTypeChecked->getType()->tag == Type::Tau); |
| |
| AutoCompressModifier acmod = inst->getAutoCompressModifier(); |
| StoreModifier UNUSED stmod = inst->getStoreModifier(); |
| |
| bool autocompress = (acmod == AutoCompress_Yes); |
| Type::Tag type = inst->getType(); |
| if (acmod == AutoCompress_Yes) { |
| assert(Type::isReference(type)); |
| assert(!Type::isCompressedReference(type)); |
| } |
| assert(stmod == Store_WriteBarrier); |
| instructionCallback.tau_stRef(getCGInst(src), |
| getCGInst(ptr), |
| getCGInst(base), |
| type, |
| autocompress, |
| getCGInst(tauNonNullBase), |
| getCGInst(tauTypeHasField), |
| getCGInst(tauFieldTypeChecked)); |
| } |
| break; |
| case Op_TauCheckBounds: |
| { |
| assert(inst->getNumSrcOperands() == 2); |
| cgInst = instructionCallback.tau_checkBounds(getCGInst(inst->getSrc(0)), |
| getCGInst(inst->getSrc(1))); |
| } |
| break; |
| case Op_TauCheckLowerBound: |
| { |
| assert(inst->getNumSrcOperands() == 2); |
| cgInst = |
| instructionCallback.tau_checkLowerBound(getCGInst(inst->getSrc(0)), |
| getCGInst(inst->getSrc(1))); |
| } |
| break; |
| case Op_TauCheckUpperBound: |
| { |
| assert(inst->getNumSrcOperands() == 2); |
| cgInst = |
| instructionCallback.tau_checkUpperBound(getCGInst(inst->getSrc(0)), |
| getCGInst(inst->getSrc(1))); |
| } |
| break; |
| case Op_TauCheckNull: |
| { |
| assert(inst->getNumSrcOperands() == 1); |
| if ( inst->getDefArgModifier() == NonNullThisArg ) { |
| if(Log::isEnabled()) { |
| Log::out() << " chknull_NonNullThisArg_check" << ::std::endl; |
| } |
| cgInst = instructionCallback.tau_checkNull(getCGInst(inst->getSrc(0)), true); |
| }else{ |
| cgInst = instructionCallback.tau_checkNull(getCGInst(inst->getSrc(0)), false); |
| assert(inst->getDefArgModifier() == DefArgNoModifier); |
| } |
| } |
| break; |
| case Op_TauCheckZero: |
| { |
| assert(inst->getNumSrcOperands() == 1); |
| cgInst = instructionCallback.tau_checkZero(getCGInst(inst->getSrc(0))); |
| } |
| break; |
| case Op_TauCheckDivOpnds: |
| { |
| assert(inst->getNumSrcOperands() == 2); |
| cgInst = instructionCallback.tau_checkDivOpnds(getCGInst(inst->getSrc(0)), |
| getCGInst(inst->getSrc(1))); |
| } |
| break; |
| case Op_TauCheckElemType: |
| { |
| assert(inst->getNumSrcOperands() == 4); |
| Opnd *array = inst->getSrc(0); |
| Opnd *src = inst->getSrc(1); |
| Opnd *tauCheckedNull = inst->getSrc(2); |
| Opnd *tauIsArray = inst->getSrc(3); |
| assert(tauCheckedNull->getType()->tag == Type::Tau); |
| cgInst = instructionCallback.tau_checkElemType(getCGInst(array), |
| getCGInst(src), |
| getCGInst(tauCheckedNull), |
| getCGInst(tauIsArray)); |
| } |
| break; |
| case Op_NewObj: |
| { |
| assert(inst->getNumSrcOperands() == 0); |
| TypeInst *typeInst = (TypeInst*)inst; |
| Type * objType = typeInst->getTypeInfo(); |
| assert(objType->isObject()); |
| cgInst = instructionCallback.newObj((ObjectType*)objType); |
| } |
| break; |
| case Op_NewArray: |
| { |
| assert(inst->getNumSrcOperands() == 1); |
| Type * arrayType = inst->getDst()->getType(); |
| assert(arrayType->isArrayType()); |
| cgInst = instructionCallback.newArray((ArrayType *)arrayType, |
| getCGInst(inst->getSrc(0))); |
| } |
| break; |
| case Op_NewMultiArray: |
| { |
| Type * arrayType = inst->getDst()->getType(); |
| assert(arrayType->isArrayType()); |
| U_32 numDims = inst->getNumSrcOperands(); |
| CG_OpndHandle ** dims = new(memManager) CG_OpndHandle*[numDims]; |
| for (U_32 i = 0; i < numDims; i++) |
| dims[i] = getCGInst(inst->getSrc(i)); |
| cgInst = instructionCallback.newMultiArray((ArrayType*)arrayType, |
| numDims, |
| dims); |
| } |
| break; |
| case Op_TauMonitorEnter: |
| { |
| assert(inst->getNumSrcOperands() == 2); |
| Opnd *tauOpnd = inst->getSrc(1); |
| instructionCallback.tau_monitorEnter(getCGInst(inst->getSrc(0)), |
| getCGInst(tauOpnd)); |
| } |
| break; |
| case Op_TauMonitorExit: |
| { |
| assert(inst->getNumSrcOperands() == 2); |
| Opnd *tauOpnd = inst->getSrc(1); |
| instructionCallback.tau_monitorExit(getCGInst(inst->getSrc(0)), |
| getCGInst(tauOpnd)); |
| } |
| break; |
| case Op_LdLockAddr: |
| { |
| assert(inst->getNumSrcOperands() == 1); |
| cgInst = instructionCallback.ldLockAddr(getCGInst(inst->getSrc(0))); |
| } |
| break; |
| case Op_IncRecCount: |
| { |
| assert(inst->getNumSrcOperands() == 2); |
| instructionCallback.incRecursionCount(getCGInst(inst->getSrc(0)), |
| getCGInst(inst->getSrc(1))); |
| } |
| break; |
| case Op_TauBalancedMonitorEnter: |
| { |
| assert(inst->getNumSrcOperands() == 3); |
| Opnd *tauOpnd = inst->getSrc(2); |
| cgInst = instructionCallback.tau_balancedMonitorEnter(getCGInst(inst->getSrc(0)), |
| getCGInst(inst->getSrc(1)), |
| getCGInst(tauOpnd)); |
| } |
| break; |
| case Op_BalancedMonitorExit: |
| { |
| assert(inst->getNumSrcOperands() == 3); |
| instructionCallback.balancedMonitorExit(getCGInst(inst->getSrc(0)), |
| getCGInst(inst->getSrc(1)), |
| getCGInst(inst->getSrc(2))); |
| } |
| break; |
| case Op_TauOptimisticBalancedMonitorEnter: |
| { |
| assert(inst->getNumSrcOperands() == 3); |
| Opnd *tauOpnd = inst->getSrc(2); |
| cgInst = instructionCallback.tau_optimisticBalancedMonitorEnter(getCGInst(inst->getSrc(0)), |
| getCGInst(inst->getSrc(1)), |
| getCGInst(tauOpnd)); |
| } |
| break; |
| case Op_OptimisticBalancedMonitorExit: |
| { |
| assert(inst->getNumSrcOperands() == 3); |
| instructionCallback.optimisticBalancedMonitorExit(getCGInst(inst->getSrc(0)), |
| getCGInst(inst->getSrc(1)), |
| getCGInst(inst->getSrc(2))); |
| } |
| break; |
| case Op_MonitorEnterFence: |
| { |
| assert(inst->getNumSrcOperands() == 1); |
| instructionCallback.monitorEnterFence(getCGInst(inst->getSrc(0))); |
| } |
| break; |
| case Op_MonitorExitFence: |
| { |
| assert(inst->getNumSrcOperands() == 1); |
| instructionCallback.monitorExitFence(getCGInst(inst->getSrc(0))); |
| } |
| break; |
| case Op_TypeMonitorEnter: |
| { |
| assert(inst->getNumSrcOperands() == 0); |
| Type * type = ((TypeInst*)inst)->getTypeInfo(); |
| assert(type->isObject() || type->isUserValue()); |
| instructionCallback.typeMonitorEnter((NamedType *)type); |
| } |
| break; |
| case Op_TypeMonitorExit: |
| { |
| assert(inst->getNumSrcOperands() == 0); |
| Type * type = ((TypeInst*)inst)->getTypeInfo(); |
| assert(type->isObject() || type->isUserValue()); |
| instructionCallback.typeMonitorExit((NamedType *)type); |
| } |
| break; |
| case Op_TauStaticCast: |
| { |
| assert(inst->getNumSrcOperands() == 2); |
| Opnd *src = inst->getSrc(0); |
| Opnd *tauCastChecked = inst->getSrc(1); |
| assert(tauCastChecked->getType()->tag == Type::Tau); |
| Type * toType = ((TypeInst*)inst)->getTypeInfo(); |
| assert(toType->isObject()); |
| cgInst = instructionCallback.tau_staticCast((ObjectType *)toType, |
| getCGInst(src), |
| getCGInst(tauCastChecked)); |
| } |
| break; |
| case Op_TauCast: |
| { |
| assert(inst->getNumSrcOperands() == 2); |
| Type * toType = ((TypeInst*)inst)->getTypeInfo(); |
| assert(toType->isObject()); |
| Opnd *src = inst->getSrc(0); |
| Opnd *tauCheckedNull = inst->getSrc(1); |
| assert(tauCheckedNull->getType()->tag == Type::Tau); |
| cgInst = instructionCallback.tau_cast((ObjectType *)toType, |
| getCGInst(src), |
| getCGInst(tauCheckedNull)); |
| } |
| break; |
| case Op_TauAsType: |
| { |
| assert(inst->getNumSrcOperands() == 2); |
| Type * toType = ((TypeInst*)inst)->getTypeInfo(); |
| assert(toType->isObject()); |
| Opnd *src = inst->getSrc(0); |
| Opnd *tauCheckedNull = inst->getSrc(1); |
| assert(tauCheckedNull->getType()->tag == Type::Tau); |
| cgInst = instructionCallback.tau_asType((ObjectType *)toType, |
| getCGInst(src), |
| getCGInst(tauCheckedNull)); |
| } |
| break; |
| case Op_TauInstanceOf: |
| { |
| assert(inst->getNumSrcOperands() == 2); |
| Type * toType = ((TypeInst*)inst)->getTypeInfo(); |
| assert(toType->isObject()); |
| Opnd *src = inst->getSrc(0); |
| Opnd *tauCheckedNull = inst->getSrc(1); |
| assert(tauCheckedNull->getType()->tag == Type::Tau); |
| cgInst = instructionCallback.tau_instanceOf((ObjectType *)toType, |
| getCGInst(src), |
| getCGInst(tauCheckedNull)); |
| } |
| break; |
| case Op_InitType: |
| { |
| assert(inst->getNumSrcOperands() == 0); |
| TypeInst *typeInst = (TypeInst*)inst; |
| instructionCallback.initType(typeInst->getTypeInfo()); |
| } |
| break; |
| case Op_Label: |
| break; // nothing to do |
| case Op_MethodEntry: |
| { |
| assert(inst->isMethodMarker()); |
| MethodMarkerInst* methEntryInst = inst->asMethodMarkerInst(); |
| instructionCallback.methodEntry(methEntryInst->getMethodDesc()); |
| } |
| break; // nothing to do |
| case Op_MethodEnd: |
| { |
| assert(inst->isMethodMarker()); |
| MethodMarkerInst* methEntryInst = inst->asMethodMarkerInst(); |
| // check that inst->getSrc(0) is really retOpnd and not thisOpnd |
| CG_OpndHandle* ret_val = inst->getNumSrcOperands()==0 ? NULL : |
| getCGInst(inst->getSrc(0)); |
| instructionCallback.methodEnd(methEntryInst->getMethodDesc(), |
| ret_val); |
| } |
| break; // nothing to do |
| case Op_Phi: |
| { |
| assert(0); // Phi nodes should be eliminated by deSSAing |
| } |
| break; |
| case Op_TauPi: |
| { |
| assert(0); |
| } |
| break; |
| case Op_IncCounter: |
| { |
| TokenInst *counterInst = (TokenInst *)inst; |
| U_32 counter = counterInst->getToken(); |
| instructionCallback.incCounter(irmanager.getTypeManager().getUInt32Type(), counter); |
| } |
| break; |
| case Op_Prefetch: |
| { |
| assert(inst->getNumSrcOperands() == 1); |
| Opnd* addr= inst->getSrc(0); |
| instructionCallback.prefetch(getCGInst(addr)); |
| } |
| break; |
| case Op_TauPoint: |
| { |
| assert(inst->getNumSrcOperands() == 0); |
| cgInst = instructionCallback.tauPoint(); |
| } |
| break; |
| case Op_TauEdge: |
| { |
| assert(inst->getNumSrcOperands() == 0); |
| cgInst = instructionCallback.tauEdge(); |
| } |
| break; |
| case Op_TauAnd: |
| { |
| U_32 numSrcs = inst->getNumSrcOperands(); |
| CG_OpndHandle **args = genCallArgs(inst, 0); |
| cgInst = instructionCallback.tauAnd(numSrcs, args); |
| } |
| break; |
| case Op_TauUnsafe: |
| { |
| assert(inst->getNumSrcOperands() == 0); |
| cgInst = instructionCallback.tauUnsafe(); |
| } |
| break; |
| case Op_TauSafe: |
| { |
| assert(inst->getNumSrcOperands() == 0); |
| cgInst = instructionCallback.tauSafe(); |
| } |
| break; |
| case Op_TauCheckCast: |
| { |
| assert(inst->getNumSrcOperands() == 2); |
| Opnd *src = inst->getSrc(0); |
| Opnd *tauCheckedNull = inst->getSrc(1); |
| assert(tauCheckedNull->getType()->tag == Type::Tau); |
| Type * toType = ((TypeInst*)inst)->getTypeInfo(); |
| assert(toType->isObject()); |
| cgInst = instructionCallback.tau_checkCast((ObjectType *)toType, |
| getCGInst(src), |
| getCGInst(tauCheckedNull)); |
| } |
| break; |
| case Op_TauHasType: |
| { |
| cgInst = instructionCallback.tauPoint(); |
| } |
| break; |
| case Op_TauHasExactType: |
| { |
| cgInst = instructionCallback.tauPoint(); |
| } |
| break; |
| case Op_TauIsNonNull: |
| { |
| cgInst = instructionCallback.tauPoint(); |
| } |
| break; |
| default: |
| assert(0); |
| } // end switch |
| |
| if (cgInst) { // record mapping from dst |
| if(Log::isEnabled()) { |
| Log::out() << "genInstCode "; |
| inst->print(Log::out()); |
| if (genConsts) { |
| Log::out() << "; genConsts=true"; |
| } else { |
| Log::out() << "; genConsts=false"; |
| } |
| Log::out() << " has cgInst" << ::std::endl; |
| } |
| |
| assert(dst); |
| if (isConstant) { |
| if(Log::isEnabled()) { |
| Log::out() << " isConstant" << ::std::endl; |
| } |
| assert(genConsts); |
| if (sinkConstants) { |
| if(Log::isEnabled()) { |
| Log::out() << " sinkConstants=true" << ::std::endl; |
| } |
| setLocalCGInst(cgInst, dst); |
| } else { |
| if(Log::isEnabled()) { |
| Log::out() << " sinkConstants=false" << ::std::endl; |
| } |
| setCGInst(cgInst, dst); |
| } |
| } else { |
| if(Log::isEnabled()) { |
| Log::out() << " isConstant=false" << ::std::endl; |
| } |
| setCGInst(cgInst, dst); |
| if (sinkConstants && sinkConstantsOne) { |
| // we just finished a non-constant inst, clear the constant inst map |
| clearLocalCGInsts(); |
| } |
| } |
| } else { |
| if(Log::isEnabled()) { |
| Log::out() << "genInstCode "; |
| inst->print(Log::out()); |
| if (genConsts) { |
| Log::out() << "; genConsts=true"; |
| } else { |
| Log::out() << "; genConsts=false"; |
| } |
| Log::out() << " has NO cgInst" << ::std::endl; |
| } |
| } |
| } |
| |
| void _BlockCodeSelector::genCode(InstructionCallback& instructionCallback) { |
| callback = &instructionCallback; |
| // |
| // go through instructions |
| // |
| Inst* labelInst = (Inst*)block->getFirstInst(); |
| Inst* inst = labelInst->getNextInst(); |
| while (inst != NULL) { |
| if(Log::isEnabled()) { |
| Log::out() << "Code select "; |
| inst->print(Log::out()); |
| Log::out() << ::std::endl; |
| } |
| genInstCode(instructionCallback, inst, !sinkConstants); |
| inst = inst->getNextInst(); |
| } |
| } |
| |
| CG_OpndHandle* _BlockCodeSelector::getCGInst(Opnd* opnd) { |
| CG_OpndHandle *res = opndToCGInstMap[opnd->getId()]; |
| if (!res) { |
| assert(sinkConstants); |
| res = localOpndToCGInstMap[opnd->getId()]; |
| if (!res) { |
| uint16 savedBCOffset = callback->getCurrentHIRInstBCOffset(); |
| genInstCode(*callback, opnd->getInst(), true); // generate code for the constant |
| res = localOpndToCGInstMap[opnd->getId()]; |
| assert(res); |
| callback->setCurrentHIRInstBCOffset(savedBCOffset); |
| } |
| } |
| return res; |
| } |
| |
| void _BlockCodeSelector::setLocalCGInst(CG_OpndHandle* inst, Opnd* opnd) { |
| assert(sinkConstants); |
| localOpndToCGInstMap[opnd->getId()] = inst; |
| } |
| |
| void _BlockCodeSelector::clearLocalCGInsts() { |
| assert(sinkConstants && sinkConstantsOne); |
| localOpndToCGInstMap.clear(); |
| } |
| |
| void _BlockCodeSelector::setCGInst(CG_OpndHandle* inst,Opnd* opnd) { |
| opndToCGInstMap[opnd->getId()] = inst; |
| if (opnd->isGlobal()) |
| callback->opndMaybeGlobal(inst); |
| } |
| |
| U_32 _BlockCodeSelector::getVarHandle(VarOpnd *var) { |
| return varIdMap[var->getId()]; |
| } |
| |
| |
| void _CFGCodeSelector::genCode(Callback& callback) { |
| bool hasEdgeProfile = flowGraph->hasEdgeProfile(); |
| // |
| // go through nodes in flow graph and call genDispatchNode for nodes |
| // that are handlers (dispatchers) and genBlock for nodes that are blocks. |
| // record the integer id that is returned and map it to the node. |
| // |
| |
| // |
| // this table maps from a node's depth-first number to the |
| // node id returned by the code selector |
| // |
| StlVector<MethodDesc*> inlineEndMarkers(memManager); |
| U_32* nodeMapTable = new (memManager) U_32[numNodes]; |
| |
| // Compute postorder list to get only reachable nodes. |
| const Nodes& nodes = flowGraph->getNodesPostOrder(); |
| |
| assert(flowGraph->getExitNode()->getTraversalNum() == flowGraph->getTraversalNum()); |
| Node* unwind = flowGraph->getUnwindNode(); |
| Node* exit = flowGraph->getExitNode(); |
| // Use reverse iterator to generate nodes in reverse postorder. |
| Nodes::const_reverse_iterator niter; |
| for(niter = nodes.rbegin(); niter != nodes.rend(); ++niter) { |
| Node* node = *niter; |
| // |
| // Count in and out edges |
| // |
| U_32 numOutEdges = node->getOutDegree(); |
| U_32 numInEdges = node->getInDegree(); |
| U_32 nodeId = MAX_UINT32; |
| double cnt = (hasEdgeProfile? node->getExecCount() : -1.0); |
| |
| if (node == exit) { |
| nodeId = callback.genExitNode(numInEdges,cnt); |
| } |
| else if (node == unwind) { |
| nodeId = callback.genUnwindNode(numInEdges,numOutEdges,cnt); |
| } |
| else if (node->isBlockNode()) { |
| _BlockCodeSelector blockCodeSelector(memManager, |
| irmanager, |
| node, |
| opndToCGInstMap, |
| varIdMap, |
| sinkConstants, |
| sinkConstantsOne); |
| |
| |
| // |
| // Derive the block kind (prolog, epilog, inner block) |
| // |
| CFGCodeSelector::Callback::BlockKind blockKind; |
| if (node == flowGraph->getEntryNode()) |
| blockKind = CFGCodeSelector::Callback::Prolog; |
| else if (node == flowGraph->getReturnNode()) |
| blockKind = CFGCodeSelector::Callback::Epilog; |
| else |
| blockKind = CFGCodeSelector::Callback::InnerBlock; |
| nodeId = callback.genBlock(numInEdges, |
| numOutEdges, |
| blockKind, |
| blockCodeSelector, |
| cnt); |
| |
| } else if (node->isDispatchNode()) { |
| if(node->getSecondInst()!=NULL) { |
| for (Inst* inst = (Inst*)node->getSecondInst(); inst!=NULL; inst = inst->getNextInst()) { |
| assert(inst->isMethodMarker()); |
| MethodMarkerInst* marker = inst->asMethodMarkerInst(); |
| assert(marker->getOpcode() == Op_MethodEnd); |
| inlineEndMarkers.push_back(marker->getMethodDesc()); |
| } |
| } |
| nodeId = callback.genDispatchNode(numInEdges,numOutEdges,inlineEndMarkers, cnt); |
| inlineEndMarkers.clear(); |
| } |
| assert(nodeId < numNodes); |
| callback.setPersistentId(nodeId, node->getId()); |
| nodeMapTable[node->getDfNum()] = nodeId; |
| } |
| // |
| // go through edges in flow graph |
| // |
| for(niter = nodes.rbegin(); niter != nodes.rend(); ++niter) { |
| double prob; |
| Node* tailNode = *niter; |
| U_32 tailNodeId = nodeMapTable[tailNode->getDfNum()]; |
| if (((Inst*)tailNode->getLastInst())->isSwitch()) { |
| // |
| // Generate switch edges |
| // |
| SwitchInst* sw = (SwitchInst *)tailNode->getLastInst(); |
| Node *defaultNode = sw->getDefaultTarget()->getNode(); |
| U_32 defaultNodeId = nodeMapTable[defaultNode->getDfNum()]; |
| U_32 numTargets = sw->getNumTargets(); |
| U_32 * targetNodeIds = new (memManager) U_32[numTargets]; |
| double * targetProbs = new (memManager) double[numTargets]; |
| U_32 i; |
| for (i = 0; i < numTargets; i++) { |
| Node *headNode = sw->getTarget(i)->getNode(); |
| Edge *edge = (Edge *) tailNode->findTargetEdge(headNode); |
| targetNodeIds[i] = nodeMapTable[headNode->getDfNum()]; |
| targetProbs[i] = (hasEdgeProfile? edge->getEdgeProb() : -1.0); |
| } |
| callback.genSwitchEdges(tailNodeId,numTargets,targetNodeIds, |
| targetProbs, defaultNodeId); |
| // |
| // Generate an exception edge if it exists |
| // |
| Edge* throwEdge = (Edge*) tailNode->getExceptionEdge(); |
| if(throwEdge != NULL) { |
| assert(0); |
| Node *succNode = throwEdge->getTargetNode(); |
| assert(succNode->isDispatchNode()); |
| U_32 headNodeId = nodeMapTable[succNode->getDfNum()]; |
| prob = (hasEdgeProfile? throwEdge->getEdgeProb() : -1.0); |
| callback.genExceptionEdge(tailNodeId,headNodeId,prob); |
| } |
| } |
| else { |
| // |
| // Gen edges for a node that does not end with a switch |
| // |
| const Edges& edges = tailNode->getOutEdges(); |
| Edges::const_iterator eiter; |
| for(eiter = edges.begin(); eiter != edges.end(); ++eiter) { |
| Edge* edge = *eiter; |
| prob = (hasEdgeProfile? edge->getEdgeProb() : -1.0); |
| Node * headNode = edge->getTargetNode(); |
| U_32 headNodeId = nodeMapTable[headNode->getDfNum()]; |
| Edge::Kind edgeKind = edge->getKind(); |
| switch (edgeKind) { |
| case Edge::Kind_Unconditional: |
| callback.genUnconditionalEdge(tailNodeId,headNodeId,prob); |
| break; |
| case Edge::Kind_True: |
| callback.genTrueEdge(tailNodeId,headNodeId,prob); |
| break; |
| case Edge::Kind_False: |
| callback.genFalseEdge(tailNodeId,headNodeId,prob); |
| break; |
| case Edge::Kind_Dispatch: |
| callback.genExceptionEdge(tailNodeId,headNodeId,prob); |
| break; |
| case Edge::Kind_Catch: |
| { |
| Inst* first = (Inst*)headNode->getFirstInst(); |
| assert(first->isLabel() && |
| ((LabelInst*)first)->isCatchLabel()); |
| CatchLabelInst * label = (CatchLabelInst *)first; |
| callback.genCatchEdge(tailNodeId,headNodeId, |
| label->getOrder(), |
| label->getExceptionType(), |
| prob); |
| break; |
| } |
| default: |
| assert(0); |
| } |
| } |
| } |
| } |
| } |
| |
| void _MethodCodeSelector::selectCode(Callback& callback) { |
| MemoryManager localMemManager("_MethodCodeSelector::genCode.localMemManager"); |
| |
| callback.setMethodDesc(methodDesc); |
| |
| U_32 *varIdMap = new (localMemManager) U_32[numVars]; |
| U_32 i; |
| for (i = 0; i < numVars; i++) { |
| varIdMap[i] = 0; |
| } |
| _VarCodeSelector varCodeSelector(varOpnds,varIdMap,irmanager.getGCBasePointerMap()); |
| callback.genVars(varCodeSelector.getNumVarOpnds(),varCodeSelector); |
| |
| CG_OpndHandle** opndToCGInstMap = new (localMemManager) CG_OpndHandle*[numOpnds]; |
| for (i=0; i<numOpnds; i++) { |
| opndToCGInstMap[i] = NULL; |
| } |
| _CFGCodeSelector cfgCodeSelector(localMemManager,irmanager,flowGraph,opndToCGInstMap, |
| varIdMap, sinkConstants, sinkConstantsOne); |
| |
| bool hasEdgeProfile = flowGraph->hasEdgeProfile(); |
| |
| callback.genCFG(cfgCodeSelector.getNumNodes(),cfgCodeSelector, hasEdgeProfile); |
| } |
| |
| } //namespace Jitrino |